From 64fe1db806050d5d794ad8bdf83554faed84308c Mon Sep 17 00:00:00 2001 From: twoeths Date: Fri, 9 Aug 2024 21:19:45 +0700 Subject: [PATCH 001/259] fix: improve sync pubkeys (#7010) * fix: improve sync pubkeys * fix: lint --- packages/state-transition/src/cache/epochCache.ts | 12 ++++++------ .../state-transition/src/cache/pubkeyCache.ts | 15 ++++++--------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 8f15dab90535..191aa7f3985c 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -264,12 +264,6 @@ export class EpochCache { {config, pubkey2index, index2pubkey}: EpochCacheImmutableData, opts?: EpochCacheOpts ): EpochCache { - // syncPubkeys here to ensure EpochCacheImmutableData is popualted before computing the rest of caches - // - computeSyncCommitteeCache() needs a fully populated pubkey2index cache - if (!opts?.skipSyncPubkeys) { - syncPubkeys(state, pubkey2index, index2pubkey); - } - const currentEpoch = computeEpochAtSlot(state.slot); const isGenesis = currentEpoch === GENESIS_EPOCH; const previousEpoch = isGenesis ? GENESIS_EPOCH : currentEpoch - 1; @@ -282,6 +276,12 @@ export class EpochCache { const validators = state.validators.getAllReadonlyValues(); const validatorCount = validators.length; + // syncPubkeys here to ensure EpochCacheImmutableData is popualted before computing the rest of caches + // - computeSyncCommitteeCache() needs a fully populated pubkey2index cache + if (!opts?.skipSyncPubkeys) { + syncPubkeys(validators, pubkey2index, index2pubkey); + } + const effectiveBalanceIncrements = getEffectiveBalanceIncrementsWithLen(validatorCount); const totalSlashingsByIncrement = getTotalSlashingsByIncrement(state); const previousActiveIndices: ValidatorIndex[] = []; diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 0fd7a80fe990..b2b45ca09d25 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -1,6 +1,5 @@ import {PublicKey} from "@chainsafe/blst"; -import {ValidatorIndex} from "@lodestar/types"; -import {BeaconStateAllForks} from "./types.js"; +import {ValidatorIndex, phase0} from "@lodestar/types"; export type Index2PubkeyCache = PublicKey[]; @@ -53,7 +52,7 @@ export class PubkeyIndexMap { * If pubkey caches are empty: SLOW CODE - 🐢 */ export function syncPubkeys( - state: BeaconStateAllForks, + validators: phase0.Validator[], pubkey2index: PubkeyIndexMap, index2pubkey: Index2PubkeyCache ): void { @@ -61,16 +60,14 @@ export function syncPubkeys( throw new Error(`Pubkey indices have fallen out of sync: ${pubkey2index.size} != ${index2pubkey.length}`); } - // Get the validators sub tree once for all the loop - const validators = state.validators; - - const newCount = state.validators.length; + const newCount = validators.length; + index2pubkey.length = newCount; for (let i = pubkey2index.size; i < newCount; i++) { - const pubkey = validators.getReadonly(i).pubkey; + const pubkey = validators[i].pubkey; pubkey2index.set(pubkey, i); // Pubkeys must be checked for group + inf. This must be done only once when the validator deposit is processed. // Afterwards any public key is the state consider validated. // > Do not do any validation here - index2pubkey.push(PublicKey.fromBytes(pubkey)); // Optimize for aggregation + index2pubkey[i] = PublicKey.fromBytes(pubkey); // Optimize for aggregation } } From 9c62011986a2b5d97ba81943e4d2169a1e94e880 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 13 Aug 2024 21:13:50 +0100 Subject: [PATCH 002/259] chore: update docker build actions (#7014) --- .github/workflows/publish-dev.yml | 6 +++--- .github/workflows/publish-rc.yml | 11 ++++++----- .github/workflows/publish-stable.yml | 11 ++++++----- Dockerfile | 4 ++-- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/.github/workflows/publish-dev.yml b/.github/workflows/publish-dev.yml index fb4197b75da9..4e8c76e0dfdd 100644 --- a/.github/workflows/publish-dev.yml +++ b/.github/workflows/publish-dev.yml @@ -112,12 +112,12 @@ jobs: - uses: actions/checkout@v4 # https://github.com/docker/setup-qemu-action - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/setup-buildx-action - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/publish-rc.yml b/.github/workflows/publish-rc.yml index f8f3b21ff349..936072de42c9 100644 --- a/.github/workflows/publish-rc.yml +++ b/.github/workflows/publish-rc.yml @@ -114,10 +114,11 @@ jobs: # In case of failure - name: Rollback on failure if: failure() - uses: author/action-rollback@9ec72a6af74774e00343c6de3e946b0901c23013 + uses: author/action-rollback@1.0.4 with: - id: ${{ steps.create_release.outputs.id }} + release_id: ${{ steps.create_release.outputs.id }} tag: ${{ needs.tag.outputs.tag }} + delete_orphan_tag: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -131,12 +132,12 @@ jobs: - run: scripts/await-release.sh ${{ needs.tag.outputs.tag }} rc 900 # https://github.com/docker/setup-qemu-action - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/setup-buildx-action - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/publish-stable.yml b/.github/workflows/publish-stable.yml index 9c41693f26f2..c2909a7e4e24 100644 --- a/.github/workflows/publish-stable.yml +++ b/.github/workflows/publish-stable.yml @@ -104,10 +104,11 @@ jobs: # In case of failure - name: Rollback on failure if: failure() - uses: author/action-rollback@9ec72a6af74774e00343c6de3e946b0901c23013 + uses: author/action-rollback@1.0.4 with: - id: ${{ steps.create_release.outputs.id }} + release_id: ${{ steps.create_release.outputs.id }} tag: ${{ needs.tag.outputs.tag }} + delete_orphan_tag: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -131,12 +132,12 @@ jobs: - run: scripts/await-release.sh ${{ needs.tag.outputs.tag }} latest 900 # https://github.com/docker/setup-qemu-action - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/setup-buildx-action - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile index e4b90c50bd20..0ee8083c85e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # --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:22.4-slim as build_src +FROM --platform=${BUILDPLATFORM:-amd64} node:22.4-slim AS build_src ARG COMMIT WORKDIR /usr/app RUN apt-get update && apt-get install -y g++ make python3 python3-setuptools && apt-get clean && rm -rf /var/lib/apt/lists/* @@ -21,7 +21,7 @@ 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:22.4-slim as build_deps +FROM node:22.4-slim AS build_deps WORKDIR /usr/app RUN apt-get update && apt-get install -y g++ make python3 python3-setuptools && apt-get clean && rm -rf /var/lib/apt/lists/* From 44b215667efb60366f28f7b11c97c7c092a3dffc Mon Sep 17 00:00:00 2001 From: twoeths Date: Wed, 14 Aug 2024 03:39:04 +0700 Subject: [PATCH 003/259] fix: reuse Buffer instance (#7016) * fix: improve message id to string conversion * fix: use shared Buffers for sszBytes util * feat: implement toRootHex() * fix: lint and check-types * Fix type checks * Add comment to vitest config * Update packages/utils/src/bytes.ts --------- Co-authored-by: Nico Flaig Co-authored-by: Cayman --- .../beacon-node/src/chain/balancesCache.ts | 4 +- .../src/chain/blocks/importBlock.ts | 10 ++-- .../chain/blocks/verifyBlocksSanityChecks.ts | 4 +- packages/beacon-node/src/chain/chain.ts | 18 ++++---- .../src/chain/errors/attestationError.ts | 4 +- .../src/chain/errors/blockError.ts | 7 ++- .../beacon-node/src/chain/forkChoice/index.ts | 16 +++---- packages/beacon-node/src/chain/initState.ts | 13 +++--- .../src/chain/lightClient/index.ts | 20 ++++---- .../opPools/aggregatedAttestationPool.ts | 5 +- .../beacon-node/src/chain/opPools/opPool.ts | 3 +- .../chain/opPools/syncCommitteeMessagePool.ts | 8 ++-- .../opPools/syncContributionAndProofPool.ts | 8 ++-- .../beacon-node/src/chain/regen/queued.ts | 7 ++- packages/beacon-node/src/chain/regen/regen.ts | 8 ++-- .../seenCache/seenCommitteeContribution.ts | 5 +- .../chain/seenCache/seenGossipBlockInput.ts | 9 ++-- .../beacon-node/src/chain/shufflingCache.ts | 5 +- .../chain/stateCache/blockStateCacheImpl.ts | 8 ++-- .../chain/stateCache/fifoBlockStateCache.ts | 6 +-- .../stateCache/inMemoryCheckpointsCache.ts | 9 ++-- .../stateCache/persistentCheckpointsCache.ts | 16 +++---- .../src/chain/validation/aggregateAndProof.ts | 4 +- .../src/chain/validation/attestation.ts | 12 ++--- .../beacon-node/src/chain/validation/block.ts | 7 ++- .../src/chain/validation/syncCommittee.ts | 4 +- .../beacon-node/src/eth1/utils/deposits.ts | 6 +-- .../src/network/gossip/encoding.ts | 9 +++- .../src/network/processor/gossipHandlers.ts | 9 ++-- .../reqresp/handlers/beaconBlocksByRoot.ts | 4 +- .../beacon-node/src/sync/backfill/backfill.ts | 25 +++++----- packages/beacon-node/src/sync/range/chain.ts | 5 +- packages/beacon-node/src/sync/unknownBlock.ts | 26 +++++------ packages/beacon-node/src/util/sszBytes.ts | 28 +++++++---- .../test/perf/network/gossip/encoding.test.ts | 46 +++++++++++++++++++ .../fork-choice/src/forkChoice/forkChoice.ts | 24 +++++----- packages/fork-choice/src/forkChoice/store.ts | 4 +- packages/utils/src/bytes.ts | 11 +++++ packages/utils/test/perf/bytes.test.ts | 27 +++++++++++ packages/utils/vitest.config.ts | 5 ++ 40 files changed, 268 insertions(+), 181 deletions(-) create mode 100644 packages/beacon-node/test/perf/network/gossip/encoding.test.ts create mode 100644 packages/utils/test/perf/bytes.test.ts diff --git a/packages/beacon-node/src/chain/balancesCache.ts b/packages/beacon-node/src/chain/balancesCache.ts index 5f4cf218c341..50a86b31b6c8 100644 --- a/packages/beacon-node/src/chain/balancesCache.ts +++ b/packages/beacon-node/src/chain/balancesCache.ts @@ -7,7 +7,7 @@ import { } from "@lodestar/state-transition"; import {CheckpointWithHex} from "@lodestar/fork-choice"; import {Epoch, RootHex} from "@lodestar/types"; -import {toHexString} from "@lodestar/utils"; +import {toRootHex} from "@lodestar/utils"; /** The number of validator balance sets that are cached within `CheckpointBalancesCache`. */ const MAX_BALANCE_CACHE_SIZE = 4; @@ -33,7 +33,7 @@ export class CheckpointBalancesCache { const epoch = state.epochCtx.epoch; const epochBoundarySlot = computeStartSlotAtEpoch(epoch); const epochBoundaryRoot = - epochBoundarySlot === state.slot ? blockRootHex : toHexString(getBlockRootAtSlot(state, epochBoundarySlot)); + epochBoundarySlot === state.slot ? blockRootHex : toRootHex(getBlockRootAtSlot(state, epochBoundarySlot)); const index = this.items.findIndex((item) => item.epoch === epoch && item.rootHex == epochBoundaryRoot); if (index === -1) { diff --git a/packages/beacon-node/src/chain/blocks/importBlock.ts b/packages/beacon-node/src/chain/blocks/importBlock.ts index 9d46410a8638..360a3f8f5db9 100644 --- a/packages/beacon-node/src/chain/blocks/importBlock.ts +++ b/packages/beacon-node/src/chain/blocks/importBlock.ts @@ -10,7 +10,7 @@ import { } from "@lodestar/state-transition"; import {routes} from "@lodestar/api"; import {ForkChoiceError, ForkChoiceErrorCode, EpochDifference, AncestorStatus} from "@lodestar/fork-choice"; -import {isErrorAborted} from "@lodestar/utils"; +import {isErrorAborted, toRootHex} from "@lodestar/utils"; import {ZERO_HASH_HEX} from "../../constants/index.js"; import {toCheckpointHex} from "../stateCache/index.js"; import {isOptimisticBlock} from "../../util/forkChoice.js"; @@ -62,7 +62,7 @@ export async function importBlock( const {block, source} = blockInput; const {slot: blockSlot} = block.message; const blockRoot = this.config.getForkTypes(blockSlot).BeaconBlock.hashTreeRoot(block.message); - const blockRootHex = toHexString(blockRoot); + const blockRootHex = toRootHex(blockRoot); const currentEpoch = computeEpochAtSlot(this.forkChoice.getTime()); const blockEpoch = computeEpochAtSlot(blockSlot); const parentEpoch = computeEpochAtSlot(parentBlockSlot); @@ -123,7 +123,7 @@ export async function importBlock( const indexedAttestation = postState.epochCtx.getIndexedAttestation(attestation); const {target, beaconBlockRoot} = attestation.data; - const attDataRoot = toHexString(ssz.phase0.AttestationData.hashTreeRoot(indexedAttestation.data)); + const attDataRoot = toRootHex(ssz.phase0.AttestationData.hashTreeRoot(indexedAttestation.data)); this.seenAggregatedAttestations.add( target.epoch, attDataRoot, @@ -371,9 +371,9 @@ export async function importBlock( const preFinalizedEpoch = parentBlockSummary.finalizedEpoch; if (finalizedEpoch > preFinalizedEpoch) { this.emitter.emit(routes.events.EventType.finalizedCheckpoint, { - block: toHexString(finalizedCheckpoint.root), + block: toRootHex(finalizedCheckpoint.root), epoch: finalizedCheckpoint.epoch, - state: toHexString(checkpointState.hashTreeRoot()), + state: toRootHex(checkpointState.hashTreeRoot()), executionOptimistic: false, }); this.logger.verbose("Checkpoint finalized", toCheckpointHex(finalizedCheckpoint)); diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts index e62355a4889d..fcbcfea05d6e 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts @@ -2,7 +2,7 @@ import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {Slot} from "@lodestar/types"; -import {toHexString} from "@lodestar/utils"; +import {toHexString, toRootHex} from "@lodestar/utils"; import {IClock} from "../../util/clock.js"; import {BlockError, BlockErrorCode} from "../errors/index.js"; import {BlockInput, ImportBlockOpts} from "./types.js"; @@ -67,7 +67,7 @@ export function verifyBlocksSanityChecks( parentBlockSlot = relevantBlocks[relevantBlocks.length - 1].block.message.slot; } else { // When importing a block segment, only the first NON-IGNORED block must be known to the fork-choice. - const parentRoot = toHexString(block.message.parentRoot); + const parentRoot = toRootHex(block.message.parentRoot); parentBlock = chain.forkChoice.getBlockHex(parentRoot); if (!parentBlock) { throw new BlockError(block, {code: BlockErrorCode.PARENT_UNKNOWN, parentRoot}); diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index a12ee4a21f64..43f72d81e882 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import {CompositeTypeAny, fromHexString, TreeView, Type, toHexString} from "@chainsafe/ssz"; +import {CompositeTypeAny, fromHexString, TreeView, Type} from "@chainsafe/ssz"; import { BeaconStateAllForks, CachedBeaconStateAllForks, @@ -35,7 +35,7 @@ import { } from "@lodestar/types"; import {CheckpointWithHex, ExecutionStatus, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice"; import {ProcessShutdownCallback} from "@lodestar/validator"; -import {Logger, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toHex} from "@lodestar/utils"; +import {Logger, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toHex, toRootHex} from "@lodestar/utils"; import {ForkSeq, GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; import {GENESIS_EPOCH, ZERO_HASH} from "../constants/index.js"; @@ -592,7 +592,7 @@ export class BeaconChain implements IBeaconChain { async produceCommonBlockBody(blockAttributes: BlockAttributes): Promise { const {slot, parentBlockRoot} = blockAttributes; const state = await this.regen.getBlockSlotState( - toHexString(parentBlockRoot), + toRootHex(parentBlockRoot), slot, {dontTransferCache: true}, RegenCaller.produceBlock @@ -641,7 +641,7 @@ export class BeaconChain implements IBeaconChain { shouldOverrideBuilder?: boolean; }> { const state = await this.regen.getBlockSlotState( - toHexString(parentBlockRoot), + toRootHex(parentBlockRoot), slot, {dontTransferCache: true}, RegenCaller.produceBlock @@ -673,7 +673,7 @@ export class BeaconChain implements IBeaconChain { : this.config.getExecutionForkTypes(slot).BlindedBeaconBlockBody.hashTreeRoot(body as BlindedBeaconBlockBody); this.logger.debug("Computing block post state from the produced body", { slot, - bodyRoot: toHexString(bodyRoot), + bodyRoot: toRootHex(bodyRoot), blockType, }); @@ -1152,10 +1152,10 @@ export class BeaconChain implements IBeaconChain { const preState = this.regen.getPreStateSync(block); if (preState === null) { - throw Error(`Pre-state is unavailable given block's parent root ${toHexString(block.parentRoot)}`); + throw Error(`Pre-state is unavailable given block's parent root ${toRootHex(block.parentRoot)}`); } - const postState = this.regen.getStateSync(toHexString(block.stateRoot)) ?? undefined; + const postState = this.regen.getStateSync(toRootHex(block.stateRoot)) ?? undefined; return computeBlockRewards(block, preState.clone(), postState?.clone()); } @@ -1173,7 +1173,7 @@ export class BeaconChain implements IBeaconChain { } const {executionOptimistic, finalized} = stateResult; - const stateRoot = toHexString(stateResult.state.hashTreeRoot()); + const stateRoot = toRootHex(stateResult.state.hashTreeRoot()); const cachedState = this.regen.getStateSync(stateRoot); @@ -1193,7 +1193,7 @@ export class BeaconChain implements IBeaconChain { const preState = this.regen.getPreStateSync(block); if (preState === null) { - throw Error(`Pre-state is unavailable given block's parent root ${toHexString(block.parentRoot)}`); + throw Error(`Pre-state is unavailable given block's parent root ${toRootHex(block.parentRoot)}`); } return computeSyncCommitteeRewards(block, preState.clone(), validatorIds); diff --git a/packages/beacon-node/src/chain/errors/attestationError.ts b/packages/beacon-node/src/chain/errors/attestationError.ts index 8e0dc925f32e..fa0635bc0115 100644 --- a/packages/beacon-node/src/chain/errors/attestationError.ts +++ b/packages/beacon-node/src/chain/errors/attestationError.ts @@ -1,5 +1,5 @@ -import {toHexString} from "@chainsafe/ssz"; import {Epoch, Slot, ValidatorIndex, RootHex} from "@lodestar/types"; +import {toRootHex} from "@lodestar/utils"; import {GossipActionError} from "./gossipValidation.js"; export enum AttestationErrorCode { @@ -167,7 +167,7 @@ export class AttestationError extends GossipActionError { const type = this.type; switch (type.code) { case AttestationErrorCode.UNKNOWN_TARGET_ROOT: - return {code: type.code, root: toHexString(type.root)}; + return {code: type.code, root: toRootHex(type.root)}; case AttestationErrorCode.MISSING_STATE_TO_VERIFY_ATTESTATION: // TODO: The stack trace gets lost here return {code: type.code, error: type.error.message}; diff --git a/packages/beacon-node/src/chain/errors/blockError.ts b/packages/beacon-node/src/chain/errors/blockError.ts index 5f12bd939342..6280533c7a68 100644 --- a/packages/beacon-node/src/chain/errors/blockError.ts +++ b/packages/beacon-node/src/chain/errors/blockError.ts @@ -1,6 +1,5 @@ -import {toHexString} from "@chainsafe/ssz"; import {RootHex, SignedBeaconBlock, Slot, ValidatorIndex} from "@lodestar/types"; -import {LodestarError} from "@lodestar/utils"; +import {LodestarError, toRootHex} from "@lodestar/utils"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {ExecutionPayloadStatus} from "../../execution/engine/interface.js"; import {QueueErrorCode} from "../../util/queue/index.js"; @@ -151,8 +150,8 @@ export function renderBlockErrorType(type: BlockErrorType): Record { this.metrics?.lightclientServer.onSyncAggregate.inc({event: "processed"}); - const signedBlockRootHex = toHexString(signedBlockRoot); + const signedBlockRootHex = toRootHex(signedBlockRoot); const attestedData = this.prevHeadData.get(signedBlockRootHex); if (!attestedData) { // Log cacheSize since at start this.prevHeadData will be empty @@ -574,7 +574,7 @@ export class LightClientServer { } catch (e) { this.logger.error( "Error updating best LightClientUpdate", - {syncPeriod, slot: attestedHeader.beacon.slot, blockRoot: toHexString(attestedData.blockRoot)}, + {syncPeriod, slot: attestedHeader.beacon.slot, blockRoot: toRootHex(attestedData.blockRoot)}, e as Error ); } @@ -619,7 +619,7 @@ export class LightClientServer { const syncCommitteeWitness = await this.db.syncCommitteeWitness.get(attestedData.blockRoot); if (!syncCommitteeWitness) { - throw Error(`syncCommitteeWitness not available at ${toHexString(attestedData.blockRoot)}`); + throw Error(`syncCommitteeWitness not available at ${toRootHex(attestedData.blockRoot)}`); } const nextSyncCommittee = await this.db.syncCommittee.get(syncCommitteeWitness.nextSyncCommitteeRoot); if (!nextSyncCommittee) { @@ -697,7 +697,7 @@ export class LightClientServer { * Get finalized header from db. Keeps a small in-memory cache to speed up most of the lookups */ private async getFinalizedHeader(finalizedBlockRoot: Uint8Array): Promise { - const finalizedBlockRootHex = toHexString(finalizedBlockRoot); + const finalizedBlockRootHex = toRootHex(finalizedBlockRoot); const cachedFinalizedHeader = this.checkpointHeaders.get(finalizedBlockRootHex); if (cachedFinalizedHeader) { return cachedFinalizedHeader; diff --git a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts index 556e1f397d60..d896c9d3cc35 100644 --- a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import {aggregateSignatures} from "@chainsafe/blst"; import {ForkName, ForkSeq, MAX_ATTESTATIONS, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params"; import {phase0, Epoch, Slot, ssz, ValidatorIndex, RootHex} from "@lodestar/types"; @@ -11,7 +10,7 @@ import { getBlockRootAtSlot, } from "@lodestar/state-transition"; import {IForkChoice, EpochDifference} from "@lodestar/fork-choice"; -import {toHex, MapDef} from "@lodestar/utils"; +import {toHex, MapDef, toRootHex} from "@lodestar/utils"; import {intersectUint8Arrays, IntersectResult} from "../../util/bitArray.js"; import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; import {InsertOutcome} from "./types.js"; @@ -573,7 +572,7 @@ function isValidShuffling( // Otherwise the shuffling is determined by the block at the end of the target epoch // minus the shuffling lookahead (usually 2). We call this the "pivot". const pivotSlot = computeStartSlotAtEpoch(targetEpoch - 1) - 1; - const stateDependentRoot = toHexString(getBlockRootAtSlot(state, pivotSlot)); + const stateDependentRoot = toRootHex(getBlockRootAtSlot(state, pivotSlot)); // Use fork choice's view of the block DAG to quickly evaluate whether the attestation's // pivot block is the same as the current state's pivot block. If it is, then the diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index 69c331f6fd39..a991a6e8630a 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -16,6 +16,7 @@ import { ForkSeq, } from "@lodestar/params"; import {Epoch, phase0, capella, ssz, ValidatorIndex, SignedBeaconBlock} from "@lodestar/types"; +import {toRootHex} from "@lodestar/utils"; import {IBeaconDb} from "../../db/index.js"; import {SignedBLSToExecutionChangeVersioned} from "../../util/types.js"; import {BlockType} from "../interface.js"; @@ -135,7 +136,7 @@ export class OpPool { if (!rootHash) rootHash = ssz.phase0.AttesterSlashing.hashTreeRoot(attesterSlashing); // TODO: Do once and cache attached to the AttesterSlashing object const intersectingIndices = getAttesterSlashableIndices(attesterSlashing); - this.attesterSlashings.set(toHexString(rootHash), { + this.attesterSlashings.set(toRootHex(rootHash), { attesterSlashing, intersectingIndices, }); diff --git a/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts b/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts index 90a310841f01..bbaba1835dce 100644 --- a/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts +++ b/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts @@ -1,8 +1,8 @@ -import {BitArray, toHexString} from "@chainsafe/ssz"; +import {BitArray} from "@chainsafe/ssz"; import {Signature, aggregateSignatures} from "@chainsafe/blst"; import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {altair, Root, Slot, SubcommitteeIndex} from "@lodestar/types"; -import {MapDef} from "@lodestar/utils"; +import {MapDef, toRootHex} from "@lodestar/utils"; import {IClock} from "../../util/clock.js"; import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js"; import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; @@ -64,7 +64,7 @@ export class SyncCommitteeMessagePool { // TODO: indexInSubcommittee: number should be indicesInSyncCommittee add(subnet: Subnet, signature: altair.SyncCommitteeMessage, indexInSubcommittee: number): InsertOutcome { const {slot, beaconBlockRoot} = signature; - const rootHex = toHexString(beaconBlockRoot); + const rootHex = toRootHex(beaconBlockRoot); const lowestPermissibleSlot = this.lowestPermissibleSlot; // Reject if too old. @@ -99,7 +99,7 @@ export class SyncCommitteeMessagePool { * This is for the aggregator to produce ContributionAndProof. */ getContribution(subnet: SubcommitteeIndex, slot: Slot, prevBlockRoot: Root): altair.SyncCommitteeContribution | null { - const contribution = this.contributionsByRootBySubnetBySlot.get(slot)?.get(subnet)?.get(toHexString(prevBlockRoot)); + const contribution = this.contributionsByRootBySubnetBySlot.get(slot)?.get(subnet)?.get(toRootHex(prevBlockRoot)); if (!contribution) { return null; } diff --git a/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts b/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts index 7834ae534501..ff0feea891e1 100644 --- a/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts +++ b/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts @@ -1,9 +1,9 @@ -import {BitArray, toHexString} from "@chainsafe/ssz"; +import {BitArray} from "@chainsafe/ssz"; import {Signature, aggregateSignatures} from "@chainsafe/blst"; import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; import {altair, Slot, Root, ssz} from "@lodestar/types"; import {G2_POINT_AT_INFINITY} from "@lodestar/state-transition"; -import {MapDef} from "@lodestar/utils"; +import {MapDef, toRootHex} from "@lodestar/utils"; import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js"; import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; @@ -72,7 +72,7 @@ export class SyncContributionAndProofPool { add(contributionAndProof: altair.ContributionAndProof, syncCommitteeParticipants: number): InsertOutcome { const {contribution} = contributionAndProof; const {slot, beaconBlockRoot} = contribution; - const rootHex = toHexString(beaconBlockRoot); + const rootHex = toRootHex(beaconBlockRoot); // Reject if too old. if (slot < this.lowestPermissibleSlot) { @@ -100,7 +100,7 @@ export class SyncContributionAndProofPool { * This is for the block factory, the same to process_sync_committee_contributions in the spec. */ getAggregate(slot: Slot, prevBlockRoot: Root): altair.SyncAggregate { - const bestContributionBySubnet = this.bestContributionBySubnetRootBySlot.get(slot)?.get(toHexString(prevBlockRoot)); + const bestContributionBySubnet = this.bestContributionBySubnetRootBySlot.get(slot)?.get(toRootHex(prevBlockRoot)); if (!bestContributionBySubnet || bestContributionBySubnet.size === 0) { // TODO: Add metric for missing SyncAggregate // Must return signature as G2_POINT_AT_INFINITY when participating bits are empty diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index ad673b334bd1..082ffbe271e4 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -1,8 +1,7 @@ -import {toHexString} from "@chainsafe/ssz"; import {phase0, Slot, RootHex, Epoch, BeaconBlock} from "@lodestar/types"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition"; -import {Logger} from "@lodestar/utils"; +import {Logger, toRootHex} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {CheckpointHex, toCheckpointHex} from "../stateCache/index.js"; import {Metrics} from "../../metrics/index.js"; @@ -89,7 +88,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { block: BeaconBlock, opts: StateCloneOpts = {dontTransferCache: true} ): CachedBeaconStateAllForks | null { - const parentRoot = toHexString(block.parentRoot); + const parentRoot = toRootHex(block.parentRoot); const parentBlock = this.forkChoice.getBlockHex(parentRoot); if (!parentBlock) { throw new RegenError({ @@ -167,7 +166,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { updateHeadState(newHead: ProtoBlock, maybeHeadState: CachedBeaconStateAllForks): void { const {stateRoot: newHeadStateRoot, blockRoot: newHeadBlockRoot, slot: newHeadSlot} = newHead; - const maybeHeadStateRoot = toHexString(maybeHeadState.hashTreeRoot()); + const maybeHeadStateRoot = toRootHex(maybeHeadState.hashTreeRoot()); const logCtx = { newHeadSlot, newHeadBlockRoot, diff --git a/packages/beacon-node/src/chain/regen/regen.ts b/packages/beacon-node/src/chain/regen/regen.ts index 2b6fc835cf7c..409c12c77b21 100644 --- a/packages/beacon-node/src/chain/regen/regen.ts +++ b/packages/beacon-node/src/chain/regen/regen.ts @@ -1,4 +1,4 @@ -import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {fromHexString} from "@chainsafe/ssz"; import {phase0, Slot, RootHex, BeaconBlock} from "@lodestar/types"; import { CachedBeaconStateAllForks, @@ -10,7 +10,7 @@ import { stateTransition, } from "@lodestar/state-transition"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; -import {Logger} from "@lodestar/utils"; +import {Logger, toRootHex} from "@lodestar/utils"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; import {Metrics} from "../../metrics/index.js"; @@ -89,7 +89,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { allowDiskReload = false ): Promise { const checkpointStartSlot = computeStartSlotAtEpoch(cp.epoch); - return this.getBlockSlotState(toHexString(cp.root), checkpointStartSlot, opts, regenCaller, allowDiskReload); + return this.getBlockSlotState(toRootHex(cp.root), checkpointStartSlot, opts, regenCaller, allowDiskReload); } /** @@ -224,7 +224,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { this.modules.metrics ); - const stateRoot = toHexString(state.hashTreeRoot()); + const stateRoot = toRootHex(state.hashTreeRoot()); if (b.stateRoot !== stateRoot) { throw new RegenError({ slot: b.slot, diff --git a/packages/beacon-node/src/chain/seenCache/seenCommitteeContribution.ts b/packages/beacon-node/src/chain/seenCache/seenCommitteeContribution.ts index fedaff8225d6..86ade618b1d1 100644 --- a/packages/beacon-node/src/chain/seenCache/seenCommitteeContribution.ts +++ b/packages/beacon-node/src/chain/seenCache/seenCommitteeContribution.ts @@ -1,7 +1,6 @@ -import {toHexString} from "@chainsafe/ssz"; import {Slot, ValidatorIndex} from "@lodestar/types"; import {ContributionAndProof, SyncCommitteeContribution} from "@lodestar/types/altair"; -import {MapDef} from "@lodestar/utils"; +import {MapDef, toRootHex} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; import {isSuperSetOrEqual} from "../../util/bitArray.js"; import {AggregationInfo, insertDesc} from "./seenAggregateAndProof.js"; @@ -101,5 +100,5 @@ function seenAggregatorKey(subcommitteeIndex: number, aggregatorIndex: Validator function toContributionDataKey(contribution: SyncCommitteeContribution): ContributionDataKey { const {slot, beaconBlockRoot, subcommitteeIndex} = contribution; - return `${slot} - ${toHexString(beaconBlockRoot)} - ${subcommitteeIndex}`; + return `${slot} - ${toRootHex(beaconBlockRoot)} - ${subcommitteeIndex}`; } diff --git a/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts b/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts index 6b51332353f2..3806668436d8 100644 --- a/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts +++ b/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts @@ -1,7 +1,6 @@ -import {toHexString} from "@chainsafe/ssz"; import {deneb, RootHex, SignedBeaconBlock, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; -import {pruneSetToMax} from "@lodestar/utils"; +import {pruneSetToMax, toRootHex} from "@lodestar/utils"; import {BLOBSIDECAR_FIXED_SIZE, isForkBlobs, ForkName} from "@lodestar/params"; import { @@ -81,9 +80,7 @@ export class SeenGossipBlockInput { const {signedBlock, blockBytes} = gossipedInput; fork = config.getForkName(signedBlock.message.slot); - blockHex = toHexString( - config.getForkTypes(signedBlock.message.slot).BeaconBlock.hashTreeRoot(signedBlock.message) - ); + blockHex = toRootHex(config.getForkTypes(signedBlock.message.slot).BeaconBlock.hashTreeRoot(signedBlock.message)); blockCache = this.blockInputCache.get(blockHex) ?? getEmptyBlockInputCacheEntry(fork); blockCache.block = signedBlock; @@ -93,7 +90,7 @@ export class SeenGossipBlockInput { const blockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(blobSidecar.signedBlockHeader.message); fork = config.getForkName(blobSidecar.signedBlockHeader.message.slot); - blockHex = toHexString(blockRoot); + blockHex = toRootHex(blockRoot); blockCache = this.blockInputCache.get(blockHex) ?? getEmptyBlockInputCacheEntry(fork); // TODO: freetheblobs check if its the same blob or a duplicate and throw/take actions diff --git a/packages/beacon-node/src/chain/shufflingCache.ts b/packages/beacon-node/src/chain/shufflingCache.ts index 23177142d846..12dd1bf3e9ae 100644 --- a/packages/beacon-node/src/chain/shufflingCache.ts +++ b/packages/beacon-node/src/chain/shufflingCache.ts @@ -1,7 +1,6 @@ -import {toHexString} from "@chainsafe/ssz"; import {CachedBeaconStateAllForks, EpochShuffling, getShufflingDecisionBlock} from "@lodestar/state-transition"; import {Epoch, RootHex, ssz} from "@lodestar/types"; -import {MapDef, pruneSetToMax} from "@lodestar/utils"; +import {MapDef, pruneSetToMax, toRootHex} from "@lodestar/utils"; import {GENESIS_SLOT} from "@lodestar/params"; import {Metrics} from "../metrics/metrics.js"; import {computeAnchorCheckpoint} from "./initState.js"; @@ -206,5 +205,5 @@ function isPromiseCacheItem(item: CacheItem): item is PromiseCacheItem { function getDecisionBlock(state: CachedBeaconStateAllForks, epoch: Epoch): RootHex { return state.slot > GENESIS_SLOT ? getShufflingDecisionBlock(state, epoch) - : toHexString(ssz.phase0.BeaconBlockHeader.hashTreeRoot(computeAnchorCheckpoint(state.config, state).blockHeader)); + : toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(computeAnchorCheckpoint(state.config, state).blockHeader)); } diff --git a/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts index fdeb3ed5a659..05073d0e515f 100644 --- a/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts +++ b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts @@ -1,7 +1,7 @@ -import {toHexString} from "@chainsafe/ssz"; import {Epoch, RootHex} from "@lodestar/types"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {routes} from "@lodestar/api"; +import {toRootHex} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; import {StateCloneOpts} from "../regen/interface.js"; import {MapTracker} from "./mapMetrics.js"; @@ -53,7 +53,7 @@ export class BlockStateCacheImpl implements BlockStateCache { } add(item: CachedBeaconStateAllForks): void { - const key = toHexString(item.hashTreeRoot()); + const key = toRootHex(item.hashTreeRoot()); if (this.cache.get(key)) { return; } @@ -70,7 +70,7 @@ export class BlockStateCacheImpl implements BlockStateCache { setHeadState(item: CachedBeaconStateAllForks | null): void { if (item) { - const key = toHexString(item.hashTreeRoot()); + const key = toRootHex(item.hashTreeRoot()); this.head = {state: item, stateRoot: key}; } else { this.head = null; @@ -130,7 +130,7 @@ export class BlockStateCacheImpl implements BlockStateCache { dumpSummary(): routes.lodestar.StateCacheItem[] { return Array.from(this.cache.entries()).map(([key, state]) => ({ slot: state.slot, - root: toHexString(state.hashTreeRoot()), + root: toRootHex(state.hashTreeRoot()), reads: this.cache.readCount.get(key) ?? 0, lastRead: this.cache.lastRead.get(key) ?? 0, checkpointState: false, diff --git a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts index 93b581633c05..602b0abaee8d 100644 --- a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts +++ b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts @@ -1,7 +1,7 @@ -import {toHexString} from "@chainsafe/ssz"; import {RootHex} from "@lodestar/types"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {routes} from "@lodestar/api"; +import {toRootHex} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; import {LinkedList} from "../../util/array.js"; import {StateCloneOpts} from "../regen/interface.js"; @@ -107,7 +107,7 @@ export class FIFOBlockStateCache implements BlockStateCache { * In importBlock() steps, normally it'll call add() with isHead = false first. Then call setHeadState() to set the head. */ add(item: CachedBeaconStateAllForks, isHead = false): void { - const key = toHexString(item.hashTreeRoot()); + const key = toRootHex(item.hashTreeRoot()); if (this.cache.get(key) != null) { if (!this.keyOrder.has(key)) { throw Error(`State exists but key not found in keyOrder: ${key}`); @@ -183,7 +183,7 @@ export class FIFOBlockStateCache implements BlockStateCache { dumpSummary(): routes.lodestar.StateCacheItem[] { return Array.from(this.cache.entries()).map(([key, state]) => ({ slot: state.slot, - root: toHexString(state.hashTreeRoot()), + root: toRootHex(state.hashTreeRoot()), reads: this.cache.readCount.get(key) ?? 0, lastRead: this.cache.lastRead.get(key) ?? 0, checkpointState: false, diff --git a/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts index 37c67c0d86b4..03cdc84de166 100644 --- a/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts @@ -1,7 +1,6 @@ -import {toHexString} from "@chainsafe/ssz"; import {phase0, Epoch, RootHex} from "@lodestar/types"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; -import {MapDef} from "@lodestar/utils"; +import {MapDef, toRootHex} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {Metrics} from "../../metrics/index.js"; import {StateCloneOpts} from "../regen/interface.js"; @@ -144,7 +143,7 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache { delete(cp: phase0.Checkpoint): void { this.cache.delete(toCheckpointKey(toCheckpointHex(cp))); - const epochKey = toHexString(cp.root); + const epochKey = toRootHex(cp.root); const value = this.epochIndex.get(cp.epoch); if (value) { value.delete(epochKey); @@ -170,7 +169,7 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache { dumpSummary(): routes.lodestar.StateCacheItem[] { return Array.from(this.cache.entries()).map(([key, state]) => ({ slot: state.slot, - root: toHexString(state.hashTreeRoot()), + root: toRootHex(state.hashTreeRoot()), reads: this.cache.readCount.get(key) ?? 0, lastRead: this.cache.lastRead.get(key) ?? 0, checkpointState: true, @@ -186,7 +185,7 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache { export function toCheckpointHex(checkpoint: phase0.Checkpoint): CheckpointHex { return { epoch: checkpoint.epoch, - rootHex: toHexString(checkpoint.root), + rootHex: toRootHex(checkpoint.root), }; } diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 58aeca061bc0..5c5901583ad8 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -1,7 +1,7 @@ import {fromHexString, toHexString} from "@chainsafe/ssz"; import {phase0, Epoch, RootHex} from "@lodestar/types"; import {CachedBeaconStateAllForks, computeStartSlotAtEpoch, getBlockRootAtSlot} from "@lodestar/state-transition"; -import {Logger, MapDef, sleep} from "@lodestar/utils"; +import {Logger, MapDef, sleep, toRootHex} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {loadCachedBeaconState} from "@lodestar/state-transition"; import {INTERVALS_PER_SLOT} from "@lodestar/params"; @@ -171,7 +171,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { for (const persistedKey of persistedKeys) { const cp = datastoreKeyToCheckpoint(persistedKey); this.cache.set(toCacheKey(cp), {type: CacheItemType.persisted, value: persistedKey}); - this.epochIndex.getOrDefault(cp.epoch).add(toHexString(cp.root)); + this.epochIndex.getOrDefault(cp.epoch).add(toRootHex(cp.root)); } this.logger.info("Loaded persisted checkpoint states from the last run", { count: persistedKeys.length, @@ -227,7 +227,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { validatorsBytes ); newCachedState.commit(); - const stateRoot = toHexString(newCachedState.hashTreeRoot()); + const stateRoot = toRootHex(newCachedState.hashTreeRoot()); timer?.(); this.logger.debug("Reload: cached state load successful", { ...logMeta, @@ -561,7 +561,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { // amongst states of the same epoch, choose the one with the same view of reloadedCp if ( reloadedCpSlot < state.slot && - toHexString(getBlockRootAtSlot(state, reloadedCpSlot)) === reloadedCp.rootHex + toRootHex(getBlockRootAtSlot(state, reloadedCpSlot)) === reloadedCp.rootHex ) { return state; } @@ -645,8 +645,8 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { const epochBoundarySlot = computeStartSlotAtEpoch(epoch); const epochBoundaryRoot = epochBoundarySlot === state.slot ? fromHexString(blockRootHex) : getBlockRootAtSlot(state, epochBoundarySlot); - const epochBoundaryHex = toHexString(epochBoundaryRoot); - const prevEpochRoot = toHexString(getBlockRootAtSlot(state, epochBoundarySlot - 1)); + const epochBoundaryHex = toRootHex(epochBoundaryRoot); + const prevEpochRoot = toRootHex(getBlockRootAtSlot(state, epochBoundarySlot - 1)); // for each epoch, usually there are 2 rootHexes respective to the 2 checkpoint states: Previous Root Checkpoint State and Current Root Checkpoint State const cpRootHexes = this.epochIndex.get(epoch) ?? []; @@ -804,7 +804,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { export function toCheckpointHex(checkpoint: phase0.Checkpoint): CheckpointHex { return { epoch: checkpoint.epoch, - rootHex: toHexString(checkpoint.root), + rootHex: toRootHex(checkpoint.root), }; } @@ -812,7 +812,7 @@ function toCacheKey(cp: CheckpointHex | phase0.Checkpoint): CacheKey { if (isCheckpointHex(cp)) { return `${cp.rootHex}_${cp.epoch}`; } - return `${toHexString(cp.root)}_${cp.epoch}`; + return `${toRootHex(cp.root)}_${cp.epoch}`; } function fromCacheKey(key: CacheKey): CheckpointHex { diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 430464683493..3c32ffe1a9ec 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import {ForkName} from "@lodestar/params"; import {phase0, RootHex, ssz} from "@lodestar/types"; import { @@ -6,6 +5,7 @@ import { isAggregatorFromCommitteeLength, createAggregateSignatureSetFromComponents, } from "@lodestar/state-transition"; +import {toRootHex} from "@lodestar/utils"; import {IBeaconChain} from ".."; import {AttestationError, AttestationErrorCode, GossipAction} from "../errors/index.js"; import {RegenCaller} from "../regen/index.js"; @@ -111,7 +111,7 @@ async function validateAggregateAndProof( // is a non-strict superset has _not_ already been seen. const attDataRootHex = cachedAttData ? cachedAttData.attDataRootHex - : toHexString(ssz.phase0.AttestationData.hashTreeRoot(attData)); + : toRootHex(ssz.phase0.AttestationData.hashTreeRoot(attData)); if ( !skipValidationKnownAttesters && chain.seenAggregatedAttestations.isKnown(targetEpoch, attDataRootHex, aggregationBits) diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index fc39534b45e6..1116e87e1d25 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import {phase0, Epoch, Root, Slot, RootHex, ssz} from "@lodestar/types"; import {ProtoBlock} from "@lodestar/fork-choice"; import {ATTESTATION_SUBNET_COUNT, SLOTS_PER_EPOCH, ForkName, ForkSeq, DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; @@ -13,6 +12,7 @@ import { computeSigningRoot, } from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; +import {toRootHex} from "@lodestar/utils"; import {AttestationError, AttestationErrorCode, GossipAction} from "../errors/index.js"; import {MAXIMUM_GOSSIP_CLOCK_DISPARITY_SEC} from "../../constants/index.js"; import {RegenCaller} from "../regen/index.js"; @@ -437,7 +437,7 @@ async function validateGossipAttestationNoSignatureCheck( ); // add cached attestation data before verifying signature - attDataRootHex = toHexString(ssz.phase0.AttestationData.hashTreeRoot(attData)); + attDataRootHex = toRootHex(ssz.phase0.AttestationData.hashTreeRoot(attData)); if (attDataBase64) { chain.seenAttestationDatas.add(attSlot, attDataBase64, { committeeIndices, @@ -643,7 +643,7 @@ function verifyHeadBlockIsKnown(chain: IBeaconChain, beaconBlockRoot: Root): Pro if (headBlock === null) { throw new AttestationError(GossipAction.IGNORE, { code: AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT, - root: toHexString(beaconBlockRoot), + root: toRootHex(beaconBlockRoot), }); } @@ -671,7 +671,7 @@ function verifyAttestationTargetRoot(headBlock: ProtoBlock, targetRoot: Root, at // https://github.com/ethereum/consensus-specs/pull/2001#issuecomment-699246659 throw new AttestationError(GossipAction.REJECT, { code: AttestationErrorCode.INVALID_TARGET_ROOT, - targetRoot: toHexString(targetRoot), + targetRoot: toRootHex(targetRoot), expected: null, }); } else { @@ -687,11 +687,11 @@ function verifyAttestationTargetRoot(headBlock: ProtoBlock, targetRoot: Root, at headBlock.blockRoot; // TODO: Do a fast comparision to convert and compare byte by byte - if (expectedTargetRoot !== toHexString(targetRoot)) { + if (expectedTargetRoot !== toRootHex(targetRoot)) { // Reject any attestation with an invalid target root. throw new AttestationError(GossipAction.REJECT, { code: AttestationErrorCode.INVALID_TARGET_ROOT, - targetRoot: toHexString(targetRoot), + targetRoot: toRootHex(targetRoot), expected: expectedTargetRoot, }); } diff --git a/packages/beacon-node/src/chain/validation/block.ts b/packages/beacon-node/src/chain/validation/block.ts index 214eeaf0ab4e..aabc1b14958a 100644 --- a/packages/beacon-node/src/chain/validation/block.ts +++ b/packages/beacon-node/src/chain/validation/block.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import { computeStartSlotAtEpoch, @@ -8,7 +7,7 @@ import { isExecutionEnabled, getBlockProposerSignatureSet, } from "@lodestar/state-transition"; -import {sleep} from "@lodestar/utils"; +import {sleep, toRootHex} from "@lodestar/utils"; import {ForkName} from "@lodestar/params"; import {SignedBeaconBlock} from "@lodestar/types"; import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../../constants/index.js"; @@ -55,7 +54,7 @@ export async function validateGossipBlock( // reboot if the `observed_block_producers` cache is empty. In that case, without this // check, we will load the parent and state from disk only to find out later that we // already know this block. - const blockRoot = toHexString(config.getForkTypes(blockSlot).BeaconBlock.hashTreeRoot(block)); + const blockRoot = toRootHex(config.getForkTypes(blockSlot).BeaconBlock.hashTreeRoot(block)); if (chain.forkChoice.getBlockHex(blockRoot) !== null) { throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.ALREADY_KNOWN, root: blockRoot}); } @@ -71,7 +70,7 @@ export async function validateGossipBlock( // [REJECT] The current finalized_checkpoint is an ancestor of block -- i.e. // get_ancestor(store, block.parent_root, compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)) == store.finalized_checkpoint.root - const parentRoot = toHexString(block.parentRoot); + const parentRoot = toRootHex(block.parentRoot); const parentBlock = chain.forkChoice.getBlockHex(parentRoot); if (parentBlock === null) { // If fork choice does *not* consider the parent to be a descendant of the finalized block, diff --git a/packages/beacon-node/src/chain/validation/syncCommittee.ts b/packages/beacon-node/src/chain/validation/syncCommittee.ts index 43a4c95c59da..f47aa53a314e 100644 --- a/packages/beacon-node/src/chain/validation/syncCommittee.ts +++ b/packages/beacon-node/src/chain/validation/syncCommittee.ts @@ -1,7 +1,7 @@ -import {toHexString} from "@chainsafe/ssz"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {SYNC_COMMITTEE_SUBNET_SIZE, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {altair} from "@lodestar/types"; +import {toRootHex} from "@lodestar/utils"; import {GossipAction, SyncCommitteeError, SyncCommitteeErrorCode} from "../errors/index.js"; import {IBeaconChain} from "../interface.js"; import {getSyncCommitteeSignatureSet} from "./signatureSets/index.js"; @@ -17,7 +17,7 @@ export async function validateGossipSyncCommittee( subnet: number ): Promise<{indexInSubcommittee: IndexInSubcommittee}> { const {slot, validatorIndex, beaconBlockRoot} = syncCommittee; - const messageRoot = toHexString(beaconBlockRoot); + const messageRoot = toRootHex(beaconBlockRoot); const headState = chain.getHeadState(); const indexInSubcommittee = validateGossipSyncCommitteeExceptSig(chain, headState, subnet, syncCommittee); diff --git a/packages/beacon-node/src/eth1/utils/deposits.ts b/packages/beacon-node/src/eth1/utils/deposits.ts index 19544917ffdc..24916264e6d8 100644 --- a/packages/beacon-node/src/eth1/utils/deposits.ts +++ b/packages/beacon-node/src/eth1/utils/deposits.ts @@ -1,9 +1,9 @@ import {toGindex, Tree} from "@chainsafe/persistent-merkle-tree"; -import {toHexString} from "@chainsafe/ssz"; import {MAX_DEPOSITS} from "@lodestar/params"; import {BeaconStateAllForks} from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; import {FilterOptions} from "@lodestar/db"; +import {toRootHex} from "@lodestar/utils"; import {Eth1Error, Eth1ErrorCode} from "../errors.js"; import {DepositTree} from "../../db/repositories/depositDataRoot.js"; @@ -51,8 +51,8 @@ export function getDepositsWithProofs( if (!ssz.Root.equals(depositRoot, eth1Data.depositRoot)) { throw new Eth1Error({ code: Eth1ErrorCode.WRONG_DEPOSIT_ROOT, - root: toHexString(depositRoot), - expectedRoot: toHexString(eth1Data.depositRoot), + root: toRootHex(depositRoot), + expectedRoot: toRootHex(eth1Data.depositRoot), }); } diff --git a/packages/beacon-node/src/network/gossip/encoding.ts b/packages/beacon-node/src/network/gossip/encoding.ts index 53847f56df7d..02c0df07b2f1 100644 --- a/packages/beacon-node/src/network/gossip/encoding.ts +++ b/packages/beacon-node/src/network/gossip/encoding.ts @@ -4,7 +4,7 @@ import {Message} from "@libp2p/interface"; import {digest} from "@chainsafe/as-sha256"; import {RPC} from "@chainsafe/libp2p-gossipsub/message"; import {DataTransform} from "@chainsafe/libp2p-gossipsub/types"; -import {intToBytes, toHex} from "@lodestar/utils"; +import {intToBytes} from "@lodestar/utils"; import {ForkName} from "@lodestar/params"; import {MESSAGE_DOMAIN_VALID_SNAPPY} from "./constants.js"; import {getGossipSSZType, GossipTopicCache} from "./topic.js"; @@ -15,6 +15,9 @@ const xxhash = await xxhashFactory(); // Use salt to prevent msgId from being mined for collisions const h64Seed = BigInt(Math.floor(Math.random() * 1e9)); +// Shared buffer to convert msgId to string +const sharedMsgIdBuf = Buffer.alloc(20); + /** * The function used to generate a gossipsub message id * We use the first 8 bytes of SHA256(data) for content addressing @@ -28,7 +31,9 @@ export function fastMsgIdFn(rpcMsg: RPC.Message): string { } export function msgIdToStrFn(msgId: Uint8Array): string { - return toHex(msgId); + // this is the same logic to `toHex(msgId)` with better performance + sharedMsgIdBuf.set(msgId); + return `0x${sharedMsgIdBuf.toString("hex")}`; } /** diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index 82fe7d8db358..6f64148b87e2 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -1,6 +1,5 @@ -import {toHexString} from "@chainsafe/ssz"; import {BeaconConfig, ChainForkConfig} from "@lodestar/config"; -import {LogLevel, Logger, prettyBytes} from "@lodestar/utils"; +import {LogLevel, Logger, prettyBytes, toRootHex} from "@lodestar/utils"; import {Root, Slot, ssz, deneb, UintNum64, SignedBeaconBlock} from "@lodestar/types"; import {ForkName, ForkSeq} from "@lodestar/params"; import {routes} from "@lodestar/api"; @@ -298,7 +297,7 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler case BlockErrorCode.DATA_UNAVAILABLE: { const slot = signedBlock.message.slot; const forkTypes = config.getForkTypes(slot); - const rootHex = toHexString(forkTypes.BeaconBlock.hashTreeRoot(signedBlock.message)); + const rootHex = toRootHex(forkTypes.BeaconBlock.hashTreeRoot(signedBlock.message)); events.emit(NetworkEvent.unknownBlock, {rootHex, peer: peerIdStr}); @@ -747,12 +746,12 @@ export async function validateGossipFnRetryUnknownRoot( ) { if (unknownBlockRootRetries === 0) { // Trigger unknown block root search here - const rootHex = toHexString(blockRoot); + const rootHex = toRootHex(blockRoot); network.searchUnknownSlotRoot({slot, root: rootHex}); } if (unknownBlockRootRetries++ < MAX_UNKNOWN_BLOCK_ROOT_RETRIES) { - const foundBlock = await chain.waitForBlock(slot, toHexString(blockRoot)); + const foundBlock = await chain.waitForBlock(slot, toRootHex(blockRoot)); // Returns true if the block was found on time. In that case, try to get it from the fork-choice again. // Otherwise, throw the error below. if (foundBlock) { diff --git a/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRoot.ts b/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRoot.ts index 0ed0e6a2d185..36d90256276e 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRoot.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRoot.ts @@ -1,6 +1,6 @@ -import {toHexString} from "@chainsafe/ssz"; import {ResponseOutgoing} from "@lodestar/reqresp"; import {Slot, phase0} from "@lodestar/types"; +import {toRootHex} from "@lodestar/utils"; import {IBeaconChain} from "../../../chain/index.js"; import {IBeaconDb} from "../../../db/index.js"; import {getSlotFromSignedBeaconBlockSerialized} from "../../../util/sszBytes.js"; @@ -33,7 +33,7 @@ export async function* onBeaconBlocksByRoot( if (slot === undefined) { const slotFromBytes = getSlotFromSignedBeaconBlockSerialized(blockBytes); if (slotFromBytes === null) { - throw Error(`Invalid block bytes for block root ${toHexString(root)}`); + throw Error(`Invalid block bytes for block root ${toRootHex(root)}`); } slot = slotFromBytes; } diff --git a/packages/beacon-node/src/sync/backfill/backfill.ts b/packages/beacon-node/src/sync/backfill/backfill.ts index 6d9716a37329..15ba34f4e583 100644 --- a/packages/beacon-node/src/sync/backfill/backfill.ts +++ b/packages/beacon-node/src/sync/backfill/backfill.ts @@ -1,10 +1,9 @@ import {EventEmitter} from "events"; import {StrictEventEmitter} from "strict-event-emitter-types"; -import {toHexString} from "@chainsafe/ssz"; import {BeaconStateAllForks, blockToHeader} from "@lodestar/state-transition"; import {BeaconConfig, ChainForkConfig} from "@lodestar/config"; import {phase0, Root, SignedBeaconBlock, Slot, ssz} from "@lodestar/types"; -import {ErrorAborted, Logger, sleep, toHex} from "@lodestar/utils"; +import {ErrorAborted, Logger, sleep, toHex, toRootHex} from "@lodestar/utils"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {IBeaconChain} from "../../chain/index.js"; @@ -251,7 +250,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} lte: backfillStartFromSlot, }); modules.logger.info("Initializing from Checkpoint", { - root: toHexString(anchorCp.root), + root: toRootHex(anchorCp.root), epoch: anchorCp.epoch, backfillStartFromSlot, previousBackfilledRanges: JSON.stringify(previousBackfilledRanges), @@ -327,7 +326,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} this.logger.error( `Backfilled till ${ this.syncAnchor.lastBackSyncedBlock.slot - } but not found previous saved finalized or wsCheckpoint with root=${toHexString( + } but not found previous saved finalized or wsCheckpoint with root=${toRootHex( this.prevFinalizedCheckpointBlock.root )}, slot=${this.prevFinalizedCheckpointBlock.slot}` ); @@ -341,7 +340,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} this.logger.error( `Invalid root synced at a previous finalized or wsCheckpoint, slot=${ this.prevFinalizedCheckpointBlock.slot - }: expected=${toHexString(this.prevFinalizedCheckpointBlock.root)}, actual=${toHexString( + }: expected=${toRootHex(this.prevFinalizedCheckpointBlock.root)}, actual=${toRootHex( this.syncAnchor.lastBackSyncedBlock.root )}` ); @@ -349,7 +348,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} break; } this.logger.verbose("Validated current prevFinalizedCheckpointBlock", { - root: toHexString(this.prevFinalizedCheckpointBlock.root), + root: toRootHex(this.prevFinalizedCheckpointBlock.root), slot: this.prevFinalizedCheckpointBlock.slot, }); @@ -379,7 +378,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} if (this.syncAnchor.lastBackSyncedBlock.slot === GENESIS_SLOT) { if (!byteArrayEquals(this.syncAnchor.lastBackSyncedBlock.block.message.parentRoot, ZERO_HASH)) { Error( - `Invalid Gensis Block with non zero parentRoot=${toHexString( + `Invalid Gensis Block with non zero parentRoot=${toRootHex( this.syncAnchor.lastBackSyncedBlock.block.message.parentRoot )}` ); @@ -537,7 +536,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} }` ); this.logger.info("wsCheckpoint validated!", { - root: toHexString(this.wsCheckpointHeader.root), + root: toRootHex(this.wsCheckpointHeader.root), epoch: this.wsCheckpointHeader.slot / SLOTS_PER_EPOCH, }); this.wsValidated = true; @@ -584,7 +583,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} this.prevFinalizedCheckpointBlock.slot === prevBackfillCpBlock.message.slot ) { this.logger.verbose("Validated current prevFinalizedCheckpointBlock", { - root: toHexString(this.prevFinalizedCheckpointBlock.root), + root: toRootHex(this.prevFinalizedCheckpointBlock.root), slot: prevBackfillCpBlock.message.slot, }); } else { @@ -689,7 +688,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} throw Error( `Skipped a prevFinalizedCheckpointBlock with slot=${toHex( this.prevFinalizedCheckpointBlock.root - )}, root=${toHexString(this.prevFinalizedCheckpointBlock.root)}` + )}, root=${toRootHex(this.prevFinalizedCheckpointBlock.root)}` ); } if (anchorBlock.message.slot === this.prevFinalizedCheckpointBlock.slot) { @@ -700,7 +699,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} throw Error( `Invalid root for prevFinalizedCheckpointBlock at slot=${ this.prevFinalizedCheckpointBlock.slot - }, expected=${toHexString(this.prevFinalizedCheckpointBlock.root)}, found=${toHex(anchorBlockRoot)}` + }, expected=${toRootHex(this.prevFinalizedCheckpointBlock.root)}, found=${toHex(anchorBlockRoot)}` ); } @@ -770,7 +769,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} this.metrics?.backfillSync.totalBlocks.inc({method: BackfillSyncMethod.blockbyroot}); this.logger.verbose("Fetched new anchorBlock", { - root: toHexString(anchorBlockRoot), + root: toRootHex(anchorBlockRoot), slot: anchorBlock.data.message.slot, }); @@ -883,7 +882,7 @@ async function extractPreviousFinOrWsCheckpoint( const root = ssz.phase0.BeaconBlockHeader.hashTreeRoot(header); prevFinalizedCheckpointBlock = {root, slot: nextPrevFinOrWsBlock.message.slot}; logger?.debug("Extracted new prevFinalizedCheckpointBlock as potential previous finalized or wsCheckpoint", { - root: toHexString(prevFinalizedCheckpointBlock.root), + root: toRootHex(prevFinalizedCheckpointBlock.root), slot: prevFinalizedCheckpointBlock.slot, }); } else { diff --git a/packages/beacon-node/src/sync/range/chain.ts b/packages/beacon-node/src/sync/range/chain.ts index 41bbce3da820..0a2fc1a3f7c3 100644 --- a/packages/beacon-node/src/sync/range/chain.ts +++ b/packages/beacon-node/src/sync/range/chain.ts @@ -1,6 +1,5 @@ -import {toHexString} from "@chainsafe/ssz"; import {Epoch, Root, Slot, phase0} from "@lodestar/types"; -import {ErrorAborted, Logger} from "@lodestar/utils"; +import {ErrorAborted, Logger, toRootHex} from "@lodestar/utils"; import {ChainForkConfig} from "@lodestar/config"; import {BlockInput, BlockInputType} from "../../chain/blocks/types.js"; import {PeerAction} from "../../network/index.js"; @@ -234,7 +233,7 @@ export class SyncChain { /** Full debug state for lodestar API */ getDebugState(): SyncChainDebugState { return { - targetRoot: toHexString(this.target.root), + targetRoot: toRootHex(this.target.root), targetSlot: this.target.slot, syncType: this.syncType, status: this.status, diff --git a/packages/beacon-node/src/sync/unknownBlock.ts b/packages/beacon-node/src/sync/unknownBlock.ts index 3c15b32eb8d8..d985847d450f 100644 --- a/packages/beacon-node/src/sync/unknownBlock.ts +++ b/packages/beacon-node/src/sync/unknownBlock.ts @@ -1,6 +1,6 @@ -import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {fromHexString} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; -import {Logger, pruneSetToMax} from "@lodestar/utils"; +import {Logger, pruneSetToMax, toRootHex} from "@lodestar/utils"; import {Root, RootHex, deneb} from "@lodestar/types"; import {INTERVALS_PER_SLOT} from "@lodestar/params"; import {sleep} from "@lodestar/utils"; @@ -139,8 +139,8 @@ export class UnknownBlockSync { private addUnknownParent(blockInput: BlockInput, peerIdStr: string): void { const block = blockInput.block.message; const blockRoot = this.config.getForkTypes(block.slot).BeaconBlock.hashTreeRoot(block); - const blockRootHex = toHexString(blockRoot); - const parentBlockRootHex = toHexString(block.parentRoot); + const blockRootHex = toRootHex(blockRoot); + const parentBlockRootHex = toRootHex(block.parentRoot); // add 1 pending block with status downloaded let pendingBlock = this.pendingBlocks.get(blockRootHex); @@ -180,9 +180,7 @@ export class UnknownBlockSync { } else { if (blockInputOrRootHex.block !== null) { const {block} = blockInputOrRootHex; - blockRootHex = toHexString( - this.config.getForkTypes(block.message.slot).BeaconBlock.hashTreeRoot(block.message) - ); + blockRootHex = toRootHex(this.config.getForkTypes(block.message.slot).BeaconBlock.hashTreeRoot(block.message)); unknownBlockType = PendingBlockType.UNKNOWN_BLOBS; } else { unknownBlockType = PendingBlockType.UNKNOWN_BLOCKINPUT; @@ -304,7 +302,7 @@ export class UnknownBlockSync { ...block, status: PendingBlockStatus.downloaded, blockInput, - parentBlockRootHex: toHexString(blockInput.block.message.parentRoot), + parentBlockRootHex: toRootHex(blockInput.block.message.parentRoot), }; this.pendingBlocks.set(block.blockRootHex, block); const blockSlot = blockInput.block.message.slot; @@ -336,7 +334,7 @@ export class UnknownBlockSync { this.logger.debug("Downloaded block is before finalized slot", { finalizedSlot, blockSlot, - parentRoot: toHexString(blockRoot), + parentRoot: toRootHex(blockRoot), unknownBlockType, }); this.removeAndDownscoreAllDescendants(block); @@ -384,7 +382,7 @@ export class UnknownBlockSync { .BeaconBlock.hashTreeRoot(pendingBlock.blockInput.block.message); this.logger.verbose("Avoid proposer boost for this block of known proposer", { blockSlot, - blockRoot: toHexString(blockRoot), + blockRoot: toRootHex(blockRoot), proposerIndex, }); await sleep(this.proposerBoostSecWindow * 1000); @@ -466,7 +464,7 @@ export class UnknownBlockSync { connectedPeers: PeerIdStr[] ): Promise<{blockInput: BlockInput; peerIdStr: string}> { const shuffledPeers = shuffle(connectedPeers); - const blockRootHex = toHexString(blockRoot); + const blockRootHex = toRootHex(blockRoot); let lastError: Error | null = null; for (let i = 0; i < MAX_ATTEMPTS_PER_BLOCK; i++) { @@ -483,7 +481,7 @@ export class UnknownBlockSync { const block = blockInput.block.message; const receivedBlockRoot = this.config.getForkTypes(block.slot).BeaconBlock.hashTreeRoot(block); if (!byteArrayEquals(receivedBlockRoot, blockRoot)) { - throw Error(`Wrong block received by peer, got ${toHexString(receivedBlockRoot)} expected ${blockRootHex}`); + throw Error(`Wrong block received by peer, got ${toRootHex(receivedBlockRoot)} expected ${blockRootHex}`); } return {blockInput, peerIdStr: peer}; @@ -527,7 +525,7 @@ export class UnknownBlockSync { blockRoot = this.config .getForkTypes(unavailableBlock.message.slot) .BeaconBlock.hashTreeRoot(unavailableBlock.message); - blockRootHex = toHexString(blockRoot); + blockRootHex = toRootHex(blockRoot); blobKzgCommitmentsLen = (unavailableBlock.message.body as deneb.BeaconBlockBody).blobKzgCommitments.length; pendingBlobs = blobKzgCommitmentsLen - unavailableBlockInput.cachedData.blobsCache.size; } @@ -554,7 +552,7 @@ export class UnknownBlockSync { const receivedBlockRoot = this.config.getForkTypes(block.slot).BeaconBlock.hashTreeRoot(block); if (!byteArrayEquals(receivedBlockRoot, blockRoot)) { - throw Error(`Wrong block received by peer, got ${toHexString(receivedBlockRoot)} expected ${blockRootHex}`); + throw Error(`Wrong block received by peer, got ${toRootHex(receivedBlockRoot)} expected ${blockRootHex}`); } if (unavailableBlockInput.block === null) { this.logger.debug("Fetched NullBlockInput", {attempts: i, blockRootHex}); diff --git a/packages/beacon-node/src/util/sszBytes.ts b/packages/beacon-node/src/util/sszBytes.ts index f87b899e9591..ce4125140075 100644 --- a/packages/beacon-node/src/util/sszBytes.ts +++ b/packages/beacon-node/src/util/sszBytes.ts @@ -1,6 +1,5 @@ import {BitArray, deserializeUint8ArrayBitListFromBytes} from "@chainsafe/ssz"; import {BLSSignature, RootHex, Slot} from "@lodestar/types"; -import {toHex} from "@lodestar/utils"; import {BYTES_PER_FIELD_ELEMENT, FIELD_ELEMENTS_PER_BLOB} from "@lodestar/params"; export type BlockRootHex = RootHex; @@ -25,6 +24,10 @@ const SLOT_SIZE = 8; const ATTESTATION_DATA_SIZE = 128; const SIGNATURE_SIZE = 96; +// shared Buffers to convert bytes to hex/base64 +const blockRootBuf = Buffer.alloc(ROOT_SIZE); +const attDataBuf = Buffer.alloc(ATTESTATION_DATA_SIZE); + /** * Extract slot from attestation serialized bytes. * Return null if data is not long enough to extract slot. @@ -46,7 +49,10 @@ export function getBlockRootFromAttestationSerialized(data: Uint8Array): BlockRo return null; } - return toHex(data.subarray(ATTESTATION_BEACON_BLOCK_ROOT_OFFSET, ATTESTATION_BEACON_BLOCK_ROOT_OFFSET + ROOT_SIZE)); + blockRootBuf.set( + data.subarray(ATTESTATION_BEACON_BLOCK_ROOT_OFFSET, ATTESTATION_BEACON_BLOCK_ROOT_OFFSET + ROOT_SIZE) + ); + return "0x" + blockRootBuf.toString("hex"); } /** @@ -59,7 +65,8 @@ export function getAttDataBase64FromAttestationSerialized(data: Uint8Array): Att } // base64 is a bit efficient than hex - return toBase64(data.slice(VARIABLE_FIELD_OFFSET, VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE)); + attDataBuf.set(data.subarray(VARIABLE_FIELD_OFFSET, VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE)); + return attDataBuf.toString("base64"); } /** @@ -130,12 +137,13 @@ export function getBlockRootFromSignedAggregateAndProofSerialized(data: Uint8Arr return null; } - return toHex( + blockRootBuf.set( data.subarray( SIGNED_AGGREGATE_AND_PROOF_BLOCK_ROOT_OFFSET, SIGNED_AGGREGATE_AND_PROOF_BLOCK_ROOT_OFFSET + ROOT_SIZE ) ); + return "0x" + blockRootBuf.toString("hex"); } /** @@ -148,9 +156,13 @@ export function getAttDataBase64FromSignedAggregateAndProofSerialized(data: Uint } // base64 is a bit efficient than hex - return toBase64( - data.slice(SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET, SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET + ATTESTATION_DATA_SIZE) + attDataBuf.set( + data.subarray( + SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET, + SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET + ATTESTATION_DATA_SIZE + ) ); + return attDataBuf.toString("base64"); } /** @@ -217,7 +229,3 @@ function getSlotFromOffsetTrusted(data: Uint8Array, offset: number): Slot { function checkSlotHighBytes(data: Uint8Array, offset: number): boolean { return (data[offset + 4] | data[offset + 5] | data[offset + 6] | data[offset + 7]) === 0; } - -function toBase64(data: Uint8Array): string { - return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString("base64"); -} diff --git a/packages/beacon-node/test/perf/network/gossip/encoding.test.ts b/packages/beacon-node/test/perf/network/gossip/encoding.test.ts new file mode 100644 index 000000000000..693c91f59249 --- /dev/null +++ b/packages/beacon-node/test/perf/network/gossip/encoding.test.ts @@ -0,0 +1,46 @@ +import {itBench} from "@dapplion/benchmark"; +import {toHex} from "@lodestar/utils"; + +/** + * This is a benchmark for different ways of converting a gossipsub message id to a hex string using Mac M1 + * encoding + ✔ toHex 6463330 ops/s 154.7190 ns/op - 7170 runs 1.26 s + ✔ Buffer.from 6696982 ops/s 149.3210 ns/op - 2023 runs 0.454 s + ✔ shared Buffer 1.013911e+7 ops/s 98.62800 ns/op - 3083 runs 0.404 s + */ +describe("encoding", function () { + const msgId = Uint8Array.from(Array.from({length: 20}, (_, i) => i)); + + const runsFactor = 1000; + itBench({ + id: "toHex", + fn: () => { + for (let i = 0; i < runsFactor; i++) { + toHex(msgId); + } + }, + runsFactor, + }); + + itBench({ + id: "Buffer.from", + fn: () => { + for (let i = 0; i < runsFactor; i++) { + "0x" + Buffer.from(msgId.buffer, msgId.byteOffset, msgId.byteLength).toString("hex"); + } + }, + runsFactor, + }); + + const sharedBuf = Buffer.from(msgId); + itBench({ + id: "shared Buffer", + fn: () => { + for (let i = 0; i < runsFactor; i++) { + sharedBuf.set(msgId); + "0x" + sharedBuf.toString("hex"); + } + }, + runsFactor, + }); +}); diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index 2e2abed95eb7..2405a442c8cd 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -1,5 +1,5 @@ import {toHexString} from "@chainsafe/ssz"; -import {Logger, fromHex} from "@lodestar/utils"; +import {Logger, fromHex, toRootHex} from "@lodestar/utils"; import {SLOTS_PER_HISTORICAL_ROOT, SLOTS_PER_EPOCH, INTERVALS_PER_SLOT} from "@lodestar/params"; import {bellatrix, Slot, ValidatorIndex, phase0, ssz, RootHex, Epoch, Root, BeaconBlock} from "@lodestar/types"; import { @@ -472,7 +472,7 @@ export class ForkChoice implements IForkChoice { dataAvailabilityStatus: DataAvailabilityStatus ): ProtoBlock { const {parentRoot, slot} = block; - const parentRootHex = toHexString(parentRoot); + const parentRootHex = toRootHex(parentRoot); // Parent block must be known const parentBlock = this.protoArray.getBlock(parentRootHex); if (!parentBlock) { @@ -529,7 +529,7 @@ export class ForkChoice implements IForkChoice { } const blockRoot = this.config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block); - const blockRootHex = toHexString(blockRoot); + const blockRootHex = toRootHex(blockRoot); // Assign proposer score boost if the block is timely // before attesting interval = before 1st interval @@ -628,14 +628,14 @@ export class ForkChoice implements IForkChoice { slot: slot, blockRoot: blockRootHex, parentRoot: parentRootHex, - targetRoot: toHexString(targetRoot), - stateRoot: toHexString(block.stateRoot), + targetRoot: toRootHex(targetRoot), + stateRoot: toRootHex(block.stateRoot), timeliness: isTimely, justifiedEpoch: stateJustifiedEpoch, - justifiedRoot: toHexString(state.currentJustifiedCheckpoint.root), + justifiedRoot: toRootHex(state.currentJustifiedCheckpoint.root), finalizedEpoch: finalizedCheckpoint.epoch, - finalizedRoot: toHexString(state.finalizedCheckpoint.root), + finalizedRoot: toRootHex(state.finalizedCheckpoint.root), unrealizedJustifiedEpoch: unrealizedJustifiedCheckpoint.epoch, unrealizedJustifiedRoot: unrealizedJustifiedCheckpoint.rootHex, unrealizedFinalizedEpoch: unrealizedFinalizedCheckpoint.epoch, @@ -694,7 +694,7 @@ export class ForkChoice implements IForkChoice { // to genesis just by being present in the chain. const attestationData = attestation.data; const {slot, beaconBlockRoot} = attestationData; - const blockRootHex = toHexString(beaconBlockRoot); + const blockRootHex = toRootHex(beaconBlockRoot); const targetEpoch = attestationData.target.epoch; if (ssz.Root.equals(beaconBlockRoot, ZERO_HASH)) { return; @@ -770,11 +770,11 @@ export class ForkChoice implements IForkChoice { /** Returns `true` if the block is known **and** a descendant of the finalized root. */ hasBlock(blockRoot: Root): boolean { - return this.hasBlockHex(toHexString(blockRoot)); + return this.hasBlockHex(toRootHex(blockRoot)); } /** Returns a `ProtoBlock` if the block is known **and** a descendant of the finalized root. */ getBlock(blockRoot: Root): ProtoBlock | null { - return this.getBlockHex(toHexString(blockRoot)); + return this.getBlockHex(toRootHex(blockRoot)); } /** @@ -793,7 +793,7 @@ export class ForkChoice implements IForkChoice { * Same to hasBlock but without checking if the block is a descendant of the finalized root. */ hasBlockUnsafe(blockRoot: Root): boolean { - return this.hasBlockHexUnsafe(toHexString(blockRoot)); + return this.hasBlockHexUnsafe(toRootHex(blockRoot)); } /** @@ -1221,7 +1221,7 @@ export class ForkChoice implements IForkChoice { forceImport?: boolean ): void { const epochNow = computeEpochAtSlot(this.fcStore.currentSlot); - const targetRootHex = toHexString(attestationData.target.root); + const targetRootHex = toRootHex(attestationData.target.root); // Attestation must be from the current of previous epoch. if (targetEpoch > epochNow) { diff --git a/packages/fork-choice/src/forkChoice/store.ts b/packages/fork-choice/src/forkChoice/store.ts index faf700241fa8..d16e021529db 100644 --- a/packages/fork-choice/src/forkChoice/store.ts +++ b/packages/fork-choice/src/forkChoice/store.ts @@ -1,4 +1,4 @@ -import {toHexString} from "@chainsafe/ssz"; +import {toRootHex} from "@lodestar/utils"; import {EffectiveBalanceIncrements, CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {phase0, Slot, RootHex, ValidatorIndex} from "@lodestar/types"; import {CheckpointHexWithTotalBalance, CheckpointHexWithBalance} from "./interface.js"; @@ -103,7 +103,7 @@ export function toCheckpointWithHex(checkpoint: phase0.Checkpoint): CheckpointWi return { epoch: checkpoint.epoch, root, - rootHex: toHexString(root), + rootHex: toRootHex(root), }; } diff --git a/packages/utils/src/bytes.ts b/packages/utils/src/bytes.ts index 5395c4315d22..f4a622da021e 100644 --- a/packages/utils/src/bytes.ts +++ b/packages/utils/src/bytes.ts @@ -56,6 +56,17 @@ export function toHex(buffer: Uint8Array | Parameters[0]): s } } +// Shared buffer to convert root to hex +const rootBuf = Buffer.alloc(32); + +/** + * Convert a Uint8Array, length 32, to 0x-prefixed hex string + */ +export function toRootHex(root: Uint8Array): string { + rootBuf.set(root); + return `0x${rootBuf.toString("hex")}`; +} + export function fromHex(hex: string): Uint8Array { const b = Buffer.from(hex.replace("0x", ""), "hex"); return new Uint8Array(b.buffer, b.byteOffset, b.length); diff --git a/packages/utils/test/perf/bytes.test.ts b/packages/utils/test/perf/bytes.test.ts new file mode 100644 index 000000000000..368758d12efe --- /dev/null +++ b/packages/utils/test/perf/bytes.test.ts @@ -0,0 +1,27 @@ +import {itBench} from "@dapplion/benchmark"; +import {toHex, toRootHex} from "../../src/bytes.js"; + +describe("bytes utils", function () { + const runsFactor = 1000; + const blockRoot = new Uint8Array(Array.from({length: 32}, (_, i) => i)); + + itBench({ + id: "block root to RootHex using toHex", + fn: () => { + for (let i = 0; i < runsFactor; i++) { + toHex(blockRoot); + } + }, + runsFactor, + }); + + itBench({ + id: "block root to RootHex using toRootHex", + fn: () => { + for (let i = 0; i < runsFactor; i++) { + toRootHex(blockRoot); + } + }, + runsFactor, + }); +}); diff --git a/packages/utils/vitest.config.ts b/packages/utils/vitest.config.ts index 7a6069341168..b2b7cc82b0e2 100644 --- a/packages/utils/vitest.config.ts +++ b/packages/utils/vitest.config.ts @@ -6,6 +6,11 @@ export default mergeConfig( defineConfig({ test: { globalSetup: ["./test/globalSetup.ts"], + typecheck: { + // For some reason Vitest tries to run perf test files which causes an error + // as we use Mocha for those. This ignores all errors outside of test files. + ignoreSourceErrors: true, + }, }, }) ); From 20c18ad85d6cb5e37d4980446d4f608ce9169c24 Mon Sep 17 00:00:00 2001 From: twoeths Date: Thu, 15 Aug 2024 08:02:25 +0700 Subject: [PATCH 004/259] fix: use toRootHex where applicable (#7021) * fix: use toRootHex where applicable * fix: toRootHex() to handle different lengths * fix: throw error if root is not 32 bytes * Fix eth1MergeBlockTracker unit test --------- Co-authored-by: Nico Flaig --- .../src/api/impl/beacon/blocks/index.ts | 16 +++++++-------- .../src/api/impl/lodestar/index.ts | 4 ++-- .../src/api/impl/validator/index.ts | 20 +++++++++---------- .../src/chain/archiver/archiveBlocks.ts | 6 +++--- .../beacon-node/src/chain/blocks/index.ts | 4 ++-- .../src/chain/blocks/verifyBlock.ts | 9 ++++----- .../blocks/verifyBlocksExecutionPayloads.ts | 13 +++++------- .../chain/blocks/verifyBlocksSanityChecks.ts | 6 ++---- .../src/chain/blocks/writeBlockInputToDb.ts | 6 +++--- packages/beacon-node/src/chain/chain.ts | 10 +++++----- .../beacon-node/src/chain/forkChoice/index.ts | 3 +-- .../opPools/aggregatedAttestationPool.ts | 6 +++--- .../chain/produceBlock/produceBlockBody.ts | 10 +++++----- .../src/chain/validation/blobSidecar.ts | 10 +++++----- .../src/eth1/eth1MergeBlockTracker.ts | 5 ++--- .../beacon-node/src/eth1/utils/eth1Vote.ts | 4 ++-- .../src/metrics/validatorMonitor.ts | 18 ++++++++--------- .../peers/utils/assertPeerRelevance.ts | 3 ++- .../reqresp/handlers/blobSidecarsByRoot.ts | 4 ++-- .../beacon-node/src/sync/backfill/backfill.ts | 14 ++++++------- packages/beacon-node/src/sync/range/range.ts | 8 ++++---- .../src/sync/range/utils/chainTarget.ts | 4 ++-- .../src/sync/range/utils/hashBlocks.ts | 8 ++++---- .../unit/eth1/eth1MergeBlockTracker.test.ts | 2 +- .../src/block/processAttestationPhase0.ts | 4 ++-- .../src/block/processBlockHeader.ts | 5 +++-- .../src/block/processWithdrawals.ts | 7 ++++--- .../state-transition/src/stateTransition.ts | 4 ++-- .../src/util/epochShuffling.ts | 5 ++--- .../src/util/weakSubjectivity.ts | 6 ++---- packages/utils/src/bytes.ts | 4 ++++ 31 files changed, 112 insertions(+), 116 deletions(-) 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 1b8a59cc8967..4d0f96d1ea08 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -7,7 +7,7 @@ import { signedBeaconBlockToBlinded, } from "@lodestar/state-transition"; import {ForkExecution, SLOTS_PER_HISTORICAL_ROOT, isForkExecution} from "@lodestar/params"; -import {sleep, fromHex, toHex} from "@lodestar/utils"; +import {sleep, fromHex, toRootHex} from "@lodestar/utils"; import { deneb, isSignedBlockContents, @@ -97,9 +97,9 @@ export function getBeaconBlockApi({ // state transition to produce the stateRoot const slot = signedBlock.message.slot; const fork = config.getForkName(slot); - const blockRoot = toHex(chain.config.getForkTypes(slot).BeaconBlock.hashTreeRoot(signedBlock.message)); + const blockRoot = toRootHex(chain.config.getForkTypes(slot).BeaconBlock.hashTreeRoot(signedBlock.message)); // bodyRoot should be the same to produced block - const bodyRoot = toHex(chain.config.getForkTypes(slot).BeaconBlockBody.hashTreeRoot(signedBlock.message.body)); + const bodyRoot = toRootHex(chain.config.getForkTypes(slot).BeaconBlockBody.hashTreeRoot(signedBlock.message.body)); const blockLocallyProduced = chain.producedBlockRoot.has(blockRoot) || chain.producedBlindedBlockRoot.has(blockRoot); const valLogMeta = {slot, blockRoot, bodyRoot, broadcastValidation, blockLocallyProduced}; @@ -147,7 +147,7 @@ export function getBeaconBlockApi({ ); throw new BlockError(signedBlock, { code: BlockErrorCode.PARENT_UNKNOWN, - parentRoot: toHex(signedBlock.message.parentRoot), + parentRoot: toRootHex(signedBlock.message.parentRoot), }); } @@ -243,7 +243,7 @@ export function getBeaconBlockApi({ opts: PublishBlockOpts = {} ) => { const slot = signedBlindedBlock.message.slot; - const blockRoot = toHex( + const blockRoot = toRootHex( chain.config .getExecutionForkTypes(signedBlindedBlock.message.slot) .BlindedBeaconBlock.hashTreeRoot(signedBlindedBlock.message) @@ -258,7 +258,7 @@ export function getBeaconBlockApi({ chain.logger.debug("Reconstructing signedBlockOrContents", {slot, blockRoot, source}); const contents = executionPayload - ? chain.producedContentsCache.get(toHex(executionPayload.blockHash)) ?? null + ? chain.producedContentsCache.get(toRootHex(executionPayload.blockHash)) ?? null : null; const signedBlockOrContents = reconstructFullBlockOrContents(signedBlindedBlock, {executionPayload, contents}); @@ -354,7 +354,7 @@ export function getBeaconBlockApi({ } finalized = false; - if (summary.blockRoot !== toHex(canonicalRoot)) { + if (summary.blockRoot !== toRootHex(canonicalRoot)) { const block = await db.block.get(fromHex(summary.blockRoot)); if (block) { result.push(toBeaconHeaderResponse(config, block)); @@ -473,7 +473,7 @@ export function getBeaconBlockApi({ } if (!blobSidecars) { - throw Error(`blobSidecars not found in db for slot=${block.message.slot} root=${toHex(blockRoot)}`); + throw Error(`blobSidecars not found in db for slot=${block.message.slot} root=${toRootHex(blockRoot)}`); } return { diff --git a/packages/beacon-node/src/api/impl/lodestar/index.ts b/packages/beacon-node/src/api/impl/lodestar/index.ts index d3083dda8e9c..0e8d2b1fa94b 100644 --- a/packages/beacon-node/src/api/impl/lodestar/index.ts +++ b/packages/beacon-node/src/api/impl/lodestar/index.ts @@ -3,7 +3,7 @@ import path from "node:path"; import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; import {Repository} from "@lodestar/db"; -import {toHex} from "@lodestar/utils"; +import {toHex, toRootHex} from "@lodestar/utils"; import {getLatestWeakSubjectivityCheckpointEpoch} from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; @@ -202,7 +202,7 @@ function regenRequestToJson(config: ChainForkConfig, regenRequest: RegenRequest) case "getPreState": { const slot = regenRequest.args[0].slot; return { - root: toHex(config.getForkTypes(slot).BeaconBlock.hashTreeRoot(regenRequest.args[0])), + root: toRootHex(config.getForkTypes(slot).BeaconBlock.hashTreeRoot(regenRequest.args[0])), slot, }; } diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index b2a0b8575f5c..9d692a4cc405 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -41,7 +41,7 @@ import { BlindedBeaconBlock, } from "@lodestar/types"; import {ExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; -import {fromHex, toHex, resolveOrRacePromises, prettyWeiToEth} from "@lodestar/utils"; +import {fromHex, toHex, resolveOrRacePromises, prettyWeiToEth, toRootHex} from "@lodestar/utils"; import { AttestationError, AttestationErrorCode, @@ -324,7 +324,7 @@ export function getValidatorApi( function notOnOptimisticBlockRoot(beaconBlockRoot: Root): void { const protoBeaconBlock = chain.forkChoice.getBlock(beaconBlockRoot); if (!protoBeaconBlock) { - throw new ApiError(400, `Block not in forkChoice, beaconBlockRoot=${toHex(beaconBlockRoot)}`); + throw new ApiError(400, `Block not in forkChoice, beaconBlockRoot=${toRootHex(beaconBlockRoot)}`); } if (protoBeaconBlock.executionStatus === ExecutionStatus.Syncing) @@ -336,7 +336,7 @@ export function getValidatorApi( function notOnOutOfRangeData(beaconBlockRoot: Root): void { const protoBeaconBlock = chain.forkChoice.getBlock(beaconBlockRoot); if (!protoBeaconBlock) { - throw new ApiError(400, `Block not in forkChoice, beaconBlockRoot=${toHex(beaconBlockRoot)}`); + throw new ApiError(400, `Block not in forkChoice, beaconBlockRoot=${toRootHex(beaconBlockRoot)}`); } if (protoBeaconBlock.dataAvailabilityStatus === DataAvailabilityStatus.OutOfRange) @@ -416,7 +416,7 @@ export function getValidatorApi( slot, executionPayloadValue, consensusBlockValue, - root: toHex(config.getExecutionForkTypes(slot).BlindedBeaconBlock.hashTreeRoot(block)), + root: toRootHex(config.getExecutionForkTypes(slot).BlindedBeaconBlock.hashTreeRoot(block)), }); if (chain.opts.persistProducedBlocks) { @@ -494,13 +494,13 @@ export function getValidatorApi( slot, executionPayloadValue, consensusBlockValue, - root: toHex(config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block)), + root: toRootHex(config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block)), }); if (chain.opts.persistProducedBlocks) { void chain.persistBlock(block, "produced_engine_block"); } if (isForkBlobs(version)) { - const blockHash = toHex((block as bellatrix.BeaconBlock).body.executionPayload.blockHash); + const blockHash = toRootHex((block as bellatrix.BeaconBlock).body.executionPayload.blockHash); const contents = chain.producedContentsCache.get(blockHash); if (contents === undefined) { throw Error("contents missing in cache"); @@ -869,7 +869,7 @@ export function getValidatorApi( // and it hasn't been in our forkchoice since we haven't seen / processing that block // see https://github.com/ChainSafe/lodestar/issues/5063 if (!chain.forkChoice.hasBlock(beaconBlockRoot)) { - const rootHex = toHex(beaconBlockRoot); + const rootHex = toRootHex(beaconBlockRoot); network.searchUnknownSlotRoot({slot, root: rootHex}); // if result of this call is false, i.e. block hasn't seen after 1 slot then the below notOnOptimisticBlockRoot call will throw error await chain.waitForBlock(slot, rootHex); @@ -954,7 +954,7 @@ export function getValidatorApi( return { data: duties, meta: { - dependentRoot: toHex(dependentRoot), + dependentRoot: toRootHex(dependentRoot), executionOptimistic: isOptimisticBlock(head), }, }; @@ -1006,7 +1006,7 @@ export function getValidatorApi( return { data: duties, meta: { - dependentRoot: toHex(dependentRoot), + dependentRoot: toRootHex(dependentRoot), executionOptimistic: isOptimisticBlock(head), }, }; @@ -1071,7 +1071,7 @@ export function getValidatorApi( await waitForSlot(slot); // Must never request for a future slot > currentSlot - const dataRootHex = toHex(attestationDataRoot); + const dataRootHex = toRootHex(attestationDataRoot); const aggregate = chain.attestationPool.getAggregate(slot, dataRootHex); if (!aggregate) { diff --git a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts index 76bfe651ad77..ed6dd5bfc091 100644 --- a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts +++ b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts @@ -1,7 +1,7 @@ import {fromHexString} from "@chainsafe/ssz"; import {Epoch, Slot, RootHex} from "@lodestar/types"; import {IForkChoice} from "@lodestar/fork-choice"; -import {Logger, toHex} from "@lodestar/utils"; +import {Logger, toRootHex} from "@lodestar/utils"; import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {KeyValue} from "@lodestar/db"; @@ -137,7 +137,7 @@ async function migrateBlocksFromHotToColdDb(db: IBeaconDb, blocks: BlockRootSlot canonicalBlocks.map(async (block) => { const blockBuffer = await db.block.getBinary(block.root); if (!blockBuffer) { - throw Error(`No block found for slot ${block.slot} root ${toHex(block.root)}`); + throw Error(`No block found for slot ${block.slot} root ${toRootHex(block.root)}`); } return { key: block.slot, @@ -177,7 +177,7 @@ async function migrateBlobSidecarsFromHotToColdDb( .map(async (block) => { const bytes = await db.blobSidecars.getBinary(block.root); if (!bytes) { - throw Error(`No blobSidecars found for slot ${block.slot} root ${toHex(block.root)}`); + throw Error(`No blobSidecars found for slot ${block.slot} root ${toRootHex(block.root)}`); } return {key: block.slot, value: bytes}; }) diff --git a/packages/beacon-node/src/chain/blocks/index.ts b/packages/beacon-node/src/chain/blocks/index.ts index eb8c2663c9b6..a7a2ced2ad7a 100644 --- a/packages/beacon-node/src/chain/blocks/index.ts +++ b/packages/beacon-node/src/chain/blocks/index.ts @@ -1,4 +1,4 @@ -import {toHex, isErrorAborted} from "@lodestar/utils"; +import {isErrorAborted, toRootHex} from "@lodestar/utils"; import {SignedBeaconBlock} from "@lodestar/types"; import {JobItemQueue, isQueueErrorAborted} from "../../util/queue/index.js"; import {Metrics} from "../../metrics/metrics.js"; @@ -127,7 +127,7 @@ export async function processBlocks( const blockSlot = signedBlock.message.slot; const {preState, postState} = err.type; const forkTypes = this.config.getForkTypes(blockSlot); - const invalidRoot = toHex(postState.hashTreeRoot()); + const invalidRoot = toRootHex(postState.hashTreeRoot()); const suffix = `slot_${blockSlot}_invalid_state_root_${invalidRoot}`; this.persistInvalidSszValue(forkTypes.SignedBeaconBlock, signedBlock, suffix); diff --git a/packages/beacon-node/src/chain/blocks/verifyBlock.ts b/packages/beacon-node/src/chain/blocks/verifyBlock.ts index bf4cc7e60dcd..4d21342bd8cc 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlock.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlock.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import { CachedBeaconStateAllForks, computeEpochAtSlot, @@ -9,7 +8,7 @@ import {bellatrix, deneb} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; import {ProtoBlock, ExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; import {ChainForkConfig} from "@lodestar/config"; -import {Logger} from "@lodestar/utils"; +import {Logger, toRootHex} from "@lodestar/utils"; import {BlockError, BlockErrorCode} from "../errors/index.js"; import {BlockProcessOpts} from "../options.js"; import {RegenCaller} from "../regen/index.js"; @@ -198,9 +197,9 @@ export async function verifyBlocksInEpoch( } function logOnPowBlock(logger: Logger, config: ChainForkConfig, mergeBlock: bellatrix.BeaconBlock): void { - const mergeBlockHash = toHexString(config.getForkTypes(mergeBlock.slot).BeaconBlock.hashTreeRoot(mergeBlock)); - const mergeExecutionHash = toHexString(mergeBlock.body.executionPayload.blockHash); - const mergePowHash = toHexString(mergeBlock.body.executionPayload.parentHash); + const mergeBlockHash = toRootHex(config.getForkTypes(mergeBlock.slot).BeaconBlock.hashTreeRoot(mergeBlock)); + const mergeExecutionHash = toRootHex(mergeBlock.body.executionPayload.blockHash); + const mergePowHash = toRootHex(mergeBlock.body.executionPayload.parentHash); logger.info(POS_PANDA_MERGE_TRANSITION_BANNER); logger.info("Execution transitioning from PoW to PoS!!!"); logger.info("Importing block referencing terminal PoW block", { diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts index d08a747259b1..284d4c0976ee 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import { CachedBeaconStateAllForks, isExecutionStateType, @@ -17,7 +16,7 @@ import { LVHInvalidResponse, } from "@lodestar/fork-choice"; import {ChainForkConfig} from "@lodestar/config"; -import {ErrorAborted, Logger} from "@lodestar/utils"; +import {ErrorAborted, Logger, toRootHex} from "@lodestar/utils"; import {ForkSeq, SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY} from "@lodestar/params"; import {IExecutionEngine} from "../../execution/engine/interface.js"; @@ -205,10 +204,8 @@ export async function verifyBlocksExecutionPayload( // in import block if (isMergeTransitionBlock) { const mergeBlock = block.message as bellatrix.BeaconBlock; - const mergeBlockHash = toHexString( - chain.config.getForkTypes(mergeBlock.slot).BeaconBlock.hashTreeRoot(mergeBlock) - ); - const powBlockRootHex = toHexString(mergeBlock.body.executionPayload.parentHash); + const mergeBlockHash = toRootHex(chain.config.getForkTypes(mergeBlock.slot).BeaconBlock.hashTreeRoot(mergeBlock)); + const powBlockRootHex = toRootHex(mergeBlock.body.executionPayload.parentHash); const powBlock = await chain.eth1.getPowBlock(powBlockRootHex).catch((error) => { // Lets just warn the user here, errors if any will be reported on // `assertValidTerminalPowBlock` checks @@ -330,7 +327,7 @@ export async function verifyBlockExecutionPayload( const lvhResponse = { executionStatus, latestValidExecHash: execResult.latestValidHash, - invalidateFromParentBlockRoot: toHexString(block.message.parentRoot), + invalidateFromParentBlockRoot: toRootHex(block.message.parentRoot), }; const execError = new BlockError(block, { code: BlockErrorCode.EXECUTION_ENGINE_ERROR, @@ -407,7 +404,7 @@ function getSegmentErrorResponse( for (let mayBeLVHIndex = blockIndex - 1; mayBeLVHIndex >= 0; mayBeLVHIndex--) { const block = blocks[mayBeLVHIndex]; if ( - toHexString((block.message.body as bellatrix.BeaconBlockBody).executionPayload.blockHash) === + toRootHex((block.message.body as bellatrix.BeaconBlockBody).executionPayload.blockHash) === lvhResponse.latestValidExecHash ) { lvhFound = true; diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts index fcbcfea05d6e..573dfa52ce8b 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts @@ -2,7 +2,7 @@ import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {Slot} from "@lodestar/types"; -import {toHexString, toRootHex} from "@lodestar/utils"; +import {toRootHex} from "@lodestar/utils"; import {IClock} from "../../util/clock.js"; import {BlockError, BlockErrorCode} from "../errors/index.js"; import {BlockInput, ImportBlockOpts} from "./types.js"; @@ -85,9 +85,7 @@ export function verifyBlocksSanityChecks( // Not already known // IGNORE if `partiallyVerifiedBlock.ignoreIfKnown` - const blockHash = toHexString( - chain.config.getForkTypes(block.message.slot).BeaconBlock.hashTreeRoot(block.message) - ); + const blockHash = toRootHex(chain.config.getForkTypes(block.message.slot).BeaconBlock.hashTreeRoot(block.message)); if (chain.forkChoice.hasBlockHex(blockHash)) { if (opts.ignoreIfKnown) { continue; diff --git a/packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts b/packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts index b0f5ab159591..89cf7ddc7556 100644 --- a/packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts +++ b/packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts @@ -1,4 +1,4 @@ -import {toHex} from "@lodestar/utils"; +import {toRootHex} from "@lodestar/utils"; import {BeaconChain} from "../chain.js"; import {BlockInput, BlockInputType} from "./types.js"; @@ -15,7 +15,7 @@ export async function writeBlockInputToDb(this: BeaconChain, blocksInput: BlockI for (const blockInput of blocksInput) { const {block, blockBytes} = blockInput; const blockRoot = this.config.getForkTypes(block.message.slot).BeaconBlock.hashTreeRoot(block.message); - const blockRootHex = toHex(blockRoot); + const blockRootHex = toRootHex(blockRoot); if (blockBytes) { // skip serializing data if we already have it this.metrics?.importBlock.persistBlockWithSerializedDataCount.inc(); @@ -59,7 +59,7 @@ export async function removeEagerlyPersistedBlockInputs(this: BeaconChain, block for (const blockInput of blockInputs) { const {block, type} = blockInput; const blockRoot = this.config.getForkTypes(block.message.slot).BeaconBlock.hashTreeRoot(block.message); - const blockRootHex = toHex(blockRoot); + const blockRootHex = toRootHex(blockRoot); if (!this.forkChoice.hasBlockHex(blockRootHex)) { blockToRemove.push(block); diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 43f72d81e882..75608ab33b2e 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -35,7 +35,7 @@ import { } from "@lodestar/types"; import {CheckpointWithHex, ExecutionStatus, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice"; import {ProcessShutdownCallback} from "@lodestar/validator"; -import {Logger, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toHex, toRootHex} from "@lodestar/utils"; +import {Logger, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toRootHex} from "@lodestar/utils"; import {ForkSeq, GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; import {GENESIS_EPOCH, ZERO_HASH} from "../constants/index.js"; @@ -691,7 +691,7 @@ export class BeaconChain implements IBeaconChain { blockType === BlockType.Full ? this.config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block) : this.config.getExecutionForkTypes(slot).BlindedBeaconBlock.hashTreeRoot(block as BlindedBeaconBlock); - const blockRootHex = toHex(blockRoot); + const blockRootHex = toRootHex(blockRoot); // track the produced block for consensus broadcast validations if (blockType === BlockType.Full) { @@ -729,7 +729,7 @@ export class BeaconChain implements IBeaconChain { * ) */ getContents(beaconBlock: deneb.BeaconBlock): deneb.Contents { - const blockHash = toHex(beaconBlock.body.executionPayload.blockHash); + const blockHash = toRootHex(beaconBlock.body.executionPayload.blockHash); const contents = this.producedContentsCache.get(blockHash); if (!contents) { throw Error(`No contents for executionPayload.blockHash ${blockHash}`); @@ -926,7 +926,7 @@ export class BeaconChain implements IBeaconChain { checkpointRoot: checkpoint.rootHex, stateId, stateSlot: state.slot, - stateRoot: toHex(state.hashTreeRoot()), + stateRoot: toRootHex(state.hashTreeRoot()), }); } @@ -997,7 +997,7 @@ export class BeaconChain implements IBeaconChain { // by default store to lodestar_archive of current dir const dirpath = path.join(this.opts.persistInvalidSszObjectsDir ?? "invalid_ssz_objects", dateStr); - const filepath = path.join(dirpath, `${typeName}_${toHex(root)}.ssz`); + const filepath = path.join(dirpath, `${typeName}_${toRootHex(root)}.ssz`); await ensureDir(dirpath); diff --git a/packages/beacon-node/src/chain/forkChoice/index.ts b/packages/beacon-node/src/chain/forkChoice/index.ts index 385b79dcf713..d57b7f86cb98 100644 --- a/packages/beacon-node/src/chain/forkChoice/index.ts +++ b/packages/beacon-node/src/chain/forkChoice/index.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import {Slot} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import { @@ -91,7 +90,7 @@ export function initializeForkChoice( ...(isExecutionStateType(state) && isMergeTransitionComplete(state) ? { - executionPayloadBlockHash: toHexString(state.latestExecutionPayloadHeader.blockHash), + executionPayloadBlockHash: toRootHex(state.latestExecutionPayloadHeader.blockHash), executionPayloadNumber: state.latestExecutionPayloadHeader.blockNumber, executionStatus: blockHeader.slot === GENESIS_SLOT ? ExecutionStatus.Valid : ExecutionStatus.Syncing, } diff --git a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts index d896c9d3cc35..8277732ea1d5 100644 --- a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts @@ -10,7 +10,7 @@ import { getBlockRootAtSlot, } from "@lodestar/state-transition"; import {IForkChoice, EpochDifference} from "@lodestar/fork-choice"; -import {toHex, MapDef, toRootHex} from "@lodestar/utils"; +import {MapDef, toRootHex} from "@lodestar/utils"; import {intersectUint8Arrays, IntersectResult} from "../../util/bitArray.js"; import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; import {InsertOutcome} from "./types.js"; @@ -514,7 +514,7 @@ export function getValidateAttestationDataFn( } // the isValidAttestationData does not depend on slot and index - const beaconBlockRootHex = toHex(attData.beaconBlockRoot); + const beaconBlockRootHex = toRootHex(attData.beaconBlockRoot); const cacheKey = beaconBlockRootHex + targetEpoch; let isValid = cachedValidatedAttestationData.get(cacheKey); if (isValid === undefined) { @@ -559,7 +559,7 @@ export function isValidAttestationData( if (stateEpoch < 2 || targetEpoch < 2) { return true; } - const beaconBlockRootHex = toHex(data.beaconBlockRoot); + const beaconBlockRootHex = toRootHex(data.beaconBlockRoot); return isValidShuffling(forkChoice, state, beaconBlockRootHex, targetEpoch); } diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index 214fbdc890ec..d1b410610a43 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -32,7 +32,7 @@ import { } from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; import {ForkSeq, ForkExecution, isForkExecution} from "@lodestar/params"; -import {toHex, sleep, Logger} from "@lodestar/utils"; +import {toHex, sleep, Logger, toRootHex} from "@lodestar/utils"; import type {BeaconChain} from "../chain.js"; import {PayloadId, IExecutionEngine, IExecutionBuilder, PayloadAttributes} from "../../execution/index.js"; import {ZERO_HASH, ZERO_HASH_HEX} from "../../constants/index.js"; @@ -273,7 +273,7 @@ export async function produceBlockBody( prepType, payloadId, fetchedTime, - executionHeadBlockHash: toHex(engineRes.executionPayload.blockHash), + executionHeadBlockHash: toRootHex(engineRes.executionPayload.blockHash), }); if (executionPayload.transactions.length === 0) { this.metrics?.blockPayload.emptyPayloads.inc({prepType}); @@ -290,7 +290,7 @@ export async function produceBlockBody( } (blockBody as deneb.BeaconBlockBody).blobKzgCommitments = blobsBundle.commitments; - const blockHash = toHex(executionPayload.blockHash); + const blockHash = toRootHex(executionPayload.blockHash); const contents = {kzgProofs: blobsBundle.proofs, blobs: blobsBundle.blobs}; blobsResult = {type: BlobsResultType.produced, contents, blockHash}; @@ -380,7 +380,7 @@ export async function prepareExecutionPayload( const prevRandao = getRandaoMix(state, state.epochCtx.epoch); const payloadIdCached = chain.executionEngine.payloadIdCache.get({ - headBlockHash: toHex(parentHash), + headBlockHash: toRootHex(parentHash), finalizedBlockHash, timestamp: numToQuantity(timestamp), prevRandao: toHex(prevRandao), @@ -414,7 +414,7 @@ export async function prepareExecutionPayload( payloadId = await chain.executionEngine.notifyForkchoiceUpdate( fork, - toHex(parentHash), + toRootHex(parentHash), safeBlockHash, finalizedBlockHash, attributes diff --git a/packages/beacon-node/src/chain/validation/blobSidecar.ts b/packages/beacon-node/src/chain/validation/blobSidecar.ts index f1ea7bfa95c8..4c82d7be153d 100644 --- a/packages/beacon-node/src/chain/validation/blobSidecar.ts +++ b/packages/beacon-node/src/chain/validation/blobSidecar.ts @@ -1,5 +1,5 @@ import {deneb, Root, Slot, ssz} from "@lodestar/types"; -import {toHex, verifyMerkleBranch} from "@lodestar/utils"; +import {toRootHex, verifyMerkleBranch} from "@lodestar/utils"; import {computeStartSlotAtEpoch, getBlockHeaderProposerSignatureSet} from "@lodestar/state-transition"; import {KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, KZG_COMMITMENT_SUBTREE_INDEX0} from "@lodestar/params"; @@ -57,7 +57,7 @@ export async function validateGossipBlobSidecar( // check, we will load the parent and state from disk only to find out later that we // already know this block. const blockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(blobSidecar.signedBlockHeader.message); - const blockHex = toHex(blockRoot); + const blockHex = toRootHex(blockRoot); if (chain.forkChoice.getBlockHex(blockHex) !== null) { throw new BlobSidecarGossipError(GossipAction.IGNORE, {code: BlobSidecarErrorCode.ALREADY_KNOWN, root: blockHex}); } @@ -68,7 +68,7 @@ export async function validateGossipBlobSidecar( // _[IGNORE]_ The blob's block's parent (defined by `sidecar.block_parent_root`) has been seen (via both // gossip and non-gossip sources) (a client MAY queue blocks for processing once the parent block is // retrieved). - const parentRoot = toHex(blobSidecar.signedBlockHeader.message.parentRoot); + const parentRoot = toRootHex(blobSidecar.signedBlockHeader.message.parentRoot); const parentBlock = chain.forkChoice.getBlockHex(parentRoot); if (parentBlock === null) { // If fork choice does *not* consider the parent to be a descendant of the finalized block, @@ -183,9 +183,9 @@ export function validateBlobSidecars( !byteArrayEquals(expectedKzgCommitments[index], blobSidecar.kzgCommitment) ) { throw new Error( - `Invalid blob with slot=${blobBlockHeader.slot} blobBlockRoot=${toHex(blobBlockRoot)} index=${ + `Invalid blob with slot=${blobBlockHeader.slot} blobBlockRoot=${toRootHex(blobBlockRoot)} index=${ blobSidecar.index - } for the block blockRoot=${toHex(blockRoot)} slot=${blockSlot} index=${index}` + } for the block blockRoot=${toRootHex(blockRoot)} slot=${blockSlot} index=${index}` ); } blobs.push(blobSidecar.blob); diff --git a/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts b/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts index 8602b3058180..9ba4a09a5549 100644 --- a/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts +++ b/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts @@ -1,7 +1,6 @@ -import {toHexString} from "@chainsafe/ssz"; import {ChainConfig} from "@lodestar/config"; import {RootHex} from "@lodestar/types"; -import {Logger, pruneSetToMax} from "@lodestar/utils"; +import {Logger, pruneSetToMax, toRootHex} from "@lodestar/utils"; import {Metrics} from "../metrics/index.js"; import {ZERO_HASH_HEX} from "../constants/index.js"; import {enumToIndexMap} from "../util/enum.js"; @@ -239,7 +238,7 @@ export class Eth1MergeBlockTracker { private async internalGetTerminalPowBlockFromEth1(): Promise { // Search merge block by hash // Terminal block hash override takes precedence over terminal total difficulty - const terminalBlockHash = toHexString(this.config.TERMINAL_BLOCK_HASH); + const terminalBlockHash = toRootHex(this.config.TERMINAL_BLOCK_HASH); if (terminalBlockHash !== ZERO_HASH_HEX) { const block = await this.getPowBlock(terminalBlockHash); if (block) { diff --git a/packages/beacon-node/src/eth1/utils/eth1Vote.ts b/packages/beacon-node/src/eth1/utils/eth1Vote.ts index 3940ccb27bae..cdc8fa04163e 100644 --- a/packages/beacon-node/src/eth1/utils/eth1Vote.ts +++ b/packages/beacon-node/src/eth1/utils/eth1Vote.ts @@ -2,7 +2,7 @@ import {EPOCHS_PER_ETH1_VOTING_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; import {phase0, RootHex} from "@lodestar/types"; import {BeaconStateAllForks, computeTimeAtSlot} from "@lodestar/state-transition"; -import {toHex} from "@lodestar/utils"; +import {toRootHex} from "@lodestar/utils"; export type Eth1DataGetter = ({ timestampRange, @@ -128,7 +128,7 @@ function getEth1DataKey(eth1Data: phase0.Eth1Data): string { * Serialize eth1Data types to a unique string ID. It is only used for comparison. */ export function fastSerializeEth1Data(eth1Data: phase0.Eth1Data): string { - return toHex(eth1Data.blockHash) + eth1Data.depositCount.toString(16) + toHex(eth1Data.depositRoot); + return toRootHex(eth1Data.blockHash) + eth1Data.depositCount.toString(16) + toRootHex(eth1Data.depositRoot); } export function votingPeriodStartTime(config: ChainForkConfig, state: BeaconStateAllForks): number { diff --git a/packages/beacon-node/src/metrics/validatorMonitor.ts b/packages/beacon-node/src/metrics/validatorMonitor.ts index e5c8eef83679..5492f57edc02 100644 --- a/packages/beacon-node/src/metrics/validatorMonitor.ts +++ b/packages/beacon-node/src/metrics/validatorMonitor.ts @@ -8,7 +8,7 @@ import { getBlockRootAtSlot, ParticipationFlags, } from "@lodestar/state-transition"; -import {LogData, LogHandler, LogLevel, Logger, MapDef, MapDefMax, toHex} from "@lodestar/utils"; +import {LogData, LogHandler, LogLevel, Logger, MapDef, MapDefMax, toRootHex} from "@lodestar/utils"; import {BeaconBlock, RootHex, altair, deneb} from "@lodestar/types"; import {ChainConfig, ChainForkConfig} from "@lodestar/config"; import {ForkSeq, INTERVALS_PER_SLOT, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params"; @@ -392,7 +392,7 @@ export function createValidatorMonitor( const summary = getEpochSummary(validator, computeEpochAtSlot(block.slot)); summary.blockProposals.push({ - blockRoot: toHex(config.getForkTypes(block.slot).BeaconBlock.hashTreeRoot(block)), + blockRoot: toRootHex(config.getForkTypes(block.slot).BeaconBlock.hashTreeRoot(block)), blockSlot: block.slot, poolSubmitDelaySec: delaySec, successfullyImported: false, @@ -416,7 +416,7 @@ export function createValidatorMonitor( proposal.successfullyImported = true; } else { summary.blockProposals.push({ - blockRoot: toHex(config.getForkTypes(block.slot).BeaconBlock.hashTreeRoot(block)), + blockRoot: toRootHex(config.getForkTypes(block.slot).BeaconBlock.hashTreeRoot(block)), blockSlot: block.slot, poolSubmitDelaySec: null, successfullyImported: true, @@ -445,7 +445,7 @@ export function createValidatorMonitor( const attestationSummary = validator.attestations .getOrDefault(indexedAttestation.data.target.epoch) - .getOrDefault(toHex(indexedAttestation.data.target.root)); + .getOrDefault(toRootHex(indexedAttestation.data.target.root)); if ( attestationSummary.poolSubmitDelayMinSec === null || attestationSummary.poolSubmitDelayMinSec > delaySec @@ -494,7 +494,7 @@ export function createValidatorMonitor( validator.attestations .getOrDefault(indexedAttestation.data.target.epoch) - .getOrDefault(toHex(indexedAttestation.data.target.root)) + .getOrDefault(toRootHex(indexedAttestation.data.target.root)) .aggregateInclusionDelaysSec.push(delaySec); } } @@ -533,7 +533,7 @@ export function createValidatorMonitor( validator.attestations .getOrDefault(indexedAttestation.data.target.epoch) - .getOrDefault(toHex(indexedAttestation.data.target.root)) + .getOrDefault(toRootHex(indexedAttestation.data.target.root)) .aggregateInclusionDelaysSec.push(delaySec); } } @@ -577,7 +577,7 @@ export function createValidatorMonitor( validator.attestations .getOrDefault(indexedAttestation.data.target.epoch) - .getOrDefault(toHex(indexedAttestation.data.target.root)) + .getOrDefault(toRootHex(indexedAttestation.data.target.root)) .blockInclusions.push({ blockRoot: inclusionBlockRoot, blockSlot: inclusionBlockSlot, @@ -650,7 +650,7 @@ export function createValidatorMonitor( if (config.getForkSeq(headState.slot) >= ForkSeq.altair) { const {previousEpochParticipation} = headState as CachedBeaconStateAltair; const prevEpochStartSlot = computeStartSlotAtEpoch(prevEpoch); - const prevEpochTargetRoot = toHex(getBlockRootAtSlot(headState, prevEpochStartSlot)); + const prevEpochTargetRoot = toRootHex(getBlockRootAtSlot(headState, prevEpochStartSlot)); // Check attestation performance for (const [index, validator] of validators.entries()) { @@ -1041,7 +1041,7 @@ export class RootHexCache { getBlockRootAtSlot(slot: Slot): RootHex { let root = this.blockRootSlotCache.get(slot); if (!root) { - root = toHex(getBlockRootAtSlot(this.state, slot)); + root = toRootHex(getBlockRootAtSlot(this.state, slot)); this.blockRootSlotCache.set(slot, root); } return root; diff --git a/packages/beacon-node/src/network/peers/utils/assertPeerRelevance.ts b/packages/beacon-node/src/network/peers/utils/assertPeerRelevance.ts index 95743331ab2a..96e35e9d317d 100644 --- a/packages/beacon-node/src/network/peers/utils/assertPeerRelevance.ts +++ b/packages/beacon-node/src/network/peers/utils/assertPeerRelevance.ts @@ -1,5 +1,6 @@ import {toHexString} from "@chainsafe/ssz"; import {ForkDigest, Root, Slot, phase0, ssz} from "@lodestar/types"; +import {toRootHex} from "@lodestar/utils"; // TODO: Why this value? (From Lighthouse) const FUTURE_SLOT_TOLERANCE = 1; @@ -82,6 +83,6 @@ export function renderIrrelevantPeerType(type: IrrelevantPeerType): string { case IrrelevantPeerCode.DIFFERENT_CLOCKS: return `DIFFERENT_CLOCKS slotDiff: ${type.slotDiff}`; case IrrelevantPeerCode.DIFFERENT_FINALIZED: - return `DIFFERENT_FINALIZED root: ${toHexString(type.remoteRoot)} expected: ${toHexString(type.expectedRoot)}`; + return `DIFFERENT_FINALIZED root: ${toRootHex(type.remoteRoot)} expected: ${toRootHex(type.expectedRoot)}`; } } diff --git a/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts b/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts index 6aa16a0c2629..144d470d7199 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts @@ -1,7 +1,7 @@ import {ResponseError, ResponseOutgoing, RespStatus} from "@lodestar/reqresp"; import {BLOBSIDECAR_FIXED_SIZE} from "@lodestar/params"; import {deneb, RootHex} from "@lodestar/types"; -import {toHex, fromHex} from "@lodestar/utils"; +import {fromHex, toRootHex} from "@lodestar/utils"; import {IBeaconChain} from "../../../chain/index.js"; import {IBeaconDb} from "../../../db/index.js"; import {BLOB_SIDECARS_IN_WRAPPER_INDEX} from "../../../db/repositories/blobSidecars.js"; @@ -20,7 +20,7 @@ export async function* onBlobSidecarsByRoot( for (const blobIdentifier of requestBody) { const {blockRoot, index} = blobIdentifier; - const blockRootHex = toHex(blockRoot); + const blockRootHex = toRootHex(blockRoot); const block = chain.forkChoice.getBlockHex(blockRootHex); // NOTE: Only support non-finalized blocks. diff --git a/packages/beacon-node/src/sync/backfill/backfill.ts b/packages/beacon-node/src/sync/backfill/backfill.ts index 15ba34f4e583..38258fde07fd 100644 --- a/packages/beacon-node/src/sync/backfill/backfill.ts +++ b/packages/beacon-node/src/sync/backfill/backfill.ts @@ -3,7 +3,7 @@ import {StrictEventEmitter} from "strict-event-emitter-types"; import {BeaconStateAllForks, blockToHeader} from "@lodestar/state-transition"; import {BeaconConfig, ChainForkConfig} from "@lodestar/config"; import {phase0, Root, SignedBeaconBlock, Slot, ssz} from "@lodestar/types"; -import {ErrorAborted, Logger, sleep, toHex, toRootHex} from "@lodestar/utils"; +import {ErrorAborted, Logger, sleep, toRootHex} from "@lodestar/utils"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {IBeaconChain} from "../../chain/index.js"; @@ -527,7 +527,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} ) // TODO: explode and stop the entire node throw new Error( - `InvalidWsCheckpoint root=${toHex(this.wsCheckpointHeader.root)}, epoch=${ + `InvalidWsCheckpoint root=${toRootHex(this.wsCheckpointHeader.root)}, epoch=${ this.wsCheckpointHeader.slot / SLOTS_PER_EPOCH }, ${ wsDbCheckpointBlock @@ -589,7 +589,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} } else { validSequence = false; this.logger.warn( - `Invalid backfill sequence: previous finalized or checkpoint block root=${toHex( + `Invalid backfill sequence: previous finalized or checkpoint block root=${toRootHex( this.prevFinalizedCheckpointBlock.root )}, slot=${this.prevFinalizedCheckpointBlock.slot} ${ prevBackfillCpBlock ? "found at slot=" + prevBackfillCpBlock.message.slot : "not found" @@ -643,7 +643,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} if (cleanupSeqs.length > 0) { await this.db.backfilledRanges.batchDelete(cleanupSeqs.map((entry) => entry.key)); this.logger.debug( - `Cleaned up the old sequences between ${this.backfillStartFromSlot},${toHex( + `Cleaned up the old sequences between ${this.backfillStartFromSlot},${toRootHex( this.syncAnchor.lastBackSyncedBlock.root )}`, {cleanupSeqs: JSON.stringify(cleanupSeqs)} @@ -669,7 +669,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} if (expectedSlot !== null && anchorBlock.message.slot !== expectedSlot) throw Error( - `Invalid slot of anchorBlock read from DB with root=${toHex( + `Invalid slot of anchorBlock read from DB with root=${toRootHex( anchorBlockRoot )}, expected=${expectedSlot}, actual=${anchorBlock.message.slot}` ); @@ -686,7 +686,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} // Before moving anchorBlock back, we need check for prevFinalizedCheckpointBlock if (anchorBlock.message.slot < this.prevFinalizedCheckpointBlock.slot) { throw Error( - `Skipped a prevFinalizedCheckpointBlock with slot=${toHex( + `Skipped a prevFinalizedCheckpointBlock with slot=${toRootHex( this.prevFinalizedCheckpointBlock.root )}, root=${toRootHex(this.prevFinalizedCheckpointBlock.root)}` ); @@ -699,7 +699,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} throw Error( `Invalid root for prevFinalizedCheckpointBlock at slot=${ this.prevFinalizedCheckpointBlock.slot - }, expected=${toRootHex(this.prevFinalizedCheckpointBlock.root)}, found=${toHex(anchorBlockRoot)}` + }, expected=${toRootHex(this.prevFinalizedCheckpointBlock.root)}, found=${toRootHex(anchorBlockRoot)}` ); } diff --git a/packages/beacon-node/src/sync/range/range.ts b/packages/beacon-node/src/sync/range/range.ts index d20e0c3690cd..887a86a3aaf2 100644 --- a/packages/beacon-node/src/sync/range/range.ts +++ b/packages/beacon-node/src/sync/range/range.ts @@ -3,7 +3,7 @@ import {StrictEventEmitter} from "strict-event-emitter-types"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; import {Epoch, phase0} from "@lodestar/types"; -import {Logger, toHex} from "@lodestar/utils"; +import {Logger, toRootHex} from "@lodestar/utils"; import {IBeaconChain} from "../../chain/index.js"; import {INetwork} from "../../network/index.js"; import {Metrics} from "../../metrics/index.js"; @@ -119,7 +119,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) { syncType, startEpoch, targetSlot: target.slot, - targetRoot: toHex(target.root), + targetRoot: toRootHex(target.root), }); // If the peer existed in any other chain, remove it. @@ -242,7 +242,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) { syncType, firstEpoch: syncChain.firstBatchEpoch, targetSlot: syncChain.target.slot, - targetRoot: toHex(syncChain.target.root), + targetRoot: toRootHex(syncChain.target.root), }); } @@ -274,7 +274,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) { lastValidatedSlot: syncChain.lastValidatedSlot, firstEpoch: syncChain.firstBatchEpoch, targetSlot: syncChain.target.slot, - targetRoot: toHex(syncChain.target.root), + targetRoot: toRootHex(syncChain.target.root), validatedEpochs: syncChain.validatedEpochs, }); diff --git a/packages/beacon-node/src/sync/range/utils/chainTarget.ts b/packages/beacon-node/src/sync/range/utils/chainTarget.ts index 221b6e1be68f..15076a028818 100644 --- a/packages/beacon-node/src/sync/range/utils/chainTarget.ts +++ b/packages/beacon-node/src/sync/range/utils/chainTarget.ts @@ -1,5 +1,5 @@ -import {toHexString} from "@chainsafe/ssz"; import {Root, Slot} from "@lodestar/types"; +import {toRootHex} from "@lodestar/utils"; /** * Sync this up to this target. Uses slot instead of epoch to re-use logic for finalized sync @@ -21,7 +21,7 @@ export function computeMostCommonTarget(targets: ChainTarget[]): ChainTarget { let mostCommonCount = 0; for (const target of targets) { - const targetId = `${target.slot}-${toHexString(target.root)}`; + const targetId = `${target.slot}-${toRootHex(target.root)}`; const count = 1 + (countById.get(targetId) ?? 0); countById.set(targetId, count); if (count > mostCommonCount) { diff --git a/packages/beacon-node/src/sync/range/utils/hashBlocks.ts b/packages/beacon-node/src/sync/range/utils/hashBlocks.ts index 522242924a3c..986d023d9ca1 100644 --- a/packages/beacon-node/src/sync/range/utils/hashBlocks.ts +++ b/packages/beacon-node/src/sync/range/utils/hashBlocks.ts @@ -1,6 +1,6 @@ import {RootHex} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; -import {toHex} from "@lodestar/utils"; +import {toRootHex} from "@lodestar/utils"; import {BlockInput} from "../../../chain/blocks/types.js"; /** @@ -12,14 +12,14 @@ export function hashBlocks(blocks: BlockInput[], config: ChainForkConfig): RootH return "0x"; case 1: { const block0 = blocks[0].block; - return toHex(config.getForkTypes(block0.message.slot).SignedBeaconBlock.hashTreeRoot(block0)); + return toRootHex(config.getForkTypes(block0.message.slot).SignedBeaconBlock.hashTreeRoot(block0)); } default: { const block0 = blocks[0].block; const blockN = blocks[blocks.length - 1].block; return ( - toHex(config.getForkTypes(block0.message.slot).SignedBeaconBlock.hashTreeRoot(block0)) + - toHex(config.getForkTypes(blockN.message.slot).SignedBeaconBlock.hashTreeRoot(blockN)) + toRootHex(config.getForkTypes(block0.message.slot).SignedBeaconBlock.hashTreeRoot(block0)) + + toRootHex(config.getForkTypes(blockN.message.slot).SignedBeaconBlock.hashTreeRoot(blockN)) ); } } diff --git a/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts b/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts index 938c272b316a..151f3931cfde 100644 --- a/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts +++ b/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts @@ -32,7 +32,7 @@ describe("eth1 / Eth1MergeBlockTracker", () => { }); it("Should find terminal pow block through TERMINAL_BLOCK_HASH", async () => { - config.TERMINAL_BLOCK_HASH = Buffer.alloc(1, 32); + config.TERMINAL_BLOCK_HASH = Buffer.alloc(32, 1); const block: EthJsonRpcBlockRaw = { number: toHex(10), hash: toRootHex(11), diff --git a/packages/state-transition/src/block/processAttestationPhase0.ts b/packages/state-transition/src/block/processAttestationPhase0.ts index 248ba83b4ed2..95fc575003ee 100644 --- a/packages/state-transition/src/block/processAttestationPhase0.ts +++ b/packages/state-transition/src/block/processAttestationPhase0.ts @@ -1,7 +1,7 @@ -import {toHexString} from "@chainsafe/ssz"; import {Slot, phase0, ssz} from "@lodestar/types"; import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH, ForkSeq} from "@lodestar/params"; +import {toRootHex} from "@lodestar/utils"; import {computeEpochAtSlot} from "../util/index.js"; import {CachedBeaconStatePhase0, CachedBeaconStateAllForks} from "../types.js"; import {isValidIndexedAttestation} from "./index.js"; @@ -113,5 +113,5 @@ export function isTimelyTarget(fork: ForkSeq, inclusionDistance: Slot): boolean } export function checkpointToStr(checkpoint: phase0.Checkpoint): string { - return `${toHexString(checkpoint.root)}:${checkpoint.epoch}`; + return `${toRootHex(checkpoint.root)}:${checkpoint.epoch}`; } diff --git a/packages/state-transition/src/block/processBlockHeader.ts b/packages/state-transition/src/block/processBlockHeader.ts index 755850969b4f..da3e389fb507 100644 --- a/packages/state-transition/src/block/processBlockHeader.ts +++ b/packages/state-transition/src/block/processBlockHeader.ts @@ -1,5 +1,6 @@ -import {toHexString, byteArrayEquals} from "@chainsafe/ssz"; +import {byteArrayEquals} from "@chainsafe/ssz"; import {BeaconBlock, BlindedBeaconBlock, ssz} from "@lodestar/types"; +import {toRootHex} from "@lodestar/utils"; import {CachedBeaconStateAllForks} from "../types.js"; import {ZERO_HASH} from "../constants/index.js"; import {blindedOrFullBlockToHeader} from "../util/index.js"; @@ -32,7 +33,7 @@ export function processBlockHeader(state: CachedBeaconStateAllForks, block: Beac // verify that the parent matches if (!byteArrayEquals(block.parentRoot, ssz.phase0.BeaconBlockHeader.hashTreeRoot(state.latestBlockHeader))) { throw new Error( - `Block parent root ${toHexString(block.parentRoot)} does not match state latest block, block slot=${slot}` + `Block parent root ${toRootHex(block.parentRoot)} does not match state latest block, block slot=${slot}` ); } diff --git a/packages/state-transition/src/block/processWithdrawals.ts b/packages/state-transition/src/block/processWithdrawals.ts index ddea73c27a26..9ae4c570e013 100644 --- a/packages/state-transition/src/block/processWithdrawals.ts +++ b/packages/state-transition/src/block/processWithdrawals.ts @@ -1,4 +1,4 @@ -import {byteArrayEquals, toHexString} from "@chainsafe/ssz"; +import {byteArrayEquals} from "@chainsafe/ssz"; import {ssz, capella} from "@lodestar/types"; import { MAX_EFFECTIVE_BALANCE, @@ -6,6 +6,7 @@ import { MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP, } from "@lodestar/params"; +import {toRootHex} from "@lodestar/utils"; import {CachedBeaconStateCapella} from "../types.js"; import {decreaseBalance, hasEth1WithdrawalCredential, isCapellaPayloadHeader} from "../util/index.js"; @@ -21,9 +22,9 @@ export function processWithdrawals( const actualWithdrawalsRoot = payload.withdrawalsRoot; if (!byteArrayEquals(expectedWithdrawalsRoot, actualWithdrawalsRoot)) { throw Error( - `Invalid withdrawalsRoot of executionPayloadHeader, expected=${toHexString( + `Invalid withdrawalsRoot of executionPayloadHeader, expected=${toRootHex( expectedWithdrawalsRoot - )}, actual=${toHexString(actualWithdrawalsRoot)}` + )}, actual=${toRootHex(actualWithdrawalsRoot)}` ); } } else { diff --git a/packages/state-transition/src/stateTransition.ts b/packages/state-transition/src/stateTransition.ts index 78bcaa140c62..a454bf4b34d0 100644 --- a/packages/state-transition/src/stateTransition.ts +++ b/packages/state-transition/src/stateTransition.ts @@ -1,6 +1,6 @@ -import {toHexString} from "@chainsafe/ssz"; import {SignedBeaconBlock, SignedBlindedBeaconBlock, Slot, ssz} from "@lodestar/types"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {toRootHex} from "@lodestar/utils"; import {BeaconStateTransitionMetrics, onPostStateMetrics, onStateCloneMetrics} from "./metrics.js"; import {beforeProcessEpoch, EpochTransitionCache, EpochTransitionCacheOpts} from "./cache/epochTransitionCache.js"; import { @@ -123,7 +123,7 @@ export function stateTransition( if (!ssz.Root.equals(block.stateRoot, stateRoot)) { throw new Error( - `Invalid state root at slot ${block.slot}, expected=${toHexString(block.stateRoot)}, actual=${toHexString( + `Invalid state root at slot ${block.slot}, expected=${toRootHex(block.stateRoot)}, actual=${toRootHex( stateRoot )}` ); diff --git a/packages/state-transition/src/util/epochShuffling.ts b/packages/state-transition/src/util/epochShuffling.ts index e101da38f297..856721d8d083 100644 --- a/packages/state-transition/src/util/epochShuffling.ts +++ b/packages/state-transition/src/util/epochShuffling.ts @@ -1,6 +1,5 @@ -import {toHexString} from "@chainsafe/ssz"; import {Epoch, RootHex, ValidatorIndex} from "@lodestar/types"; -import {intDiv} from "@lodestar/utils"; +import {intDiv, toRootHex} from "@lodestar/utils"; import { DOMAIN_BEACON_ATTESTER, MAX_COMMITTEES_PER_SLOT, @@ -108,5 +107,5 @@ export function computeEpochShuffling( export function getShufflingDecisionBlock(state: BeaconStateAllForks, epoch: Epoch): RootHex { const pivotSlot = computeStartSlotAtEpoch(epoch - 1) - 1; - return toHexString(getBlockRootAtSlot(state, pivotSlot)); + return toRootHex(getBlockRootAtSlot(state, pivotSlot)); } diff --git a/packages/state-transition/src/util/weakSubjectivity.ts b/packages/state-transition/src/util/weakSubjectivity.ts index 6bd6636c3e70..0e606e66340f 100644 --- a/packages/state-transition/src/util/weakSubjectivity.ts +++ b/packages/state-transition/src/util/weakSubjectivity.ts @@ -1,9 +1,9 @@ -import {toHexString} from "@chainsafe/ssz"; import {BeaconConfig, ChainForkConfig} from "@lodestar/config"; import {EFFECTIVE_BALANCE_INCREMENT, MAX_DEPOSITS, MAX_EFFECTIVE_BALANCE, SLOTS_PER_EPOCH} from "@lodestar/params"; import {Epoch, Root} from "@lodestar/types"; import {ssz} from "@lodestar/types"; import {Checkpoint} from "@lodestar/types/phase0"; +import {toRootHex} from "@lodestar/utils"; import {ZERO_HASH} from "../constants/constants.js"; import {BeaconStateAllForks, CachedBeaconStateAllForks} from "../types.js"; import {computeEpochAtSlot, getCurrentEpoch, computeCheckpointEpochAtStateSlot} from "./epoch.js"; @@ -127,9 +127,7 @@ export function ensureWithinWeakSubjectivityPeriod( const wsStateEpoch = computeCheckpointEpochAtStateSlot(wsState.slot); const blockRoot = getLatestBlockRoot(wsState); if (!ssz.Root.equals(blockRoot, wsCheckpoint.root)) { - throw new Error( - `Roots do not match. expected=${toHexString(wsCheckpoint.root)}, actual=${toHexString(blockRoot)}` - ); + throw new Error(`Roots do not match. expected=${toRootHex(wsCheckpoint.root)}, actual=${toRootHex(blockRoot)}`); } if (!ssz.Epoch.equals(wsStateEpoch, wsCheckpoint.epoch)) { throw new Error(`Epochs do not match. expected=${wsCheckpoint.epoch}, actual=${wsStateEpoch}`); diff --git a/packages/utils/src/bytes.ts b/packages/utils/src/bytes.ts index f4a622da021e..820cf7d63300 100644 --- a/packages/utils/src/bytes.ts +++ b/packages/utils/src/bytes.ts @@ -63,6 +63,10 @@ const rootBuf = Buffer.alloc(32); * Convert a Uint8Array, length 32, to 0x-prefixed hex string */ export function toRootHex(root: Uint8Array): string { + if (root.length !== 32) { + throw Error(`Expect root to be 32 bytes, got ${root.length}`); + } + rootBuf.set(root); return `0x${rootBuf.toString("hex")}`; } From 550c349259cb458cf58926cc042d23fe08fd9c1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:38:46 +0000 Subject: [PATCH 005/259] chore(deps): bump axios from 1.6.0 to 1.7.4 (#7020) * chore(deps): bump axios from 1.6.0 to 1.7.4 Bumps [axios](https://github.com/axios/axios) from 1.6.0 to 1.7.4. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.6.0...v1.7.4) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production ... Signed-off-by: dependabot[bot] * chore: dedupe dependency versions * chore: dedupe dependency versions --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cayman --- yarn.lock | 105 ++++++++++++++++++++++-------------------------------- 1 file changed, 43 insertions(+), 62 deletions(-) diff --git a/yarn.lock b/yarn.lock index f561a557351e..d47feb4514f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2636,18 +2636,18 @@ integrity sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ== "@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" - integrity sha512-hZ/JhxPIceWaGSEzUZp83/8M49CoxlkuThfTR7t4AoCu5+ZvJ3vktLm60Otww2TXeROB5igiZ8D9oPQh6ckBVg== + version "2.3.0" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.3.0.tgz#791ea7d80450fea24eb19fb1d70c367ad4e08cae" + integrity sha512-ioXoq9gPxkss4MYhD+SFaU9p1IHFUX0ILAWFPyjGaBdjLsYAlZw6j1iLA0N/m12uVHLFDfSYNF7EQccjinIMDA== dependencies: - debug "4.3.4" - extract-zip "2.0.1" - progress "2.0.3" - proxy-agent "6.4.0" - semver "7.6.0" - tar-fs "3.0.5" - unbzip2-stream "1.4.3" - yargs "17.7.2" + debug "^4.3.5" + extract-zip "^2.0.1" + progress "^2.0.3" + proxy-agent "^6.4.0" + semver "^7.6.3" + tar-fs "^3.0.6" + unbzip2-stream "^1.4.3" + yargs "^17.7.2" "@rollup/plugin-inject@^5.0.5": version "5.0.5" @@ -4313,11 +4313,11 @@ aws-sdk@^2.932.0: xml2js "0.4.19" axios@^1.0.0, axios@^1.3.4: - version "1.6.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" - integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== + version "1.7.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2" + integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw== dependencies: - follow-redirects "^1.15.0" + follow-redirects "^1.15.6" form-data "^4.0.0" proxy-from-env "^1.1.0" @@ -6550,7 +6550,7 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" -extract-zip@2.0.1, extract-zip@^2.0.1: +extract-zip@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== @@ -6831,7 +6831,7 @@ fn.name@1.x.x: resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -follow-redirects@^1.0.0, follow-redirects@^1.15.0: +follow-redirects@^1.0.0, follow-redirects@^1.15.6: version "1.15.6" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== @@ -7057,7 +7057,7 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.0: +get-func-name@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== @@ -7642,18 +7642,10 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" - integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== - dependencies: - agent-base "^7.0.2" - debug "4" - -https-proxy-agent@^7.0.3, https-proxy-agent@^7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz#8e97b841a029ad8ddc8731f26595bad868cb4168" - integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg== +https-proxy-agent@^7.0.2, https-proxy-agent@^7.0.3, https-proxy-agent@^7.0.4: + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== dependencies: agent-base "^7.0.2" debug "4" @@ -9029,11 +9021,11 @@ loglevel@^1.6.0: integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg== loupe@^2.3.6, loupe@^3.1.0, loupe@^3.1.1: - version "2.3.6" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" - integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== dependencies: - get-func-name "^2.0.0" + get-func-name "^2.0.1" lowercase-keys@^2.0.0: version "2.0.0" @@ -9703,9 +9695,9 @@ n12@0.4.0: integrity sha512-p/hj4zQ8d3pbbFLQuN1K9honUxiDDhueOWyFLw/XgBv+wZCE44bcLH4CIcsolOceJQduh4Jf7m/LfaTxyGmGtQ== 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== + version "2.20.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" + integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw== nanoid@3.3.3: version "3.3.3" @@ -10845,7 +10837,7 @@ progress-events@^1.0.0: resolved "https://registry.yarnpkg.com/progress-events/-/progress-events-1.0.0.tgz#34f5e8fdb5dae3561837b22672d1e02277bb2109" integrity sha512-zIB6QDrSbPfRg+33FZalluFIowkbV5Xh1xSuetjG+rlC5he6u2dc6VQJ0TbMdlN3R1RHdpOqxEFMKTnQ+itUwA== -progress@2.0.3, progress@^2.0.3: +progress@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -10916,7 +10908,7 @@ proxy-addr@^2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -proxy-agent@6.4.0: +proxy-agent@^6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.4.0.tgz#b4e2dd51dee2b377748aef8d45604c2d7608652d" integrity sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ== @@ -11600,19 +11592,17 @@ semver@7.5.3: dependencies: lru-cache "^6.0.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== - dependencies: - lru-cache "^6.0.0" - semver@^6.1.0, semver@^6.2.0, semver@^6.3.1: version "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.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.6.0, semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +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== @@ -12309,10 +12299,10 @@ tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tar-fs@3.0.5, tar-fs@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.5.tgz#f954d77767e4e6edf973384e1eb95f8f81d64ed9" - integrity sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg== +tar-fs@^3.0.4, tar-fs@^3.0.5, tar-fs@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.6.tgz#eaccd3a67d5672f09ca8e8f9c3d2b89fa173f217" + integrity sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w== dependencies: pump "^3.0.0" tar-stream "^3.1.5" @@ -12320,15 +12310,6 @@ tar-fs@3.0.5, tar-fs@^3.0.5: bare-fs "^2.1.1" bare-path "^2.1.0" -tar-fs@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.4.tgz#a21dc60a2d5d9f55e0089ccd78124f1d3771dbbf" - integrity sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w== - dependencies: - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^3.1.5" - tar-fs@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2" @@ -12877,7 +12858,7 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -unbzip2-stream@1.4.3: +unbzip2-stream@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== @@ -13886,7 +13867,7 @@ yargs@16.2.0, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@17.7.2, yargs@^17.1.1, yargs@^17.5.1, yargs@^17.6.2, yargs@^17.7.1, yargs@^17.7.2: +yargs@^17.1.1, yargs@^17.5.1, yargs@^17.6.2, yargs@^17.7.1, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== From 6f470f8a35dcd5f39be8cdc5f59c513e1ab00fec Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sun, 18 Aug 2024 03:00:02 +0100 Subject: [PATCH 006/259] fix: return 404 error if no sync committee contribution is available (#6649) * fix: return 404 error if no sync committee contribution is available * Return 404 error if block not in fork choice --- packages/beacon-node/src/api/impl/validator/index.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 9d692a4cc405..ca0fe1ac95a2 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -324,7 +324,7 @@ export function getValidatorApi( function notOnOptimisticBlockRoot(beaconBlockRoot: Root): void { const protoBeaconBlock = chain.forkChoice.getBlock(beaconBlockRoot); if (!protoBeaconBlock) { - throw new ApiError(400, `Block not in forkChoice, beaconBlockRoot=${toRootHex(beaconBlockRoot)}`); + throw new ApiError(404, `Block not in forkChoice, beaconBlockRoot=${toRootHex(beaconBlockRoot)}`); } if (protoBeaconBlock.executionStatus === ExecutionStatus.Syncing) @@ -336,7 +336,7 @@ export function getValidatorApi( function notOnOutOfRangeData(beaconBlockRoot: Root): void { const protoBeaconBlock = chain.forkChoice.getBlock(beaconBlockRoot); if (!protoBeaconBlock) { - throw new ApiError(400, `Block not in forkChoice, beaconBlockRoot=${toRootHex(beaconBlockRoot)}`); + throw new ApiError(404, `Block not in forkChoice, beaconBlockRoot=${toRootHex(beaconBlockRoot)}`); } if (protoBeaconBlock.dataAvailabilityStatus === DataAvailabilityStatus.OutOfRange) @@ -880,7 +880,12 @@ export function getValidatorApi( notOnOutOfRangeData(beaconBlockRoot); const contribution = chain.syncCommitteeMessagePool.getContribution(subcommitteeIndex, slot, beaconBlockRoot); - if (!contribution) throw new ApiError(500, "No contribution available"); + if (!contribution) { + throw new ApiError( + 404, + `No sync committee contribution for slot=${slot}, subnet=${subcommitteeIndex}, beaconBlockRoot=${toRootHex(beaconBlockRoot)}` + ); + } metrics?.production.producedSyncContributionParticipants.observe( contribution.aggregationBits.getTrueBitIndexes().length From 4ea7edd6a7482f3131a03f9cde931bf835ce0e03 Mon Sep 17 00:00:00 2001 From: Phil Ngo <58080811+philknows@users.noreply.github.com> Date: Mon, 19 Aug 2024 10:33:33 -0400 Subject: [PATCH 007/259] chore: update license on state-transition (#7037) Update LICENSE --- packages/state-transition/LICENSE | 366 ++++++++++++++++-------------- 1 file changed, 201 insertions(+), 165 deletions(-) diff --git a/packages/state-transition/LICENSE b/packages/state-transition/LICENSE index 153d416dc8d2..261eeb9e9f8b 100644 --- a/packages/state-transition/LICENSE +++ b/packages/state-transition/LICENSE @@ -1,165 +1,201 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. \ No newline at end of file + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From 6d015933230fdb4d3a5c512c570caea3b3ff7e13 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 22 Aug 2024 11:47:55 +0100 Subject: [PATCH 008/259] chore: update keymanager spec tests to run against v1.1.0 (#7044) --- packages/api/test/unit/keymanager/oapiSpec.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/test/unit/keymanager/oapiSpec.test.ts b/packages/api/test/unit/keymanager/oapiSpec.test.ts index 10c29f0cea55..97011f5d3660 100644 --- a/packages/api/test/unit/keymanager/oapiSpec.test.ts +++ b/packages/api/test/unit/keymanager/oapiSpec.test.ts @@ -12,7 +12,7 @@ import {testData} from "./testData.js"; // eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const version = "v1.0.0"; +const version = "v1.1.0"; const openApiFile: OpenApiFile = { url: `https://github.com/ethereum/keymanager-APIs/releases/download/${version}/keymanager-oapi.json`, filepath: path.join(__dirname, "../../../oapi-schemas/keymanager-oapi.json"), From 5d2e1a7228483af92930a32ce76277eee9977b01 Mon Sep 17 00:00:00 2001 From: Phil Ngo <58080811+philknows@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:04:16 -0400 Subject: [PATCH 009/259] chore: generate funding.json for OP RPGF (#7051) generate funding.json for OP RPGF --- funding.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 funding.json diff --git a/funding.json b/funding.json new file mode 100644 index 000000000000..872321cdca5b --- /dev/null +++ b/funding.json @@ -0,0 +1,5 @@ +{ + "opRetro": { + "projectId": "0x8ec88058175ef4c1c9b1f26910c4d4f2cfa733d6fcd1dbd9385476a313d9e12d" + } +} From d87e63729104bfb9d0925d936046ec4a057822e4 Mon Sep 17 00:00:00 2001 From: harkamal Date: Wed, 24 Jan 2024 17:38:11 +0530 Subject: [PATCH 010/259] feat: placeholder PR for electra add types stub and epoch config fix types --- .../beacon-node/src/chain/blocks/types.ts | 2 +- .../test/spec/presets/fork.test.ts | 2 + .../test/spec/presets/transition.test.ts | 8 + .../upgradeLightClientHeader.test.ts | 33 +++- .../test/unit/network/fork.test.ts | 13 +- packages/beacon-node/test/utils/config.ts | 8 + .../config/src/chainConfig/configs/mainnet.ts | 4 + .../config/src/chainConfig/configs/minimal.ts | 4 + packages/config/src/chainConfig/types.ts | 6 + packages/config/src/forkConfig/index.ts | 10 +- packages/light-client/src/spec/utils.ts | 4 + packages/params/src/forkName.ts | 2 + .../test/unit/upgradeState.test.ts | 8 + packages/types/src/electra/index.ts | 3 + packages/types/src/electra/sszTypes.ts | 148 ++++++++++++++++++ packages/types/src/electra/types.ts | 29 ++++ packages/types/src/sszTypes.ts | 4 +- packages/types/src/types.ts | 36 +++++ packages/validator/src/util/params.ts | 5 + 19 files changed, 323 insertions(+), 6 deletions(-) create mode 100644 packages/types/src/electra/index.ts create mode 100644 packages/types/src/electra/sszTypes.ts create mode 100644 packages/types/src/electra/types.ts diff --git a/packages/beacon-node/src/chain/blocks/types.ts b/packages/beacon-node/src/chain/blocks/types.ts index da573bb76334..5eb5eebc7840 100644 --- a/packages/beacon-node/src/chain/blocks/types.ts +++ b/packages/beacon-node/src/chain/blocks/types.ts @@ -36,7 +36,7 @@ export enum GossipedInputType { type BlobsCacheMap = Map; -type ForkBlobsInfo = {fork: ForkName.deneb}; +type ForkBlobsInfo = {fork: ForkName.deneb | ForkName.electra}; type BlobsData = {blobs: deneb.BlobSidecars; blobsBytes: (Uint8Array | null)[]; blobsSource: BlobsSource}; export type BlockInputDataBlobs = ForkBlobsInfo & BlobsData; export type BlockInputData = BlockInputDataBlobs; diff --git a/packages/beacon-node/test/spec/presets/fork.test.ts b/packages/beacon-node/test/spec/presets/fork.test.ts index 228ab6a38935..c880d24bbbe3 100644 --- a/packages/beacon-node/test/spec/presets/fork.test.ts +++ b/packages/beacon-node/test/spec/presets/fork.test.ts @@ -35,6 +35,8 @@ const fork: TestRunnerFn = (forkNext) => { return slotFns.upgradeStateToCapella(preState as CachedBeaconStateBellatrix); case ForkName.deneb: return slotFns.upgradeStateToDeneb(preState as CachedBeaconStateCapella); + case ForkName.electra: + throw Error("not Implemented"); } }, options: { diff --git a/packages/beacon-node/test/spec/presets/transition.test.ts b/packages/beacon-node/test/spec/presets/transition.test.ts index d9925f292677..cae7c667b590 100644 --- a/packages/beacon-node/test/spec/presets/transition.test.ts +++ b/packages/beacon-node/test/spec/presets/transition.test.ts @@ -102,6 +102,14 @@ function getTransitionConfig(fork: ForkName, forkEpoch: number): Partial${toFork}`, function () { + lcHeaderByFork[fromFork].beacon.slot = testSlots[fromFork]; + lcHeaderByFork[toFork].beacon.slot = testSlots[fromFork]; + + expect(() => { + upgradeLightClientHeader(config, toFork, lcHeaderByFork[fromFork]); + }).toThrow("Not Implemented"); + }); + } + + // Since electra is not implemented for loop is till deneb (Object.values(ForkName).length-1) + // Once electra is implemnted run for loop till Object.values(ForkName).length + + // for (let i = ForkSeq.altair; i < Object.values(ForkName).length; i++) { + + for (let i = ForkSeq.altair; i < Object.values(ForkName).length - 1; i++) { for (let j = i; j > 0; j--) { const fromFork = ForkName[ForkSeq[i] as ForkName]; const toFork = ForkName[ForkSeq[j] as ForkName]; diff --git a/packages/beacon-node/test/unit/network/fork.test.ts b/packages/beacon-node/test/unit/network/fork.test.ts index be748d2e8185..bbe1c0870d30 100644 --- a/packages/beacon-node/test/unit/network/fork.test.ts +++ b/packages/beacon-node/test/unit/network/fork.test.ts @@ -9,12 +9,14 @@ function getForkConfig({ bellatrix, capella, deneb, + electra, }: { phase0: number; altair: number; bellatrix: number; capella: number; deneb: number; + electra: number; }): BeaconConfig { const forks: Record = { phase0: { @@ -57,6 +59,14 @@ function getForkConfig({ prevVersion: Buffer.from([0, 0, 0, 3]), prevForkName: ForkName.capella, }, + electra: { + name: ForkName.electra, + seq: ForkSeq.electra, + epoch: electra, + version: Buffer.from([0, 0, 0, 5]), + prevVersion: Buffer.from([0, 0, 0, 4]), + prevForkName: ForkName.deneb, + }, }; const forksAscendingEpochOrder = Object.values(forks); const forksDescendingEpochOrder = Object.values(forks).reverse(); @@ -133,9 +143,10 @@ const testScenarios = [ for (const testScenario of testScenarios) { const {phase0, altair, bellatrix, capella, testCases} = testScenario; const deneb = Infinity; + const electra = Infinity; describe(`network / fork: phase0: ${phase0}, altair: ${altair}, bellatrix: ${bellatrix} capella: ${capella}`, () => { - const forkConfig = getForkConfig({phase0, altair, bellatrix, capella, deneb}); + const forkConfig = getForkConfig({phase0, altair, bellatrix, capella, deneb, electra}); const forks = forkConfig.forks; for (const testCase of testCases) { const {epoch, currentFork, nextFork, activeForks} = testCase; diff --git a/packages/beacon-node/test/utils/config.ts b/packages/beacon-node/test/utils/config.ts index 54c058d30722..2aad1c14c03e 100644 --- a/packages/beacon-node/test/utils/config.ts +++ b/packages/beacon-node/test/utils/config.ts @@ -31,5 +31,13 @@ export function getConfig(fork: ForkName, forkEpoch = 0): ChainForkConfig { CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: forkEpoch, }); + case ForkName.electra: + return createChainForkConfig({ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: forkEpoch, + }); } } diff --git a/packages/config/src/chainConfig/configs/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts index 883688ca821b..0de1bee666ec 100644 --- a/packages/config/src/chainConfig/configs/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -49,6 +49,10 @@ export const chainConfig: ChainConfig = { DENEB_FORK_VERSION: b("0x04000000"), DENEB_FORK_EPOCH: 269568, // March 13, 2024, 01:55:35pm UTC + // Electra + ELECTRA_FORK_VERSION: b("0x05000000"), + ELECTRA_FORK_EPOCH: Infinity, + // Time parameters // --------------------------------------------------------------- // 12 seconds diff --git a/packages/config/src/chainConfig/configs/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts index 23cd14e763ec..c99a76d1ee40 100644 --- a/packages/config/src/chainConfig/configs/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -46,6 +46,10 @@ export const chainConfig: ChainConfig = { DENEB_FORK_VERSION: b("0x04000001"), DENEB_FORK_EPOCH: Infinity, + // Electra + ELECTRA_FORK_VERSION: b("0x05000001"), + ELECTRA_FORK_EPOCH: Infinity, + // Time parameters // --------------------------------------------------------------- // [customized] Faster for testing purposes diff --git a/packages/config/src/chainConfig/types.ts b/packages/config/src/chainConfig/types.ts index 45f05bfaa724..234a08558be5 100644 --- a/packages/config/src/chainConfig/types.ts +++ b/packages/config/src/chainConfig/types.ts @@ -40,6 +40,9 @@ export type ChainConfig = { // DENEB DENEB_FORK_VERSION: Uint8Array; DENEB_FORK_EPOCH: number; + // ELECTRA + ELECTRA_FORK_VERSION: Uint8Array; + ELECTRA_FORK_EPOCH: number; // Time parameters SECONDS_PER_SLOT: number; @@ -99,6 +102,9 @@ export const chainConfigTypes: SpecTypes = { // DENEB DENEB_FORK_VERSION: "bytes", DENEB_FORK_EPOCH: "number", + // ELECTRA + ELECTRA_FORK_VERSION: "bytes", + ELECTRA_FORK_EPOCH: "number", // Time parameters SECONDS_PER_SLOT: "number", diff --git a/packages/config/src/forkConfig/index.ts b/packages/config/src/forkConfig/index.ts index 16d8952548b8..54edc8b618e0 100644 --- a/packages/config/src/forkConfig/index.ts +++ b/packages/config/src/forkConfig/index.ts @@ -59,10 +59,18 @@ export function createForkConfig(config: ChainConfig): ForkConfig { prevVersion: config.CAPELLA_FORK_VERSION, prevForkName: ForkName.capella, }; + const electra: ForkInfo = { + name: ForkName.electra, + seq: ForkSeq.electra, + epoch: config.ELECTRA_FORK_EPOCH, + version: config.ELECTRA_FORK_VERSION, + prevVersion: config.DENEB_FORK_VERSION, + prevForkName: ForkName.deneb, + }; /** Forks in order order of occurence, `phase0` first */ // Note: Downstream code relies on proper ordering. - const forks = {phase0, altair, bellatrix, capella, deneb}; + const forks = {phase0, altair, bellatrix, capella, deneb, electra}; // Prevents allocating an array on every getForkInfo() call const forksAscendingEpochOrder = Object.values(forks); diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 65d6f3e84c59..aafd81c9250a 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -112,6 +112,10 @@ export function upgradeLightClientHeader( // Break if no further upgradation is required else fall through if (ForkSeq[targetFork] <= ForkSeq.deneb) break; + + // eslint-disable-next-line no-fallthrough + case ForkName.electra: + throw Error("Not Implemented"); } return upgradedHeader; } diff --git a/packages/params/src/forkName.ts b/packages/params/src/forkName.ts index a5f6d49d1cef..e1f1b2eda73a 100644 --- a/packages/params/src/forkName.ts +++ b/packages/params/src/forkName.ts @@ -7,6 +7,7 @@ export enum ForkName { bellatrix = "bellatrix", capella = "capella", deneb = "deneb", + electra = "electra", } /** @@ -18,6 +19,7 @@ export enum ForkSeq { bellatrix = 2, capella = 3, deneb = 4, + electra = 5, } function exclude(coll: T[], val: U[]): Exclude[] { diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 2ea8eef182ac..75ba415c1bea 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -55,5 +55,13 @@ function getConfig(fork: ForkName, forkEpoch = 0): ChainForkConfig { CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: forkEpoch, }); + case ForkName.electra: + return createChainForkConfig({ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: forkEpoch, + }); } } diff --git a/packages/types/src/electra/index.ts b/packages/types/src/electra/index.ts new file mode 100644 index 000000000000..7856cd729620 --- /dev/null +++ b/packages/types/src/electra/index.ts @@ -0,0 +1,3 @@ +export * from "./types.js"; +export * as ts from "./types.js"; +export * as ssz from "./sszTypes.js"; diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts new file mode 100644 index 000000000000..30690a499845 --- /dev/null +++ b/packages/types/src/electra/sszTypes.ts @@ -0,0 +1,148 @@ +import {ContainerType} from "@chainsafe/ssz"; +import {ssz as primitiveSsz} from "../primitive/index.js"; +import {ssz as denebSsz} from "../deneb/index.js"; + +const {BLSSignature} = primitiveSsz; + +export const ExecutionPayload = new ContainerType( + { + ...denebSsz.ExecutionPayload.fields, + }, + {typeName: "ExecutionPayload", jsonCase: "eth2"} +); + +export const ExecutionPayloadHeader = new ContainerType( + { + ...denebSsz.ExecutionPayloadHeader.fields, + }, + {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} +); + +export const BeaconBlockBody = new ContainerType( + { + ...denebSsz.BeaconBlockBody.fields, + }, + {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const BeaconBlock = new ContainerType( + { + ...denebSsz.BeaconBlock.fields, + }, + {typeName: "BeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const SignedBeaconBlock = new ContainerType( + { + message: BeaconBlock, + signature: BLSSignature, + }, + {typeName: "SignedBeaconBlock", jsonCase: "eth2"} +); + +export const BlobSidecar = new ContainerType( + { + ...denebSsz.BlobSidecar.fields, + }, + {typeName: "BlobSidecar", jsonCase: "eth2"} +); + +export const BlindedBeaconBlockBody = new ContainerType( + { + ...denebSsz.BlindedBeaconBlockBody.fields, + }, + {typeName: "BlindedBeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const BlindedBeaconBlock = new ContainerType( + { + ...denebSsz.BlindedBeaconBlock.fields, + }, + {typeName: "BlindedBeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const SignedBlindedBeaconBlock = new ContainerType( + { + message: BlindedBeaconBlock, + signature: BLSSignature, + }, + {typeName: "SignedBlindedBeaconBlock", jsonCase: "eth2"} +); + +export const BuilderBid = new ContainerType( + { + ...denebSsz.BuilderBid.fields, + }, + {typeName: "BuilderBid", jsonCase: "eth2"} +); + +export const SignedBuilderBid = new ContainerType( + { + message: BuilderBid, + signature: BLSSignature, + }, + {typeName: "SignedBuilderBid", jsonCase: "eth2"} +); + +export const ExecutionPayloadAndBlobsBundle = new ContainerType( + { + ...denebSsz.ExecutionPayloadAndBlobsBundle.fields, + }, + {typeName: "ExecutionPayloadAndBlobsBundle", jsonCase: "eth2"} +); + +export const BeaconState = new ContainerType( + { + ...denebSsz.BeaconState.fields, + }, + {typeName: "BeaconState", jsonCase: "eth2"} +); + +export const LightClientHeader = new ContainerType( + { + ...denebSsz.LightClientHeader.fields, + }, + {typeName: "LightClientHeader", jsonCase: "eth2"} +); + +export const LightClientBootstrap = new ContainerType( + { + ...denebSsz.LightClientBootstrap.fields, + }, + {typeName: "LightClientBootstrap", jsonCase: "eth2"} +); + +export const LightClientUpdate = new ContainerType( + { + ...denebSsz.LightClientUpdate.fields, + }, + {typeName: "LightClientUpdate", jsonCase: "eth2"} +); + +export const LightClientFinalityUpdate = new ContainerType( + { + ...denebSsz.LightClientFinalityUpdate.fields, + }, + {typeName: "LightClientFinalityUpdate", jsonCase: "eth2"} +); + +export const LightClientOptimisticUpdate = new ContainerType( + { + ...denebSsz.LightClientOptimisticUpdate.fields, + }, + {typeName: "LightClientOptimisticUpdate", jsonCase: "eth2"} +); + +export const LightClientStore = new ContainerType( + { + ...denebSsz.LightClientStore.fields, + }, + {typeName: "LightClientStore", jsonCase: "eth2"} +); + +export const SSEPayloadAttributes = new ContainerType( + { + ...denebSsz.SSEPayloadAttributes.fields, + }, + {typeName: "SSEPayloadAttributes", jsonCase: "eth2"} +); diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts new file mode 100644 index 000000000000..198259eed1dd --- /dev/null +++ b/packages/types/src/electra/types.ts @@ -0,0 +1,29 @@ +import {ValueOf} from "@chainsafe/ssz"; +import * as ssz from "./sszTypes.js"; + +export type BlobSidecar = ValueOf; +export type ExecutionPayloadAndBlobsBundle = ValueOf; + +export type ExecutionPayload = ValueOf; +export type ExecutionPayloadHeader = ValueOf; + +export type BeaconBlockBody = ValueOf; +export type BeaconBlock = ValueOf; +export type SignedBeaconBlock = ValueOf; + +export type BeaconState = ValueOf; + +export type BlindedBeaconBlockBody = ValueOf; +export type BlindedBeaconBlock = ValueOf; +export type SignedBlindedBeaconBlock = ValueOf; + +export type BuilderBid = ValueOf; +export type SignedBuilderBid = ValueOf; +export type SSEPayloadAttributes = ValueOf; + +export type LightClientHeader = ValueOf; +export type LightClientBootstrap = ValueOf; +export type LightClientUpdate = ValueOf; +export type LightClientFinalityUpdate = ValueOf; +export type LightClientOptimisticUpdate = ValueOf; +export type LightClientStore = ValueOf; diff --git a/packages/types/src/sszTypes.ts b/packages/types/src/sszTypes.ts index 60980fa0822a..c2044edb5e98 100644 --- a/packages/types/src/sszTypes.ts +++ b/packages/types/src/sszTypes.ts @@ -5,9 +5,10 @@ import {ssz as altair} from "./altair/index.js"; import {ssz as bellatrix} from "./bellatrix/index.js"; import {ssz as capella} from "./capella/index.js"; import {ssz as deneb} from "./deneb/index.js"; +import {ssz as electra} from "./electra/index.js"; export * from "./primitive/sszTypes.js"; -export {phase0, altair, bellatrix, capella, deneb}; +export {phase0, altair, bellatrix, capella, deneb, electra}; /** * Index the ssz types that differ by fork @@ -19,6 +20,7 @@ const typesByFork = { [ForkName.bellatrix]: {...phase0, ...altair, ...bellatrix}, [ForkName.capella]: {...phase0, ...altair, ...bellatrix, ...capella}, [ForkName.deneb]: {...phase0, ...altair, ...bellatrix, ...capella, ...deneb}, + [ForkName.deneb]: {...phase0, ...altair, ...bellatrix, ...capella, ...deneb, ...electra}, }; /** diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 3602299ae5e1..c0cc6591dd56 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -4,6 +4,7 @@ import {ts as altair} from "./altair/index.js"; import {ts as bellatrix} from "./bellatrix/index.js"; import {ts as capella} from "./capella/index.js"; import {ts as deneb} from "./deneb/index.js"; +import {ts as electra} from "./electra/index.js"; import {Slot} from "./primitive/types.js"; export * from "./primitive/types.js"; @@ -12,6 +13,7 @@ export {ts as altair} from "./altair/index.js"; export {ts as bellatrix} from "./bellatrix/index.js"; export {ts as capella} from "./capella/index.js"; export {ts as deneb} from "./deneb/index.js"; +export {ts as electra} from "./electra/index.js"; /** Common non-spec type to represent roots as strings */ export type RootHex = string; @@ -132,6 +134,40 @@ type TypesByFork = { SyncCommittee: altair.SyncCommittee; SyncAggregate: altair.SyncAggregate; }; + [ForkName.electra]: { + BeaconBlockHeader: phase0.BeaconBlockHeader; + SignedBeaconBlockHeader: phase0.SignedBeaconBlockHeader; + BeaconBlock: electra.BeaconBlock; + BeaconBlockBody: electra.BeaconBlockBody; + BeaconState: electra.BeaconState; + SignedBeaconBlock: electra.SignedBeaconBlock; + Metadata: altair.Metadata; + LightClientHeader: electra.LightClientHeader; + LightClientBootstrap: electra.LightClientBootstrap; + LightClientUpdate: electra.LightClientUpdate; + LightClientFinalityUpdate: electra.LightClientFinalityUpdate; + LightClientOptimisticUpdate: electra.LightClientOptimisticUpdate; + LightClientStore: electra.LightClientStore; + BlindedBeaconBlock: electra.BlindedBeaconBlock; + BlindedBeaconBlockBody: electra.BlindedBeaconBlockBody; + SignedBlindedBeaconBlock: electra.SignedBlindedBeaconBlock; + ExecutionPayload: electra.ExecutionPayload; + ExecutionPayloadHeader: electra.ExecutionPayloadHeader; + BuilderBid: electra.BuilderBid; + SignedBuilderBid: electra.SignedBuilderBid; + SSEPayloadAttributes: electra.SSEPayloadAttributes; + BlockContents: {block: BeaconBlock; kzgProofs: deneb.KZGProofs; blobs: deneb.Blobs}; + SignedBlockContents: { + signedBlock: SignedBeaconBlock; + kzgProofs: deneb.KZGProofs; + blobs: deneb.Blobs; + }; + ExecutionPayloadAndBlobsBundle: deneb.ExecutionPayloadAndBlobsBundle; + BlobsBundle: deneb.BlobsBundle; + Contents: deneb.Contents; + SyncCommittee: altair.SyncCommittee; + SyncAggregate: altair.SyncAggregate; + }; }; export type TypesFor = K extends void diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 8ccaf9fe75ba..0afede39b951 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -73,6 +73,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Tue, 20 Feb 2024 02:51:21 +0800 Subject: [PATCH 011/259] feat: implement EIP-6110 (#6042) * Add immutable in the dependencies * Initial change to pubkeyCache * Added todos * Moved unfinalized cache to epochCache * Move populating finalized cache to afterProcessEpoch * Specify unfinalized cache during state cloning * Move from unfinalized to finalized cache in afterProcessEpoch * Confused myself * Clean up * Change logic * Fix cloning issue * Clean up redundant code * Add CarryoverData in epochCtx.createFromState * Fix typo * Update usage of pubkeyCache * Update pubkeyCache usage * Fix lint * Fix lint * Add 6110 to ChainConfig * Add 6110 to BeaconPreset * Define 6110 fork and container * Add V6110 api to execution engine * Update test * Add depositReceiptsRoot to process_execution_payload * State transitioning to EIP6110 * State transitioning to EIP6110 * Light client change in EIP-6110 * Update tests * produceBlock * Refactor processDeposit to match the spec * Implement processDepositReceipt * Implement 6110 fork guard for pubkeyCache * Handle changes in eth1 deposit * Update eth1 deposit test * Fix typo * Lint * Remove embarassing comments * Address comments * Modify applyDeposit signature * Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Update packages/state-transition/src/cache/pubkeyCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Remove old code * Rename fields in epochCache and immutableData * Remove CarryoverData * Move isAfter6110 from var to method * Fix cyclic import * Fix operations spec runner * Fix for spec test * Fix spec test * state.depositReceiptsStartIndex to BigInt * getDeposit requires cached state * default depositReceiptsStartIndex value in genesis * Fix pubkeyCache bug * newUnfinalizedPubkeyIndexMap in createCachedBeaconState * Lint * Pass epochCache instead of pubkey2IndexFn in apis * Address comments * Add unit test on pubkey cache cloning * Add unfinalizedPubkeyCacheSize to metrics * Add unfinalizedPubkeyCacheSize to metrics * Clean up code * Add besu to el-interop * Add 6110 genesis file * Template for sim test * Add unit test for getEth1DepositCount * Update sim test * Update besudocker * Finish beacon api calls in sim test * Update epochCache.createFromState() * Fix bug unfinalized validators are not finalized * Add sim test to run a few blocks * Lint * Merge branch 'unstable' into 611 * Add more check to sim test * Update besu docker image instruction * Update sim test with correct tx * Address comment + cleanup * Clean up code * Properly handle promise rejection * Lint * Update packages/beacon-node/src/execution/engine/types.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Update comments * Accept type undefined in ExecutionPayloadBodyRpc * Update comment and semantic * Remove if statement when adding finalized validator * Comment on repeated insert on finalized cache * rename createFromState * Add comment on getPubkey() * Stash change to reduce diffs * Stash change to reduce diffs * Lint * addFinalizedPubkey on finalized checkpoint * Update comment * Use OrderedMap for unfinalized cache * Pull out logic of deleting pubkeys for batch op * Add updateUnfinalizedPubkeys in regen * Update updateUnfinalizedPubkeys logic * Add comment * Add metrics for state context caches * Address comment * Address comment * Deprecate eth1Data polling when condition is reached * Fix conflicts * Fix sim test * Lint * Fix type * Fix test * Fix test * Lint * Update packages/light-client/src/spec/utils.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Fix spec test * Address comments * Improve cache logic on checkpoint finalized * Update sim test according to new cache logic * Update comment * Lint * Finalized pubkey cache only update once per checkpoint * Add perf test for updateUnfinalizedPubkeys * Add perf test for updateUnfinalizedPubkeys * Tweak params for perf test * Freeze besu docker image version for 6110 * Add benchmark result * Use Map instead of OrderedMap. Update benchmark * Minor optimization * Minor optimization * Add memory test for immutable.js * Update test * Reduce code duplication * Lint * Remove try/catch in updateUnfinalizedPubkeys * Introduce EpochCache metric * Add historicalValidatorLengths * Polish code * Migrate state-transition unit tests to vitest * Fix calculation of pivot index * `historicalValidatorLengths` only activate post 6110 * Update sim test * Lint * Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Improve readability on historicalValidatorLengths * Update types * Fix calculation * Add eth1data poll todo * Add epochCache.getValidatorCountAtEpoch * Add todo * Add getStateIterator for state cache * Partial commit * Update perf test * updateUnfinalizedPubkeys directly modify states from regen * Update sim test. Lint * Add todo * some improvements and a fix for effectiveBalanceIncrements fork safeness * rename eip6110 to elctra * fix electra-interop.test.ts --------- Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Co-authored-by: gajinder lint and tsc small cleanup fix rebase issue --- packages/beacon-node/src/chain/chain.ts | 37 ++ .../beacon-node/src/chain/regen/queued.ts | 50 +- .../chain/stateCache/blockStateCacheImpl.ts | 6 +- .../chain/stateCache/fifoBlockStateCache.ts | 4 + .../stateCache/inMemoryCheckpointsCache.ts | 4 + .../stateCache/persistentCheckpointsCache.ts | 4 + .../beacon-node/src/chain/stateCache/types.ts | 2 + .../src/eth1/eth1DepositDataTracker.ts | 32 +- packages/beacon-node/src/eth1/index.ts | 8 + packages/beacon-node/src/eth1/interface.ts | 5 + .../beacon-node/src/eth1/utils/deposits.ts | 16 +- .../beacon-node/src/execution/engine/http.ts | 10 +- .../src/execution/engine/interface.ts | 4 +- .../beacon-node/src/execution/engine/mock.ts | 4 + .../src/execution/engine/payloadIdCache.ts | 8 + .../beacon-node/src/execution/engine/types.ts | 68 ++- .../beacon-node/src/metrics/metrics/beacon.ts | 7 + .../src/metrics/metrics/lodestar.ts | 31 ++ .../test/memory/unfinalizedPubkey2Index.ts | 54 +++ .../opPools/aggregatedAttestationPool.test.ts | 2 +- .../test/perf/chain/opPools/opPool.test.ts | 2 +- .../produceBlock/produceBlockBody.test.ts | 2 +- .../updateUnfinalizedPubkeys.test.ts | 110 +++++ .../scripts/el-interop/besu/common-setup.sh | 19 + .../test/scripts/el-interop/besu/electra.tmpl | 77 +++ .../scripts/el-interop/besu/post-merge.sh | 8 + .../el-interop/besudocker/common-setup.sh | 22 + .../el-interop/besudocker/electra.tmpl | 77 +++ .../el-interop/besudocker/post-merge.sh | 8 + .../test/sim/electra-interop.test.ts | 457 ++++++++++++++++++ .../test/spec/presets/fork.test.ts | 3 +- .../test/spec/presets/genesis.test.ts | 2 +- .../test/spec/presets/operations.test.ts | 9 +- .../test/spec/presets/ssz_static.test.ts | 1 + .../test/spec/utils/specTestIterator.ts | 1 - .../upgradeLightClientHeader.test.ts | 34 +- .../opPools/aggregatedAttestationPool.test.ts | 4 +- .../test/unit/chain/shufflingCache.test.ts | 8 +- .../stateCache/fifoBlockStateCache.test.ts | 3 +- .../test/unit/eth1/utils/deposits.test.ts | 52 +- .../test/unit/executionEngine/http.test.ts | 4 + .../beaconBlocksMaybeBlobsByRange.test.ts | 1 + packages/beacon-node/test/utils/state.ts | 23 +- .../test/utils/validationData/attestation.ts | 7 +- .../config/src/chainConfig/configs/mainnet.ts | 2 +- .../config/src/chainConfig/configs/minimal.ts | 3 +- packages/light-client/src/spec/utils.ts | 12 +- packages/params/src/index.ts | 5 + packages/params/src/presets/mainnet.ts | 3 + packages/params/src/presets/minimal.ts | 3 + packages/params/src/types.ts | 6 + packages/state-transition/package.json | 7 +- .../src/block/processDeposit.ts | 110 +++-- .../src/block/processDepositReceipt.ts | 17 + .../src/block/processOperations.ts | 17 +- .../state-transition/src/cache/epochCache.ts | 182 ++++++- .../state-transition/src/cache/pubkeyCache.ts | 22 +- .../state-transition/src/cache/stateCache.ts | 5 +- packages/state-transition/src/cache/types.ts | 1 + packages/state-transition/src/index.ts | 9 +- packages/state-transition/src/metrics.ts | 5 + .../src/signatureSets/attesterSlashings.ts | 3 +- packages/state-transition/src/slot/index.ts | 1 + .../src/slot/upgradeStateToElectra.ts | 33 ++ .../state-transition/src/stateTransition.ts | 5 + packages/state-transition/src/types.ts | 2 + packages/state-transition/src/util/deposit.ts | 24 + .../state-transition/src/util/execution.ts | 6 + packages/state-transition/src/util/genesis.ts | 12 + packages/state-transition/src/util/index.ts | 1 + .../test/unit/cachedBeaconState.test.ts | 62 ++- .../test/unit/upgradeState.test.ts | 16 + .../test/unit/util/deposit.test.ts | 99 ++++ packages/types/package.json | 3 + packages/types/src/electra/sszTypes.ts | 147 +++++- packages/types/src/electra/types.ts | 8 +- packages/types/src/primitive/sszTypes.ts | 1 + packages/validator/src/util/params.ts | 4 +- yarn.lock | 5 + 79 files changed, 1960 insertions(+), 171 deletions(-) create mode 100644 packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts create mode 100644 packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts create mode 100755 packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh create mode 100644 packages/beacon-node/test/scripts/el-interop/besu/electra.tmpl create mode 100755 packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh create mode 100644 packages/beacon-node/test/scripts/el-interop/besudocker/common-setup.sh create mode 100644 packages/beacon-node/test/scripts/el-interop/besudocker/electra.tmpl create mode 100755 packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh create mode 100644 packages/beacon-node/test/sim/electra-interop.test.ts create mode 100644 packages/state-transition/src/block/processDepositReceipt.ts create mode 100644 packages/state-transition/src/slot/upgradeStateToElectra.ts create mode 100644 packages/state-transition/src/util/deposit.ts create mode 100644 packages/state-transition/test/unit/util/deposit.test.ts diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 75608ab33b2e..9f67857fe530 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -1027,6 +1027,9 @@ export class BeaconChain implements IBeaconChain { metrics.forkChoice.balancesLength.set(forkChoiceMetrics.balancesLength); metrics.forkChoice.nodes.set(forkChoiceMetrics.nodes); metrics.forkChoice.indices.set(forkChoiceMetrics.indices); + + const headState = this.getHeadState(); + metrics.headState.unfinalizedPubkeyCacheSize.set(headState.epochCtx.unfinalizedPubkey2index.size); } private onClockSlot(slot: Slot): void { @@ -1115,6 +1118,40 @@ export class BeaconChain implements IBeaconChain { if (headState) { this.opPool.pruneAll(headBlock, headState); } + + const cpEpoch = cp.epoch; + const electraEpoch = headState?.config.ELECTRA_FORK_EPOCH ?? Infinity; + + if (headState === null) { + this.logger.verbose("Head state is null"); + } else if (cpEpoch >= electraEpoch) { + // Get the validator.length from the state at cpEpoch + // We are confident the last element in the list is from headEpoch + // Thus we query from the end of the list. (cpEpoch - headEpoch - 1) is negative number + const pivotValidatorIndex = headState.epochCtx.getValidatorCountAtEpoch(cpEpoch); + + if (pivotValidatorIndex !== undefined) { + // Note EIP-6914 will break this logic + const newFinalizedValidators = headState.epochCtx.unfinalizedPubkey2index.filter( + (index, _pubkey) => index < pivotValidatorIndex + ); + + // Populate finalized pubkey cache and remove unfinalized pubkey cache + if (!newFinalizedValidators.isEmpty()) { + this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); + } + } + } + + // TODO-Electra: Deprecating eth1Data poll requires a check on a finalized checkpoint state. + // Will resolve this later + // if (cpEpoch >= (this.config.ELECTRA_FORK_EPOCH ?? Infinity)) { + // // finalizedState can be safely casted to Electra state since cp is already post-Electra + // if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateElectra).depositReceiptsStartIndex) { + // // Signal eth1 to stop polling eth1Data + // this.eth1.stopPollingEth1Data(); + // } + // } } async updateBeaconProposerData(epoch: Epoch, proposers: ProposerPreparationData[]): Promise { diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index 082ffbe271e4..84907ea163af 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -1,6 +1,6 @@ import {phase0, Slot, RootHex, Epoch, BeaconBlock} from "@lodestar/types"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; -import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition"; +import {CachedBeaconStateAllForks, UnfinalizedPubkeyIndexMap, computeEpochAtSlot} from "@lodestar/state-transition"; import {Logger, toRootHex} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {CheckpointHex, toCheckpointHex} from "../stateCache/index.js"; @@ -206,6 +206,54 @@ export class QueuedStateRegenerator implements IStateRegenerator { return this.checkpointStateCache.updatePreComputedCheckpoint(rootHex, epoch); } + /** + * Remove `validators` from all unfinalized cache's epochCtx.UnfinalizedPubkey2Index, + * and add them to epochCtx.pubkey2index and epochCtx.index2pubkey + */ + updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { + let numStatesUpdated = 0; + const states = this.stateCache.getStates(); + const cpStates = this.checkpointStateCache.getStates(); + + // Add finalized pubkeys to all states. + const addTimer = this.metrics?.regenFnAddPubkeyTime.startTimer(); + + // We only need to add pubkeys to any one of the states since the finalized caches is shared globally across all states + const firstState = (states.next().value ?? cpStates.next().value) as CachedBeaconStateAllForks | undefined; + + if (firstState !== undefined) { + firstState.epochCtx.addFinalizedPubkeys(validators, this.metrics?.epochCache ?? undefined); + } else { + this.logger.warn("Attempt to delete finalized pubkey from unfinalized pubkey cache. But no state is available"); + } + + addTimer?.(); + + // Delete finalized pubkeys from unfinalized pubkey cache for all states + const deleteTimer = this.metrics?.regenFnDeletePubkeyTime.startTimer(); + const pubkeysToDelete = Array.from(validators.keys()); + + for (const s of states) { + s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + numStatesUpdated++; + } + + for (const s of cpStates) { + s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + numStatesUpdated++; + } + + // Since first state is consumed from the iterator. Will need to perform delete explicitly + if (firstState !== undefined) { + firstState?.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + numStatesUpdated++; + } + + deleteTimer?.(); + + this.metrics?.regenFnNumStatesUpdated.observe(numStatesUpdated); + } + /** * Get the state to run with `block`. * - State after `block.parentRoot` dialed forward to block.slot diff --git a/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts index 05073d0e515f..1cb67cd6cf09 100644 --- a/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts +++ b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts @@ -34,7 +34,7 @@ export class BlockStateCacheImpl implements BlockStateCache { this.maxStates = maxStates; this.cache = new MapTracker(metrics?.stateCache); if (metrics) { - this.metrics = metrics.stateCache; + this.metrics = {...metrics.stateCache, ...metrics.epochCache}; metrics.stateCache.size.addCollect(() => metrics.stateCache.size.set(this.cache.size)); } } @@ -137,6 +137,10 @@ export class BlockStateCacheImpl implements BlockStateCache { })); } + getStates(): IterableIterator { + return this.cache.values(); + } + private deleteAllEpochItems(epoch: Epoch): void { for (const rootHex of this.epochIndex.get(epoch) || []) { this.cache.delete(rootHex); diff --git a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts index 602b0abaee8d..f115806874f8 100644 --- a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts +++ b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts @@ -190,6 +190,10 @@ export class FIFOBlockStateCache implements BlockStateCache { })); } + getStates(): IterableIterator { + throw new Error("Method not implemented."); + } + /** * For unit test only. */ diff --git a/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts index 03cdc84de166..38aeabb97955 100644 --- a/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts @@ -176,6 +176,10 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache { })); } + getStates(): IterableIterator { + return this.cache.values(); + } + /** ONLY FOR DEBUGGING PURPOSES. For spec tests on error */ dumpCheckpointKeys(): string[] { return Array.from(this.cache.keys()); diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 5c5901583ad8..c59c15de616d 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -594,6 +594,10 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { }); } + getStates(): IterableIterator { + throw new Error("Method not implemented."); + } + /** ONLY FOR DEBUGGING PURPOSES. For spec tests on error */ dumpCheckpointKeys(): string[] { return Array.from(this.cache.keys()); diff --git a/packages/beacon-node/src/chain/stateCache/types.ts b/packages/beacon-node/src/chain/stateCache/types.ts index 41e9b91aaa43..ad93def481e7 100644 --- a/packages/beacon-node/src/chain/stateCache/types.ts +++ b/packages/beacon-node/src/chain/stateCache/types.ts @@ -33,6 +33,7 @@ export interface BlockStateCache { prune(headStateRootHex: RootHex): void; deleteAllBeforeEpoch(finalizedEpoch: Epoch): void; dumpSummary(): routes.lodestar.StateCacheItem[]; + getStates(): IterableIterator; // Expose beacon states stored in cache. Use with caution } /** @@ -74,6 +75,7 @@ export interface CheckpointStateCache { processState(blockRootHex: RootHex, state: CachedBeaconStateAllForks): Promise; clear(): void; dumpSummary(): routes.lodestar.StateCacheItem[]; + getStates(): IterableIterator; // Expose beacon states stored in cache. Use with caution } export enum CacheItemType { diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index f36f70abbbc4..c0b3ab35a73a 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -1,6 +1,11 @@ import {phase0, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; -import {BeaconStateAllForks, becomesNewEth1Data} from "@lodestar/state-transition"; +import { + BeaconStateAllForks, + CachedBeaconStateAllForks, + CachedBeaconStateElectra, + becomesNewEth1Data, +} from "@lodestar/state-transition"; import {ErrorAborted, TimeoutError, fromHex, Logger, isErrorAborted, sleep} from "@lodestar/utils"; import {IBeaconDb} from "../db/index.js"; @@ -67,6 +72,8 @@ export class Eth1DepositDataTracker { /** Dynamically adjusted batch size to fetch deposit logs */ private eth1GetLogsBatchSizeDynamic = MAX_BLOCKS_PER_LOG_QUERY; private readonly forcedEth1DataVote: phase0.Eth1Data | null; + /** To stop `runAutoUpdate()` in addition to AbortSignal */ + private stopPolling: boolean; constructor( opts: Eth1Options, @@ -81,6 +88,8 @@ export class Eth1DepositDataTracker { this.depositsCache = new Eth1DepositsCache(opts, config, db); this.eth1DataCache = new Eth1DataCache(config, db); this.eth1FollowDistance = config.ETH1_FOLLOW_DISTANCE; + // TODO Electra: fix scenario where node starts post-Electra and `stopPolling` will always be false + this.stopPolling = false; this.forcedEth1DataVote = opts.forcedEth1DataVote ? ssz.phase0.Eth1Data.deserialize(fromHex(opts.forcedEth1DataVote)) @@ -109,10 +118,22 @@ export class Eth1DepositDataTracker { } } + // TODO Electra: Figure out how an elegant way to stop eth1data polling + stopPollingEth1Data(): void { + this.stopPolling = true; + } + /** * Return eth1Data and deposits ready for block production for a given state */ - async getEth1DataAndDeposits(state: BeaconStateAllForks): Promise { + async getEth1DataAndDeposits(state: CachedBeaconStateAllForks): Promise { + if ( + state.epochCtx.isAfterElectra() && + state.eth1DepositIndex >= (state as CachedBeaconStateElectra).depositReceiptsStartIndex + ) { + // No need to poll eth1Data since Electra deprecates the mechanism after depositReceiptsStartIndex is reached + return {eth1Data: state.eth1Data, deposits: []}; + } const eth1Data = this.forcedEth1DataVote ?? (await this.getEth1Data(state)); const deposits = await this.getDeposits(state, eth1Data); return {eth1Data, deposits}; @@ -141,7 +162,10 @@ export class Eth1DepositDataTracker { * Returns deposits to be included for a given state and eth1Data vote. * Requires internal caches to be updated regularly to return good results */ - private async getDeposits(state: BeaconStateAllForks, eth1DataVote: phase0.Eth1Data): Promise { + private async getDeposits( + state: CachedBeaconStateAllForks, + eth1DataVote: phase0.Eth1Data + ): Promise { // No new deposits have to be included, continue if (eth1DataVote.depositCount === state.eth1DepositIndex) { return []; @@ -162,7 +186,7 @@ export class Eth1DepositDataTracker { private async runAutoUpdate(): Promise { let lastRunMs = 0; - while (!this.signal.aborted) { + while (!this.signal.aborted && !this.stopPolling) { lastRunMs = Date.now(); try { diff --git a/packages/beacon-node/src/eth1/index.ts b/packages/beacon-node/src/eth1/index.ts index 9fdba90258a2..a8ba55c54141 100644 --- a/packages/beacon-node/src/eth1/index.ts +++ b/packages/beacon-node/src/eth1/index.ts @@ -106,6 +106,10 @@ export class Eth1ForBlockProduction implements IEth1ForBlockProduction { startPollingMergeBlock(): void { return this.eth1MergeBlockTracker.startPollingMergeBlock(); } + + stopPollingEth1Data(): void { + return this.eth1DepositDataTracker?.stopPollingEth1Data(); + } } /** @@ -140,4 +144,8 @@ export class Eth1ForBlockProductionDisabled implements IEth1ForBlockProduction { startPollingMergeBlock(): void { // Ignore } + + stopPollingEth1Data(): void { + // Ignore + } } diff --git a/packages/beacon-node/src/eth1/interface.ts b/packages/beacon-node/src/eth1/interface.ts index fc9626eb5b8a..898041ac8947 100644 --- a/packages/beacon-node/src/eth1/interface.ts +++ b/packages/beacon-node/src/eth1/interface.ts @@ -62,6 +62,11 @@ export interface IEth1ForBlockProduction { * - head state not isMergeTransitionComplete */ startPollingMergeBlock(): void; + + /** + * Should stop polling eth1Data after a Electra block is finalized AND deposit_receipts_start_index is reached + */ + stopPollingEth1Data(): void; } /** Different Eth1Block from phase0.Eth1Block with blockHash */ diff --git a/packages/beacon-node/src/eth1/utils/deposits.ts b/packages/beacon-node/src/eth1/utils/deposits.ts index 24916264e6d8..8d0331fc01d6 100644 --- a/packages/beacon-node/src/eth1/utils/deposits.ts +++ b/packages/beacon-node/src/eth1/utils/deposits.ts @@ -1,9 +1,9 @@ import {toGindex, Tree} from "@chainsafe/persistent-merkle-tree"; -import {MAX_DEPOSITS} from "@lodestar/params"; -import {BeaconStateAllForks} from "@lodestar/state-transition"; +import {toRootHex} from "@lodestar/utils"; +import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; import {FilterOptions} from "@lodestar/db"; -import {toRootHex} from "@lodestar/utils"; +import {getEth1DepositCount} from "@lodestar/state-transition"; import {Eth1Error, Eth1ErrorCode} from "../errors.js"; import {DepositTree} from "../../db/repositories/depositDataRoot.js"; @@ -11,7 +11,7 @@ export type DepositGetter = (indexRange: FilterOptions, eth1Data: pha export async function getDeposits( // eth1_deposit_index represents the next deposit index to be added - state: BeaconStateAllForks, + state: CachedBeaconStateAllForks, eth1Data: phase0.Eth1Data, depositsGetter: DepositGetter ): Promise { @@ -22,9 +22,11 @@ export async function getDeposits( throw new Eth1Error({code: Eth1ErrorCode.DEPOSIT_INDEX_TOO_HIGH, depositIndex, depositCount}); } - // Spec v0.12.2 - // assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index) - const depositsLen = Math.min(MAX_DEPOSITS, depositCount - depositIndex); + const depositsLen = getEth1DepositCount(state, eth1Data); + + if (depositsLen === 0) { + return []; // If depositsLen === 0, we can return early since no deposit with be returned from depositsGetter + } const indexRange = {gte: depositIndex, lt: depositIndex + depositsLen}; const deposits = await depositsGetter(indexRange, eth1Data); diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index c64a9715589f..d29387794327 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -198,7 +198,9 @@ export class ExecutionEngineHttp implements IExecutionEngine { parentBlockRoot?: Root ): Promise { const method = - ForkSeq[fork] >= ForkSeq.deneb + ForkSeq[fork] >= ForkSeq.electra + ? "engine_newPayloadV6110" + : ForkSeq[fork] >= ForkSeq.deneb ? "engine_newPayloadV3" : ForkSeq[fork] >= ForkSeq.capella ? "engine_newPayloadV2" @@ -218,7 +220,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { const serializedVersionedHashes = serializeVersionedHashes(versionedHashes); const parentBeaconBlockRoot = serializeBeaconBlockRoot(parentBlockRoot); - const method = "engine_newPayloadV3"; + const method = ForkSeq[fork] >= ForkSeq.electra ? "engine_newPayloadV6110" : "engine_newPayloadV3"; engineRequest = { method, params: [serializedExecutionPayload, serializedVersionedHashes, parentBeaconBlockRoot], @@ -392,7 +394,9 @@ export class ExecutionEngineHttp implements IExecutionEngine { shouldOverrideBuilder?: boolean; }> { const method = - ForkSeq[fork] >= ForkSeq.deneb + ForkSeq[fork] >= ForkSeq.electra + ? "engine_getPayloadV6110" + : ForkSeq[fork] >= ForkSeq.deneb ? "engine_getPayloadV3" : ForkSeq[fork] >= ForkSeq.capella ? "engine_getPayloadV2" diff --git a/packages/beacon-node/src/execution/engine/interface.ts b/packages/beacon-node/src/execution/engine/interface.ts index fa1da210cd12..91a8ce1cffe3 100644 --- a/packages/beacon-node/src/execution/engine/interface.ts +++ b/packages/beacon-node/src/execution/engine/interface.ts @@ -3,10 +3,10 @@ import {KZGCommitment, Blob, KZGProof} from "@lodestar/types/deneb"; import {Root, RootHex, capella, Wei, ExecutionPayload} from "@lodestar/types"; import {DATA} from "../../eth1/provider/utils.js"; -import {PayloadIdCache, PayloadId, WithdrawalV1} from "./payloadIdCache.js"; +import {PayloadIdCache, PayloadId, WithdrawalV1, DepositReceiptV1} from "./payloadIdCache.js"; import {ExecutionPayloadBody} from "./types.js"; -export {PayloadIdCache, type PayloadId, type WithdrawalV1}; +export {PayloadIdCache, type PayloadId, type WithdrawalV1, type DepositReceiptV1}; export enum ExecutionPayloadStatus { /** given payload is valid */ diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index a99a76508df8..5a50f1697de9 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -35,6 +35,7 @@ export type ExecutionEngineMockOpts = { onlyPredefinedResponses?: boolean; capellaForkTimestamp?: number; denebForkTimestamp?: number; + electraForkTimestamp?: number; }; type ExecutionBlock = { @@ -88,12 +89,14 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { engine_newPayloadV1: this.notifyNewPayload.bind(this), engine_newPayloadV2: this.notifyNewPayload.bind(this), engine_newPayloadV3: this.notifyNewPayload.bind(this), + engine_newPayloadV6110: this.notifyNewPayload.bind(this), engine_forkchoiceUpdatedV1: this.notifyForkchoiceUpdate.bind(this), engine_forkchoiceUpdatedV2: this.notifyForkchoiceUpdate.bind(this), engine_forkchoiceUpdatedV3: this.notifyForkchoiceUpdate.bind(this), engine_getPayloadV1: this.getPayload.bind(this), engine_getPayloadV2: this.getPayload.bind(this), engine_getPayloadV3: this.getPayload.bind(this), + engine_getPayloadV6110: this.getPayload.bind(this), engine_getPayloadBodiesByHashV1: this.getPayloadBodiesByHash.bind(this), engine_getPayloadBodiesByRangeV1: this.getPayloadBodiesByRange.bind(this), engine_getClientVersionV1: this.getClientVersionV1.bind(this), @@ -394,6 +397,7 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { } private timestampToFork(timestamp: number): ForkExecution { + if (timestamp > (this.opts.electraForkTimestamp ?? Infinity)) return ForkName.electra; if (timestamp > (this.opts.denebForkTimestamp ?? Infinity)) return ForkName.deneb; if (timestamp > (this.opts.capellaForkTimestamp ?? Infinity)) return ForkName.capella; return ForkName.bellatrix; diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index ea37e0922e9c..e5baa9fba92d 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -18,6 +18,14 @@ export type WithdrawalV1 = { amount: QUANTITY; }; +export type DepositReceiptV1 = { + pubkey: DATA; + withdrawalCredentials: DATA; + amount: QUANTITY; + signature: DATA; + index: QUANTITY; +}; + type FcuAttributes = {headBlockHash: DATA; finalizedBlockHash: DATA} & Omit; export class PayloadIdCache { diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 85f514c953b0..999c77f86b9c 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -1,4 +1,4 @@ -import {capella, deneb, Wei, bellatrix, Root, ExecutionPayload} from "@lodestar/types"; +import {capella, deneb, electra, Wei, bellatrix, Root, ExecutionPayload} from "@lodestar/types"; import { BYTES_PER_LOGS_BLOOM, FIELD_ELEMENTS_PER_BLOB, @@ -17,7 +17,7 @@ import { quantityToBigint, } from "../../eth1/provider/utils.js"; import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js"; -import {WithdrawalV1} from "./payloadIdCache.js"; +import {WithdrawalV1, DepositReceiptV1} from "./payloadIdCache.js"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -28,6 +28,7 @@ export type EngineApiRpcParamTypes = { engine_newPayloadV1: [ExecutionPayloadRpc]; engine_newPayloadV2: [ExecutionPayloadRpc]; engine_newPayloadV3: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; + engine_newPayloadV6110: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; /** * 1. Object - Payload validity status with respect to the consensus rules: * - blockHash: DATA, 32 Bytes - block hash value of the payload @@ -51,6 +52,7 @@ export type EngineApiRpcParamTypes = { engine_getPayloadV1: [QUANTITY]; engine_getPayloadV2: [QUANTITY]; engine_getPayloadV3: [QUANTITY]; + engine_getPayloadV6110: [QUANTITY]; /** * 1. Array of DATA - Array of block_hash field values of the ExecutionPayload structure @@ -83,6 +85,7 @@ export type EngineApiRpcReturnTypes = { engine_newPayloadV1: PayloadStatus; engine_newPayloadV2: PayloadStatus; engine_newPayloadV3: PayloadStatus; + engine_newPayloadV6110: PayloadStatus; engine_forkchoiceUpdatedV1: { payloadStatus: PayloadStatus; payloadId: QUANTITY | null; @@ -101,6 +104,7 @@ export type EngineApiRpcReturnTypes = { engine_getPayloadV1: ExecutionPayloadRpc; engine_getPayloadV2: ExecutionPayloadResponse; engine_getPayloadV3: ExecutionPayloadResponse; + engine_getPayloadV6110: ExecutionPayloadResponse; engine_getPayloadBodiesByHashV1: (ExecutionPayloadBodyRpc | null)[]; @@ -118,9 +122,17 @@ type ExecutionPayloadRpcWithValue = { }; type ExecutionPayloadResponse = ExecutionPayloadRpc | ExecutionPayloadRpcWithValue; -export type ExecutionPayloadBodyRpc = {transactions: DATA[]; withdrawals: WithdrawalV1[] | null}; +export type ExecutionPayloadBodyRpc = { + transactions: DATA[]; + withdrawals: WithdrawalV1[] | null | undefined; + depositReceipts: DepositReceiptV1[] | null | undefined; +}; -export type ExecutionPayloadBody = {transactions: bellatrix.Transaction[]; withdrawals: capella.Withdrawals | null}; +export type ExecutionPayloadBody = { + transactions: bellatrix.Transaction[]; + withdrawals: capella.Withdrawals | null; + depositReceipts: electra.DepositReceipts | null; +}; export type ExecutionPayloadRpc = { parentHash: DATA; // 32 bytes @@ -141,6 +153,7 @@ export type ExecutionPayloadRpc = { blobGasUsed?: QUANTITY; // DENEB excessBlobGas?: QUANTITY; // DENEB parentBeaconBlockRoot?: QUANTITY; // DENEB + depositReceipts?: DepositReceiptRpc[]; // ELECTRA }; export type WithdrawalRpc = { @@ -150,6 +163,14 @@ export type WithdrawalRpc = { amount: QUANTITY; }; +export type DepositReceiptRpc = { + pubkey: DATA; + withdrawalCredentials: DATA; + amount: QUANTITY; + signature: DATA; + index: QUANTITY; +}; + export type VersionedHashesRpc = DATA[]; export type PayloadAttributesRpc = { @@ -212,6 +233,12 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload payload.excessBlobGas = numToQuantity(excessBlobGas); } + // ELECTRA adds depositReceipts to the ExecutionPayload + if (ForkSeq[fork] >= ForkSeq.electra) { + const {depositReceipts} = data as electra.ExecutionPayload; + payload.depositReceipts = depositReceipts.map(serializeDepositReceipt); + } + return payload; } @@ -297,6 +324,17 @@ export function parseExecutionPayload( (executionPayload as deneb.ExecutionPayload).excessBlobGas = quantityToBigint(excessBlobGas); } + if (ForkSeq[fork] >= ForkSeq.electra) { + const {depositReceipts} = data; + // Geth can also reply with null + if (depositReceipts == null) { + throw Error( + `depositReceipts missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` + ); + } + (executionPayload as electra.ExecutionPayload).depositReceipts = depositReceipts.map(deserializeDepositReceipts); + } + return {executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder}; } @@ -363,11 +401,32 @@ export function deserializeWithdrawal(serialized: WithdrawalRpc): capella.Withdr } as capella.Withdrawal; } +export function serializeDepositReceipt(depositReceipt: electra.DepositReceipt): DepositReceiptRpc { + return { + pubkey: bytesToData(depositReceipt.pubkey), + withdrawalCredentials: bytesToData(depositReceipt.withdrawalCredentials), + amount: numToQuantity(depositReceipt.amount), + signature: bytesToData(depositReceipt.signature), + index: numToQuantity(depositReceipt.index), + }; +} + +export function deserializeDepositReceipts(serialized: DepositReceiptRpc): electra.DepositReceipt { + return { + pubkey: dataToBytes(serialized.pubkey, 48), + withdrawalCredentials: dataToBytes(serialized.withdrawalCredentials, 32), + amount: quantityToNum(serialized.amount), + signature: dataToBytes(serialized.signature, 96), + index: quantityToNum(serialized.index), + } as electra.DepositReceipt; +} + export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | null): ExecutionPayloadBody | null { return data ? { transactions: data.transactions.map((tran) => dataToBytes(tran, null)), withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null, + depositReceipts: data.depositReceipts ? data.depositReceipts.map(deserializeDepositReceipts) : null, } : null; } @@ -377,6 +436,7 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null) ? { transactions: data.transactions.map((tran) => bytesToData(tran)), withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null, + depositReceipts: data.depositReceipts ? data.depositReceipts.map(serializeDepositReceipt) : null, } : null; } diff --git a/packages/beacon-node/src/metrics/metrics/beacon.ts b/packages/beacon-node/src/metrics/metrics/beacon.ts index 141121de9079..96bb6bea4174 100644 --- a/packages/beacon-node/src/metrics/metrics/beacon.ts +++ b/packages/beacon-node/src/metrics/metrics/beacon.ts @@ -120,6 +120,13 @@ export function createBeaconMetrics(register: RegistryMetricCreator) { }), }, + headState: { + unfinalizedPubkeyCacheSize: register.gauge({ + name: "head_state_unfinalized_pubkey_cache_size", + help: "Current size of the unfinalizedPubkey2Index cache in the head state", + }), + }, + parentBlockDistance: register.histogram({ name: "beacon_imported_block_parent_distance", help: "Histogram of distance to parent block of valid imported blocks", diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index f43a3f1cdbe6..595e4a7a45fc 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -374,6 +374,17 @@ export function createLodestarMetrics( help: "Total count state.validators nodesPopulated is false on stfn for post state", }), + epochCache: { + finalizedPubkeyDuplicateInsert: register.gauge({ + name: "lodestar_epoch_cache_finalized_pubkey_duplicate_insert", + help: "Total count of duplicate insert of finalized pubkeys", + }), + newUnFinalizedPubkey: register.gauge({ + name: "lodestar_epoch_cache_new_unfinalized_pubkey", + help: "Total count of unfinalized pubkeys added", + }), + }, + // BLS verifier thread pool and queue bls: { @@ -1205,6 +1216,11 @@ export function createLodestarMetrics( help: "Histogram of time to serialize state to db", buckets: [0.1, 0.5, 1, 2, 3, 4], }), + numStatesUpdated: register.histogram({ + name: "lodestar_cp_state_cache_state_updated_count", + help: "Histogram of number of state cache items updated every time removing and adding pubkeys to pubkey cache", + buckets: [1, 2, 5, 10, 50, 250], + }), statePruneFromMemoryCount: register.gauge({ name: "lodestar_cp_state_cache_state_prune_from_memory_count", help: "Total number of states pruned from memory", @@ -1373,6 +1389,21 @@ export function createLodestarMetrics( help: "regen function total errors", labelNames: ["entrypoint", "caller"], }), + regenFnAddPubkeyTime: register.histogram({ + name: "lodestar_regen_fn_add_pubkey_time_seconds", + help: "Historgram of time spent on adding pubkeys to all state cache items in seconds", + buckets: [0.01, 0.1, 0.5, 1, 2, 5], + }), + regenFnDeletePubkeyTime: register.histogram({ + name: "lodestar_regen_fn_delete_pubkey_time_seconds", + help: "Histrogram of time spent on deleting pubkeys from all state cache items in seconds", + buckets: [0.01, 0.1, 0.5, 1, 2, 5], + }), + regenFnNumStatesUpdated: register.histogram({ + name: "lodestar_regen_state_cache_state_updated_count", + help: "Histogram of number of state cache items updated every time removing pubkeys from unfinalized cache", + buckets: [1, 2, 5, 10, 50, 250], + }), unhandledPromiseRejections: register.gauge({ name: "lodestar_unhandled_promise_rejections_total", help: "UnhandledPromiseRejection total count", diff --git a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts new file mode 100644 index 000000000000..b37967d16ca4 --- /dev/null +++ b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts @@ -0,0 +1,54 @@ +import crypto from "node:crypto"; +import {Map} from "immutable"; +import {ValidatorIndex} from "@lodestar/types"; +import {toMemoryEfficientHexStr} from "@lodestar/state-transition/src/cache/pubkeyCache.js"; +import {testRunnerMemory} from "./testRunnerMemory.js"; + +// Results in MacOS Nov 2023 +// +// UnfinalizedPubkey2Index 1000 keys - 274956.5 bytes / instance +// UnfinalizedPubkey2Index 10000 keys - 2591129.3 bytes / instance +// UnfinalizedPubkey2Index 100000 keys - 27261443.4 bytes / instance + +testRunnerMemoryBpi([ + { + id: "UnfinalizedPubkey2Index 1000 keys", + getInstance: () => getRandomMap(1000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), + }, + { + id: "UnfinalizedPubkey2Index 10000 keys", + getInstance: () => getRandomMap(10000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), + }, + { + id: "UnfinalizedPubkey2Index 100000 keys", + getInstance: () => getRandomMap(100000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), + }, +]); + +function getRandomMap(n: number, getKey: (i: number) => string): Map { + const map = Map(); + + return map.withMutations((m) => { + for (let i = 0; i < n; i++) { + m.set(getKey(i), i); + } + }); +} + +/** + * Test bytes per instance in different representations of raw binary data + */ +function testRunnerMemoryBpi(testCases: {getInstance: (bytes: number) => unknown; id: string}[]): void { + const longestId = Math.max(...testCases.map(({id}) => id.length)); + + for (const {id, getInstance} of testCases) { + const bpi = testRunnerMemory({ + getInstance, + convergeFactor: 1 / 100, + sampleEvery: 5, + }); + + // eslint-disable-next-line no-console + console.log(`${id.padEnd(longestId)} - ${bpi.toFixed(1)} bytes / instance`); + } +} diff --git a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts index 60ff6ce48302..7a882b03af0e 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -32,7 +32,7 @@ describe(`getAttestationsForBlock vc=${vc}`, () => { before(function () { this.timeout(5 * 60 * 1000); // Generating the states for the first time is very slow - originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true, vc}); + originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true, vc}) as unknown as CachedBeaconStateAltair; const {blockHeader, checkpoint} = computeAnchorCheckpoint(originalState.config, originalState); // TODO figure out why getBlockRootAtSlot(originalState, justifiedSlot) is not the same to justifiedCheckpoint.root diff --git a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts index 6e420f0e1011..7998a204f09d 100644 --- a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts @@ -24,7 +24,7 @@ describe("opPool", () => { before(function () { this.timeout(2 * 60 * 1000); // Generating the states for the first time is very slow - originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true}); + originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true}) as unknown as CachedBeaconStateAltair; }); itBench({ diff --git a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts index 7bf8c2f7252f..2386f3538205 100644 --- a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts +++ b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts @@ -25,7 +25,7 @@ describe("produceBlockBody", () => { before(async () => { db = new BeaconDb(config, await LevelDbController.create({name: ".tmpdb"}, {logger})); - state = stateOg.clone(); + state = stateOg.clone() as unknown as CachedBeaconStateAltair; chain = new BeaconChain( { proposerBoost: true, diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts new file mode 100644 index 000000000000..900f6a6fb873 --- /dev/null +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -0,0 +1,110 @@ +import {itBench, setBenchOpts} from "@dapplion/benchmark"; +import {Map} from "immutable"; +import {toBufferBE} from "bigint-buffer"; +import {digest} from "@chainsafe/as-sha256"; +import type {SecretKey} from "@chainsafe/bls/types"; +import bls from "@chainsafe/bls"; +import {ssz} from "@lodestar/types"; +import {type CachedBeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; +import {bytesToBigInt, intToBytes} from "@lodestar/utils"; +import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; +import {generateCachedElectraState} from "../../../utils/state.js"; + +// Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz +// ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 1444.173 ops/s 692.4380 us/op - 1057 runs 6.03 s +// ✔ updateUnfinalizedPubkeys - updating 100 pubkeys 189.5965 ops/s 5.274358 ms/op - 57 runs 1.15 s +// ✔ updateUnfinalizedPubkeys - updating 1000 pubkeys 12.90495 ops/s 77.48967 ms/op - 13 runs 1.62 s +describe("updateUnfinalizedPubkeys perf tests", function () { + setBenchOpts({noThreshold: true}); + + const numPubkeysToBeFinalizedCases = [10, 100, 1000]; + const numCheckpointStateCache = 8; + const numStateCache = 3 * 32; + + let checkpointStateCache: CheckpointStateCache; + let stateCache: StateContextCache; + + const unfinalizedPubkey2Index = generatePubkey2Index(0, Math.max.apply(null, numPubkeysToBeFinalizedCases)); + const baseState = generateCachedElectraState(); + + for (const numPubkeysToBeFinalized of numPubkeysToBeFinalizedCases) { + itBench({ + id: `updateUnfinalizedPubkeys - updating ${numPubkeysToBeFinalized} pubkeys`, + beforeEach: async () => { + baseState.epochCtx.unfinalizedPubkey2index = Map(unfinalizedPubkey2Index.map); + baseState.epochCtx.pubkey2index = new PubkeyIndexMap(); + baseState.epochCtx.index2pubkey = []; + + checkpointStateCache = new CheckpointStateCache({}); + stateCache = new StateContextCache({}); + + for (let i = 0; i < numCheckpointStateCache; i++) { + const clonedState = baseState.clone(); + const checkpoint = ssz.phase0.Checkpoint.defaultValue(); + + clonedState.slot = i; + checkpoint.epoch = i; // Assigning arbitrary non-duplicate values to ensure checkpointStateCache correctly saves all the states + + checkpointStateCache.add(checkpoint, clonedState); + } + + for (let i = 0; i < numStateCache; i++) { + const clonedState = baseState.clone(); + clonedState.slot = i; + stateCache.add(clonedState); + } + }, + fn: async () => { + const newFinalizedValidators = baseState.epochCtx.unfinalizedPubkey2index.filter( + (index, _pubkey) => index < numPubkeysToBeFinalized + ); + + const states = stateCache.getStates(); + const cpStates = checkpointStateCache.getStates(); + + const firstState = states.next().value as CachedBeaconStateAllForks; + firstState.epochCtx.addFinalizedPubkeys(newFinalizedValidators); + + const pubkeysToDelete = Array.from(newFinalizedValidators.keys()); + + firstState.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + + for (const s of states) { + s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + } + + for (const s of cpStates) { + s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + } + }, + }); + } + + function generatePubkey2Index(startIndex: number, endIndex: number): PubkeyIndexMap { + const pubkey2Index = new PubkeyIndexMap(); + const pubkeys = generatePubkeys(endIndex - startIndex); + + for (let i = startIndex; i < endIndex; i++) { + pubkey2Index.set(pubkeys[i], i); + } + + return pubkey2Index; + } + + function generatePubkeys(validatorCount: number): Uint8Array[] { + const keys = []; + + for (let i = 0; i < validatorCount; i++) { + const sk = generatePrivateKey(i); + const pk = sk.toPublicKey().toBytes(); + keys.push(pk); + } + + return keys; + } + + function generatePrivateKey(index: number): SecretKey { + const secretKeyBytes = toBufferBE(bytesToBigInt(digest(intToBytes(index, 32))) % BigInt("38581184513"), 32); + return bls.SecretKey.fromBytes(secretKeyBytes); + } +}); diff --git a/packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh b/packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh new file mode 100755 index 000000000000..1444f6d3a479 --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh @@ -0,0 +1,19 @@ +#!/bin/bash -x + +echo $TTD +echo $DATA_DIR +echo $EL_BINARY_DIR +echo $JWT_SECRET_HEX +echo $TEMPLATE_FILE + +echo $scriptDir +echo $currentDir + + +env TTD=$TTD envsubst < $scriptDir/$TEMPLATE_FILE > $DATA_DIR/genesis.json +echo "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" > $DATA_DIR/sk.json +echo "12345678" > $DATA_DIR/password.txt +pubKey="0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" + +# echo a hex encoded 256 bit secret into a file +echo $JWT_SECRET_HEX> $DATA_DIR/jwtsecret \ No newline at end of file diff --git a/packages/beacon-node/test/scripts/el-interop/besu/electra.tmpl b/packages/beacon-node/test/scripts/el-interop/besu/electra.tmpl new file mode 100644 index 000000000000..7a63bfbe36d6 --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besu/electra.tmpl @@ -0,0 +1,77 @@ +{ + "config": { + "chainId":6110, + "homesteadBlock":0, + "eip150Block":0, + "eip155Block":0, + "eip158Block":0, + "byzantiumBlock":0, + "constantinopleBlock":0, + "petersburgBlock":0, + "istanbulBlock":0, + "muirGlacierBlock":0, + "berlinBlock":0, + "londonBlock":0, + "terminalTotalDifficulty":0, + "cancunTime":0, + "experimentalEipsTime":10, + "clique": { + "period": 5, + "epoch": 30000 + }, + "depositContractAddress": "0x4242424242424242424242424242424242424242" + }, + "nonce":"0x42", + "timestamp":"0x0", + "extraData":"0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit":"0x1C9C380", + "difficulty":"0x400000000", + "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase":"0x0000000000000000000000000000000000000000", + "alloc":{ + "0xa4664C40AACeBD82A2Db79f0ea36C06Bc6A19Adb": { + "balance": "1000000000000000000000000000" + }, + "0x4242424242424242424242424242424242424242": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + } + }, + "number":"0x0", + "gasUsed":"0x0", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas":"0x7" +} diff --git a/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh b/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh new file mode 100755 index 000000000000..47bec71cf8bb --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh @@ -0,0 +1,8 @@ +#!/bin/bash -x + +scriptDir=$(dirname $0) +currentDir=$(pwd) + +. $scriptDir/common-setup.sh + +$EL_BINARY_DIR/besu --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ADMIN,ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-rpc-port $ENGINE_PORT --engine-jwt-secret $currentDir/$DATA_DIR/jwtsecret --data-path $DATA_DIR --data-storage-format BONSAI --genesis-file $DATA_DIR/genesis.json \ No newline at end of file diff --git a/packages/beacon-node/test/scripts/el-interop/besudocker/common-setup.sh b/packages/beacon-node/test/scripts/el-interop/besudocker/common-setup.sh new file mode 100644 index 000000000000..b3d93190ef2d --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besudocker/common-setup.sh @@ -0,0 +1,22 @@ +#!/bin/bash -x + +echo $TTD +echo $DATA_DIR +echo $EL_BINARY_DIR +echo $JWT_SECRET_HEX +echo $TEMPLATE_FILE + +echo $scriptDir +echo $currentDir + + +env TTD=$TTD envsubst < $scriptDir/$TEMPLATE_FILE > $DATA_DIR/genesis.json +echo "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" > $DATA_DIR/sk.json +echo "12345678" > $DATA_DIR/password.txt +pubKey="0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" + +# echo a hex encoded 256 bit secret into a file +echo $JWT_SECRET_HEX> $DATA_DIR/jwtsecret +# clear any previous docker dangling docker run +docker rm -f custom-execution +rm -rf $DATA_DIR/besu diff --git a/packages/beacon-node/test/scripts/el-interop/besudocker/electra.tmpl b/packages/beacon-node/test/scripts/el-interop/besudocker/electra.tmpl new file mode 100644 index 000000000000..7a63bfbe36d6 --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besudocker/electra.tmpl @@ -0,0 +1,77 @@ +{ + "config": { + "chainId":6110, + "homesteadBlock":0, + "eip150Block":0, + "eip155Block":0, + "eip158Block":0, + "byzantiumBlock":0, + "constantinopleBlock":0, + "petersburgBlock":0, + "istanbulBlock":0, + "muirGlacierBlock":0, + "berlinBlock":0, + "londonBlock":0, + "terminalTotalDifficulty":0, + "cancunTime":0, + "experimentalEipsTime":10, + "clique": { + "period": 5, + "epoch": 30000 + }, + "depositContractAddress": "0x4242424242424242424242424242424242424242" + }, + "nonce":"0x42", + "timestamp":"0x0", + "extraData":"0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit":"0x1C9C380", + "difficulty":"0x400000000", + "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase":"0x0000000000000000000000000000000000000000", + "alloc":{ + "0xa4664C40AACeBD82A2Db79f0ea36C06Bc6A19Adb": { + "balance": "1000000000000000000000000000" + }, + "0x4242424242424242424242424242424242424242": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + } + }, + "number":"0x0", + "gasUsed":"0x0", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas":"0x7" +} diff --git a/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh b/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh new file mode 100755 index 000000000000..fb091a7d838b --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh @@ -0,0 +1,8 @@ +#!/bin/bash -x + +scriptDir=$(dirname $0) +currentDir=$(pwd) + +. $scriptDir/common-setup.sh + +docker run --rm -u $(id -u ${USER}):$(id -g ${USER}) --name custom-execution -p $ETH_PORT:$ETH_PORT -p $ENGINE_PORT:$ENGINE_PORT -v $currentDir/$DATA_DIR:/data $EL_BINARY_DIR --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ADMIN,ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-rpc-port $ENGINE_PORT --engine-jwt-secret /data/jwtsecret --data-path /data/besu --data-storage-format BONSAI --genesis-file /data/genesis.json \ No newline at end of file diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts new file mode 100644 index 000000000000..c1663211cbd9 --- /dev/null +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -0,0 +1,457 @@ +import fs from "node:fs"; +import {describe, it, vi, afterAll, afterEach} from "vitest"; +/* eslint-disable @typescript-eslint/naming-convention */ +import _ from "lodash"; +import {LogLevel, sleep} from "@lodestar/utils"; +import {ForkName, SLOTS_PER_EPOCH, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; +import {electra, Epoch, Slot} from "@lodestar/types"; +import {ValidatorProposerConfig} from "@lodestar/validator"; + +import {ChainConfig} from "@lodestar/config"; +import {TimestampFormatCode} from "@lodestar/logger"; +import {CachedBeaconStateElectra} from "@lodestar/state-transition"; +import {initializeExecutionEngine} from "../../src/execution/index.js"; +import {ExecutionPayloadStatus, PayloadAttributes} from "../../src/execution/engine/interface.js"; + +import {testLogger, TestLoggerOpts} from "../utils/logger.js"; +import {runEL, ELStartMode, ELClient, sendRawTransactionBig} from "../utils/runEl.js"; +import {defaultExecutionEngineHttpOpts} from "../../src/execution/engine/http.js"; +import {getDevBeaconNode} from "../utils/node/beacon.js"; +import {BeaconRestApiServerOpts} from "../../src/api/index.js"; +import {simTestInfoTracker} from "../utils/node/simTest.js"; +import {getAndInitDevValidators} from "../utils/node/validator.js"; +import {ClockEvent} from "../../src/util/clock.js"; +import {dataToBytes} from "../../src/eth1/provider/utils.js"; +import {bytesToData} from "../../lib/eth1/provider/utils.js"; +import {BeaconNode} from "../../src/index.js"; +import {logFilesDir} from "./params.js"; +import {shell} from "./shell.js"; + +// NOTE: How to run +// DEV_RUN=true EL_BINARY_DIR=naviechan/besu:v6110 EL_SCRIPT_DIR=besudocker yarn vitest --run test/sim/electra-interop.test.ts +// or +// DEV_RUN=true EL_BINARY_DIR=/Volumes/fast_boi/navie/Documents/workspace/besu/build/install/besu/bin EL_SCRIPT_DIR=besu yarn vitest --run test/sim/electra-interop.test.ts +// ``` + +/* eslint-disable no-console, @typescript-eslint/naming-convention */ + +const jwtSecretHex = "0xdc6457099f127cf0bac78de8b297df04951281909db4f58b43def7c7151e765d"; +const retries = defaultExecutionEngineHttpOpts.retries; +const retryDelay = defaultExecutionEngineHttpOpts.retryDelay; +describe("executionEngine / ExecutionEngineHttp", function () { + if (!process.env.EL_BINARY_DIR || !process.env.EL_SCRIPT_DIR) { + throw Error( + `EL ENV must be provided, EL_BINARY_DIR: ${process.env.EL_BINARY_DIR}, EL_SCRIPT_DIR: ${process.env.EL_SCRIPT_DIR}` + ); + } + vi.setConfig({testTimeout: 1000 * 60 * 10, hookTimeout: 1000 * 60 * 10}); + + const dataPath = fs.mkdtempSync("lodestar-test-electra"); + const elSetupConfig = { + elScriptDir: process.env.EL_SCRIPT_DIR, + elBinaryDir: process.env.EL_BINARY_DIR, + }; + const elRunOptions = { + dataPath, + jwtSecretHex, + enginePort: parseInt(process.env.ENGINE_PORT ?? "8551"), + ethPort: parseInt(process.env.ETH_PORT ?? "8545"), + }; + + const controller = new AbortController(); + afterAll(async () => { + controller?.abort(); + await shell(`sudo rm -rf ${dataPath}`); + }); + + const afterEachCallbacks: (() => Promise | void)[] = []; + afterEach(async () => { + while (afterEachCallbacks.length > 0) { + const callback = afterEachCallbacks.pop(); + if (callback) await callback(); + } + }); + + it("Send and get payloads with depositReceipts to/from EL", async () => { + const {elClient, tearDownCallBack} = await runEL( + {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "electra.tmpl"}, + {...elRunOptions, ttd: BigInt(0)}, + controller.signal + ); + afterEachCallbacks.push(() => tearDownCallBack()); + const {genesisBlockHash, engineRpcUrl, ethRpcUrl} = elClient; + console.log({genesisBlockHash}); + + const loggerExecutionEngine = testLogger("executionEngine"); + + const executionEngine = initializeExecutionEngine( + {mode: "http", urls: [engineRpcUrl], jwtSecretHex, retries, retryDelay}, + {signal: controller.signal, logger: loggerExecutionEngine} + ); + + // 1. Prepare payload + const preparePayloadParams: PayloadAttributes = { + // Note: this is created with a pre-defined genesis.json + timestamp: 10, + prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + suggestedFeeRecipient: "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + withdrawals: [], + parentBeaconBlockRoot: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + }; + const payloadId = await executionEngine.notifyForkchoiceUpdate( + ForkName.electra, + genesisBlockHash, + //use finalizedBlockHash as safeBlockHash + genesisBlockHash, + genesisBlockHash, + preparePayloadParams + ); + if (!payloadId) throw Error("InvalidPayloadId"); + + // 2. Send raw deposit transaction A and B. tx A is to be imported via newPayload, tx B is to be included in payload via getPayload + const depositTransactionA = + "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; + const depositReceiptA = { + amount: 32000000000, + index: 0, + pubkey: dataToBytes( + "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9", + 48 + ), + signature: dataToBytes( + "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9", + 96 + ), + withdrawalCredentials: dataToBytes("0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2", 32), + }; + + const depositTransactionB = + "0x02f9021c8217de018459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120a18b4c7cab0afa273ea9504904521ea8421a4e32740b7611bd3d5095ca99f0cb0000000000000000000000000000000000000000000000000000000000000030a5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca00000000000000000000000000000000000000000000000000000000000000609561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1c001a0644e0a763a34b4bfb9f56a677857b57fcf15e3db57e2f57060e92084f75f3d82a018ba8eaacbd8e6f6917675b1d0362b12ca82850ca8ef9c010430760c2b2e0cb5"; + const depositReceiptB = { + amount: 32000000000, + index: 1, + pubkey: dataToBytes( + "0xa5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b", + 48 + ), + signature: dataToBytes( + "0x9561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1", + 96 + ), + withdrawalCredentials: dataToBytes("0x001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca", 32), + }; + + sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e: Error) => { + loggerExecutionEngine.error("Fail to send raw deposit transaction A", undefined, e); + }); + + sendRawTransactionBig(ethRpcUrl, depositTransactionB, `${dataPath}/deposit.json`).catch((e: Error) => { + loggerExecutionEngine.error("Fail to send raw deposit transaction B", undefined, e); + }); + + // 3. Import new payload with tx A and deposit receipt A + const newPayloadBlockHash = "0xfd1189e6ea0814b7d40d4e50b31ae5feabbb2acff39399457bbdda7cb5ccd490"; + const newPayload = { + parentHash: dataToBytes("0x26118cf71453320edcebbc4ebb34af5b578087a32385b80108bf691fa23efc42", 32), + feeRecipient: dataToBytes("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 20), + stateRoot: dataToBytes("0x14208ac0e218167936e220b72d5d5887a963cb858ea2f2d268518f014a3da3fa", 32), + logsBloom: dataToBytes( + "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", + 256 + ), + prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + gasLimit: 30000000, + gasUsed: 84846, + timestamp: 16, + extraData: dataToBytes("0x", 0), + baseFeePerGas: 7n, + excessBlobGas: 0n, + transactions: [dataToBytes(depositTransactionA, null)], + withdrawals: [], + depositReceipts: [depositReceiptA], + blockNumber: 1, + blockHash: dataToBytes(newPayloadBlockHash, 32), + receiptsRoot: dataToBytes("0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9", 32), + blobGasUsed: 0n, + }; + const parentBeaconBlockRoot = dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32); + const payloadResult = await executionEngine.notifyNewPayload( + ForkName.electra, + newPayload, + [], + parentBeaconBlockRoot + ); + if (payloadResult.status !== ExecutionPayloadStatus.VALID) { + throw Error("getPayload returned payload that notifyNewPayload deems invalid"); + } + + // 4. Update fork choice + const preparePayloadParams2: PayloadAttributes = { + timestamp: 48, + prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + suggestedFeeRecipient: "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + withdrawals: [], + parentBeaconBlockRoot: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + }; + + const payloadId2 = await executionEngine.notifyForkchoiceUpdate( + ForkName.electra, + newPayloadBlockHash, + //use finalizedBlockHash as safeBlockHash + newPayloadBlockHash, + newPayloadBlockHash, + preparePayloadParams2 + ); + if (!payloadId2) throw Error("InvalidPayloadId"); + + // 5. Get the payload. Check depositReceipts field contains deposit + // Wait a bit first for besu to pick up tx from the tx pool. + await sleep(1000); + const payloadAndBlockValue = await executionEngine.getPayload(ForkName.electra, payloadId2); + const payload = payloadAndBlockValue.executionPayload as electra.ExecutionPayload; + + if (payload.transactions.length !== 1) { + throw Error(`Number of transactions mismatched. Expected: 1, actual: ${payload.transactions.length}`); + } else { + const actualTransaction = bytesToData(payload.transactions[0]); + + if (actualTransaction !== depositTransactionB) { + throw Error(`Transaction mismatched. Expected: ${depositTransactionB}, actual: ${actualTransaction}`); + } + } + + if (payload.depositReceipts.length !== 1) { + throw Error(`Number of depositReceipts mismatched. Expected: 1, actual: ${payload.depositReceipts.length}`); + } + + const actualDepositReceipt = payload.depositReceipts[0]; + if (!_.isEqual(actualDepositReceipt, depositReceiptB)) { + throw Error( + `Deposit receipts mismatched. Expected: ${JSON.stringify(depositReceiptB)}, actual: ${JSON.stringify( + actualDepositReceipt + )}` + ); + } + }); + + it("Post-merge, run for a few blocks", async function () { + console.log("\n\nPost-merge, run for a few blocks\n\n"); + const {elClient, tearDownCallBack} = await runEL( + {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "electra.tmpl"}, + {...elRunOptions, ttd: BigInt(0)}, + controller.signal + ); + afterEachCallbacks.push(() => tearDownCallBack()); + + await runNodeWithEL({ + elClient, + electraEpoch: 0, + testName: "post-merge", + }); + }); + + /** + * Want to test two things: + * 1) Send two raw deposit transactions, and see if two new validators with corrent balances show up in the state.validators and unfinalized cache + * 2) Upon state-transition, see if the two new validators move from unfinalized cache to finalized cache + */ + async function runNodeWithEL({ + elClient, + electraEpoch, + testName, + }: { + elClient: ELClient; + electraEpoch: Epoch; + testName: string; + }): Promise { + const {genesisBlockHash, ttd, engineRpcUrl, ethRpcUrl} = elClient; + const validatorClientCount = 1; + const validatorsPerClient = 32; + + const testParams: Pick = { + SECONDS_PER_SLOT: 2, + }; + + // Just enough to have a checkpoint finalized + const expectedEpochsToFinish = 4; + // 1 epoch of margin of error + const epochsOfMargin = 1; + const timeoutSetupMargin = 30 * 1000; // Give extra 30 seconds of margin + + // delay a bit so regular sync sees it's up to date and sync is completed from the beginning + const genesisSlotsDelay = 8; + + const timeout = + ((epochsOfMargin + expectedEpochsToFinish) * SLOTS_PER_EPOCH + genesisSlotsDelay) * + testParams.SECONDS_PER_SLOT * + 1000; + + vi.setConfig({testTimeout: timeout + 2 * timeoutSetupMargin}); + + const genesisTime = Math.floor(Date.now() / 1000) + genesisSlotsDelay * testParams.SECONDS_PER_SLOT; + + const testLoggerOpts: TestLoggerOpts = { + level: LogLevel.info, + file: { + filepath: `${logFilesDir}/mergemock-${testName}.log`, + level: LogLevel.debug, + }, + timestampFormat: { + format: TimestampFormatCode.EpochSlot, + genesisTime, + slotsPerEpoch: SLOTS_PER_EPOCH, + secondsPerSlot: testParams.SECONDS_PER_SLOT, + }, + }; + const loggerNodeA = testLogger("Node-A", testLoggerOpts); + + const bn = await getDevBeaconNode({ + params: { + ...testParams, + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: electraEpoch, + TERMINAL_TOTAL_DIFFICULTY: ttd, + }, + options: { + api: {rest: {enabled: true} as BeaconRestApiServerOpts}, + sync: {isSingleNode: true}, + network: {allowPublishToZeroPeers: true, discv5: null}, + // Now eth deposit/merge tracker methods directly available on engine endpoints + eth1: {enabled: false, providerUrls: [engineRpcUrl], jwtSecretHex}, + executionEngine: {urls: [engineRpcUrl], jwtSecretHex}, + chain: {suggestedFeeRecipient: "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}, + }, + validatorCount: validatorClientCount * validatorsPerClient, + logger: loggerNodeA, + genesisTime, + eth1BlockHash: dataToBytes(genesisBlockHash, 32), + withEth1Credentials: true, + }); + + afterEachCallbacks.push(async function () { + await bn.close(); + await sleep(1000); + }); + + const stopInfoTracker = simTestInfoTracker(bn, loggerNodeA); + const valProposerConfig = { + defaultConfig: { + feeRecipient: "0xcccccccccccccccccccccccccccccccccccccccc", + }, + } as ValidatorProposerConfig; + + const {validators} = await getAndInitDevValidators({ + node: bn, + logPrefix: "Node-A", + validatorsPerClient, + validatorClientCount, + startIndex: 0, + // At least one sim test must use the REST API for beacon <-> validator comms + useRestApi: true, + testLoggerOpts, + valProposerConfig, + }); + + afterEachCallbacks.push(async function () { + await Promise.all(validators.map((v) => v.close())); + }); + + await waitForSlot(bn, 1); + + // send raw tx at slot 1 + const depositTransaction = + "0x02f9021e8217de8085012a05f20085019254d380830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120ef950826b191ebea0bbafa92a2c6bffa8239c6f456d92891ce2852b8360f0d30000000000000000000000000000000000000000000000000000000000000003095e4f91aea91a9e00387fad9d60997cff6cbf68d42d1b6629a7b248cdef255f94a2a2381e5d4125273fe42da5f7aa0e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b6c06e65228046268aa918baf78e072c25e65aa0bcf258cefcac3371c47df81bc4d43ca942f5fc28f9a563e925fd9c5010bc8c300add3faf3af0d61fabaaf03694020feaafb03e47c1bc4fcf082684c7ed3f7d5839d1722214b24f95ad2b226cc080a0be1161617492e4ca2fcb89edcadf5e71e8cac0d6447d18cfde9b55e5a8412417a07ec8c47dd484036c745049bb2e2980d44e38d4dacac50dc4a14a2f23c52f2e5f"; + sendRawTransactionBig(ethRpcUrl, depositTransaction, `${dataPath}/deposit.json`).catch((e: Error) => { + loggerNodeA.error("Fail to send raw deposit transaction", undefined, e); + }); + + await waitForSlot(bn, 5); + // Expect new validator to be in unfinalized cache, in state.validators and not in finalized cache + let headState = bn.chain.getHeadState(); + let epochCtx = headState.epochCtx; + if (headState.validators.length !== 33 || headState.balances.length !== 33) { + throw Error("New validator is not reflected in the beacon state at slot 5"); + } + if (epochCtx.index2pubkey.length !== 32 || epochCtx.pubkey2index.size !== 32) { + throw Error("Finalized cache is modified."); + } + if (epochCtx.unfinalizedPubkey2index.size !== 1) { + throw Error( + `Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}` + ); + } + // validator count at epoch 1 should be empty at this point since no epoch transition has happened. + if (epochCtx.getValidatorCountAtEpoch(1) !== undefined) { + throw Error("Historical validator lengths is modified"); + } + + await new Promise((resolve, _reject) => { + bn.chain.clock.on(ClockEvent.epoch, (epoch) => { + // Resolve only if the finalized checkpoint includes execution payload + if (epoch >= expectedEpochsToFinish) { + console.log("\nGot event epoch, stopping validators and nodes\n"); + resolve(); + } + }); + }); + + // Stop chain and un-subscribe events so the execution engine won't update it's head + // Allow some time to broadcast finalized events and complete the importBlock routine + await Promise.all(validators.map((v) => v.close())); + await bn.close(); + await sleep(500); + + // Check if new validator is in finalized cache + headState = bn.chain.getHeadState() as CachedBeaconStateElectra; + epochCtx = headState.epochCtx; + + if (headState.validators.length !== 33 || headState.balances.length !== 33) { + throw Error("New validator is not reflected in the beacon state."); + } + if (epochCtx.index2pubkey.length !== 33 || epochCtx.pubkey2index.size !== 33) { + throw Error("New validator is not in finalized cache"); + } + if (!epochCtx.unfinalizedPubkey2index.isEmpty()) { + throw Error("Unfinalized cache still contains new validator"); + } + // After 4 epochs, headState's finalized cp epoch should be 2 + // epochCtx should only have validator count for epoch 3 and 4. + if (epochCtx.getValidatorCountAtEpoch(4) === undefined || epochCtx.getValidatorCountAtEpoch(3) === undefined) { + throw Error("Missing historical validator length for epoch 3 or 4"); + } + + if (epochCtx.getValidatorCountAtEpoch(4) !== 33 || epochCtx.getValidatorCountAtEpoch(3) !== 33) { + throw Error("Incorrect historical validator length for epoch 3 or 4"); + } + + if (epochCtx.getValidatorCountAtEpoch(2) !== undefined || epochCtx.getValidatorCountAtEpoch(1) !== undefined) { + throw Error("Historical validator length for epoch 1 or 2 is not dropped properly"); + } + + if (headState.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + throw Error("state.depositReceiptsStartIndex is not set upon processing new deposit receipt"); + } + + // wait for 1 slot to print current epoch stats + await sleep(1 * bn.config.SECONDS_PER_SLOT * 1000); + stopInfoTracker(); + console.log("\n\nDone\n\n"); + } +}); + +async function waitForSlot(bn: BeaconNode, targetSlot: Slot): Promise { + await new Promise((resolve, reject) => { + bn.chain.clock.on(ClockEvent.slot, (currentSlot) => { + if (currentSlot === targetSlot) { + resolve(); + return; + } + if (currentSlot > targetSlot) { + reject(Error(`Beacon node has passed target slot ${targetSlot}. Current slot ${currentSlot}`)); + } + }); + }); +} diff --git a/packages/beacon-node/test/spec/presets/fork.test.ts b/packages/beacon-node/test/spec/presets/fork.test.ts index c880d24bbbe3..c121e651fcea 100644 --- a/packages/beacon-node/test/spec/presets/fork.test.ts +++ b/packages/beacon-node/test/spec/presets/fork.test.ts @@ -5,6 +5,7 @@ import { CachedBeaconStateAltair, CachedBeaconStatePhase0, CachedBeaconStateCapella, + CachedBeaconStateDeneb, } from "@lodestar/state-transition"; import * as slotFns from "@lodestar/state-transition/slot"; import {phase0, ssz} from "@lodestar/types"; @@ -36,7 +37,7 @@ const fork: TestRunnerFn = (forkNext) => { case ForkName.deneb: return slotFns.upgradeStateToDeneb(preState as CachedBeaconStateCapella); case ForkName.electra: - throw Error("not Implemented"); + return slotFns.upgradeStateToElectra(preState as CachedBeaconStateDeneb); } }, options: { diff --git a/packages/beacon-node/test/spec/presets/genesis.test.ts b/packages/beacon-node/test/spec/presets/genesis.test.ts index f03f2595a566..d8f85dd9b5b8 100644 --- a/packages/beacon-node/test/spec/presets/genesis.test.ts +++ b/packages/beacon-node/test/spec/presets/genesis.test.ts @@ -61,7 +61,7 @@ const genesisInitialization: TestRunnerFn + testcase["execution_payload_header"] as ExecutionPayloadHeader ) ); }, diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index 4c1c10e0cb66..cc032bec6fa2 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -4,11 +4,12 @@ import { CachedBeaconStateAllForks, CachedBeaconStateBellatrix, CachedBeaconStateCapella, + CachedBeaconStateElectra, ExecutionPayloadStatus, getBlockRootAtSlot, } from "@lodestar/state-transition"; import * as blockFns from "@lodestar/state-transition/block"; -import {ssz, phase0, altair, bellatrix, capella, sszTypesFor} from "@lodestar/types"; +import {ssz, phase0, altair, bellatrix, capella, electra, sszTypesFor} from "@lodestar/types"; import {InputType} from "@lodestar/spec-test-util"; import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; @@ -56,6 +57,11 @@ const operationFns: Record> = blockFns.processDeposit(fork, state, testCase.deposit); }, + deposit_receipt: (state, testCase: {deposit_receipt: electra.DepositReceipt}) => { + const fork = state.config.getForkSeq(state.slot); + blockFns.processDepositReceipt(fork, state as CachedBeaconStateElectra, testCase.deposit_receipt); + }, + proposer_slashing: (state, testCase: {proposer_slashing: phase0.ProposerSlashing}) => { const fork = state.config.getForkSeq(state.slot); blockFns.processProposerSlashing(fork, state, testCase.proposer_slashing); @@ -121,6 +127,7 @@ const operations: TestRunnerFn = (fork, block: ssz[fork].BeaconBlock, body: ssz[fork].BeaconBlockBody, deposit: ssz.phase0.Deposit, + deposit_receipt: ssz.electra.DepositReceipt, proposer_slashing: ssz.phase0.ProposerSlashing, voluntary_exit: ssz.phase0.SignedVoluntaryExit, // Altair diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index d81b9dee0098..d81b47ecf587 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -45,6 +45,7 @@ const sszStatic = /* eslint-disable @typescript-eslint/strict-boolean-expressions */ const sszType = (sszTypesFor(fork) as Types)[typeName] || + (ssz.deneb as Types)[typeName] || (ssz.capella as Types)[typeName] || (ssz.bellatrix as Types)[typeName] || (ssz.altair as Types)[typeName] || diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index 6aa683cb6530..3201fb15dbf3 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -57,7 +57,6 @@ const coveredTestRunners = [ // ], // ``` export const defaultSkipOpts: SkipOpts = { - skippedForks: ["eip6110"], // TODO: capella // BeaconBlockBody proof in lightclient is the new addition in v1.3.0-rc.2-hotfix // Skip them for now to enable subsequently diff --git a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts index ba8014c47c9e..abb520bddafb 100644 --- a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts +++ b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts @@ -15,7 +15,7 @@ describe("UpgradeLightClientHeader", function () { BELLATRIX_FORK_EPOCH: 2, CAPELLA_FORK_EPOCH: 3, DENEB_FORK_EPOCH: 4, - ELECTRA_FORK_EPOCH: Infinity, + ELECTRA_FORK_EPOCH: 5, }); const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); @@ -37,18 +37,12 @@ describe("UpgradeLightClientHeader", function () { bellatrix: 17, capella: 25, deneb: 33, - electra: 0, + electra: 41, }; }); - // Since electra is not implemented for loop is till deneb (Object.values(ForkName).length-1) - // Once electra is implemnted run for loop till Object.values(ForkName).length - - // for (let i = ForkSeq.altair; i < Object.values(ForkName).length; i++) { - // for (let j = i + 1; j < Object.values(ForkName).length; j++) { - - for (let i = ForkSeq.altair; i < Object.values(ForkName).length - 1; i++) { - for (let j = i + 1; j < Object.values(ForkName).length - 1; j++) { + for (let i = ForkSeq.altair; i < Object.values(ForkName).length; i++) { + for (let j = i + 1; j < Object.values(ForkName).length; j++) { const fromFork = ForkName[ForkSeq[i] as ForkName]; const toFork = ForkName[ForkSeq[j] as ForkName]; @@ -62,27 +56,7 @@ describe("UpgradeLightClientHeader", function () { } } - // for electra not implemented for (let i = ForkSeq.altair; i < Object.values(ForkName).length; i++) { - const fromFork = ForkName[ForkSeq[i] as ForkName]; - const toFork = ForkName["electra"]; - - it(`Throw error ${fromFork}=>${toFork}`, function () { - lcHeaderByFork[fromFork].beacon.slot = testSlots[fromFork]; - lcHeaderByFork[toFork].beacon.slot = testSlots[fromFork]; - - expect(() => { - upgradeLightClientHeader(config, toFork, lcHeaderByFork[fromFork]); - }).toThrow("Not Implemented"); - }); - } - - // Since electra is not implemented for loop is till deneb (Object.values(ForkName).length-1) - // Once electra is implemnted run for loop till Object.values(ForkName).length - - // for (let i = ForkSeq.altair; i < Object.values(ForkName).length; i++) { - - for (let i = ForkSeq.altair; i < Object.values(ForkName).length - 1; i++) { for (let j = i; j > 0; j--) { const fromFork = ForkName[ForkSeq[i] as ForkName]; const toFork = ForkName[ForkSeq[j] as ForkName]; diff --git a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts index 800984fa84bc..41c205cdd0e9 100644 --- a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts @@ -61,9 +61,9 @@ describe("AggregatedAttestationPool", function () { epochParticipation[committee[i]] = 0b000; } } - (originalState as CachedBeaconStateAltair).previousEpochParticipation = + (originalState as unknown as CachedBeaconStateAltair).previousEpochParticipation = ssz.altair.EpochParticipation.toViewDU(epochParticipation); - (originalState as CachedBeaconStateAltair).currentEpochParticipation = + (originalState as unknown as CachedBeaconStateAltair).currentEpochParticipation = ssz.altair.EpochParticipation.toViewDU(epochParticipation); originalState.commit(); let altairState: CachedBeaconStateAllForks; diff --git a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts index 6295a993c072..e6a7e8706bbe 100644 --- a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts +++ b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts @@ -1,6 +1,6 @@ import {describe, it, expect, beforeEach} from "vitest"; -import {getShufflingDecisionBlock} from "@lodestar/state-transition"; +import {getShufflingDecisionBlock, CachedBeaconStateAllForks} from "@lodestar/state-transition"; // eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../state-transition/test/perf/util.js"; import {ShufflingCache} from "../../../src/chain/shufflingCache.js"; @@ -14,7 +14,7 @@ describe("ShufflingCache", function () { beforeEach(() => { shufflingCache = new ShufflingCache(null, {maxShufflingCacheEpochs: 1}); - shufflingCache.processState(state, currentEpoch); + shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, currentEpoch); }); it("should get shuffling from cache", async function () { @@ -29,7 +29,7 @@ describe("ShufflingCache", function () { shufflingCache.insertPromise(currentEpoch, "0x00"); expect(await shufflingCache.get(currentEpoch, decisionRoot)).toEqual(state.epochCtx.currentShuffling); // insert shufflings at other epochs does prune the cache - shufflingCache.processState(state, currentEpoch + 1); + shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, currentEpoch + 1); // the current shuffling is not available anymore expect(await shufflingCache.get(currentEpoch, decisionRoot)).toBeNull(); }); @@ -39,7 +39,7 @@ describe("ShufflingCache", function () { shufflingCache.insertPromise(currentEpoch + 1, nextDecisionRoot); const shufflingRequest0 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); const shufflingRequest1 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); - shufflingCache.processState(state, currentEpoch + 1); + shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, currentEpoch + 1); expect(await shufflingRequest0).toEqual(state.epochCtx.nextShuffling); expect(await shufflingRequest1).toEqual(state.epochCtx.nextShuffling); }); diff --git a/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts index 7d3f34ddac36..b4aac92dd9bb 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts @@ -1,8 +1,7 @@ import {describe, it, expect, beforeEach} from "vitest"; import {toHexString} from "@chainsafe/ssz"; -import {EpochShuffling} from "@lodestar/state-transition"; +import {EpochShuffling, CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {CachedBeaconStateAllForks} from "@lodestar/state-transition/src/types.js"; import {FIFOBlockStateCache} from "../../../../src/chain/stateCache/index.js"; import {generateCachedState} from "../../../utils/state.js"; diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index ce0d7fae1fad..6cc3ae8f1ce0 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -1,13 +1,15 @@ import {describe, it, expect} from "vitest"; import {phase0, ssz} from "@lodestar/types"; -import {MAX_DEPOSITS} from "@lodestar/params"; +import {MAX_DEPOSITS, SLOTS_PER_EPOCH} from "@lodestar/params"; import {verifyMerkleBranch} from "@lodestar/utils"; +import {createChainForkConfig} from "@lodestar/config"; import {filterBy} from "../../../utils/db.js"; import {Eth1ErrorCode} from "../../../../src/eth1/errors.js"; import {generateState} from "../../../utils/state.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {getDeposits, getDepositsWithProofs, DepositGetter} from "../../../../src/eth1/utils/deposits.js"; import {DepositTree} from "../../../../src/db/repositories/depositDataRoot.js"; +import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; describe("eth1 / util / deposits", function () { describe("getDeposits", () => { @@ -18,6 +20,7 @@ describe("eth1 / util / deposits", function () { depositIndexes: number[]; expectedReturnedIndexes?: number[]; error?: Eth1ErrorCode; + postElectra?: boolean; }; const testCases: TestCase[] = [ @@ -70,18 +73,59 @@ describe("eth1 / util / deposits", function () { depositIndexes: [], expectedReturnedIndexes: [], }, + { + id: "No deposits to be included post Electra after deposit_receipts_start_index", + depositCount: 2030, + eth1DepositIndex: 2025, + depositIndexes: Array.from({length: 2030}, (_, i) => i), + expectedReturnedIndexes: [], + postElectra: true, + }, + { + id: "Should return deposits post Electra before deposit_receipts_start_index", + depositCount: 2022, + eth1DepositIndex: 2018, + depositIndexes: Array.from({length: 2022}, (_, i) => i), + expectedReturnedIndexes: [2018, 2019, 2020, 2021], + postElectra: true, + }, + { + id: "Should return deposits less than MAX_DEPOSITS post Electra before deposit_receipts_start_index", + depositCount: 10 * MAX_DEPOSITS, + eth1DepositIndex: 0, + depositIndexes: Array.from({length: 10 * MAX_DEPOSITS}, (_, i) => i), + expectedReturnedIndexes: Array.from({length: MAX_DEPOSITS}, (_, i) => i), + postElectra: true, + }, ]; + /* eslint-disable @typescript-eslint/naming-convention */ + const postElectraConfig = createChainForkConfig({ + ALTAIR_FORK_EPOCH: 1, + BELLATRIX_FORK_EPOCH: 2, + CAPELLA_FORK_EPOCH: 3, + DENEB_FORK_EPOCH: 4, + ELECTRA_FORK_EPOCH: 5, + }); + const postElectraSlot = postElectraConfig.ELECTRA_FORK_EPOCH * SLOTS_PER_EPOCH + 1; + for (const testCase of testCases) { - const {id, depositIndexes, eth1DepositIndex, depositCount, expectedReturnedIndexes, error} = testCase; + const {id, depositIndexes, eth1DepositIndex, depositCount, expectedReturnedIndexes, error, postElectra} = + testCase; it(id, async function () { - const state = generateState({eth1DepositIndex}); + const state = postElectra + ? generateState({slot: postElectraSlot, eth1DepositIndex}, postElectraConfig) + : generateState({eth1DepositIndex}); + const cachedState = createCachedBeaconStateTest( + state, + postElectra ? postElectraConfig : createChainForkConfig({}) + ); const eth1Data = generateEth1Data(depositCount); const deposits = depositIndexes.map((index) => generateDepositEvent(index)); const depositsGetter: DepositGetter = async (indexRange) => filterBy(deposits, indexRange, (deposit) => deposit.index); - const resultPromise = getDeposits(state, eth1Data, depositsGetter); + const resultPromise = getDeposits(cachedState, eth1Data, depositsGetter); if (expectedReturnedIndexes) { const result = await resultPromise; diff --git a/packages/beacon-node/test/unit/executionEngine/http.test.ts b/packages/beacon-node/test/unit/executionEngine/http.test.ts index aa33c7dbbc40..b0e20ad1f2b5 100644 --- a/packages/beacon-node/test/unit/executionEngine/http.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/http.test.ts @@ -193,6 +193,7 @@ describe("ExecutionEngine / http", () => { amount: "0x7b", }, ], + depositReceipts: null, // depositReceipts is null pre-electra }, null, // null returned for missing blocks { @@ -201,6 +202,7 @@ describe("ExecutionEngine / http", () => { "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", ], withdrawals: null, // withdrawals is null pre-capella + depositReceipts: null, // depositReceipts is null pre-electra }, ], }; @@ -248,6 +250,7 @@ describe("ExecutionEngine / http", () => { amount: "0x7b", }, ], + depositReceipts: null, // depositReceipts is null pre-electra }, null, // null returned for missing blocks { @@ -256,6 +259,7 @@ describe("ExecutionEngine / http", () => { "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", ], withdrawals: null, // withdrawals is null pre-capella + depositReceipts: null, // depositReceipts is null pre-electra }, ], }; diff --git a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts index 3fb9cb8e1c79..c7de35d468df 100644 --- a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts +++ b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts @@ -24,6 +24,7 @@ describe("beaconBlocksMaybeBlobsByRange", () => { BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: 0, }); const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); const config = createBeaconConfig(chainConfig, genesisValidatorsRoot); diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index 1e9f614e8093..ad4dd4b88dac 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -7,8 +7,10 @@ import { PubkeyIndexMap, CachedBeaconStateBellatrix, BeaconStateBellatrix, + CachedBeaconStateElectra, + BeaconStateElectra, } from "@lodestar/state-transition"; -import {BeaconState, altair, bellatrix, ssz} from "@lodestar/types"; +import {BeaconState, altair, bellatrix, electra, ssz} from "@lodestar/types"; import {createBeaconConfig, ChainForkConfig} from "@lodestar/config"; import {FAR_FUTURE_EPOCH, ForkName, ForkSeq, MAX_EFFECTIVE_BALANCE, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; @@ -64,6 +66,7 @@ export function generateState( : generateValidators(numValidators, validatorOpts)); state.genesisTime = Math.floor(Date.now() / 1000); + state.slot = stateSlot; state.fork.previousVersion = config.GENESIS_FORK_VERSION; state.fork.currentVersion = config.GENESIS_FORK_VERSION; state.latestBlockHeader.bodyRoot = ssz.phase0.BeaconBlockBody.hashTreeRoot(ssz.phase0.BeaconBlockBody.defaultValue()); @@ -92,6 +95,12 @@ export function generateState( }; } + if (forkSeq >= ForkSeq.electra) { + const stateElectra = state as electra.BeaconState; + stateElectra.depositReceiptsStartIndex = 2023n; + stateElectra.latestExecutionPayloadHeader = ssz.electra.ExecutionPayloadHeader.defaultValue(); + } + return config.getForkTypes(stateSlot).BeaconState.toViewDU(state); } @@ -137,6 +146,18 @@ export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeac }); } +/** + * This generates state with default pubkey + */ +export function generateCachedElectraState(opts?: TestBeaconState): CachedBeaconStateElectra { + const config = getConfig(ForkName.electra); + const state = generateState(opts, config); + return createCachedBeaconState(state as BeaconStateElectra, { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], + }); +} export const zeroProtoBlock: ProtoBlock = { slot: 0, blockRoot: ZERO_HASH_HEX, diff --git a/packages/beacon-node/test/utils/validationData/attestation.ts b/packages/beacon-node/test/utils/validationData/attestation.ts index c33d942dabc5..335ec81870c6 100644 --- a/packages/beacon-node/test/utils/validationData/attestation.ts +++ b/packages/beacon-node/test/utils/validationData/attestation.ts @@ -4,6 +4,7 @@ import { computeSigningRoot, computeStartSlotAtEpoch, getShufflingDecisionBlock, + CachedBeaconStateAllForks, } from "@lodestar/state-transition"; import {ProtoBlock, IForkChoice, ExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; @@ -82,8 +83,8 @@ export function getAttestationValidData(opts: AttestationValidDataOpts): { }; const shufflingCache = new ShufflingCache(); - shufflingCache.processState(state, state.epochCtx.currentShuffling.epoch); - shufflingCache.processState(state, state.epochCtx.nextShuffling.epoch); + shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, state.epochCtx.currentShuffling.epoch); + shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, state.epochCtx.nextShuffling.epoch); const dependentRoot = getShufflingDecisionBlock(state, state.epochCtx.currentShuffling.epoch); const forkChoice = { @@ -133,7 +134,7 @@ export function getAttestationValidData(opts: AttestationValidDataOpts): { getState: async () => state, // TODO: remove this once we have a better way to get state getStateSync: () => state, - } as Partial as IStateRegenerator; + } as unknown as Partial as IStateRegenerator; const chain = { clock, diff --git a/packages/config/src/chainConfig/configs/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts index 0de1bee666ec..6d1fd9b75952 100644 --- a/packages/config/src/chainConfig/configs/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -49,7 +49,7 @@ export const chainConfig: ChainConfig = { DENEB_FORK_VERSION: b("0x04000000"), DENEB_FORK_EPOCH: 269568, // March 13, 2024, 01:55:35pm UTC - // Electra + // ELECTRA ELECTRA_FORK_VERSION: b("0x05000000"), ELECTRA_FORK_EPOCH: Infinity, diff --git a/packages/config/src/chainConfig/configs/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts index c99a76d1ee40..44a28ca36ec7 100644 --- a/packages/config/src/chainConfig/configs/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -45,8 +45,7 @@ export const chainConfig: ChainConfig = { // Deneb DENEB_FORK_VERSION: b("0x04000001"), DENEB_FORK_EPOCH: Infinity, - - // Electra + // ELECTRA ELECTRA_FORK_VERSION: b("0x05000001"), ELECTRA_FORK_EPOCH: Infinity, diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index aafd81c9250a..152c55ac6d15 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -115,7 +115,11 @@ export function upgradeLightClientHeader( // eslint-disable-next-line no-fallthrough case ForkName.electra: - throw Error("Not Implemented"); + (upgradedHeader as LightClientHeader).execution.depositReceiptsRoot = + ssz.electra.LightClientHeader.fields.execution.fields.depositReceiptsRoot.defaultValue(); + + // Break if no further upgrades is required else fall through + if (ForkSeq[targetFork] <= ForkSeq.electra) break; } return upgradedHeader; } @@ -149,6 +153,12 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: LightC } } + if (epoch < config.ELECTRA_FORK_EPOCH) { + if ((header as LightClientHeader).execution.depositReceiptsRoot !== undefined) { + return false; + } + } + return isValidMerkleBranch( config .getExecutionForkTypes(header.beacon.slot) diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 6a95e3ca632e..482e591123b6 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -93,6 +93,8 @@ export const { MAX_BLOB_COMMITMENTS_PER_BLOCK, MAX_BLOBS_PER_BLOCK, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, + + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, } = activePreset; //////////// @@ -244,3 +246,6 @@ export const KZG_COMMITMENT_SUBTREE_INDEX0 = KZG_COMMITMENT_GINDEX0 - 2 ** KZG_C // ssz.deneb.BlobSidecars.elementType.fixedSize export const BLOBSIDECAR_FIXED_SIZE = ACTIVE_PRESET === PresetName.minimal ? 131672 : 131928; + +// Electra Misc +export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = 2n ** 64n - 1n; diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 42a705a07f03..86f5c39c539e 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -118,4 +118,7 @@ export const mainnetPreset: BeaconPreset = { MAX_BLOB_COMMITMENTS_PER_BLOCK: 4096, MAX_BLOBS_PER_BLOCK: 6, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 17, + + // ELECTRA + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index b940841a0429..6239a8c1a3eb 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -119,4 +119,7 @@ export const minimalPreset: BeaconPreset = { MAX_BLOB_COMMITMENTS_PER_BLOCK: 16, MAX_BLOBS_PER_BLOCK: 6, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 9, + + // ELECTRA + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 4, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index 3c5ba6381131..57ee8230a77d 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -82,6 +82,9 @@ export type BeaconPreset = { MAX_BLOB_COMMITMENTS_PER_BLOCK: number; MAX_BLOBS_PER_BLOCK: number; KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: number; + + // ELECTRA + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: number; }; /** @@ -167,6 +170,9 @@ export const beaconPresetTypes: BeaconPresetTypes = { MAX_BLOB_COMMITMENTS_PER_BLOCK: "number", MAX_BLOBS_PER_BLOCK: "number", KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: "number", + + // ELECTRA + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: "number", }; type BeaconPresetTypes = { diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 6fcf70f58987..61b73ef7efc1 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -67,7 +67,12 @@ "@lodestar/params": "^1.21.0", "@lodestar/types": "^1.21.0", "@lodestar/utils": "^1.21.0", - "bigint-buffer": "^1.1.5" + "bigint-buffer": "^1.1.5", + "buffer-xor": "^2.0.2", + "immutable": "^4.3.2" + }, + "devDependencies": { + "@types/buffer-xor": "^2.0.0" }, "keywords": [ "ethereum", diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 7ade79fd7739..5a2a892a5c9b 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -1,5 +1,5 @@ import {PublicKey, Signature, verify} from "@chainsafe/blst"; -import {phase0, ssz} from "@lodestar/types"; +import {BLSPubkey, Bytes32, UintNum64, phase0, ssz} from "@lodestar/types"; import {verifyMerkleBranch} from "@lodestar/utils"; import { @@ -11,6 +11,8 @@ import { MAX_EFFECTIVE_BALANCE, } from "@lodestar/params"; +import {DepositData} from "@lodestar/types/lib/phase0/types.js"; +import {DepositReceipt} from "@lodestar/types/lib/electra/types.js"; import {ZERO_HASH} from "../constants/index.js"; import {computeDomain, computeSigningRoot, increaseBalance} from "../util/index.js"; import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; @@ -22,8 +24,6 @@ import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; * PERF: Work depends on number of Deposit per block. On regular networks the average is 0 / block. */ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, deposit: phase0.Deposit): void { - const {config, validators, epochCtx} = state; - // verify the merkle branch if ( !verifyMerkleBranch( @@ -40,15 +40,29 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, // deposits must be processed in order state.eth1DepositIndex += 1; - const pubkey = deposit.data.pubkey; // Drop tree - const amount = deposit.data.amount; - const cachedIndex = epochCtx.pubkey2index.get(pubkey); + applyDeposit(fork, state, deposit.data); +} + +/** + * Adds a new validator into the registry. Or increase balance if already exist. + * Follows applyDeposit() in consensus spec. Will be used by processDeposit() and processDepositReceipt() + * + */ +export function applyDeposit( + fork: ForkSeq, + state: CachedBeaconStateAllForks, + deposit: DepositData | DepositReceipt +): void { + const {config, validators, epochCtx} = state; + const {pubkey, withdrawalCredentials, amount} = deposit; + + const cachedIndex = epochCtx.getValidatorIndex(pubkey); if (cachedIndex === undefined || !Number.isSafeInteger(cachedIndex) || cachedIndex >= validators.length) { // verify the deposit signature (proof of posession) which is not checked by the deposit contract const depositMessage = { - pubkey: deposit.data.pubkey, // Retain tree for hashing - withdrawalCredentials: deposit.data.withdrawalCredentials, // Retain tree for hashing - amount: deposit.data.amount, + pubkey, + withdrawalCredentials, + amount, }; // fork-agnostic domain since deposits are valid across forks const domain = computeDomain(DOMAIN_DEPOSIT, config.GENESIS_FORK_VERSION, ZERO_HASH); @@ -63,45 +77,55 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, } catch (e) { return; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature } + addValidatorToRegistry(fork, state, pubkey, withdrawalCredentials, amount); + } else { + // increase balance by deposit amount + increaseBalance(state, cachedIndex, amount); + } +} - // add validator and balance entries - const effectiveBalance = Math.min(amount - (amount % EFFECTIVE_BALANCE_INCREMENT), MAX_EFFECTIVE_BALANCE); - validators.push( - ssz.phase0.Validator.toViewDU({ - pubkey, - withdrawalCredentials: deposit.data.withdrawalCredentials, - activationEligibilityEpoch: FAR_FUTURE_EPOCH, - activationEpoch: FAR_FUTURE_EPOCH, - exitEpoch: FAR_FUTURE_EPOCH, - withdrawableEpoch: FAR_FUTURE_EPOCH, - effectiveBalance, - slashed: false, - }) - ); - state.balances.push(amount); +function addValidatorToRegistry( + fork: ForkSeq, + state: CachedBeaconStateAllForks, + pubkey: BLSPubkey, + withdrawalCredentials: Bytes32, + amount: UintNum64 +): void { + const {validators, epochCtx} = state; + // add validator and balance entries + const effectiveBalance = Math.min(amount - (amount % EFFECTIVE_BALANCE_INCREMENT), MAX_EFFECTIVE_BALANCE); + validators.push( + ssz.phase0.Validator.toViewDU({ + pubkey, + withdrawalCredentials, + activationEligibilityEpoch: FAR_FUTURE_EPOCH, + activationEpoch: FAR_FUTURE_EPOCH, + exitEpoch: FAR_FUTURE_EPOCH, + withdrawableEpoch: FAR_FUTURE_EPOCH, + effectiveBalance, + slashed: false, + }) + ); + state.balances.push(amount); - const validatorIndex = validators.length - 1; - // Updating here is better than updating at once on epoch transition - // - Simplify genesis fn applyDeposits(): effectiveBalanceIncrements is populated immediately - // - Keep related code together to reduce risk of breaking this cache - // - Should have equal performance since it sets a value in a flat array - epochCtx.effectiveBalanceIncrementsSet(validatorIndex, effectiveBalance); + const validatorIndex = validators.length - 1; + // Updating here is better than updating at once on epoch transition + // - Simplify genesis fn applyDeposits(): effectiveBalanceIncrements is populated immediately + // - Keep related code together to reduce risk of breaking this cache + // - Should have equal performance since it sets a value in a flat array + epochCtx.effectiveBalanceIncrementsSet(validatorIndex, effectiveBalance); - // now that there is a new validator, update the epoch context with the new pubkey - epochCtx.addPubkey(validatorIndex, pubkey); + // now that there is a new validator, update the epoch context with the new pubkey + epochCtx.addPubkey(validatorIndex, pubkey); - // Only after altair: - if (fork >= ForkSeq.altair) { - const stateAltair = state as CachedBeaconStateAltair; + // Only after altair: + if (fork >= ForkSeq.altair) { + const stateAltair = state as CachedBeaconStateAltair; - stateAltair.inactivityScores.push(0); + stateAltair.inactivityScores.push(0); - // add participation caches - stateAltair.previousEpochParticipation.push(0); - stateAltair.currentEpochParticipation.push(0); - } - } else { - // increase balance by deposit amount - increaseBalance(state, cachedIndex, amount); + // add participation caches + stateAltair.previousEpochParticipation.push(0); + stateAltair.currentEpochParticipation.push(0); } } diff --git a/packages/state-transition/src/block/processDepositReceipt.ts b/packages/state-transition/src/block/processDepositReceipt.ts new file mode 100644 index 000000000000..140e38d634fd --- /dev/null +++ b/packages/state-transition/src/block/processDepositReceipt.ts @@ -0,0 +1,17 @@ +import {electra} from "@lodestar/types"; +import {ForkSeq, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; + +import {CachedBeaconStateElectra} from "../types.js"; +import {applyDeposit} from "./processDeposit.js"; + +export function processDepositReceipt( + fork: ForkSeq, + state: CachedBeaconStateElectra, + depositReceipt: electra.DepositReceipt +): void { + if (state.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + state.depositReceiptsStartIndex = BigInt(depositReceipt.index); + } + + applyDeposit(fork, state, depositReceipt); +} diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index 38716bb42a40..7b8b39efe743 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -1,13 +1,15 @@ -import {BeaconBlockBody, capella} from "@lodestar/types"; -import {ForkSeq, MAX_DEPOSITS} from "@lodestar/params"; +import {BeaconBlockBody, capella, electra} from "@lodestar/types"; +import {ForkSeq} from "@lodestar/params"; -import {CachedBeaconStateAllForks, CachedBeaconStateCapella} from "../types.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateCapella, CachedBeaconStateElectra} from "../types.js"; +import {getEth1DepositCount} from "../util/deposit.js"; import {processAttestations} from "./processAttestations.js"; import {processProposerSlashing} from "./processProposerSlashing.js"; import {processAttesterSlashing} from "./processAttesterSlashing.js"; import {processDeposit} from "./processDeposit.js"; import {processVoluntaryExit} from "./processVoluntaryExit.js"; import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js"; +import {processDepositReceipt} from "./processDepositReceipt.js"; import {ProcessBlockOpts} from "./types.js"; export { @@ -17,6 +19,7 @@ export { processDeposit, processVoluntaryExit, processBlsToExecutionChange, + processDepositReceipt, }; export function processOperations( @@ -26,7 +29,7 @@ export function processOperations( opts: ProcessBlockOpts = {verifySignatures: true} ): void { // verify that outstanding deposits are processed up to the maximum number of deposits - const maxDeposits = Math.min(MAX_DEPOSITS, state.eth1Data.depositCount - state.eth1DepositIndex); + const maxDeposits = getEth1DepositCount(state); if (body.deposits.length !== maxDeposits) { throw new Error( `Block contains incorrect number of deposits: depositCount=${body.deposits.length} expected=${maxDeposits}` @@ -54,4 +57,10 @@ export function processOperations( processBlsToExecutionChange(state as CachedBeaconStateCapella, blsToExecutionChange); } } + + if (fork >= ForkSeq.electra) { + for (const depositReceipt of (body as electra.BeaconBlockBody).executionPayload.depositReceipts) { + processDepositReceipt(fork, state as CachedBeaconStateElectra, depositReceipt); + } + } } diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 191aa7f3985c..41f8031d903e 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -1,4 +1,6 @@ import {PublicKey} from "@chainsafe/blst"; +import * as immutable from "immutable"; +import {fromHexString} from "@chainsafe/ssz"; import {BLSSignature, CommitteeIndex, Epoch, Slot, ValidatorIndex, phase0, SyncPeriod} from "@lodestar/types"; import {createBeaconConfig, BeaconConfig, ChainConfig} from "@lodestar/config"; import { @@ -29,8 +31,17 @@ import {computeEpochShuffling, EpochShuffling, getShufflingDecisionBlock} from " import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {getTotalSlashingsByIncrement} from "../epoch/processSlashings.js"; +import {EpochCacheMetrics} from "../metrics.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; -import {Index2PubkeyCache, PubkeyIndexMap, syncPubkeys} from "./pubkeyCache.js"; +import { + Index2PubkeyCache, + PubkeyIndexMap, + UnfinalizedPubkeyIndexMap, + syncPubkeys, + toMemoryEfficientHexStr, + PubkeyHex, + newUnfinalizedPubkeyIndexMap, +} from "./pubkeyCache.js"; import {BeaconStateAllForks, BeaconStateAltair, ShufflingGetter} from "./types.js"; import { computeSyncCommitteeCache, @@ -82,23 +93,31 @@ type ProposersDeferred = {computed: false; seed: Uint8Array} | {computed: true; export class EpochCache { config: BeaconConfig; /** - * Unique globally shared pubkey registry. There should only exist one for the entire application. + * Unique globally shared finalized pubkey registry. There should only exist one for the entire application. * * TODO: this is a hack, we need a safety mechanism in case a bad eth1 majority vote is in, * or handle non finalized data differently, or use an immutable.js structure for cheap copies - * Warning: may contain pubkeys that do not yet exist in the current state, but do in a later processed state. + * + * New: This would include only validators whose activation_eligibility_epoch != FAR_FUTURE_EPOCH and hence it is + * insert only. Validators could be 1) Active 2) In the activation queue 3) Initialized but pending queued * * $VALIDATOR_COUNT x 192 char String -> Number Map */ pubkey2index: PubkeyIndexMap; /** - * Unique globally shared pubkey registry. There should only exist one for the entire application. + * Unique globally shared finalized pubkey registry. There should only exist one for the entire application. * - * Warning: may contain indices that do not yet exist in the current state, but do in a later processed state. + * New: This would include only validators whose activation_eligibility_epoch != FAR_FUTURE_EPOCH and hence it is + * insert only. Validators could be 1) Active 2) In the activation queue 3) Initialized but pending queued * * $VALIDATOR_COUNT x BLST deserialized pubkey (Jacobian coordinates) */ index2pubkey: Index2PubkeyCache; + /** + * Unique pubkey registry shared in the same fork. There should only exist one for the fork. + */ + unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; + /** * Indexes of the block proposers for the current epoch. * @@ -198,11 +217,21 @@ export class EpochCache { // TODO: Helper stats epoch: Epoch; syncPeriod: SyncPeriod; + /** + * state.validators.length of every state at epoch boundary + * They are saved in increasing order of epoch. + * The first validator length in the list corresponds to the state AFTER the latest finalized checkpoint state. ie. state.finalizedCheckpoint.epoch - 1 + * The last validator length corresponds to the latest epoch state ie. this.epoch + * eg. latest epoch = 105, latest finalized cp state epoch = 102 + * then the list will be (in terms of epoch) [103, 104, 105] + */ + private historicalValidatorLengths: immutable.List; constructor(data: { config: BeaconConfig; pubkey2index: PubkeyIndexMap; index2pubkey: Index2PubkeyCache; + unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; proposers: number[]; proposersPrevEpoch: number[] | null; proposersNextEpoch: ProposersDeferred; @@ -225,10 +254,12 @@ export class EpochCache { nextSyncCommitteeIndexed: SyncCommitteeCache; epoch: Epoch; syncPeriod: SyncPeriod; + historialValidatorLengths: immutable.List; }) { this.config = data.config; this.pubkey2index = data.pubkey2index; this.index2pubkey = data.index2pubkey; + this.unfinalizedPubkey2index = data.unfinalizedPubkey2index; this.proposers = data.proposers; this.proposersPrevEpoch = data.proposersPrevEpoch; this.proposersNextEpoch = data.proposersNextEpoch; @@ -251,11 +282,12 @@ export class EpochCache { this.nextSyncCommitteeIndexed = data.nextSyncCommitteeIndexed; this.epoch = data.epoch; this.syncPeriod = data.syncPeriod; + this.historicalValidatorLengths = data.historialValidatorLengths; } /** * Create an epoch cache - * @param validators cached validators that matches `state.validators` + * @param state a finalized beacon state. Passing in unfinalized state may cause unexpected behaviour eg. empty unfinalized cache * * SLOW CODE - 🐢 */ @@ -431,6 +463,8 @@ export class EpochCache { config, pubkey2index, index2pubkey, + // `createFromFinalizedState()` creates cache with empty unfinalizedPubkey2index. Be cautious to only pass in finalized state + unfinalizedPubkey2index: newUnfinalizedPubkeyIndexMap(), proposers, // On first epoch, set to null to prevent unnecessary work since this is only used for metrics proposersPrevEpoch: null, @@ -454,6 +488,7 @@ export class EpochCache { nextSyncCommitteeIndexed, epoch: currentEpoch, syncPeriod: computeSyncPeriodAtEpoch(currentEpoch), + historialValidatorLengths: immutable.List(), }); } @@ -469,6 +504,8 @@ export class EpochCache { // Common append-only structures shared with all states, no need to clone pubkey2index: this.pubkey2index, index2pubkey: this.index2pubkey, + // No need to clone this reference. On each mutation the `unfinalizedPubkey2index` reference is replaced, @see `addPubkey` + unfinalizedPubkey2index: this.unfinalizedPubkey2index, // Immutable data proposers: this.proposers, proposersPrevEpoch: this.proposersPrevEpoch, @@ -495,6 +532,7 @@ export class EpochCache { nextSyncCommitteeIndexed: this.nextSyncCommitteeIndexed, epoch: this.epoch, syncPeriod: this.syncPeriod, + historialValidatorLengths: this.historicalValidatorLengths, }); } @@ -505,6 +543,7 @@ export class EpochCache { afterProcessEpoch( state: BeaconStateAllForks, epochTransitionCache: { + indicesEligibleForActivationQueue: ValidatorIndex[]; nextEpochShufflingActiveValidatorIndices: ValidatorIndex[]; nextEpochShufflingActiveIndicesLength: number; nextEpochTotalActiveBalanceByIncrement: number; @@ -579,6 +618,25 @@ export class EpochCache { // ``` this.epoch = computeEpochAtSlot(state.slot); this.syncPeriod = computeSyncPeriodAtEpoch(this.epoch); + // ELECTRA Only: Add current cpState.validators.length + // Only keep validatorLength for epochs after finalized cpState.epoch + // eg. [100(epoch 1), 102(epoch 2)].push(104(epoch 3)), this.epoch = 3, finalized cp epoch = 1 + // We keep the last (3 - 1) items = [102, 104] + if (currEpoch >= this.config.ELECTRA_FORK_EPOCH) { + this.historicalValidatorLengths = this.historicalValidatorLengths.push(state.validators.length); + + // If number of validatorLengths we want to keep exceeds the current list size, it implies + // finalized checkpoint hasn't advanced, and no need to slice + const hasFinalizedCpAdvanced = + this.epoch - state.finalizedCheckpoint.epoch < this.historicalValidatorLengths.size; + + if (hasFinalizedCpAdvanced) { + // We use finalized cp epoch - this.epoch which is a negative number to keep the last n entries and discard the rest + this.historicalValidatorLengths = this.historicalValidatorLengths.slice( + state.finalizedCheckpoint.epoch - this.epoch + ); + } + } } beforeEpochTransition(): void { @@ -766,9 +824,75 @@ export class EpochCache { return isAggregatorFromCommitteeLength(committee.length, slotSignature); } + /** + * Return finalized pubkey given the validator index. + * Only finalized pubkey as we do not store unfinalized pubkey because no where in the spec has a + * need to make such enquiry + */ + getPubkey(index: ValidatorIndex): PublicKey | undefined { + return this.index2pubkey[index]; + } + + getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { + if (this.isAfterElectra()) { + return this.pubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); + } else { + return this.pubkey2index.get(pubkey); + } + } + + /** + * + * Add unfinalized pubkeys + * + */ addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { + if (this.isAfterElectra()) { + this.addUnFinalizedPubkey(index, pubkey); + } else { + // deposit mechanism pre ELECTRA follows a safe distance with assumption + // that they are already canonical + this.addFinalizedPubkey(index, pubkey); + } + } + + addUnFinalizedPubkey(index: ValidatorIndex, pubkey: PubkeyHex | Uint8Array, metrics?: EpochCacheMetrics): void { + this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); + metrics?.newUnFinalizedPubkey.inc(); + } + + addFinalizedPubkeys(pubkeyMap: UnfinalizedPubkeyIndexMap, metrics?: EpochCacheMetrics): void { + pubkeyMap.forEach((index, pubkey) => this.addFinalizedPubkey(index, pubkey, metrics)); + } + + /** + * Add finalized validator index and pubkey into finalized cache. + * Since addFinalizedPubkey() primarily takes pubkeys from unfinalized cache, it can take pubkey hex string directly + */ + addFinalizedPubkey(index: ValidatorIndex, pubkey: PubkeyHex | Uint8Array, metrics?: EpochCacheMetrics): void { + const existingIndex = this.pubkey2index.get(pubkey); + + if (existingIndex !== undefined) { + if (existingIndex === index) { + // Repeated insert. + metrics?.finalizedPubkeyDuplicateInsert.inc(); + return; + } else { + // attempt to insert the same pubkey with different index, should never happen. + throw Error("inserted existing pubkey into finalizedPubkey2index cache with a different index"); + } + } + this.pubkey2index.set(pubkey, index); - this.index2pubkey[index] = PublicKey.fromBytes(pubkey); // Optimize for aggregation + const pubkeyBytes = pubkey instanceof Uint8Array ? pubkey : fromHexString(pubkey); + this.index2pubkey[index] = PublicKey.fromBytes(pubkeyBytes); // Optimize for aggregation + } + + /** + * Delete pubkeys from unfinalized cache + */ + deleteUnfinalizedPubkeys(pubkeys: Iterable): void { + this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.deleteAll(pubkeys); } getShufflingAtSlot(slot: Slot): EpochShuffling { @@ -845,15 +969,53 @@ export class EpochCache { } effectiveBalanceIncrementsSet(index: number, effectiveBalance: number): void { - if (index >= this.effectiveBalanceIncrements.length) { - // Clone and extend effectiveBalanceIncrements + if (this.isAfterElectra()) { + // TODO: electra + // getting length and setting getEffectiveBalanceIncrementsByteLen is not fork safe + // so each time we add an index, we should new the Uint8Array to keep it forksafe + // one simple optimization could be to increment the length once per block rather + // on each add/set + // + // there could still be some unused length remaining from the prev ELECTRA padding + const newLength = + index >= this.effectiveBalanceIncrements.length ? index + 1 : this.effectiveBalanceIncrements.length; const effectiveBalanceIncrements = this.effectiveBalanceIncrements; - this.effectiveBalanceIncrements = new Uint8Array(getEffectiveBalanceIncrementsByteLen(index + 1)); + this.effectiveBalanceIncrements = new Uint8Array(newLength); this.effectiveBalanceIncrements.set(effectiveBalanceIncrements, 0); + } else { + if (index >= this.effectiveBalanceIncrements.length) { + // Clone and extend effectiveBalanceIncrements + const effectiveBalanceIncrements = this.effectiveBalanceIncrements; + this.effectiveBalanceIncrements = new Uint8Array(getEffectiveBalanceIncrementsByteLen(index + 1)); + this.effectiveBalanceIncrements.set(effectiveBalanceIncrements, 0); + } } this.effectiveBalanceIncrements[index] = Math.floor(effectiveBalance / EFFECTIVE_BALANCE_INCREMENT); } + + isAfterElectra(): boolean { + return this.epoch >= (this.config.ELECTRA_FORK_EPOCH ?? Infinity); + } + + getValidatorCountAtEpoch(targetEpoch: Epoch): number | undefined { + const currentEpoch = this.epoch; + + if (targetEpoch === currentEpoch) { + return this.historicalValidatorLengths.get(-1); + } + + // Attempt to get validator count from future epoch + if (targetEpoch > currentEpoch) { + return undefined; + } + + // targetEpoch is so far back that historicalValidatorLengths doesnt contain such info + if (targetEpoch < currentEpoch - this.historicalValidatorLengths.size + 1) { + return undefined; + } + return this.historicalValidatorLengths.get(targetEpoch - currentEpoch - 1); + } } function getEffectiveBalanceIncrementsByteLen(validatorCount: number): number { diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index b2b45ca09d25..a7eacb7961fd 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -1,9 +1,18 @@ import {PublicKey} from "@chainsafe/blst"; +import * as immutable from "immutable"; import {ValidatorIndex, phase0} from "@lodestar/types"; +import {BeaconStateAllForks} from "./types.js"; export type Index2PubkeyCache = PublicKey[]; +/** + * OrderedMap preserves the order of entries in which they are `set()`. + * We assume `values()` yields validator indices in strictly increasing order + * as new validator indices are assigned in increasing order. + * EIP-6914 will break this assumption. + */ +export type UnfinalizedPubkeyIndexMap = immutable.Map; -type PubkeyHex = string; +export type PubkeyHex = string; /** * toHexString() creates hex strings via string concatenation, which are very memory inefficient. @@ -13,7 +22,7 @@ type PubkeyHex = string; * * See https://github.com/ChainSafe/lodestar/issues/3446 */ -function toMemoryEfficientHexStr(hex: Uint8Array | string): string { +export function toMemoryEfficientHexStr(hex: Uint8Array | string): string { if (typeof hex === "string") { if (hex.startsWith("0x")) { hex = hex.slice(2); @@ -24,6 +33,13 @@ function toMemoryEfficientHexStr(hex: Uint8Array | string): string { return Buffer.from(hex.buffer, hex.byteOffset, hex.byteLength).toString("hex"); } +/** + * A wrapper for calling immutable.js. To abstract the initialization of UnfinalizedPubkeyIndexMap + */ +export function newUnfinalizedPubkeyIndexMap(): UnfinalizedPubkeyIndexMap { + return immutable.Map(); +} + export class PubkeyIndexMap { // We don't really need the full pubkey. We could just use the first 20 bytes like an Ethereum address readonly map = new Map(); @@ -39,7 +55,7 @@ export class PubkeyIndexMap { return this.map.get(toMemoryEfficientHexStr(key)); } - set(key: Uint8Array, value: ValidatorIndex): void { + set(key: Uint8Array | PubkeyHex, value: ValidatorIndex): void { this.map.set(toMemoryEfficientHexStr(key), value); } } diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index f4e637e5d665..0435e8829d21 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -10,6 +10,7 @@ import { BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, + BeaconStateElectra, } from "./types.js"; import {RewardCache, createEmptyRewardCache} from "./rewardCache.js"; @@ -130,11 +131,13 @@ export type CachedBeaconStateAltair = CachedBeaconState; export type CachedBeaconStateBellatrix = CachedBeaconState; export type CachedBeaconStateCapella = CachedBeaconState; export type CachedBeaconStateDeneb = CachedBeaconState; +export type CachedBeaconStateElectra = CachedBeaconState; export type CachedBeaconStateAllForks = CachedBeaconState; export type CachedBeaconStateExecutions = CachedBeaconState; /** * Create CachedBeaconState computing a new EpochCache instance + * TODO ELECTRA: rename this to createFinalizedCachedBeaconState() as it's intended for finalized state only */ export function createCachedBeaconState( state: T, @@ -158,7 +161,7 @@ export function createCachedBeaconState( * Create a CachedBeaconState given a cached seed state and state bytes * This guarantees that the returned state shares the same tree with the seed state * Check loadState() api for more details - * // TODO: rename to loadUnfinalizedCachedBeaconState() due to EIP-6110 + * // TODO: rename to loadUnfinalizedCachedBeaconState() due to ELECTRA */ export function loadCachedBeaconState( cachedSeedState: T, diff --git a/packages/state-transition/src/cache/types.ts b/packages/state-transition/src/cache/types.ts index d6d8a3c37904..b3fe6fc8ed5b 100644 --- a/packages/state-transition/src/cache/types.ts +++ b/packages/state-transition/src/cache/types.ts @@ -8,6 +8,7 @@ export type BeaconStateAltair = CompositeViewDU>; export type BeaconStateCapella = CompositeViewDU>; export type BeaconStateDeneb = CompositeViewDU>; +export type BeaconStateElectra = CompositeViewDU>; export type BeaconStateAllForks = CompositeViewDU>; export type BeaconStateExecutions = CompositeViewDU>; diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index 0ef460e784af..4ed801e3c490 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -11,6 +11,7 @@ export type { CachedBeaconStateBellatrix, CachedBeaconStateCapella, CachedBeaconStateDeneb, + CachedBeaconStateElectra, CachedBeaconStateAllForks, CachedBeaconStateExecutions, // Non-cached states @@ -19,6 +20,7 @@ export type { BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, + BeaconStateElectra, BeaconStateAllForks, BeaconStateExecutions, } from "./types.js"; @@ -42,7 +44,12 @@ export { export {type EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js"; // Aux data-structures -export {PubkeyIndexMap, type Index2PubkeyCache} from "./cache/pubkeyCache.js"; +export { + PubkeyIndexMap, + type Index2PubkeyCache, + type UnfinalizedPubkeyIndexMap, + newUnfinalizedPubkeyIndexMap, +} from "./cache/pubkeyCache.js"; export { type EffectiveBalanceIncrements, diff --git a/packages/state-transition/src/metrics.ts b/packages/state-transition/src/metrics.ts index 12cec46d9a49..48e0bc921876 100644 --- a/packages/state-transition/src/metrics.ts +++ b/packages/state-transition/src/metrics.ts @@ -30,6 +30,11 @@ export type BeaconStateTransitionMetrics = { ) => void; }; +export type EpochCacheMetrics = { + finalizedPubkeyDuplicateInsert: Gauge; + newUnFinalizedPubkey: Gauge; +}; + export function onStateCloneMetrics( state: CachedBeaconStateAllForks, metrics: BeaconStateTransitionMetrics, diff --git a/packages/state-transition/src/signatureSets/attesterSlashings.ts b/packages/state-transition/src/signatureSets/attesterSlashings.ts index f0de50e5d0b2..256582afe368 100644 --- a/packages/state-transition/src/signatureSets/attesterSlashings.ts +++ b/packages/state-transition/src/signatureSets/attesterSlashings.ts @@ -27,13 +27,12 @@ export function getIndexedAttestationBigintSignatureSet( state: CachedBeaconStateAllForks, indexedAttestation: phase0.IndexedAttestationBigint ): ISignatureSet { - const {index2pubkey} = state.epochCtx; const slot = computeStartSlotAtEpoch(Number(indexedAttestation.data.target.epoch as bigint)); const domain = state.config.getDomain(state.slot, DOMAIN_BEACON_ATTESTER, slot); return { type: SignatureSetType.aggregate, - pubkeys: indexedAttestation.attestingIndices.map((i) => index2pubkey[i]), + pubkeys: indexedAttestation.attestingIndices.map((i) => state.epochCtx.index2pubkey[i]), signingRoot: computeSigningRoot(ssz.phase0.AttestationDataBigint, indexedAttestation.data, domain), signature: indexedAttestation.signature, }; diff --git a/packages/state-transition/src/slot/index.ts b/packages/state-transition/src/slot/index.ts index 6c4add1d1230..b05bd7ac93f2 100644 --- a/packages/state-transition/src/slot/index.ts +++ b/packages/state-transition/src/slot/index.ts @@ -7,6 +7,7 @@ export {upgradeStateToAltair} from "./upgradeStateToAltair.js"; export {upgradeStateToBellatrix} from "./upgradeStateToBellatrix.js"; export {upgradeStateToCapella} from "./upgradeStateToCapella.js"; export {upgradeStateToDeneb} from "./upgradeStateToDeneb.js"; +export {upgradeStateToElectra} from "./upgradeStateToElectra.js"; /** * Dial state to next slot. Common for all forks diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts new file mode 100644 index 000000000000..19cac8811f77 --- /dev/null +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -0,0 +1,33 @@ +import {ssz} from "@lodestar/types"; +import {UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; +import {CachedBeaconStateDeneb} from "../types.js"; +import {CachedBeaconStateElectra, getCachedBeaconState} from "../cache/stateCache.js"; + +/** + * Upgrade a state from Capella to Deneb. + */ +export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): CachedBeaconStateElectra { + const {config} = stateDeneb; + + const stateElectraNode = ssz.deneb.BeaconState.commitViewDU(stateDeneb); + const stateElectraView = ssz.electra.BeaconState.getViewDU(stateElectraNode); + + const stateElectra = getCachedBeaconState(stateElectraView, stateDeneb); + + stateElectra.fork = ssz.phase0.Fork.toViewDU({ + previousVersion: stateDeneb.fork.currentVersion, + currentVersion: config.ELECTRA_FORK_VERSION, + epoch: stateDeneb.epochCtx.epoch, + }); + + // latestExecutionPayloadHeader's depositReceiptsRoot set to zeros by default + // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX + stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + + // Commit new added fields ViewDU to the root node + stateElectra.commit(); + // Clear cache to ensure the cache of deneb fields is not used by new ELECTRA fields + stateElectra["clearCache"](); + + return stateElectra; +} diff --git a/packages/state-transition/src/stateTransition.ts b/packages/state-transition/src/stateTransition.ts index a454bf4b34d0..5f433918415a 100644 --- a/packages/state-transition/src/stateTransition.ts +++ b/packages/state-transition/src/stateTransition.ts @@ -9,6 +9,7 @@ import { CachedBeaconStateAltair, CachedBeaconStateBellatrix, CachedBeaconStateCapella, + CachedBeaconStateDeneb, } from "./types.js"; import {computeEpochAtSlot} from "./util/index.js"; import {verifyProposerSignature} from "./signatureSets/index.js"; @@ -18,6 +19,7 @@ import { upgradeStateToBellatrix, upgradeStateToCapella, upgradeStateToDeneb, + upgradeStateToElectra, } from "./slot/index.js"; import {processBlock} from "./block/index.js"; import {EpochTransitionStep, processEpoch} from "./epoch/index.js"; @@ -239,6 +241,9 @@ function processSlotsWithTransientCache( if (stateSlot === config.DENEB_FORK_EPOCH) { postState = upgradeStateToDeneb(postState as CachedBeaconStateCapella) as CachedBeaconStateAllForks; } + if (stateSlot === config.ELECTRA_FORK_EPOCH) { + postState = upgradeStateToElectra(postState as CachedBeaconStateDeneb) as CachedBeaconStateAllForks; + } } else { postState.slot++; } diff --git a/packages/state-transition/src/types.ts b/packages/state-transition/src/types.ts index 6b6b1f6260b2..d3a1ed69a7a9 100644 --- a/packages/state-transition/src/types.ts +++ b/packages/state-transition/src/types.ts @@ -9,6 +9,7 @@ export type { CachedBeaconStateBellatrix, CachedBeaconStateCapella, CachedBeaconStateDeneb, + CachedBeaconStateElectra, } from "./cache/stateCache.js"; export type { @@ -19,4 +20,5 @@ export type { BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, + BeaconStateElectra, } from "./cache/types.js"; diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts new file mode 100644 index 000000000000..493099fdd982 --- /dev/null +++ b/packages/state-transition/src/util/deposit.ts @@ -0,0 +1,24 @@ +import {ForkSeq, MAX_DEPOSITS} from "@lodestar/params"; +import {UintNum64, phase0} from "@lodestar/types"; +import {CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; + +export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: phase0.Eth1Data): UintNum64 { + const eth1DataToUse = eth1Data ?? state.eth1Data; + if (state.config.getForkSeq(state.slot) >= ForkSeq.electra) { + const electraState = state as CachedBeaconStateElectra; + // eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64 + // since the result lies within upper and lower bound of UintNum64 + const eth1DataIndexLimit: UintNum64 = + eth1DataToUse.depositCount < electraState.depositReceiptsStartIndex + ? eth1DataToUse.depositCount + : Number(electraState.depositReceiptsStartIndex); + + if (state.eth1DepositIndex < eth1DataIndexLimit) { + return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); + } else { + return 0; + } + } else { + return Math.min(MAX_DEPOSITS, eth1DataToUse.depositCount - state.eth1DepositIndex); + } +} diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index 1c5046354fcb..d9a88e5475b5 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -2,6 +2,7 @@ import { bellatrix, capella, deneb, + electra, isBlindedBeaconBlockBody, ssz, BeaconBlock, @@ -170,5 +171,10 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio ).excessBlobGas; } + if (fork >= ForkSeq.electra) { + (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositReceiptsRoot = + ssz.electra.DepositReceipts.hashTreeRoot((payload as electra.ExecutionPayload).depositReceipts); + } + return bellatrixPayloadFields; } diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 1041c33d0eb3..6c700436d7f6 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -7,6 +7,7 @@ import { GENESIS_EPOCH, GENESIS_SLOT, MAX_EFFECTIVE_BALANCE, + UNSET_DEPOSIT_RECEIPTS_START_INDEX, } from "@lodestar/params"; import {Bytes32, phase0, Root, ssz, TimeSeconds} from "@lodestar/types"; @@ -214,6 +215,7 @@ export function initializeBeaconStateFromEth1( | typeof ssz.bellatrix.ExecutionPayloadHeader | typeof ssz.capella.ExecutionPayloadHeader | typeof ssz.deneb.ExecutionPayloadHeader + | typeof ssz.electra.ExecutionPayloadHeader > ): CachedBeaconStateAllForks { const stateView = getGenesisBeaconState( @@ -284,6 +286,16 @@ export function initializeBeaconStateFromEth1( ssz.deneb.ExecutionPayloadHeader.defaultViewDU(); } + if (GENESIS_SLOT >= config.ELECTRA_FORK_EPOCH) { + const stateElectra = state as CompositeViewDU; + stateElectra.fork.previousVersion = config.ELECTRA_FORK_VERSION; + stateElectra.fork.currentVersion = config.ELECTRA_FORK_VERSION; + stateElectra.latestExecutionPayloadHeader = + (executionPayloadHeader as CompositeViewDU) ?? + ssz.electra.ExecutionPayloadHeader.defaultViewDU(); + stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + } + state.commit(); return state; diff --git a/packages/state-transition/src/util/index.ts b/packages/state-transition/src/util/index.ts index 3f2e91da9a77..ba998f65b254 100644 --- a/packages/state-transition/src/util/index.ts +++ b/packages/state-transition/src/util/index.ts @@ -23,3 +23,4 @@ export * from "./slot.js"; export * from "./syncCommittee.js"; export * from "./validator.js"; export * from "./weakSubjectivity.js"; +export * from "./deposit.js"; diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index 2891cd3e6216..9b05b8947f73 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -1,8 +1,9 @@ +import {fromHexString} from "@chainsafe/ssz"; import {describe, it, expect} from "vitest"; import {Epoch, ssz, RootHex} from "@lodestar/types"; import {toHexString} from "@lodestar/utils"; import {config as defaultConfig} from "@lodestar/config/default"; -import {createBeaconConfig} from "@lodestar/config"; +import {createBeaconConfig, createChainForkConfig} from "@lodestar/config"; import {createCachedBeaconStateTest} from "../utils/state.js"; import {PubkeyIndexMap} from "../../src/cache/pubkeyCache.js"; import {createCachedBeaconState, loadCachedBeaconState} from "../../src/cache/stateCache.js"; @@ -28,6 +29,65 @@ describe("CachedBeaconState", () => { expect(state2.epochCtx.epoch).toBe(0); }); + it("Clone and mutate cache pre-Electra", () => { + const stateView = ssz.altair.BeaconState.defaultViewDU(); + const state1 = createCachedBeaconStateTest(stateView); + + const pubkey1 = fromHexString( + "0x84105a985058fc8740a48bf1ede9d223ef09e8c6b1735ba0a55cf4a9ff2ff92376b778798365e488dab07a652eb04576" + ); + const index1 = 123; + const pubkey2 = fromHexString( + "0xa41726266b1d83ef609d759ba7796d54cfe549154e01e4730a3378309bc81a7638140d7e184b33593c072595f23f032d" + ); + const index2 = 456; + + state1.epochCtx.addPubkey(index1, pubkey1); + + const state2 = state1.clone(); + state2.epochCtx.addPubkey(index2, pubkey2); + + expect(state1.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); + expect(state2.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); + expect(state1.epochCtx.getValidatorIndex(pubkey2)).toBe(index2); + expect(state2.epochCtx.getValidatorIndex(pubkey2)).toBe(index2); + }); + + /* eslint-disable @typescript-eslint/naming-convention */ + it("Clone and mutate cache post-Electra", () => { + const stateView = ssz.electra.BeaconState.defaultViewDU(); + const state1 = createCachedBeaconStateTest( + stateView, + createChainForkConfig({ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: 0, + }), + {skipSyncCommitteeCache: true, skipSyncPubkeys: true} + ); + + const pubkey1 = fromHexString( + "0x84105a985058fc8740a48bf1ede9d223ef09e8c6b1735ba0a55cf4a9ff2ff92376b778798365e488dab07a652eb04576" + ); + const index1 = 123; + const pubkey2 = fromHexString( + "0xa41726266b1d83ef609d759ba7796d54cfe549154e01e4730a3378309bc81a7638140d7e184b33593c072595f23f032d" + ); + const index2 = 456; + + state1.epochCtx.addPubkey(index1, pubkey1); + + const state2 = state1.clone(); + state2.epochCtx.addPubkey(index2, pubkey2); + + expect(state1.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); + expect(state2.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); + expect(state1.epochCtx.getValidatorIndex(pubkey2)).toBe(undefined); + expect(state2.epochCtx.getValidatorIndex(pubkey2)).toBe(index2); + }); + it("Auto-commit on hashTreeRoot", () => { // Use Checkpoint instead of BeaconState to speed up the test const cp1 = ssz.phase0.Checkpoint.defaultViewDU(); diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 75ba415c1bea..df9b052542f9 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -5,6 +5,7 @@ import {createBeaconConfig, ChainForkConfig, createChainForkConfig} from "@lodes import {config as chainConfig} from "@lodestar/config/default"; import {upgradeStateToDeneb} from "../../src/slot/upgradeStateToDeneb.js"; +import {upgradeStateToElectra} from "../../src/slot/upgradeStateToElectra.js"; import {createCachedBeaconState} from "../../src/cache/stateCache.js"; import {PubkeyIndexMap} from "../../src/cache/pubkeyCache.js"; @@ -24,6 +25,21 @@ describe("upgradeState", () => { const newState = upgradeStateToDeneb(stateView); expect(() => newState.toValue()).not.toThrow(); }); + it("upgradeStateToElectra", () => { + const denebState = ssz.deneb.BeaconState.defaultViewDU(); + const config = getConfig(ForkName.deneb); + const stateView = createCachedBeaconState( + denebState, + { + config: createBeaconConfig(config, denebState.genesisValidatorsRoot), + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], + }, + {skipSyncCommitteeCache: true} + ); + const newState = upgradeStateToElectra(stateView); + expect(() => newState.toValue()).not.toThrow(); + }); }); const ZERO_HASH = Buffer.alloc(32, 0); diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts new file mode 100644 index 000000000000..e8f7f7a86af8 --- /dev/null +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -0,0 +1,99 @@ +import {describe, it, expect} from "vitest"; +import {ssz} from "@lodestar/types"; +import {createChainForkConfig} from "@lodestar/config"; +import {MAX_DEPOSITS} from "@lodestar/params"; +import {CachedBeaconStateElectra, getEth1DepositCount} from "../../../src/index.js"; +import {createCachedBeaconStateTest} from "../../utils/state.js"; + +describe("getEth1DepositCount", () => { + it("Pre Electra", () => { + const stateView = ssz.altair.BeaconState.defaultViewDU(); + const preElectraState = createCachedBeaconStateTest(stateView); + + if (preElectraState.epochCtx.isAfterElectra()) { + throw Error("Not a pre-Electra state"); + } + + preElectraState.eth1Data.depositCount = 123; + + // 1. Should get less than MAX_DEPOSIT + preElectraState.eth1DepositIndex = 120; + expect(getEth1DepositCount(preElectraState)).toBe(3); + + // 2. Should get MAX_DEPOSIT + preElectraState.eth1DepositIndex = 100; + expect(getEth1DepositCount(preElectraState)).toBe(MAX_DEPOSITS); + }); + it("Post Electra with eth1 deposit", () => { + const stateView = ssz.electra.BeaconState.defaultViewDU(); + const postElectraState = createCachedBeaconStateTest( + stateView, + createChainForkConfig({ + /* eslint-disable @typescript-eslint/naming-convention */ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: 0, + }), + {skipSyncCommitteeCache: true, skipSyncPubkeys: true} + ) as CachedBeaconStateElectra; + + if (!postElectraState.epochCtx.isAfterElectra()) { + throw Error("Not a post-Electra state"); + } + + postElectraState.depositReceiptsStartIndex = 1000n; + postElectraState.eth1Data.depositCount = 995; + + // 1. Should get less than MAX_DEPOSIT + postElectraState.eth1DepositIndex = 990; + expect(getEth1DepositCount(postElectraState)).toBe(5); + + // 2. Should get MAX_DEPOSIT + postElectraState.eth1DepositIndex = 100; + expect(getEth1DepositCount(postElectraState)).toBe(MAX_DEPOSITS); + + // 3. Should be 0 + postElectraState.eth1DepositIndex = 1000; + expect(getEth1DepositCount(postElectraState)).toBe(0); + }); + it("Post Electra without eth1 deposit", () => { + const stateView = ssz.electra.BeaconState.defaultViewDU(); + const postElectraState = createCachedBeaconStateTest( + stateView, + createChainForkConfig({ + /* eslint-disable @typescript-eslint/naming-convention */ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: 0, + }), + {skipSyncCommitteeCache: true, skipSyncPubkeys: true} + ) as CachedBeaconStateElectra; + + if (!postElectraState.epochCtx.isAfterElectra()) { + throw Error("Not a post-Electra state"); + } + + postElectraState.depositReceiptsStartIndex = 1000n; + postElectraState.eth1Data.depositCount = 1005; + + // Before eth1DepositIndex reaching the start index + // 1. Should get less than MAX_DEPOSIT + postElectraState.eth1DepositIndex = 990; + expect(getEth1DepositCount(postElectraState)).toBe(10); + + // 2. Should get MAX_DEPOSIT + postElectraState.eth1DepositIndex = 983; + expect(getEth1DepositCount(postElectraState)).toBe(MAX_DEPOSITS); + + // After eth1DepositIndex reaching the start index + // 1. Should be 0 + postElectraState.eth1DepositIndex = 1000; + expect(getEth1DepositCount(postElectraState)).toBe(0); + postElectraState.eth1DepositIndex = 1003; + expect(getEth1DepositCount(postElectraState)).toBe(0); + }); +}); diff --git a/packages/types/package.json b/packages/types/package.json index 9a36e311def2..f29229485e99 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -29,6 +29,9 @@ "./deneb": { "import": "./lib/deneb/index.js" }, + "./electra": { + "import": "./lib/electra/index.js" + }, "./phase0": { "import": "./lib/phase0/index.js" } diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 30690a499845..b347b20df9c7 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -1,12 +1,37 @@ -import {ContainerType} from "@chainsafe/ssz"; +import {ContainerType, ListCompositeType, VectorCompositeType} from "@chainsafe/ssz"; +import { + HISTORICAL_ROOTS_LIMIT, + BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, + EPOCHS_PER_SYNC_COMMITTEE_PERIOD, + SLOTS_PER_EPOCH, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, +} from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; +import {ssz as phase0Ssz} from "../phase0/index.js"; +import {ssz as altairSsz} from "../altair/index.js"; +import {ssz as bellatrixSsz} from "../bellatrix/index.js"; +import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; -const {BLSSignature} = primitiveSsz; +const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, DepositIndex, UintBn64} = primitiveSsz; + +export const DepositReceipt = new ContainerType( + { + pubkey: BLSPubkey, + withdrawalCredentials: Bytes32, + amount: UintNum64, + signature: BLSSignature, + index: DepositIndex, + }, + {typeName: "DepositReceipt", jsonCase: "eth2"} +); + +export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); export const ExecutionPayload = new ContainerType( { ...denebSsz.ExecutionPayload.fields, + depositReceipts: DepositReceipts, // New in ELECTRA }, {typeName: "ExecutionPayload", jsonCase: "eth2"} ); @@ -14,13 +39,18 @@ export const ExecutionPayload = new ContainerType( export const ExecutionPayloadHeader = new ContainerType( { ...denebSsz.ExecutionPayloadHeader.fields, + depositReceiptsRoot: Root, // New in ELECTRA }, {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} ); +// We have to preserve Fields ordering while changing the type of ExecutionPayload export const BeaconBlockBody = new ContainerType( { - ...denebSsz.BeaconBlockBody.fields, + ...altairSsz.BeaconBlockBody.fields, + executionPayload: ExecutionPayload, // Modified in ELECTRA + blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, + blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, }, {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); @@ -28,28 +58,25 @@ export const BeaconBlockBody = new ContainerType( export const BeaconBlock = new ContainerType( { ...denebSsz.BeaconBlock.fields, + body: BeaconBlockBody, // Modified in ELECTRA }, {typeName: "BeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} ); export const SignedBeaconBlock = new ContainerType( { - message: BeaconBlock, + message: BeaconBlock, // Modified in ELECTRA signature: BLSSignature, }, {typeName: "SignedBeaconBlock", jsonCase: "eth2"} ); -export const BlobSidecar = new ContainerType( - { - ...denebSsz.BlobSidecar.fields, - }, - {typeName: "BlobSidecar", jsonCase: "eth2"} -); - export const BlindedBeaconBlockBody = new ContainerType( { - ...denebSsz.BlindedBeaconBlockBody.fields, + ...altairSsz.BeaconBlockBody.fields, + executionPayloadHeader: ExecutionPayloadHeader, // Modified in ELECTRA + blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, + blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, }, {typeName: "BlindedBeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); @@ -57,13 +84,14 @@ export const BlindedBeaconBlockBody = new ContainerType( export const BlindedBeaconBlock = new ContainerType( { ...denebSsz.BlindedBeaconBlock.fields, + body: BlindedBeaconBlockBody, // Modified in ELECTRA }, {typeName: "BlindedBeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} ); export const SignedBlindedBeaconBlock = new ContainerType( { - message: BlindedBeaconBlock, + message: BlindedBeaconBlock, // Modified in ELECTRA signature: BLSSignature, }, {typeName: "SignedBlindedBeaconBlock", jsonCase: "eth2"} @@ -71,7 +99,10 @@ export const SignedBlindedBeaconBlock = new ContainerType( export const BuilderBid = new ContainerType( { - ...denebSsz.BuilderBid.fields, + header: ExecutionPayloadHeader, // Modified in ELECTRA + blindedBlobsBundle: denebSsz.BlobKzgCommitments, + value: UintBn256, + pubkey: BLSPubkey, }, {typeName: "BuilderBid", jsonCase: "eth2"} ); @@ -86,63 +117,133 @@ export const SignedBuilderBid = new ContainerType( export const ExecutionPayloadAndBlobsBundle = new ContainerType( { - ...denebSsz.ExecutionPayloadAndBlobsBundle.fields, + executionPayload: ExecutionPayload, // Modified in ELECTRA + blobsBundle: denebSsz.BlobsBundle, }, {typeName: "ExecutionPayloadAndBlobsBundle", jsonCase: "eth2"} ); +// We don't spread deneb.BeaconState fields since we need to replace +// latestExecutionPayloadHeader and we cannot keep order doing that export const BeaconState = new ContainerType( { - ...denebSsz.BeaconState.fields, + genesisTime: UintNum64, + genesisValidatorsRoot: Root, + slot: primitiveSsz.Slot, + fork: phase0Ssz.Fork, + // History + latestBlockHeader: phase0Ssz.BeaconBlockHeader, + blockRoots: phase0Ssz.HistoricalBlockRoots, + stateRoots: phase0Ssz.HistoricalStateRoots, + // historical_roots Frozen in Capella, replaced by historical_summaries + historicalRoots: new ListCompositeType(Root, HISTORICAL_ROOTS_LIMIT), + // Eth1 + eth1Data: phase0Ssz.Eth1Data, + eth1DataVotes: phase0Ssz.Eth1DataVotes, + eth1DepositIndex: UintNum64, + // Registry + validators: phase0Ssz.Validators, + balances: phase0Ssz.Balances, + randaoMixes: phase0Ssz.RandaoMixes, + // Slashings + slashings: phase0Ssz.Slashings, + // Participation + previousEpochParticipation: altairSsz.EpochParticipation, + currentEpochParticipation: altairSsz.EpochParticipation, + // Finality + justificationBits: phase0Ssz.JustificationBits, + previousJustifiedCheckpoint: phase0Ssz.Checkpoint, + currentJustifiedCheckpoint: phase0Ssz.Checkpoint, + finalizedCheckpoint: phase0Ssz.Checkpoint, + // Inactivity + inactivityScores: altairSsz.InactivityScores, + // Sync + currentSyncCommittee: altairSsz.SyncCommittee, + nextSyncCommittee: altairSsz.SyncCommittee, + // Execution + latestExecutionPayloadHeader: ExecutionPayloadHeader, // Modified in ELECTRA + // Withdrawals + nextWithdrawalIndex: capellaSsz.BeaconState.fields.nextWithdrawalIndex, + nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex, + // Deep history valid from Capella onwards + historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, + depositReceiptsStartIndex: UintBn64, // New in ELECTRA }, {typeName: "BeaconState", jsonCase: "eth2"} ); export const LightClientHeader = new ContainerType( { - ...denebSsz.LightClientHeader.fields, + beacon: phase0Ssz.BeaconBlockHeader, + execution: ExecutionPayloadHeader, // Modified in ELECTRA + executionBranch: new VectorCompositeType(Bytes32, EXECUTION_PAYLOAD_DEPTH), }, {typeName: "LightClientHeader", jsonCase: "eth2"} ); export const LightClientBootstrap = new ContainerType( { - ...denebSsz.LightClientBootstrap.fields, + header: LightClientHeader, + currentSyncCommittee: altairSsz.SyncCommittee, + currentSyncCommitteeBranch: altairSsz.LightClientBootstrap.fields.currentSyncCommitteeBranch, }, {typeName: "LightClientBootstrap", jsonCase: "eth2"} ); export const LightClientUpdate = new ContainerType( { - ...denebSsz.LightClientUpdate.fields, + attestedHeader: LightClientHeader, + nextSyncCommittee: altairSsz.SyncCommittee, + nextSyncCommitteeBranch: altairSsz.LightClientUpdate.fields.nextSyncCommitteeBranch, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, }, {typeName: "LightClientUpdate", jsonCase: "eth2"} ); export const LightClientFinalityUpdate = new ContainerType( { - ...denebSsz.LightClientFinalityUpdate.fields, + attestedHeader: LightClientHeader, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientFinalityUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, }, {typeName: "LightClientFinalityUpdate", jsonCase: "eth2"} ); export const LightClientOptimisticUpdate = new ContainerType( { - ...denebSsz.LightClientOptimisticUpdate.fields, + attestedHeader: LightClientHeader, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, }, {typeName: "LightClientOptimisticUpdate", jsonCase: "eth2"} ); export const LightClientStore = new ContainerType( { - ...denebSsz.LightClientStore.fields, + snapshot: LightClientBootstrap, + validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), }, {typeName: "LightClientStore", jsonCase: "eth2"} ); +// PayloadAttributes primarily for SSE event +export const PayloadAttributes = new ContainerType( + { + ...capellaSsz.PayloadAttributes.fields, + parentBeaconBlockRoot: Root, + }, + {typeName: "PayloadAttributes", jsonCase: "eth2"} +); + export const SSEPayloadAttributes = new ContainerType( { - ...denebSsz.SSEPayloadAttributes.fields, + ...bellatrixSsz.SSEPayloadAttributesCommon.fields, + payloadAttributes: PayloadAttributes, }, {typeName: "SSEPayloadAttributes", jsonCase: "eth2"} ); diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index 198259eed1dd..3286c10a0334 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -1,12 +1,14 @@ import {ValueOf} from "@chainsafe/ssz"; import * as ssz from "./sszTypes.js"; -export type BlobSidecar = ValueOf; -export type ExecutionPayloadAndBlobsBundle = ValueOf; +export type DepositReceipt = ValueOf; +export type DepositReceipts = ValueOf; export type ExecutionPayload = ValueOf; export type ExecutionPayloadHeader = ValueOf; +export type ExecutionPayloadAndBlobsBundle = ValueOf; + export type BeaconBlockBody = ValueOf; export type BeaconBlock = ValueOf; export type SignedBeaconBlock = ValueOf; @@ -17,6 +19,8 @@ export type BlindedBeaconBlockBody = ValueOf; export type BlindedBeaconBlock = ValueOf; export type SignedBlindedBeaconBlock = ValueOf; +export type FullOrBlindedExecutionPayload = ExecutionPayload | ExecutionPayloadHeader; + export type BuilderBid = ValueOf; export type SignedBuilderBid = ValueOf; export type SSEPayloadAttributes = ValueOf; diff --git a/packages/types/src/primitive/sszTypes.ts b/packages/types/src/primitive/sszTypes.ts index 068a32e2cc17..376e17c3f1b6 100644 --- a/packages/types/src/primitive/sszTypes.ts +++ b/packages/types/src/primitive/sszTypes.ts @@ -50,6 +50,7 @@ export const SubcommitteeIndex = UintNum64; */ export const ValidatorIndex = UintNum64; export const WithdrawalIndex = UintNum64; +export const DepositIndex = UintNum64; export const Gwei = UintBn64; export const Wei = UintBn256; export const Root = new ByteVectorType(32); diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 0afede39b951..298707c07303 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -106,7 +106,6 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Fri, 12 Apr 2024 23:38:07 +0800 Subject: [PATCH 012/259] chore: fix CI failure due to recent merge from `unstable` (#6646) --- .../beacon-node/src/execution/engine/http.ts | 16 ++++++++-------- .../updateUnfinalizedPubkeys.test.ts | 6 +++--- .../test/sim/electra-interop.test.ts | 18 +++++++++--------- .../test/spec/utils/specTestIterator.ts | 1 + .../state-transition/src/cache/epochCache.ts | 2 +- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index d29387794327..ac3402852c35 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -201,10 +201,10 @@ export class ExecutionEngineHttp implements IExecutionEngine { ForkSeq[fork] >= ForkSeq.electra ? "engine_newPayloadV6110" : ForkSeq[fork] >= ForkSeq.deneb - ? "engine_newPayloadV3" - : ForkSeq[fork] >= ForkSeq.capella - ? "engine_newPayloadV2" - : "engine_newPayloadV1"; + ? "engine_newPayloadV3" + : ForkSeq[fork] >= ForkSeq.capella + ? "engine_newPayloadV2" + : "engine_newPayloadV1"; const serializedExecutionPayload = serializeExecutionPayload(fork, executionPayload); @@ -397,10 +397,10 @@ export class ExecutionEngineHttp implements IExecutionEngine { ForkSeq[fork] >= ForkSeq.electra ? "engine_getPayloadV6110" : ForkSeq[fork] >= ForkSeq.deneb - ? "engine_getPayloadV3" - : ForkSeq[fork] >= ForkSeq.capella - ? "engine_getPayloadV2" - : "engine_getPayloadV1"; + ? "engine_getPayloadV3" + : ForkSeq[fork] >= ForkSeq.capella + ? "engine_getPayloadV2" + : "engine_getPayloadV1"; const payloadResponse = await this.rpc.fetchWithRetries< EngineApiRpcReturnTypes[typeof method], EngineApiRpcParamTypes[typeof method] diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 900f6a6fb873..39bf1a1551c9 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -7,7 +7,7 @@ import bls from "@chainsafe/bls"; import {ssz} from "@lodestar/types"; import {type CachedBeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; import {bytesToBigInt, intToBytes} from "@lodestar/utils"; -import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; +import {InMemoryCheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; import {generateCachedElectraState} from "../../../utils/state.js"; // Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz @@ -21,7 +21,7 @@ describe("updateUnfinalizedPubkeys perf tests", function () { const numCheckpointStateCache = 8; const numStateCache = 3 * 32; - let checkpointStateCache: CheckpointStateCache; + let checkpointStateCache: InMemoryCheckpointStateCache; let stateCache: StateContextCache; const unfinalizedPubkey2Index = generatePubkey2Index(0, Math.max.apply(null, numPubkeysToBeFinalizedCases)); @@ -35,7 +35,7 @@ describe("updateUnfinalizedPubkeys perf tests", function () { baseState.epochCtx.pubkey2index = new PubkeyIndexMap(); baseState.epochCtx.index2pubkey = []; - checkpointStateCache = new CheckpointStateCache({}); + checkpointStateCache = new InMemoryCheckpointStateCache({}); stateCache = new StateContextCache({}); for (let i = 0; i < numCheckpointStateCache; i++) { diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index c1663211cbd9..428bba3c63ad 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; +import assert from "node:assert"; import {describe, it, vi, afterAll, afterEach} from "vitest"; -/* eslint-disable @typescript-eslint/naming-convention */ -import _ from "lodash"; + import {LogLevel, sleep} from "@lodestar/utils"; import {ForkName, SLOTS_PER_EPOCH, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; import {electra, Epoch, Slot} from "@lodestar/types"; @@ -225,13 +225,13 @@ describe("executionEngine / ExecutionEngineHttp", function () { } const actualDepositReceipt = payload.depositReceipts[0]; - if (!_.isEqual(actualDepositReceipt, depositReceiptB)) { - throw Error( - `Deposit receipts mismatched. Expected: ${JSON.stringify(depositReceiptB)}, actual: ${JSON.stringify( - actualDepositReceipt - )}` - ); - } + assert.deepStrictEqual( + actualDepositReceipt, + depositReceiptB, + `Deposit receipts mismatched. Expected: ${JSON.stringify(depositReceiptB)}, actual: ${JSON.stringify( + actualDepositReceipt + )}` + ); }); it("Post-merge, run for a few blocks", async function () { diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index 3201fb15dbf3..6aa683cb6530 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -57,6 +57,7 @@ const coveredTestRunners = [ // ], // ``` export const defaultSkipOpts: SkipOpts = { + skippedForks: ["eip6110"], // TODO: capella // BeaconBlockBody proof in lightclient is the new addition in v1.3.0-rc.2-hotfix // Skip them for now to enable subsequently diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 41f8031d903e..a7433e848a44 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -225,7 +225,7 @@ export class EpochCache { * eg. latest epoch = 105, latest finalized cp state epoch = 102 * then the list will be (in terms of epoch) [103, 104, 105] */ - private historicalValidatorLengths: immutable.List; + historicalValidatorLengths: immutable.List; constructor(data: { config: BeaconConfig; From 4b707a9c8bdb8fc8827275a624bf4f9a62d20081 Mon Sep 17 00:00:00 2001 From: g11tech Date: Mon, 22 Apr 2024 19:18:35 +0530 Subject: [PATCH 013/259] feat: implement execution layer exits eip 7002 (#6651) * feat: implement execution layer exits eip 7002 * lint and tsc fix * apply feedback * improve comment --- .../src/execution/engine/payloadIdCache.ts | 5 ++ .../beacon-node/src/execution/engine/types.ts | 48 +++++++++++----- .../opPools/aggregatedAttestationPool.test.ts | 2 +- .../test/perf/chain/opPools/opPool.test.ts | 2 +- .../produceBlock/produceBlockBody.test.ts | 2 +- .../test/sim/electra-interop.test.ts | 1 + .../opPools/aggregatedAttestationPool.test.ts | 4 +- .../test/unit/chain/shufflingCache.test.ts | 6 +- .../test/unit/executionEngine/http.test.ts | 4 ++ .../test/utils/validationData/attestation.ts | 4 +- packages/light-client/src/spec/utils.ts | 7 ++- packages/params/src/index.ts | 1 + packages/params/src/presets/mainnet.ts | 1 + packages/params/src/presets/minimal.ts | 1 + packages/params/src/types.ts | 2 + .../src/block/processExecutionLayerExit.ts | 56 +++++++++++++++++++ .../src/block/processOperations.ts | 8 +++ .../src/slot/upgradeStateToElectra.ts | 2 +- .../state-transition/src/util/execution.ts | 3 + packages/types/src/electra/sszTypes.ts | 15 ++++- packages/types/src/electra/types.ts | 3 + packages/validator/src/util/params.ts | 1 + 22 files changed, 152 insertions(+), 26 deletions(-) create mode 100644 packages/state-transition/src/block/processExecutionLayerExit.ts diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index e5baa9fba92d..960b061f12da 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -26,6 +26,11 @@ export type DepositReceiptV1 = { index: QUANTITY; }; +export type ExecutionLayerExitV1 = { + sourceAddress: DATA; + validatorPubkey: DATA; +}; + type FcuAttributes = {headBlockHash: DATA; finalizedBlockHash: DATA} & Omit; export class PayloadIdCache { diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 999c77f86b9c..f12f98e1a0f7 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -17,7 +17,7 @@ import { quantityToBigint, } from "../../eth1/provider/utils.js"; import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js"; -import {WithdrawalV1, DepositReceiptV1} from "./payloadIdCache.js"; +import {WithdrawalV1, DepositReceiptV1, ExecutionLayerExitV1} from "./payloadIdCache.js"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -126,12 +126,14 @@ export type ExecutionPayloadBodyRpc = { transactions: DATA[]; withdrawals: WithdrawalV1[] | null | undefined; depositReceipts: DepositReceiptV1[] | null | undefined; + exits: ExecutionLayerExitV1[] | null | undefined; }; export type ExecutionPayloadBody = { transactions: bellatrix.Transaction[]; withdrawals: capella.Withdrawals | null; depositReceipts: electra.DepositReceipts | null; + exits: electra.ExecutionLayerExits | null; }; export type ExecutionPayloadRpc = { @@ -154,6 +156,7 @@ export type ExecutionPayloadRpc = { excessBlobGas?: QUANTITY; // DENEB parentBeaconBlockRoot?: QUANTITY; // DENEB depositReceipts?: DepositReceiptRpc[]; // ELECTRA + exits?: ExecutionLayerExitRpc[]; // ELECTRA }; export type WithdrawalRpc = { @@ -163,13 +166,8 @@ export type WithdrawalRpc = { amount: QUANTITY; }; -export type DepositReceiptRpc = { - pubkey: DATA; - withdrawalCredentials: DATA; - amount: QUANTITY; - signature: DATA; - index: QUANTITY; -}; +export type DepositReceiptRpc = DepositReceiptV1; +export type ExecutionLayerExitRpc = ExecutionLayerExitV1; export type VersionedHashesRpc = DATA[]; @@ -235,8 +233,9 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload // ELECTRA adds depositReceipts to the ExecutionPayload if (ForkSeq[fork] >= ForkSeq.electra) { - const {depositReceipts} = data as electra.ExecutionPayload; + const {depositReceipts, exits} = data as electra.ExecutionPayload; payload.depositReceipts = depositReceipts.map(serializeDepositReceipt); + payload.exits = exits.map(serializeExecutionLayerExit); } return payload; @@ -325,14 +324,21 @@ export function parseExecutionPayload( } if (ForkSeq[fork] >= ForkSeq.electra) { - const {depositReceipts} = data; + const {depositReceipts, exits} = data; // Geth can also reply with null if (depositReceipts == null) { throw Error( `depositReceipts missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` ); } - (executionPayload as electra.ExecutionPayload).depositReceipts = depositReceipts.map(deserializeDepositReceipts); + (executionPayload as electra.ExecutionPayload).depositReceipts = depositReceipts.map(deserializeDepositReceipt); + + if (exits == null) { + throw Error( + `exits missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` + ); + } + (executionPayload as electra.ExecutionPayload).exits = exits.map(deserializeExecutionLayerExit); } return {executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder}; @@ -411,7 +417,7 @@ export function serializeDepositReceipt(depositReceipt: electra.DepositReceipt): }; } -export function deserializeDepositReceipts(serialized: DepositReceiptRpc): electra.DepositReceipt { +export function deserializeDepositReceipt(serialized: DepositReceiptRpc): electra.DepositReceipt { return { pubkey: dataToBytes(serialized.pubkey, 48), withdrawalCredentials: dataToBytes(serialized.withdrawalCredentials, 32), @@ -421,12 +427,27 @@ export function deserializeDepositReceipts(serialized: DepositReceiptRpc): elect } as electra.DepositReceipt; } +export function serializeExecutionLayerExit(exit: electra.ExecutionLayerExit): ExecutionLayerExitRpc { + return { + sourceAddress: bytesToData(exit.sourceAddress), + validatorPubkey: bytesToData(exit.validatorPubkey), + }; +} + +export function deserializeExecutionLayerExit(exit: ExecutionLayerExitRpc): electra.ExecutionLayerExit { + return { + sourceAddress: dataToBytes(exit.sourceAddress, 20), + validatorPubkey: dataToBytes(exit.validatorPubkey, 48), + }; +} + export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | null): ExecutionPayloadBody | null { return data ? { transactions: data.transactions.map((tran) => dataToBytes(tran, null)), withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null, - depositReceipts: data.depositReceipts ? data.depositReceipts.map(deserializeDepositReceipts) : null, + depositReceipts: data.depositReceipts ? data.depositReceipts.map(deserializeDepositReceipt) : null, + exits: data.exits ? data.exits.map(deserializeExecutionLayerExit) : null, } : null; } @@ -437,6 +458,7 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null) transactions: data.transactions.map((tran) => bytesToData(tran)), withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null, depositReceipts: data.depositReceipts ? data.depositReceipts.map(serializeDepositReceipt) : null, + exits: data.exits ? data.exits.map(serializeExecutionLayerExit) : null, } : null; } diff --git a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts index 7a882b03af0e..ee14eb27b51d 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -32,7 +32,7 @@ describe(`getAttestationsForBlock vc=${vc}`, () => { before(function () { this.timeout(5 * 60 * 1000); // Generating the states for the first time is very slow - originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true, vc}) as unknown as CachedBeaconStateAltair; + originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true, vc}) as CachedBeaconStateAltair; const {blockHeader, checkpoint} = computeAnchorCheckpoint(originalState.config, originalState); // TODO figure out why getBlockRootAtSlot(originalState, justifiedSlot) is not the same to justifiedCheckpoint.root diff --git a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts index 7998a204f09d..2632c593e78c 100644 --- a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts @@ -24,7 +24,7 @@ describe("opPool", () => { before(function () { this.timeout(2 * 60 * 1000); // Generating the states for the first time is very slow - originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true}) as unknown as CachedBeaconStateAltair; + originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true}) as CachedBeaconStateAltair; }); itBench({ diff --git a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts index 2386f3538205..f90f148f3e01 100644 --- a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts +++ b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts @@ -25,7 +25,7 @@ describe("produceBlockBody", () => { before(async () => { db = new BeaconDb(config, await LevelDbController.create({name: ".tmpdb"}, {logger})); - state = stateOg.clone() as unknown as CachedBeaconStateAltair; + state = stateOg.clone() as CachedBeaconStateAltair; chain = new BeaconChain( { proposerBoost: true, diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index 428bba3c63ad..ab3f1ae6b2c1 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -173,6 +173,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { blockHash: dataToBytes(newPayloadBlockHash, 32), receiptsRoot: dataToBytes("0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9", 32), blobGasUsed: 0n, + exits: [], }; const parentBeaconBlockRoot = dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32); const payloadResult = await executionEngine.notifyNewPayload( diff --git a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts index 41c205cdd0e9..800984fa84bc 100644 --- a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts @@ -61,9 +61,9 @@ describe("AggregatedAttestationPool", function () { epochParticipation[committee[i]] = 0b000; } } - (originalState as unknown as CachedBeaconStateAltair).previousEpochParticipation = + (originalState as CachedBeaconStateAltair).previousEpochParticipation = ssz.altair.EpochParticipation.toViewDU(epochParticipation); - (originalState as unknown as CachedBeaconStateAltair).currentEpochParticipation = + (originalState as CachedBeaconStateAltair).currentEpochParticipation = ssz.altair.EpochParticipation.toViewDU(epochParticipation); originalState.commit(); let altairState: CachedBeaconStateAllForks; diff --git a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts index e6a7e8706bbe..035746438563 100644 --- a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts +++ b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts @@ -14,7 +14,7 @@ describe("ShufflingCache", function () { beforeEach(() => { shufflingCache = new ShufflingCache(null, {maxShufflingCacheEpochs: 1}); - shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, currentEpoch); + shufflingCache.processState(state as CachedBeaconStateAllForks, currentEpoch); }); it("should get shuffling from cache", async function () { @@ -29,7 +29,7 @@ describe("ShufflingCache", function () { shufflingCache.insertPromise(currentEpoch, "0x00"); expect(await shufflingCache.get(currentEpoch, decisionRoot)).toEqual(state.epochCtx.currentShuffling); // insert shufflings at other epochs does prune the cache - shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, currentEpoch + 1); + shufflingCache.processState(state as CachedBeaconStateAllForks, currentEpoch + 1); // the current shuffling is not available anymore expect(await shufflingCache.get(currentEpoch, decisionRoot)).toBeNull(); }); @@ -39,7 +39,7 @@ describe("ShufflingCache", function () { shufflingCache.insertPromise(currentEpoch + 1, nextDecisionRoot); const shufflingRequest0 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); const shufflingRequest1 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); - shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, currentEpoch + 1); + shufflingCache.processState(state as CachedBeaconStateAllForks, currentEpoch + 1); expect(await shufflingRequest0).toEqual(state.epochCtx.nextShuffling); expect(await shufflingRequest1).toEqual(state.epochCtx.nextShuffling); }); diff --git a/packages/beacon-node/test/unit/executionEngine/http.test.ts b/packages/beacon-node/test/unit/executionEngine/http.test.ts index b0e20ad1f2b5..d58eefa10368 100644 --- a/packages/beacon-node/test/unit/executionEngine/http.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/http.test.ts @@ -194,6 +194,7 @@ describe("ExecutionEngine / http", () => { }, ], depositReceipts: null, // depositReceipts is null pre-electra + exits: null, }, null, // null returned for missing blocks { @@ -203,6 +204,7 @@ describe("ExecutionEngine / http", () => { ], withdrawals: null, // withdrawals is null pre-capella depositReceipts: null, // depositReceipts is null pre-electra + exits: null, }, ], }; @@ -251,6 +253,7 @@ describe("ExecutionEngine / http", () => { }, ], depositReceipts: null, // depositReceipts is null pre-electra + exits: null, }, null, // null returned for missing blocks { @@ -260,6 +263,7 @@ describe("ExecutionEngine / http", () => { ], withdrawals: null, // withdrawals is null pre-capella depositReceipts: null, // depositReceipts is null pre-electra + exits: null, }, ], }; diff --git a/packages/beacon-node/test/utils/validationData/attestation.ts b/packages/beacon-node/test/utils/validationData/attestation.ts index 335ec81870c6..82bdca901889 100644 --- a/packages/beacon-node/test/utils/validationData/attestation.ts +++ b/packages/beacon-node/test/utils/validationData/attestation.ts @@ -83,8 +83,8 @@ export function getAttestationValidData(opts: AttestationValidDataOpts): { }; const shufflingCache = new ShufflingCache(); - shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, state.epochCtx.currentShuffling.epoch); - shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, state.epochCtx.nextShuffling.epoch); + shufflingCache.processState(state as CachedBeaconStateAllForks, state.epochCtx.currentShuffling.epoch); + shufflingCache.processState(state as CachedBeaconStateAllForks, state.epochCtx.nextShuffling.epoch); const dependentRoot = getShufflingDecisionBlock(state, state.epochCtx.currentShuffling.epoch); const forkChoice = { diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 152c55ac6d15..8e6b3456a600 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -117,6 +117,8 @@ export function upgradeLightClientHeader( case ForkName.electra: (upgradedHeader as LightClientHeader).execution.depositReceiptsRoot = ssz.electra.LightClientHeader.fields.execution.fields.depositReceiptsRoot.defaultValue(); + (upgradedHeader as electra.LightClientHeader).execution.exitsRoot = + ssz.electra.LightClientHeader.fields.execution.fields.exitsRoot.defaultValue(); // Break if no further upgrades is required else fall through if (ForkSeq[targetFork] <= ForkSeq.electra) break; @@ -154,7 +156,10 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: LightC } if (epoch < config.ELECTRA_FORK_EPOCH) { - if ((header as LightClientHeader).execution.depositReceiptsRoot !== undefined) { + if ( + (header as LightClientHeader).execution.depositReceiptsRoot !== undefined || + (header as LightClientHeader).execution.exitsRoot !== undefined + ) { return false; } } diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 482e591123b6..d903a404dfb5 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -95,6 +95,7 @@ export const { KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_EXECUTION_LAYER_EXITS, } = activePreset; //////////// diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 86f5c39c539e..802a6691c311 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -121,4 +121,5 @@ export const mainnetPreset: BeaconPreset = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192, + MAX_EXECUTION_LAYER_EXITS: 16, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 6239a8c1a3eb..d10b420ed97c 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -122,4 +122,5 @@ export const minimalPreset: BeaconPreset = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 4, + MAX_EXECUTION_LAYER_EXITS: 16, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index 57ee8230a77d..7856f1be72ba 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -85,6 +85,7 @@ export type BeaconPreset = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: number; + MAX_EXECUTION_LAYER_EXITS: number; }; /** @@ -173,6 +174,7 @@ export const beaconPresetTypes: BeaconPresetTypes = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: "number", + MAX_EXECUTION_LAYER_EXITS: "number", }; type BeaconPresetTypes = { diff --git a/packages/state-transition/src/block/processExecutionLayerExit.ts b/packages/state-transition/src/block/processExecutionLayerExit.ts new file mode 100644 index 000000000000..5068d9af8667 --- /dev/null +++ b/packages/state-transition/src/block/processExecutionLayerExit.ts @@ -0,0 +1,56 @@ +import {CompositeViewDU} from "@chainsafe/ssz"; +import {electra, ssz} from "@lodestar/types"; +import {ETH1_ADDRESS_WITHDRAWAL_PREFIX, FAR_FUTURE_EPOCH} from "@lodestar/params"; + +import {isActiveValidator} from "../util/index.js"; +import {CachedBeaconStateElectra} from "../types.js"; +import {initiateValidatorExit} from "./index.js"; + +/** + * Process execution layer exit messages and initiate exit incase they belong to a valid active validator + * otherwise silent ignore. + */ +export function processExecutionLayerExit(state: CachedBeaconStateElectra, exit: electra.ExecutionLayerExit): void { + const validator = isValidExecutionLayerExit(state, exit); + if (validator === null) { + return; + } + + initiateValidatorExit(state, validator); +} + +export function isValidExecutionLayerExit( + state: CachedBeaconStateElectra, + exit: electra.ExecutionLayerExit +): CompositeViewDU | null { + const {config, epochCtx} = state; + const validatorIndex = epochCtx.getValidatorIndex(exit.validatorPubkey); + const validator = validatorIndex !== undefined ? state.validators.getReadonly(validatorIndex) : undefined; + if (validator === undefined) { + return null; + } + + const {withdrawalCredentials} = validator; + if (withdrawalCredentials[0] !== ETH1_ADDRESS_WITHDRAWAL_PREFIX) { + return null; + } + + const executionAddress = withdrawalCredentials.subarray(12, 32); + if (Buffer.compare(executionAddress, exit.sourceAddress) !== 0) { + return null; + } + + const currentEpoch = epochCtx.epoch; + if ( + // verify the validator is active + isActiveValidator(validator, currentEpoch) && + // verify exit has not been initiated + validator.exitEpoch === FAR_FUTURE_EPOCH && + // verify the validator had been active long enough + currentEpoch >= validator.activationEpoch + config.SHARD_COMMITTEE_PERIOD + ) { + return validator; + } else { + return null; + } +} diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index 7b8b39efe743..c4879da4aa71 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -8,6 +8,7 @@ import {processProposerSlashing} from "./processProposerSlashing.js"; import {processAttesterSlashing} from "./processAttesterSlashing.js"; import {processDeposit} from "./processDeposit.js"; import {processVoluntaryExit} from "./processVoluntaryExit.js"; +import {processExecutionLayerExit} from "./processExecutionLayerExit.js"; import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js"; import {processDepositReceipt} from "./processDepositReceipt.js"; import {ProcessBlockOpts} from "./types.js"; @@ -18,6 +19,7 @@ export { processAttestations, processDeposit, processVoluntaryExit, + processExecutionLayerExit, processBlsToExecutionChange, processDepositReceipt, }; @@ -48,9 +50,15 @@ export function processOperations( for (const deposit of body.deposits) { processDeposit(fork, state, deposit); } + for (const voluntaryExit of body.voluntaryExits) { processVoluntaryExit(state, voluntaryExit, opts.verifySignatures); } + if (fork >= ForkSeq.electra) { + for (const elExit of (body as electra.BeaconBlockBody).executionPayload.exits) { + processExecutionLayerExit(state as CachedBeaconStateElectra, elExit); + } + } if (fork >= ForkSeq.capella) { for (const blsToExecutionChange of (body as capella.BeaconBlockBody).blsToExecutionChanges) { diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 19cac8811f77..369ab19c447b 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -20,7 +20,7 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache epoch: stateDeneb.epochCtx.epoch, }); - // latestExecutionPayloadHeader's depositReceiptsRoot set to zeros by default + // latestExecutionPayloadHeader's depositReceiptsRoot and exitsRoot set to zeros by default // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index d9a88e5475b5..2975b84bf747 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -174,6 +174,9 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio if (fork >= ForkSeq.electra) { (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositReceiptsRoot = ssz.electra.DepositReceipts.hashTreeRoot((payload as electra.ExecutionPayload).depositReceipts); + (bellatrixPayloadFields as electra.ExecutionPayloadHeader).exitsRoot = ssz.electra.ExecutionLayerExits.hashTreeRoot( + (payload as electra.ExecutionPayload).exits + ); } return bellatrixPayloadFields; diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index b347b20df9c7..7b5ed51fb786 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -5,6 +5,7 @@ import { EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_EXECUTION_LAYER_EXITS, } from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; @@ -13,7 +14,8 @@ import {ssz as bellatrixSsz} from "../bellatrix/index.js"; import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; -const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, DepositIndex, UintBn64} = primitiveSsz; +const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, DepositIndex, UintBn64, ExecutionAddress} = + primitiveSsz; export const DepositReceipt = new ContainerType( { @@ -28,10 +30,20 @@ export const DepositReceipt = new ContainerType( export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); +export const ExecutionLayerExit = new ContainerType( + { + sourceAddress: ExecutionAddress, + validatorPubkey: BLSPubkey, + }, + {typeName: "ExecutionLayerExit", jsonCase: "eth2"} +); +export const ExecutionLayerExits = new ListCompositeType(ExecutionLayerExit, MAX_EXECUTION_LAYER_EXITS); + export const ExecutionPayload = new ContainerType( { ...denebSsz.ExecutionPayload.fields, depositReceipts: DepositReceipts, // New in ELECTRA + exits: ExecutionLayerExits, // New in ELECTRA }, {typeName: "ExecutionPayload", jsonCase: "eth2"} ); @@ -40,6 +52,7 @@ export const ExecutionPayloadHeader = new ContainerType( { ...denebSsz.ExecutionPayloadHeader.fields, depositReceiptsRoot: Root, // New in ELECTRA + exitsRoot: Root, // New in ELECTRA }, {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} ); diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index 3286c10a0334..1b9b42217b8c 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -4,6 +4,9 @@ import * as ssz from "./sszTypes.js"; export type DepositReceipt = ValueOf; export type DepositReceipts = ValueOf; +export type ExecutionLayerExit = ValueOf; +export type ExecutionLayerExits = ValueOf; + export type ExecutionPayload = ValueOf; export type ExecutionPayloadHeader = ValueOf; diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 298707c07303..ca1b36883a90 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -224,5 +224,6 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Wed, 1 May 2024 21:46:27 +0800 Subject: [PATCH 014/259] chore: update spec test version for electra fork (#6717) * Update spec-test version * Skip electra --- packages/beacon-node/test/spec/specTestVersioning.ts | 2 +- packages/beacon-node/test/spec/utils/specTestIterator.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/beacon-node/test/spec/specTestVersioning.ts b/packages/beacon-node/test/spec/specTestVersioning.ts index 37167c9bd5a1..06b02ab5304e 100644 --- a/packages/beacon-node/test/spec/specTestVersioning.ts +++ b/packages/beacon-node/test/spec/specTestVersioning.ts @@ -15,7 +15,7 @@ import {DownloadTestsOptions} from "@lodestar/spec-test-util/downloadTests"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const ethereumConsensusSpecsTests: DownloadTestsOptions = { - specVersion: "v1.4.0-beta.6", + specVersion: "v1.5.0-alpha.1", // Target directory is the host package root: 'packages/*/spec-tests' outputDir: path.join(__dirname, "../../spec-tests"), specTestsRepoUrl: "https://github.com/ethereum/consensus-spec-tests", diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index 6aa683cb6530..88d7cbdea9e6 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -57,7 +57,7 @@ const coveredTestRunners = [ // ], // ``` export const defaultSkipOpts: SkipOpts = { - skippedForks: ["eip6110"], + skippedForks: ["electra", "eip7594"], // TODO: capella // BeaconBlockBody proof in lightclient is the new addition in v1.3.0-rc.2-hotfix // Skip them for now to enable subsequently @@ -65,7 +65,7 @@ export const defaultSkipOpts: SkipOpts = { "capella/light_client/single_merkle_proof/BeaconBlockBody", "deneb/light_client/single_merkle_proof/BeaconBlockBody", ], - skippedRunners: ["merkle_proof"], + skippedRunners: ["merkle_proof", "networking"], }; /** From bef3eff3acdbb812e8fb7bbb91295c9fff1c9faa Mon Sep 17 00:00:00 2001 From: NC Date: Sat, 4 May 2024 21:24:26 +0800 Subject: [PATCH 015/259] feat: add presets and ssz types for EIP-7549 (#6715) * Add types * Update unit test * lint * Address comments * Address comments * Lint * Update packages/beacon-node/src/util/sszBytes.ts Co-authored-by: tuyennhv * Add isElectraAttestation * Update unit test * Update unit test * chore: add comments for sszBytes.ts --------- Co-authored-by: tuyennhv Co-authored-by: Tuyen Nguyen Co-authored-by: Gajinder --- .../src/chain/validation/attestation.ts | 4 +- packages/beacon-node/src/util/sszBytes.ts | 63 +++++++--- .../test/unit/util/sszBytes.test.ts | 46 +++++-- packages/params/src/index.ts | 2 + packages/params/src/presets/mainnet.ts | 2 + packages/params/src/presets/minimal.ts | 2 + packages/params/src/types.ts | 4 + packages/types/src/electra/sszTypes.ts | 113 +++++++++++++++++- packages/types/src/electra/types.ts | 8 ++ packages/types/src/sszTypes.ts | 2 +- packages/types/src/types.ts | 8 ++ packages/types/src/utils/typeguards.ts | 9 +- packages/validator/src/util/params.ts | 2 + 13 files changed, 233 insertions(+), 32 deletions(-) diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index 1116e87e1d25..a66b95b782e4 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -305,7 +305,7 @@ async function validateGossipAttestationNoSignatureCheck( // > TODO: Do this check **before** getting the target state but don't recompute zipIndexes const aggregationBits = attestationOrCache.attestation ? attestationOrCache.attestation.aggregationBits - : getAggregationBitsFromAttestationSerialized(attestationOrCache.serializedData); + : getAggregationBitsFromAttestationSerialized(fork, attestationOrCache.serializedData); if (aggregationBits === null) { throw new AttestationError(GossipAction.REJECT, { code: AttestationErrorCode.INVALID_SERIALIZED_BYTES, @@ -414,7 +414,7 @@ async function validateGossipAttestationNoSignatureCheck( let attDataRootHex: RootHex; const signature = attestationOrCache.attestation ? attestationOrCache.attestation.signature - : getSignatureFromAttestationSerialized(attestationOrCache.serializedData); + : getSignatureFromAttestationSerialized(fork, attestationOrCache.serializedData); if (signature === null) { throw new AttestationError(GossipAction.REJECT, { code: AttestationErrorCode.INVALID_SERIALIZED_BYTES, diff --git a/packages/beacon-node/src/util/sszBytes.ts b/packages/beacon-node/src/util/sszBytes.ts index ce4125140075..3ba2691be357 100644 --- a/packages/beacon-node/src/util/sszBytes.ts +++ b/packages/beacon-node/src/util/sszBytes.ts @@ -1,15 +1,30 @@ import {BitArray, deserializeUint8ArrayBitListFromBytes} from "@chainsafe/ssz"; import {BLSSignature, RootHex, Slot} from "@lodestar/types"; -import {BYTES_PER_FIELD_ELEMENT, FIELD_ELEMENTS_PER_BLOB} from "@lodestar/params"; +import { + BYTES_PER_FIELD_ELEMENT, + FIELD_ELEMENTS_PER_BLOB, + ForkName, + ForkSeq, + MAX_COMMITTEES_PER_SLOT, +} from "@lodestar/params"; export type BlockRootHex = RootHex; export type AttDataBase64 = string; +// pre-electra // class Attestation(Container): // aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE] - offset 4 // data: AttestationData - target data - 128 // signature: BLSSignature - 96 + +// electra +// class Attestation(Container): +// aggregation_bits: BitList[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] - offset 4 +// data: AttestationData - target data - 128 +// committee_bits: BitVector[MAX_COMMITTEES_PER_SLOT] +// signature: BLSSignature - 96 // +// for all forks // class AttestationData(Container): 128 bytes fixed size // slot: Slot - data 8 // index: CommitteeIndex - data 8 @@ -22,6 +37,7 @@ const ATTESTATION_BEACON_BLOCK_ROOT_OFFSET = VARIABLE_FIELD_OFFSET + 8 + 8; const ROOT_SIZE = 32; const SLOT_SIZE = 8; const ATTESTATION_DATA_SIZE = 128; +const COMMITTEE_BITS_SIZE = Math.max(Math.ceil(MAX_COMMITTEES_PER_SLOT / 8), 1); const SIGNATURE_SIZE = 96; // shared Buffers to convert bytes to hex/base64 @@ -73,16 +89,17 @@ export function getAttDataBase64FromAttestationSerialized(data: Uint8Array): Att * Extract aggregation bits from attestation serialized bytes. * Return null if data is not long enough to extract aggregation bits. */ -export function getAggregationBitsFromAttestationSerialized(data: Uint8Array): BitArray | null { - if (data.length < VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + SIGNATURE_SIZE) { +export function getAggregationBitsFromAttestationSerialized(fork: ForkName, data: Uint8Array): BitArray | null { + const aggregationBitsStartIndex = + ForkSeq[fork] >= ForkSeq.electra + ? VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + COMMITTEE_BITS_SIZE + SIGNATURE_SIZE + : VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + SIGNATURE_SIZE; + + if (data.length < aggregationBitsStartIndex) { return null; } - const {uint8Array, bitLen} = deserializeUint8ArrayBitListFromBytes( - data, - VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + SIGNATURE_SIZE, - data.length - ); + const {uint8Array, bitLen} = deserializeUint8ArrayBitListFromBytes(data, aggregationBitsStartIndex, data.length); return new BitArray(uint8Array, bitLen); } @@ -90,15 +107,33 @@ export function getAggregationBitsFromAttestationSerialized(data: Uint8Array): B * Extract signature from attestation serialized bytes. * Return null if data is not long enough to extract signature. */ -export function getSignatureFromAttestationSerialized(data: Uint8Array): BLSSignature | null { - if (data.length < VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + SIGNATURE_SIZE) { +export function getSignatureFromAttestationSerialized(fork: ForkName, data: Uint8Array): BLSSignature | null { + const signatureStartIndex = + ForkSeq[fork] >= ForkSeq.electra + ? VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + COMMITTEE_BITS_SIZE + : VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE; + + if (data.length < signatureStartIndex + SIGNATURE_SIZE) { return null; } - return data.subarray( - VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE, - VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + SIGNATURE_SIZE - ); + return data.subarray(signatureStartIndex, signatureStartIndex + SIGNATURE_SIZE); +} + +/** + * Extract committee bits from Electra attestation serialized bytes. + * Return null if data is not long enough to extract committee bits. + */ +export function getCommitteeBitsFromAttestationSerialized(data: Uint8Array): BitArray | null { + const committeeBitsStartIndex = VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE; + + if (data.length < committeeBitsStartIndex + COMMITTEE_BITS_SIZE) { + return null; + } + + const uint8Array = data.subarray(committeeBitsStartIndex, committeeBitsStartIndex + COMMITTEE_BITS_SIZE); + + return new BitArray(uint8Array, MAX_COMMITTEES_PER_SLOT); } // diff --git a/packages/beacon-node/test/unit/util/sszBytes.test.ts b/packages/beacon-node/test/unit/util/sszBytes.test.ts index 4285f4ca88b5..dd1b5aa747bf 100644 --- a/packages/beacon-node/test/unit/util/sszBytes.test.ts +++ b/packages/beacon-node/test/unit/util/sszBytes.test.ts @@ -1,6 +1,8 @@ import {describe, it, expect} from "vitest"; -import {deneb, Epoch, phase0, RootHex, Slot, ssz} from "@lodestar/types"; +import {BitArray} from "@chainsafe/ssz"; +import {allForks, deneb, Epoch, isElectraAttestation, phase0, RootHex, Slot, ssz} from "@lodestar/types"; import {fromHex, toHex} from "@lodestar/utils"; +import {ForkName, MAX_COMMITTEES_PER_SLOT} from "@lodestar/params"; import { getAttDataBase64FromAttestationSerialized, getAttDataBase64FromSignedAggregateAndProofSerialized, @@ -12,10 +14,11 @@ import { getSignatureFromAttestationSerialized, getSlotFromSignedBeaconBlockSerialized, getSlotFromBlobSidecarSerialized, + getCommitteeBitsFromAttestationSerialized, } from "../../../src/util/sszBytes.js"; describe("attestation SSZ serialized picking", () => { - const testCases: phase0.Attestation[] = [ + const testCases: allForks.Attestation[] = [ ssz.phase0.Attestation.defaultValue(), attestationFromValues( 4_000_000, @@ -23,18 +26,40 @@ describe("attestation SSZ serialized picking", () => { 200_00, "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffffffffff" ), + ssz.electra.Attestation.defaultValue(), + { + ...attestationFromValues( + 4_000_000, + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + 200_00, + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffffffffff" + ), + committeeBits: BitArray.fromSingleBit(MAX_COMMITTEES_PER_SLOT, 3), + }, ]; for (const [i, attestation] of testCases.entries()) { it(`attestation ${i}`, () => { - const bytes = ssz.phase0.Attestation.serialize(attestation); + const isElectra = isElectraAttestation(attestation); + const bytes = isElectra + ? ssz.electra.Attestation.serialize(attestation) + : ssz.phase0.Attestation.serialize(attestation); expect(getSlotFromAttestationSerialized(bytes)).toBe(attestation.data.slot); expect(getBlockRootFromAttestationSerialized(bytes)).toBe(toHex(attestation.data.beaconBlockRoot)); - expect(getAggregationBitsFromAttestationSerialized(bytes)?.toBoolArray()).toEqual( - attestation.aggregationBits.toBoolArray() - ); - expect(getSignatureFromAttestationSerialized(bytes)).toEqual(attestation.signature); + + if (isElectra) { + expect(getAggregationBitsFromAttestationSerialized(ForkName.electra, bytes)?.toBoolArray()).toEqual( + attestation.aggregationBits.toBoolArray() + ); + expect(getCommitteeBitsFromAttestationSerialized(bytes)).toEqual(attestation.committeeBits); + expect(getSignatureFromAttestationSerialized(ForkName.electra, bytes)).toEqual(attestation.signature); + } else { + expect(getAggregationBitsFromAttestationSerialized(ForkName.phase0, bytes)?.toBoolArray()).toEqual( + attestation.aggregationBits.toBoolArray() + ); + expect(getSignatureFromAttestationSerialized(ForkName.phase0, bytes)).toEqual(attestation.signature); + } const attDataBase64 = ssz.phase0.AttestationData.serialize(attestation.data); expect(getAttDataBase64FromAttestationSerialized(bytes)).toBe(Buffer.from(attDataBase64).toString("base64")); @@ -65,14 +90,16 @@ describe("attestation SSZ serialized picking", () => { it("getAggregateionBitsFromAttestationSerialized - invalid data", () => { const invalidAggregationBitsDataSizes = [0, 4, 100, 128, 227]; for (const size of invalidAggregationBitsDataSizes) { - expect(getAggregationBitsFromAttestationSerialized(Buffer.alloc(size))).toBeNull(); + expect(getAggregationBitsFromAttestationSerialized(ForkName.phase0, Buffer.alloc(size))).toBeNull(); + expect(getAggregationBitsFromAttestationSerialized(ForkName.electra, Buffer.alloc(size))).toBeNull(); } }); it("getSignatureFromAttestationSerialized - invalid data", () => { const invalidSignatureDataSizes = [0, 4, 100, 128, 227]; for (const size of invalidSignatureDataSizes) { - expect(getSignatureFromAttestationSerialized(Buffer.alloc(size))).toBeNull(); + expect(getSignatureFromAttestationSerialized(ForkName.phase0, Buffer.alloc(size))).toBeNull(); + expect(getSignatureFromAttestationSerialized(ForkName.electra, Buffer.alloc(size))).toBeNull(); } }); }); @@ -86,6 +113,7 @@ describe("aggregateAndProof SSZ serialized picking", () => { 200_00, "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffffffffff" ), + ssz.electra.SignedAggregateAndProof.defaultValue(), ]; for (const [i, signedAggregateAndProof] of testCases.entries()) { diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index d903a404dfb5..3e56effc4138 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -96,6 +96,8 @@ export const { MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, MAX_EXECUTION_LAYER_EXITS, + MAX_ATTESTER_SLASHINGS_ELECTRA, + MAX_ATTESTATIONS_ELECTRA, } = activePreset; //////////// diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 802a6691c311..27cb7640b2dd 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -122,4 +122,6 @@ export const mainnetPreset: BeaconPreset = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192, MAX_EXECUTION_LAYER_EXITS: 16, + MAX_ATTESTER_SLASHINGS_ELECTRA: 1, + MAX_ATTESTATIONS_ELECTRA: 8, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index d10b420ed97c..022532a49e6f 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -123,4 +123,6 @@ export const minimalPreset: BeaconPreset = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 4, MAX_EXECUTION_LAYER_EXITS: 16, + MAX_ATTESTER_SLASHINGS_ELECTRA: 1, + MAX_ATTESTATIONS_ELECTRA: 8, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index 7856f1be72ba..34f40a66707e 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -86,6 +86,8 @@ export type BeaconPreset = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: number; MAX_EXECUTION_LAYER_EXITS: number; + MAX_ATTESTER_SLASHINGS_ELECTRA: number; + MAX_ATTESTATIONS_ELECTRA: number; }; /** @@ -175,6 +177,8 @@ export const beaconPresetTypes: BeaconPresetTypes = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: "number", MAX_EXECUTION_LAYER_EXITS: "number", + MAX_ATTESTER_SLASHINGS_ELECTRA: "number", + MAX_ATTESTATIONS_ELECTRA: "number", }; type BeaconPresetTypes = { diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 7b5ed51fb786..3404baf04110 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -1,10 +1,21 @@ -import {ContainerType, ListCompositeType, VectorCompositeType} from "@chainsafe/ssz"; +import { + BitListType, + BitVectorType, + ContainerType, + ListBasicType, + ListCompositeType, + VectorCompositeType, +} from "@chainsafe/ssz"; import { HISTORICAL_ROOTS_LIMIT, BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_COMMITTEES_PER_SLOT, + MAX_ATTESTATIONS_ELECTRA, + MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_EXECUTION_LAYER_EXITS, } from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; @@ -14,8 +25,84 @@ import {ssz as bellatrixSsz} from "../bellatrix/index.js"; import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; -const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, DepositIndex, UintBn64, ExecutionAddress} = - primitiveSsz; +const { + UintNum64, + Slot, + Root, + BLSSignature, + UintBn256, + Bytes32, + BLSPubkey, + DepositIndex, + UintBn64, + ExecutionAddress, + ValidatorIndex, +} = primitiveSsz; + +export const AggregationBits = new BitListType(MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT); + +// This CommitteeBits serves a different purpose than CommitteeBits in phase0 +// TODO Electra: Rename phase0.CommitteeBits to ParticipationBits to avoid confusion +export const CommitteeBits = new BitVectorType(MAX_COMMITTEES_PER_SLOT); + +export const AttestingIndices = new ListBasicType( + ValidatorIndex, + MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT +); + +export const Attestation = new ContainerType( + { + aggregationBits: AggregationBits, // Modified in ELECTRA + data: phase0Ssz.AttestationData, + committeeBits: CommitteeBits, // New in ELECTRA + signature: BLSSignature, + }, + {typeName: "Attestation", jsonCase: "eth2"} +); + +export const IndexedAttestation = new ContainerType( + { + attestingIndices: AttestingIndices, // Modified in ELECTRA + data: phase0Ssz.AttestationData, + signature: BLSSignature, + }, + {typeName: "IndexedAttestation", jsonCase: "eth2"} +); + +/** Same as `IndexedAttestation` but epoch, slot and index are not bounded and must be a bigint */ +export const IndexedAttestationBigint = new ContainerType( + { + attestingIndices: AttestingIndices, // Modified in ELECTRA + data: phase0Ssz.AttestationDataBigint, + signature: BLSSignature, + }, + {typeName: "IndexedAttestation", jsonCase: "eth2"} +); + +export const AttesterSlashing = new ContainerType( + { + attestation1: IndexedAttestationBigint, // Modified in ELECTRA + attestation2: IndexedAttestationBigint, // Modified in ELECTRA + }, + {typeName: "AttesterSlashing", jsonCase: "eth2"} +); + +export const AggregateAndProof = new ContainerType( + { + aggregatorIndex: ValidatorIndex, + aggregate: Attestation, // Modified in ELECTRA + selectionProof: BLSSignature, + }, + {typeName: "AggregateAndProof", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const SignedAggregateAndProof = new ContainerType( + { + message: AggregateAndProof, // Modified in ELECTRA + signature: BLSSignature, + }, + {typeName: "SignedAggregateAndProof", jsonCase: "eth2"} +); export const DepositReceipt = new ContainerType( { @@ -60,7 +147,15 @@ export const ExecutionPayloadHeader = new ContainerType( // We have to preserve Fields ordering while changing the type of ExecutionPayload export const BeaconBlockBody = new ContainerType( { - ...altairSsz.BeaconBlockBody.fields, + randaoReveal: phase0Ssz.BeaconBlockBody.fields.randaoReveal, + eth1Data: phase0Ssz.BeaconBlockBody.fields.eth1Data, + graffiti: phase0Ssz.BeaconBlockBody.fields.graffiti, + proposerSlashings: phase0Ssz.BeaconBlockBody.fields.proposerSlashings, + attesterSlashings: new ListCompositeType(AttesterSlashing, MAX_ATTESTER_SLASHINGS_ELECTRA), // Modified in ELECTRA + attestations: new ListCompositeType(Attestation, MAX_ATTESTATIONS_ELECTRA), // Modified in ELECTRA + deposits: phase0Ssz.BeaconBlockBody.fields.deposits, + voluntaryExits: phase0Ssz.BeaconBlockBody.fields.voluntaryExits, + syncAggregate: altairSsz.BeaconBlockBody.fields.syncAggregate, executionPayload: ExecutionPayload, // Modified in ELECTRA blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, @@ -86,7 +181,15 @@ export const SignedBeaconBlock = new ContainerType( export const BlindedBeaconBlockBody = new ContainerType( { - ...altairSsz.BeaconBlockBody.fields, + randaoReveal: phase0Ssz.BeaconBlockBody.fields.randaoReveal, + eth1Data: phase0Ssz.BeaconBlockBody.fields.eth1Data, + graffiti: phase0Ssz.BeaconBlockBody.fields.graffiti, + proposerSlashings: phase0Ssz.BeaconBlockBody.fields.proposerSlashings, + attesterSlashings: new ListCompositeType(AttesterSlashing, MAX_ATTESTER_SLASHINGS_ELECTRA), // Modified in ELECTRA + attestations: new ListCompositeType(Attestation, MAX_ATTESTATIONS_ELECTRA), // Modified in ELECTRA + deposits: phase0Ssz.BeaconBlockBody.fields.deposits, + voluntaryExits: phase0Ssz.BeaconBlockBody.fields.voluntaryExits, + syncAggregate: altairSsz.SyncAggregate, executionPayloadHeader: ExecutionPayloadHeader, // Modified in ELECTRA blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index 1b9b42217b8c..2925885b3af3 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -1,6 +1,14 @@ import {ValueOf} from "@chainsafe/ssz"; import * as ssz from "./sszTypes.js"; +export type Attestation = ValueOf; +export type IndexedAttestation = ValueOf; +export type IndexedAttestationBigint = ValueOf; +export type AttesterSlashing = ValueOf; + +export type AggregateAndProof = ValueOf; +export type SignedAggregateAndProof = ValueOf; + export type DepositReceipt = ValueOf; export type DepositReceipts = ValueOf; diff --git a/packages/types/src/sszTypes.ts b/packages/types/src/sszTypes.ts index c2044edb5e98..4399904a94bc 100644 --- a/packages/types/src/sszTypes.ts +++ b/packages/types/src/sszTypes.ts @@ -20,7 +20,7 @@ const typesByFork = { [ForkName.bellatrix]: {...phase0, ...altair, ...bellatrix}, [ForkName.capella]: {...phase0, ...altair, ...bellatrix, ...capella}, [ForkName.deneb]: {...phase0, ...altair, ...bellatrix, ...capella, ...deneb}, - [ForkName.deneb]: {...phase0, ...altair, ...bellatrix, ...capella, ...deneb, ...electra}, + [ForkName.electra]: {...phase0, ...altair, ...bellatrix, ...capella, ...deneb, ...electra}, }; /** diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index c0cc6591dd56..73cb84f5eab6 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -36,6 +36,7 @@ type TypesByFork = { BeaconState: phase0.BeaconState; SignedBeaconBlock: phase0.SignedBeaconBlock; Metadata: phase0.Metadata; + Attestation: phase0.Attestation; }; [ForkName.altair]: { BeaconBlockHeader: phase0.BeaconBlockHeader; @@ -53,6 +54,7 @@ type TypesByFork = { LightClientStore: altair.LightClientStore; SyncCommittee: altair.SyncCommittee; SyncAggregate: altair.SyncAggregate; + Attestation: phase0.Attestation; }; [ForkName.bellatrix]: { BeaconBlockHeader: phase0.BeaconBlockHeader; @@ -78,6 +80,7 @@ type TypesByFork = { SSEPayloadAttributes: bellatrix.SSEPayloadAttributes; SyncCommittee: altair.SyncCommittee; SyncAggregate: altair.SyncAggregate; + Attestation: phase0.Attestation; }; [ForkName.capella]: { BeaconBlockHeader: phase0.BeaconBlockHeader; @@ -103,6 +106,7 @@ type TypesByFork = { SSEPayloadAttributes: capella.SSEPayloadAttributes; SyncCommittee: altair.SyncCommittee; SyncAggregate: altair.SyncAggregate; + Attestation: phase0.Attestation; }; [ForkName.deneb]: { BeaconBlockHeader: phase0.BeaconBlockHeader; @@ -133,6 +137,7 @@ type TypesByFork = { Contents: deneb.Contents; SyncCommittee: altair.SyncCommittee; SyncAggregate: altair.SyncAggregate; + Attestation: phase0.Attestation; }; [ForkName.electra]: { BeaconBlockHeader: phase0.BeaconBlockHeader; @@ -167,6 +172,7 @@ type TypesByFork = { Contents: deneb.Contents; SyncCommittee: altair.SyncCommittee; SyncAggregate: altair.SyncAggregate; + Attestation: electra.Attestation; }; }; @@ -225,3 +231,5 @@ export type Metadata = TypesByFork[F]["Metadata"]; export type BuilderBid = TypesByFork[F]["BuilderBid"]; export type SignedBuilderBid = TypesByFork[F]["SignedBuilderBid"]; export type SSEPayloadAttributes = TypesByFork[F]["SSEPayloadAttributes"]; + +export type Attestation = TypesByFork[F]["Attestation"]; diff --git a/packages/types/src/utils/typeguards.ts b/packages/types/src/utils/typeguards.ts index f006227e03c9..a41b45eec546 100644 --- a/packages/types/src/utils/typeguards.ts +++ b/packages/types/src/utils/typeguards.ts @@ -1,4 +1,4 @@ -import {ForkBlobs, ForkExecution} from "@lodestar/params"; +import {ForkBlobs, ForkExecution, ForkName} from "@lodestar/params"; import { BlockContents, SignedBeaconBlock, @@ -13,6 +13,7 @@ import { BlindedBeaconBlockBody, SignedBlockContents, BeaconBlock, + Attestation, } from "../types.js"; export function isExecutionPayload( @@ -66,3 +67,9 @@ export function isSignedBlockContents( ): data is SignedBlockContents { return (data as SignedBlockContents).kzgProofs !== undefined; } + +export function isElectraAttestation( + attestation: Attestation +): attestation is Attestation { + return (attestation as Attestation).committeeBits !== undefined; +} diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index ca1b36883a90..1eda005b70c3 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -225,5 +225,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Sun, 5 May 2024 00:17:57 +0530 Subject: [PATCH 016/259] chore: fix the rebase build (#6735) * chore: fix the rebase build * fix test --- packages/beacon-node/src/chain/regen/queued.ts | 2 +- .../perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index 84907ea163af..57e64bd364ea 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -212,7 +212,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { */ updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { let numStatesUpdated = 0; - const states = this.stateCache.getStates(); + const states = this.blockStateCache.getStates(); const cpStates = this.checkpointStateCache.getStates(); // Add finalized pubkeys to all states. diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 39bf1a1551c9..b8f5c30a70ea 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -7,7 +7,8 @@ import bls from "@chainsafe/bls"; import {ssz} from "@lodestar/types"; import {type CachedBeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; import {bytesToBigInt, intToBytes} from "@lodestar/utils"; -import {InMemoryCheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; +import {InMemoryCheckpointStateCache, BlockStateCacheImpl} from "../../../../src/chain/stateCache/index.js"; +import {BlockStateCache} from "../../../../src/chain/stateCache/types.js"; import {generateCachedElectraState} from "../../../utils/state.js"; // Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz @@ -22,7 +23,7 @@ describe("updateUnfinalizedPubkeys perf tests", function () { const numStateCache = 3 * 32; let checkpointStateCache: InMemoryCheckpointStateCache; - let stateCache: StateContextCache; + let stateCache: BlockStateCache; const unfinalizedPubkey2Index = generatePubkey2Index(0, Math.max.apply(null, numPubkeysToBeFinalizedCases)); const baseState = generateCachedElectraState(); @@ -36,7 +37,7 @@ describe("updateUnfinalizedPubkeys perf tests", function () { baseState.epochCtx.index2pubkey = []; checkpointStateCache = new InMemoryCheckpointStateCache({}); - stateCache = new StateContextCache({}); + stateCache = new BlockStateCacheImpl({}); for (let i = 0; i < numCheckpointStateCache; i++) { const clonedState = baseState.clone(); From 8db4adaecb852cde7bb5d7c04492167e9b092483 Mon Sep 17 00:00:00 2001 From: g11tech Date: Mon, 6 May 2024 00:08:09 +0530 Subject: [PATCH 017/259] feat: upgrade 7002 exits to withdrawal request (#6736) * feat: upgrade 7002 exits to withdrawal request * fix types * fix types and references * further fix the types references and get build passing * update the process ops fn but needs to be extended by maxeb --- .../src/execution/engine/payloadIdCache.ts | 3 +- .../beacon-node/src/execution/engine/types.ts | 50 ++++++++++++------- packages/light-client/src/spec/utils.ts | 6 +-- packages/params/src/index.ts | 2 +- packages/params/src/presets/mainnet.ts | 2 +- packages/params/src/presets/minimal.ts | 2 +- packages/params/src/types.ts | 4 +- ...processExecutionLayerWithdrawalRequest.ts} | 25 +++++++--- .../src/block/processOperations.ts | 8 +-- .../src/slot/upgradeStateToElectra.ts | 2 +- .../state-transition/src/util/execution.ts | 7 +-- packages/types/src/electra/sszTypes.ts | 16 +++--- packages/types/src/electra/types.ts | 4 +- packages/validator/src/util/params.ts | 2 +- 14 files changed, 81 insertions(+), 52 deletions(-) rename packages/state-transition/src/block/{processExecutionLayerExit.ts => processExecutionLayerWithdrawalRequest.ts} (71%) diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index 960b061f12da..b5fe3d33e267 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -26,9 +26,10 @@ export type DepositReceiptV1 = { index: QUANTITY; }; -export type ExecutionLayerExitV1 = { +export type ExecutionLayerWithdrawalRequestV1 = { sourceAddress: DATA; validatorPubkey: DATA; + amount: QUANTITY; }; type FcuAttributes = {headBlockHash: DATA; finalizedBlockHash: DATA} & Omit; diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index f12f98e1a0f7..54b3a415ec98 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -17,7 +17,7 @@ import { quantityToBigint, } from "../../eth1/provider/utils.js"; import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js"; -import {WithdrawalV1, DepositReceiptV1, ExecutionLayerExitV1} from "./payloadIdCache.js"; +import {WithdrawalV1, DepositReceiptV1, ExecutionLayerWithdrawalRequestV1} from "./payloadIdCache.js"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -126,14 +126,14 @@ export type ExecutionPayloadBodyRpc = { transactions: DATA[]; withdrawals: WithdrawalV1[] | null | undefined; depositReceipts: DepositReceiptV1[] | null | undefined; - exits: ExecutionLayerExitV1[] | null | undefined; + withdrawalRequests: ExecutionLayerWithdrawalRequestV1[] | null | undefined; }; export type ExecutionPayloadBody = { transactions: bellatrix.Transaction[]; withdrawals: capella.Withdrawals | null; depositReceipts: electra.DepositReceipts | null; - exits: electra.ExecutionLayerExits | null; + withdrawalRequests: electra.ExecutionLayerWithdrawalRequests | null; }; export type ExecutionPayloadRpc = { @@ -156,7 +156,7 @@ export type ExecutionPayloadRpc = { excessBlobGas?: QUANTITY; // DENEB parentBeaconBlockRoot?: QUANTITY; // DENEB depositReceipts?: DepositReceiptRpc[]; // ELECTRA - exits?: ExecutionLayerExitRpc[]; // ELECTRA + withdrawalRequests?: ExecutionLayerWithdrawalRequestRpc[]; // ELECTRA }; export type WithdrawalRpc = { @@ -167,7 +167,7 @@ export type WithdrawalRpc = { }; export type DepositReceiptRpc = DepositReceiptV1; -export type ExecutionLayerExitRpc = ExecutionLayerExitV1; +export type ExecutionLayerWithdrawalRequestRpc = ExecutionLayerWithdrawalRequestV1; export type VersionedHashesRpc = DATA[]; @@ -233,9 +233,9 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload // ELECTRA adds depositReceipts to the ExecutionPayload if (ForkSeq[fork] >= ForkSeq.electra) { - const {depositReceipts, exits} = data as electra.ExecutionPayload; + const {depositReceipts, withdrawalRequests} = data as electra.ExecutionPayload; payload.depositReceipts = depositReceipts.map(serializeDepositReceipt); - payload.exits = exits.map(serializeExecutionLayerExit); + payload.withdrawalRequests = withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest); } return payload; @@ -324,7 +324,7 @@ export function parseExecutionPayload( } if (ForkSeq[fork] >= ForkSeq.electra) { - const {depositReceipts, exits} = data; + const {depositReceipts, withdrawalRequests} = data; // Geth can also reply with null if (depositReceipts == null) { throw Error( @@ -333,12 +333,14 @@ export function parseExecutionPayload( } (executionPayload as electra.ExecutionPayload).depositReceipts = depositReceipts.map(deserializeDepositReceipt); - if (exits == null) { + if (withdrawalRequests == null) { throw Error( - `exits missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` + `withdrawalRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` ); } - (executionPayload as electra.ExecutionPayload).exits = exits.map(deserializeExecutionLayerExit); + (executionPayload as electra.ExecutionPayload).withdrawalRequests = withdrawalRequests.map( + deserializeExecutionLayerWithdrawalRequest + ); } return {executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder}; @@ -427,17 +429,23 @@ export function deserializeDepositReceipt(serialized: DepositReceiptRpc): electr } as electra.DepositReceipt; } -export function serializeExecutionLayerExit(exit: electra.ExecutionLayerExit): ExecutionLayerExitRpc { +export function serializeExecutionLayerWithdrawalRequest( + withdrawalRequest: electra.ExecutionLayerWithdrawalRequest +): ExecutionLayerWithdrawalRequestRpc { return { - sourceAddress: bytesToData(exit.sourceAddress), - validatorPubkey: bytesToData(exit.validatorPubkey), + sourceAddress: bytesToData(withdrawalRequest.sourceAddress), + validatorPubkey: bytesToData(withdrawalRequest.validatorPubkey), + amount: numToQuantity(withdrawalRequest.amount), }; } -export function deserializeExecutionLayerExit(exit: ExecutionLayerExitRpc): electra.ExecutionLayerExit { +export function deserializeExecutionLayerWithdrawalRequest( + withdrawalRequest: ExecutionLayerWithdrawalRequestRpc +): electra.ExecutionLayerWithdrawalRequest { return { - sourceAddress: dataToBytes(exit.sourceAddress, 20), - validatorPubkey: dataToBytes(exit.validatorPubkey, 48), + sourceAddress: dataToBytes(withdrawalRequest.sourceAddress, 20), + validatorPubkey: dataToBytes(withdrawalRequest.validatorPubkey, 48), + amount: quantityToNum(withdrawalRequest.amount), }; } @@ -447,7 +455,9 @@ export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | transactions: data.transactions.map((tran) => dataToBytes(tran, null)), withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null, depositReceipts: data.depositReceipts ? data.depositReceipts.map(deserializeDepositReceipt) : null, - exits: data.exits ? data.exits.map(deserializeExecutionLayerExit) : null, + withdrawalRequests: data.withdrawalRequests + ? data.withdrawalRequests.map(deserializeExecutionLayerWithdrawalRequest) + : null, } : null; } @@ -458,7 +468,9 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null) transactions: data.transactions.map((tran) => bytesToData(tran)), withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null, depositReceipts: data.depositReceipts ? data.depositReceipts.map(serializeDepositReceipt) : null, - exits: data.exits ? data.exits.map(serializeExecutionLayerExit) : null, + withdrawalRequests: data.withdrawalRequests + ? data.withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest) + : null, } : null; } diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 8e6b3456a600..1b460dd39cf2 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -117,8 +117,8 @@ export function upgradeLightClientHeader( case ForkName.electra: (upgradedHeader as LightClientHeader).execution.depositReceiptsRoot = ssz.electra.LightClientHeader.fields.execution.fields.depositReceiptsRoot.defaultValue(); - (upgradedHeader as electra.LightClientHeader).execution.exitsRoot = - ssz.electra.LightClientHeader.fields.execution.fields.exitsRoot.defaultValue(); + (upgradedHeader as electra.LightClientHeader).execution.withdrawalRequestsRoot = + ssz.electra.LightClientHeader.fields.execution.fields.withdrawalRequestsRoot.defaultValue(); // Break if no further upgrades is required else fall through if (ForkSeq[targetFork] <= ForkSeq.electra) break; @@ -158,7 +158,7 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: LightC if (epoch < config.ELECTRA_FORK_EPOCH) { if ( (header as LightClientHeader).execution.depositReceiptsRoot !== undefined || - (header as LightClientHeader).execution.exitsRoot !== undefined + (header as LightClientHeader).execution.withdrawalRequestsRoot !== undefined ) { return false; } diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 3e56effc4138..b261e07959d0 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -95,7 +95,7 @@ export const { KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, - MAX_EXECUTION_LAYER_EXITS, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_ATTESTATIONS_ELECTRA, } = activePreset; diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 27cb7640b2dd..5343966a43f4 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -121,7 +121,7 @@ export const mainnetPreset: BeaconPreset = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192, - MAX_EXECUTION_LAYER_EXITS: 16, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 16, MAX_ATTESTER_SLASHINGS_ELECTRA: 1, MAX_ATTESTATIONS_ELECTRA: 8, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 022532a49e6f..e4938d501a51 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -122,7 +122,7 @@ export const minimalPreset: BeaconPreset = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 4, - MAX_EXECUTION_LAYER_EXITS: 16, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 16, MAX_ATTESTER_SLASHINGS_ELECTRA: 1, MAX_ATTESTATIONS_ELECTRA: 8, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index 34f40a66707e..e5b85a9e2224 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -85,7 +85,7 @@ export type BeaconPreset = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: number; - MAX_EXECUTION_LAYER_EXITS: number; + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: number; MAX_ATTESTER_SLASHINGS_ELECTRA: number; MAX_ATTESTATIONS_ELECTRA: number; }; @@ -176,7 +176,7 @@ export const beaconPresetTypes: BeaconPresetTypes = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: "number", - MAX_EXECUTION_LAYER_EXITS: "number", + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: "number", MAX_ATTESTER_SLASHINGS_ELECTRA: "number", MAX_ATTESTATIONS_ELECTRA: "number", }; diff --git a/packages/state-transition/src/block/processExecutionLayerExit.ts b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts similarity index 71% rename from packages/state-transition/src/block/processExecutionLayerExit.ts rename to packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts index 5068d9af8667..cfe719bf57f3 100644 --- a/packages/state-transition/src/block/processExecutionLayerExit.ts +++ b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts @@ -6,22 +6,33 @@ import {isActiveValidator} from "../util/index.js"; import {CachedBeaconStateElectra} from "../types.js"; import {initiateValidatorExit} from "./index.js"; +const FULL_EXIT_REQUEST_AMOUNT = 0; /** * Process execution layer exit messages and initiate exit incase they belong to a valid active validator * otherwise silent ignore. */ -export function processExecutionLayerExit(state: CachedBeaconStateElectra, exit: electra.ExecutionLayerExit): void { - const validator = isValidExecutionLayerExit(state, exit); - if (validator === null) { - return; - } +export function processExecutionLayerWithdrawalRequest( + state: CachedBeaconStateElectra, + withdrawalRequest: electra.ExecutionLayerWithdrawalRequest +): void { + const isFullExitRequest = withdrawalRequest.amount === FULL_EXIT_REQUEST_AMOUNT; + + if (isFullExitRequest) { + const validator = isValidExecutionLayerExit(state, withdrawalRequest); + if (validator === null) { + return; + } - initiateValidatorExit(state, validator); + initiateValidatorExit(state, validator); + } else { + // partial withdral request add codeblock + } } +// TODO electra : add pending withdrawal check before exit export function isValidExecutionLayerExit( state: CachedBeaconStateElectra, - exit: electra.ExecutionLayerExit + exit: electra.ExecutionLayerWithdrawalRequest ): CompositeViewDU | null { const {config, epochCtx} = state; const validatorIndex = epochCtx.getValidatorIndex(exit.validatorPubkey); diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index c4879da4aa71..228b4eef6fd3 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -8,7 +8,7 @@ import {processProposerSlashing} from "./processProposerSlashing.js"; import {processAttesterSlashing} from "./processAttesterSlashing.js"; import {processDeposit} from "./processDeposit.js"; import {processVoluntaryExit} from "./processVoluntaryExit.js"; -import {processExecutionLayerExit} from "./processExecutionLayerExit.js"; +import {processExecutionLayerWithdrawalRequest} from "./processExecutionLayerWithdrawalRequest.js"; import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js"; import {processDepositReceipt} from "./processDepositReceipt.js"; import {ProcessBlockOpts} from "./types.js"; @@ -19,7 +19,7 @@ export { processAttestations, processDeposit, processVoluntaryExit, - processExecutionLayerExit, + processExecutionLayerWithdrawalRequest, processBlsToExecutionChange, processDepositReceipt, }; @@ -55,8 +55,8 @@ export function processOperations( processVoluntaryExit(state, voluntaryExit, opts.verifySignatures); } if (fork >= ForkSeq.electra) { - for (const elExit of (body as electra.BeaconBlockBody).executionPayload.exits) { - processExecutionLayerExit(state as CachedBeaconStateElectra, elExit); + for (const elWithdrawalRequest of (body as electra.BeaconBlockBody).executionPayload.withdrawalRequests) { + processExecutionLayerWithdrawalRequest(state as CachedBeaconStateElectra, elWithdrawalRequest); } } diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 369ab19c447b..f41c37af94aa 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -20,7 +20,7 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache epoch: stateDeneb.epochCtx.epoch, }); - // latestExecutionPayloadHeader's depositReceiptsRoot and exitsRoot set to zeros by default + // latestExecutionPayloadHeader's depositReceiptsRoot and withdrawalRequestsRoot set to zeros by default // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index 2975b84bf747..c7f0ec2f395c 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -174,9 +174,10 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio if (fork >= ForkSeq.electra) { (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositReceiptsRoot = ssz.electra.DepositReceipts.hashTreeRoot((payload as electra.ExecutionPayload).depositReceipts); - (bellatrixPayloadFields as electra.ExecutionPayloadHeader).exitsRoot = ssz.electra.ExecutionLayerExits.hashTreeRoot( - (payload as electra.ExecutionPayload).exits - ); + (bellatrixPayloadFields as electra.ExecutionPayloadHeader).withdrawalRequestsRoot = + ssz.electra.ExecutionLayerWithdrawalRequests.hashTreeRoot( + (payload as electra.ExecutionPayload).withdrawalRequests + ); } return bellatrixPayloadFields; diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 3404baf04110..53195f30de11 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -16,7 +16,7 @@ import { MAX_COMMITTEES_PER_SLOT, MAX_ATTESTATIONS_ELECTRA, MAX_ATTESTER_SLASHINGS_ELECTRA, - MAX_EXECUTION_LAYER_EXITS, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, } from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; @@ -117,20 +117,24 @@ export const DepositReceipt = new ContainerType( export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); -export const ExecutionLayerExit = new ContainerType( +export const ExecutionLayerWithdrawalRequest = new ContainerType( { sourceAddress: ExecutionAddress, validatorPubkey: BLSPubkey, + amount: UintNum64, }, - {typeName: "ExecutionLayerExit", jsonCase: "eth2"} + {typeName: "ExecutionLayerWithdrawalRequest", jsonCase: "eth2"} +); +export const ExecutionLayerWithdrawalRequests = new ListCompositeType( + ExecutionLayerWithdrawalRequest, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD ); -export const ExecutionLayerExits = new ListCompositeType(ExecutionLayerExit, MAX_EXECUTION_LAYER_EXITS); export const ExecutionPayload = new ContainerType( { ...denebSsz.ExecutionPayload.fields, depositReceipts: DepositReceipts, // New in ELECTRA - exits: ExecutionLayerExits, // New in ELECTRA + withdrawalRequests: ExecutionLayerWithdrawalRequests, // New in ELECTRA }, {typeName: "ExecutionPayload", jsonCase: "eth2"} ); @@ -139,7 +143,7 @@ export const ExecutionPayloadHeader = new ContainerType( { ...denebSsz.ExecutionPayloadHeader.fields, depositReceiptsRoot: Root, // New in ELECTRA - exitsRoot: Root, // New in ELECTRA + withdrawalRequestsRoot: Root, // New in ELECTRA }, {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} ); diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index 2925885b3af3..d1d0109e6ae6 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -12,8 +12,8 @@ export type SignedAggregateAndProof = ValueOf; export type DepositReceipts = ValueOf; -export type ExecutionLayerExit = ValueOf; -export type ExecutionLayerExits = ValueOf; +export type ExecutionLayerWithdrawalRequest = ValueOf; +export type ExecutionLayerWithdrawalRequests = ValueOf; export type ExecutionPayload = ValueOf; export type ExecutionPayloadHeader = ValueOf; diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 1eda005b70c3..ff1c8c0fdc25 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -224,7 +224,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Tue, 7 May 2024 21:18:41 +0300 Subject: [PATCH 018/259] feat: implement maxEB EIP-7251 (#6539) * feat: implement EIP-6110 (#6042) * Add immutable in the dependencies * Initial change to pubkeyCache * Added todos * Moved unfinalized cache to epochCache * Move populating finalized cache to afterProcessEpoch * Specify unfinalized cache during state cloning * Move from unfinalized to finalized cache in afterProcessEpoch * Confused myself * Clean up * Change logic * Fix cloning issue * Clean up redundant code * Add CarryoverData in epochCtx.createFromState * Fix typo * Update usage of pubkeyCache * Update pubkeyCache usage * Fix lint * Fix lint * Add 6110 to ChainConfig * Add 6110 to BeaconPreset * Define 6110 fork and container * Add V6110 api to execution engine * Update test * Add depositReceiptsRoot to process_execution_payload * State transitioning to EIP6110 * State transitioning to EIP6110 * Light client change in EIP-6110 * Update tests * produceBlock * Refactor processDeposit to match the spec * Implement processDepositReceipt * Implement 6110 fork guard for pubkeyCache * Handle changes in eth1 deposit * Update eth1 deposit test * Fix typo * Lint * Remove embarassing comments * Address comments * Modify applyDeposit signature * Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Update packages/state-transition/src/cache/pubkeyCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Remove old code * Rename fields in epochCache and immutableData * Remove CarryoverData * Move isAfter6110 from var to method * Fix cyclic import * Fix operations spec runner * Fix for spec test * Fix spec test * state.depositReceiptsStartIndex to BigInt * getDeposit requires cached state * default depositReceiptsStartIndex value in genesis * Fix pubkeyCache bug * newUnfinalizedPubkeyIndexMap in createCachedBeaconState * Lint * Pass epochCache instead of pubkey2IndexFn in apis * Address comments * Add unit test on pubkey cache cloning * Add unfinalizedPubkeyCacheSize to metrics * Add unfinalizedPubkeyCacheSize to metrics * Clean up code * Add besu to el-interop * Add 6110 genesis file * Template for sim test * Add unit test for getEth1DepositCount * Update sim test * Update besudocker * Finish beacon api calls in sim test * Update epochCache.createFromState() * Fix bug unfinalized validators are not finalized * Add sim test to run a few blocks * Lint * Merge branch 'unstable' into 611 * Add more check to sim test * Update besu docker image instruction * Update sim test with correct tx * Address comment + cleanup * Clean up code * Properly handle promise rejection * Lint * Update packages/beacon-node/src/execution/engine/types.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Update comments * Accept type undefined in ExecutionPayloadBodyRpc * Update comment and semantic * Remove if statement when adding finalized validator * Comment on repeated insert on finalized cache * rename createFromState * Add comment on getPubkey() * Stash change to reduce diffs * Stash change to reduce diffs * Lint * addFinalizedPubkey on finalized checkpoint * Update comment * Use OrderedMap for unfinalized cache * Pull out logic of deleting pubkeys for batch op * Add updateUnfinalizedPubkeys in regen * Update updateUnfinalizedPubkeys logic * Add comment * Add metrics for state context caches * Address comment * Address comment * Deprecate eth1Data polling when condition is reached * Fix conflicts * Fix sim test * Lint * Fix type * Fix test * Fix test * Lint * Update packages/light-client/src/spec/utils.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Fix spec test * Address comments * Improve cache logic on checkpoint finalized * Update sim test according to new cache logic * Update comment * Lint * Finalized pubkey cache only update once per checkpoint * Add perf test for updateUnfinalizedPubkeys * Add perf test for updateUnfinalizedPubkeys * Tweak params for perf test * Freeze besu docker image version for 6110 * Add benchmark result * Use Map instead of OrderedMap. Update benchmark * Minor optimization * Minor optimization * Add memory test for immutable.js * Update test * Reduce code duplication * Lint * Remove try/catch in updateUnfinalizedPubkeys * Introduce EpochCache metric * Add historicalValidatorLengths * Polish code * Migrate state-transition unit tests to vitest * Fix calculation of pivot index * `historicalValidatorLengths` only activate post 6110 * Update sim test * Lint * Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Improve readability on historicalValidatorLengths * Update types * Fix calculation * Add eth1data poll todo * Add epochCache.getValidatorCountAtEpoch * Add todo * Add getStateIterator for state cache * Partial commit * Update perf test * updateUnfinalizedPubkeys directly modify states from regen * Update sim test. Lint * Add todo * some improvements and a fix for effectiveBalanceIncrements fork safeness * rename eip6110 to elctra * fix electra-interop.test.ts --------- Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Co-authored-by: gajinder lint and tsc small cleanup fix rebase issue * feat: implement EIP-6110 (#6042) * Add immutable in the dependencies * Initial change to pubkeyCache * Added todos * Moved unfinalized cache to epochCache * Move populating finalized cache to afterProcessEpoch * Specify unfinalized cache during state cloning * Move from unfinalized to finalized cache in afterProcessEpoch * Confused myself * Clean up * Change logic * Fix cloning issue * Clean up redundant code * Add CarryoverData in epochCtx.createFromState * Fix typo * Update usage of pubkeyCache * Update pubkeyCache usage * Fix lint * Fix lint * Add 6110 to ChainConfig * Add 6110 to BeaconPreset * Define 6110 fork and container * Add V6110 api to execution engine * Update test * Add depositReceiptsRoot to process_execution_payload * State transitioning to EIP6110 * State transitioning to EIP6110 * Light client change in EIP-6110 * Update tests * produceBlock * Refactor processDeposit to match the spec * Implement processDepositReceipt * Implement 6110 fork guard for pubkeyCache * Handle changes in eth1 deposit * Update eth1 deposit test * Fix typo * Lint * Remove embarassing comments * Address comments * Modify applyDeposit signature * Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Update packages/state-transition/src/cache/pubkeyCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Remove old code * Rename fields in epochCache and immutableData * Remove CarryoverData * Move isAfter6110 from var to method * Fix cyclic import * Fix operations spec runner * Fix for spec test * Fix spec test * state.depositReceiptsStartIndex to BigInt * getDeposit requires cached state * default depositReceiptsStartIndex value in genesis * Fix pubkeyCache bug * newUnfinalizedPubkeyIndexMap in createCachedBeaconState * Lint * Pass epochCache instead of pubkey2IndexFn in apis * Address comments * Add unit test on pubkey cache cloning * Add unfinalizedPubkeyCacheSize to metrics * Add unfinalizedPubkeyCacheSize to metrics * Clean up code * Add besu to el-interop * Add 6110 genesis file * Template for sim test * Add unit test for getEth1DepositCount * Update sim test * Update besudocker * Finish beacon api calls in sim test * Update epochCache.createFromState() * Fix bug unfinalized validators are not finalized * Add sim test to run a few blocks * Lint * Merge branch 'unstable' into 611 * Add more check to sim test * Update besu docker image instruction * Update sim test with correct tx * Address comment + cleanup * Clean up code * Properly handle promise rejection * Lint * Update packages/beacon-node/src/execution/engine/types.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Update comments * Accept type undefined in ExecutionPayloadBodyRpc * Update comment and semantic * Remove if statement when adding finalized validator * Comment on repeated insert on finalized cache * rename createFromState * Add comment on getPubkey() * Stash change to reduce diffs * Stash change to reduce diffs * Lint * addFinalizedPubkey on finalized checkpoint * Update comment * Use OrderedMap for unfinalized cache * Pull out logic of deleting pubkeys for batch op * Add updateUnfinalizedPubkeys in regen * Update updateUnfinalizedPubkeys logic * Add comment * Add metrics for state context caches * Address comment * Address comment * Deprecate eth1Data polling when condition is reached * Fix conflicts * Fix sim test * Lint * Fix type * Fix test * Fix test * Lint * Update packages/light-client/src/spec/utils.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Fix spec test * Address comments * Improve cache logic on checkpoint finalized * Update sim test according to new cache logic * Update comment * Lint * Finalized pubkey cache only update once per checkpoint * Add perf test for updateUnfinalizedPubkeys * Add perf test for updateUnfinalizedPubkeys * Tweak params for perf test * Freeze besu docker image version for 6110 * Add benchmark result * Use Map instead of OrderedMap. Update benchmark * Minor optimization * Minor optimization * Add memory test for immutable.js * Update test * Reduce code duplication * Lint * Remove try/catch in updateUnfinalizedPubkeys * Introduce EpochCache metric * Add historicalValidatorLengths * Polish code * Migrate state-transition unit tests to vitest * Fix calculation of pivot index * `historicalValidatorLengths` only activate post 6110 * Update sim test * Lint * Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> * Improve readability on historicalValidatorLengths * Update types * Fix calculation * Add eth1data poll todo * Add epochCache.getValidatorCountAtEpoch * Add todo * Add getStateIterator for state cache * Partial commit * Update perf test * updateUnfinalizedPubkeys directly modify states from regen * Update sim test. Lint * Add todo * some improvements and a fix for effectiveBalanceIncrements fork safeness * rename eip6110 to elctra * fix electra-interop.test.ts --------- Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Co-authored-by: gajinder lint and tsc small cleanup * Add presets * Update config * Add necessary containers * Update presets * Update config * Add todo comments * Update constants and params * Impl new process withdrawal * Add withdrawaRequests to payload * Add processConsolidation * Add process withdraw request * Update deposit and withdrawal flow * epoch processing * Implement churn limits * Lint * lint * Update state-transition utils * processExecutionLayerWithdrawRequest * processConsolidation * queueExcessActiveBalance * isValidDepositSignature * Add jsdoc and timer for new processEpoch functions * Lint * Update maxEB * update voluntary exit * Fix config * Update initiateValidatorExit * Remove churn limit in processRegistryUpdates * Fix conflict * Add MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD * Reflect latest spec changes * rebase fixes, fixes, improvements and cleanup lint * Upgrade ssz version * Use sliceFrom() * cleanup as per specs feedback subarry * simplify * fix withdrawals * remove slice * fix the slashing quotient determination in slashvalidator --------- Co-authored-by: harkamal --- .../chain/produceBlock/produceBlockBody.ts | 2 + .../test/sim/electra-interop.test.ts | 2 +- .../test/spec/presets/operations.test.ts | 4 +- .../test/unit/executionEngine/http.test.ts | 8 +- .../config/src/chainConfig/configs/mainnet.ts | 6 + .../config/src/chainConfig/configs/minimal.ts | 6 + packages/config/src/chainConfig/types.ts | 4 + packages/params/src/index.ts | 14 +- packages/params/src/presets/mainnet.ts | 11 ++ packages/params/src/presets/minimal.ts | 13 +- packages/params/src/types.ts | 18 +++ packages/state-transition/src/block/index.ts | 2 + .../src/block/initiateValidatorExit.ts | 39 ++++-- .../src/block/processConsolidation.ts | 111 +++++++++++++++ .../src/block/processDeposit.ts | 98 ++++++++++---- .../processExecutionLayerWithdrawalRequest.ts | 126 +++++++++++------- .../src/block/processOperations.ts | 25 ++-- .../src/block/processVoluntaryExit.ts | 30 ++++- .../src/block/processWithdrawals.ts | 87 +++++++++--- .../src/block/slashValidator.ts | 15 ++- .../state-transition/src/cache/epochCache.ts | 2 + .../src/cache/epochTransitionCache.ts | 8 +- packages/state-transition/src/epoch/index.ts | 32 ++++- .../epoch/processEffectiveBalanceUpdates.ts | 22 ++- .../epoch/processPendingBalanceDeposits.ts | 35 +++++ .../src/epoch/processPendingConsolidations.ts | 45 +++++++ .../src/epoch/processRegistryUpdates.ts | 14 +- .../src/signatureSets/consolidation.ts | 51 +++++++ .../src/signatureSets/index.ts | 16 ++- .../src/slot/upgradeStateToElectra.ts | 24 +++- packages/state-transition/src/util/electra.ts | 103 ++++++++++++++ packages/state-transition/src/util/epoch.ts | 56 ++++++++ packages/state-transition/src/util/genesis.ts | 2 +- packages/state-transition/src/util/index.ts | 1 + .../state-transition/src/util/validator.ts | 55 +++++++- .../test/perf/analyzeEpochs.ts | 3 + .../perf/block/processWithdrawals.test.ts | 5 +- .../unit/block/processWithdrawals.test.ts | 4 +- packages/types/src/electra/sszTypes.ts | 60 ++++++++- packages/types/src/electra/types.ts | 7 + packages/types/src/phase0/sszTypes.ts | 2 +- packages/validator/src/util/params.ts | 11 ++ .../test/unit/utils/interopConfigs.ts | 34 +++++ 43 files changed, 1056 insertions(+), 157 deletions(-) create mode 100644 packages/state-transition/src/block/processConsolidation.ts create mode 100644 packages/state-transition/src/epoch/processPendingBalanceDeposits.ts create mode 100644 packages/state-transition/src/epoch/processPendingConsolidations.ts create mode 100644 packages/state-transition/src/signatureSets/consolidation.ts create mode 100644 packages/state-transition/src/util/electra.ts diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index d1b410610a43..ba560d5a7ff0 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -559,7 +559,9 @@ function preparePayloadAttributes( }; if (ForkSeq[fork] >= ForkSeq.capella) { + // withdrawals logic is now fork aware as it changes on electra fork post capella (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals = getExpectedWithdrawals( + ForkSeq[fork], prepareState as CachedBeaconStateCapella ).withdrawals; } diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index ab3f1ae6b2c1..29483b249c85 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -173,7 +173,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { blockHash: dataToBytes(newPayloadBlockHash, 32), receiptsRoot: dataToBytes("0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9", 32), blobGasUsed: 0n, - exits: [], + withdrawalRequests: [], }; const parentBeaconBlockRoot = dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32); const payloadResult = await executionEngine.notifyNewPayload( diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index cc032bec6fa2..9b8214a88c0a 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -11,7 +11,7 @@ import { import * as blockFns from "@lodestar/state-transition/block"; import {ssz, phase0, altair, bellatrix, capella, electra, sszTypesFor} from "@lodestar/types"; import {InputType} from "@lodestar/spec-test-util"; -import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; +import {ACTIVE_PRESET, ForkName, ForkSeq} from "@lodestar/params"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; @@ -88,7 +88,7 @@ const operationFns: Record> = }, withdrawals: (state, testCase: {execution_payload: capella.ExecutionPayload}) => { - blockFns.processWithdrawals(state as CachedBeaconStateCapella, testCase.execution_payload); + blockFns.processWithdrawals(ForkSeq.capella, state as CachedBeaconStateCapella, testCase.execution_payload); }, }; diff --git a/packages/beacon-node/test/unit/executionEngine/http.test.ts b/packages/beacon-node/test/unit/executionEngine/http.test.ts index d58eefa10368..842f39a5ff90 100644 --- a/packages/beacon-node/test/unit/executionEngine/http.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/http.test.ts @@ -194,7 +194,7 @@ describe("ExecutionEngine / http", () => { }, ], depositReceipts: null, // depositReceipts is null pre-electra - exits: null, + withdrawalRequests: null, }, null, // null returned for missing blocks { @@ -204,7 +204,7 @@ describe("ExecutionEngine / http", () => { ], withdrawals: null, // withdrawals is null pre-capella depositReceipts: null, // depositReceipts is null pre-electra - exits: null, + withdrawalRequests: null, }, ], }; @@ -253,7 +253,7 @@ describe("ExecutionEngine / http", () => { }, ], depositReceipts: null, // depositReceipts is null pre-electra - exits: null, + withdrawalRequests: null, }, null, // null returned for missing blocks { @@ -263,7 +263,7 @@ describe("ExecutionEngine / http", () => { ], withdrawals: null, // withdrawals is null pre-capella depositReceipts: null, // depositReceipts is null pre-electra - exits: null, + withdrawalRequests: null, }, ], }; diff --git a/packages/config/src/chainConfig/configs/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts index 6d1fd9b75952..741ddc99f8cd 100644 --- a/packages/config/src/chainConfig/configs/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -102,4 +102,10 @@ export const chainConfig: ChainConfig = { // Deneb // `2**12` (= 4096 epochs, ~18 days) MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096, + + // Electra + // 2**8 * 10**9 (= 256,000,000,000) + MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 256000000000, + // 2*7 * 10**9 (= 128,000,000,000) + MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000, }; diff --git a/packages/config/src/chainConfig/configs/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts index 44a28ca36ec7..26f49cc3e47d 100644 --- a/packages/config/src/chainConfig/configs/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -99,4 +99,10 @@ export const chainConfig: ChainConfig = { // Deneb // `2**12` (= 4096 epochs, ~18 days) MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096, + + // Electra + // 2**7 * 10**9 (= 128,000,000,000) + MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 128000000000, + // 2**6 * 10**9 (= 64,000,000,000) + MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000, }; diff --git a/packages/config/src/chainConfig/types.ts b/packages/config/src/chainConfig/types.ts index 234a08558be5..05fff02f2eaf 100644 --- a/packages/config/src/chainConfig/types.ts +++ b/packages/config/src/chainConfig/types.ts @@ -58,6 +58,8 @@ export type ChainConfig = { MIN_PER_EPOCH_CHURN_LIMIT: number; MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: number; CHURN_LIMIT_QUOTIENT: number; + MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: number; + MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: number; // Fork choice PROPOSER_SCORE_BOOST: number; @@ -120,6 +122,8 @@ export const chainConfigTypes: SpecTypes = { MIN_PER_EPOCH_CHURN_LIMIT: "number", MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: "number", CHURN_LIMIT_QUOTIENT: "number", + MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: "number", + MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: "number", // Fork choice PROPOSER_SCORE_BOOST: "number", diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index b261e07959d0..c1d3f1bc1981 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -94,10 +94,20 @@ export const { MAX_BLOBS_PER_BLOCK, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, + MAX_EFFECTIVE_BALANCE_ELECTRA, + MIN_ACTIVATION_BALANCE, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA, + MAX_CONSOLIDATIONS, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_ATTESTATIONS_ELECTRA, + MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP, + WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA, } = activePreset; //////////// @@ -119,6 +129,7 @@ export const JUSTIFICATION_BITS_LENGTH = 4; // Since the prefixes are just 1 byte, we define and use them as number export const BLS_WITHDRAWAL_PREFIX = 0; export const ETH1_ADDRESS_WITHDRAWAL_PREFIX = 1; +export const COMPOUNDING_WITHDRAWAL_PREFIX = 2; // Domain types @@ -133,7 +144,7 @@ export const DOMAIN_SYNC_COMMITTEE = Uint8Array.from([7, 0, 0, 0]); export const DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF = Uint8Array.from([8, 0, 0, 0]); export const DOMAIN_CONTRIBUTION_AND_PROOF = Uint8Array.from([9, 0, 0, 0]); export const DOMAIN_BLS_TO_EXECUTION_CHANGE = Uint8Array.from([10, 0, 0, 0]); -export const DOMAIN_BLOB_SIDECAR = Uint8Array.from([11, 0, 0, 0]); +export const DOMAIN_CONSOLIDATION = Uint8Array.from([11, 0, 0, 0]); // Application specific domains @@ -252,3 +263,4 @@ export const BLOBSIDECAR_FIXED_SIZE = ACTIVE_PRESET === PresetName.minimal ? 131 // Electra Misc export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = 2n ** 64n - 1n; +export const FULL_EXIT_REQUEST_AMOUNT = 0; diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 5343966a43f4..2495f7ef97a1 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -124,4 +124,15 @@ export const mainnetPreset: BeaconPreset = { MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 16, MAX_ATTESTER_SLASHINGS_ELECTRA: 1, MAX_ATTESTATIONS_ELECTRA: 8, + MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 8, + // 2**11 * 10**9 (= 2,048,000,000,000) Gwei + MAX_EFFECTIVE_BALANCE_ELECTRA: 2048000000000, + // 2**16 (= 65536) + MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: 4096, + MIN_ACTIVATION_BALANCE: 32000000000, + PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, + PENDING_PARTIAL_WITHDRAWALS_LIMIT: 134217728, + PENDING_CONSOLIDATIONS_LIMIT: 262144, + MAX_CONSOLIDATIONS: 1, + WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: 4096, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index e4938d501a51..8e71407965d7 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -122,7 +122,18 @@ export const minimalPreset: BeaconPreset = { // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 4, - MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 16, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 2, MAX_ATTESTER_SLASHINGS_ELECTRA: 1, MAX_ATTESTATIONS_ELECTRA: 8, + MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 1, + // 2**11 * 10**9 (= 2,048,000,000,000) Gwei + MAX_EFFECTIVE_BALANCE_ELECTRA: 2048000000000, + // 2**16 (= 65536) + MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: 4096, + MIN_ACTIVATION_BALANCE: 32000000000, + PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, + PENDING_PARTIAL_WITHDRAWALS_LIMIT: 64, + PENDING_CONSOLIDATIONS_LIMIT: 64, + MAX_CONSOLIDATIONS: 1, + WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: 4096, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index e5b85a9e2224..dffd98518006 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -88,6 +88,15 @@ export type BeaconPreset = { MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: number; MAX_ATTESTER_SLASHINGS_ELECTRA: number; MAX_ATTESTATIONS_ELECTRA: number; + MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: number; + MAX_EFFECTIVE_BALANCE_ELECTRA: number; + MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: number; + MIN_ACTIVATION_BALANCE: number; + PENDING_BALANCE_DEPOSITS_LIMIT: number; + PENDING_PARTIAL_WITHDRAWALS_LIMIT: number; + PENDING_CONSOLIDATIONS_LIMIT: number; + MAX_CONSOLIDATIONS: number; + WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: number; }; /** @@ -179,6 +188,15 @@ export const beaconPresetTypes: BeaconPresetTypes = { MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: "number", MAX_ATTESTER_SLASHINGS_ELECTRA: "number", MAX_ATTESTATIONS_ELECTRA: "number", + MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: "number", + MAX_EFFECTIVE_BALANCE_ELECTRA: "number", + MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: "number", + MIN_ACTIVATION_BALANCE: "number", + PENDING_BALANCE_DEPOSITS_LIMIT: "number", + PENDING_PARTIAL_WITHDRAWALS_LIMIT: "number", + PENDING_CONSOLIDATIONS_LIMIT: "number", + MAX_CONSOLIDATIONS: "number", + WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: "number", }; type BeaconPresetTypes = { diff --git a/packages/state-transition/src/block/index.ts b/packages/state-transition/src/block/index.ts index fdfc9e903518..3857511292c8 100644 --- a/packages/state-transition/src/block/index.ts +++ b/packages/state-transition/src/block/index.ts @@ -47,10 +47,12 @@ export function processBlock( // https://github.com/ethereum/consensus-specs/blob/b62c9e877990242d63aa17a2a59a49bc649a2f2e/specs/eip4844/beacon-chain.md#disabling-withdrawals if (fork >= ForkSeq.capella) { processWithdrawals( + fork, state as CachedBeaconStateCapella, fullOrBlindedPayload as capella.FullOrBlindedExecutionPayload ); } + processExecutionPayload(fork, state as CachedBeaconStateBellatrix, block.body, externalData); } diff --git a/packages/state-transition/src/block/initiateValidatorExit.ts b/packages/state-transition/src/block/initiateValidatorExit.ts index e34d4dda7002..d1420daef84c 100644 --- a/packages/state-transition/src/block/initiateValidatorExit.ts +++ b/packages/state-transition/src/block/initiateValidatorExit.ts @@ -1,7 +1,8 @@ import {CompositeViewDU} from "@chainsafe/ssz"; -import {FAR_FUTURE_EPOCH} from "@lodestar/params"; +import {FAR_FUTURE_EPOCH, ForkSeq} from "@lodestar/params"; import {ssz} from "@lodestar/types"; -import {CachedBeaconStateAllForks} from "../types.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; +import {computeExitEpochAndUpdateChurn} from "../util/epoch.js"; /** * Initiate the exit of the validator with index ``index``. @@ -24,6 +25,7 @@ import {CachedBeaconStateAllForks} from "../types.js"; * Forcing consumers to pass the SubTree of `validator` directly mitigates this issue. */ export function initiateValidatorExit( + fork: ForkSeq, state: CachedBeaconStateAllForks, validator: CompositeViewDU ): void { @@ -34,18 +36,27 @@ export function initiateValidatorExit( return; } - // Limits the number of validators that can exit on each epoch. - // Expects all state.validators to follow this rule, i.e. no validator.exitEpoch is greater than exitQueueEpoch. - // If there the churnLimit is reached at this current exitQueueEpoch, advance epoch and reset churn. - if (epochCtx.exitQueueChurn >= epochCtx.churnLimit) { - epochCtx.exitQueueEpoch += 1; - epochCtx.exitQueueChurn = 1; // = 1 to account for this validator with exitQueueEpoch + if (fork < ForkSeq.electra) { + // Limits the number of validators that can exit on each epoch. + // Expects all state.validators to follow this rule, i.e. no validator.exitEpoch is greater than exitQueueEpoch. + // If there the churnLimit is reached at this current exitQueueEpoch, advance epoch and reset churn. + if (epochCtx.exitQueueChurn >= epochCtx.churnLimit) { + epochCtx.exitQueueEpoch += 1; + epochCtx.exitQueueChurn = 1; // = 1 to account for this validator with exitQueueEpoch + } else { + // Add this validator to the current exitQueueEpoch churn + epochCtx.exitQueueChurn += 1; + } + + // set validator exit epoch + validator.exitEpoch = epochCtx.exitQueueEpoch; } else { - // Add this validator to the current exitQueueEpoch churn - epochCtx.exitQueueChurn += 1; + // set validator exit epoch + // Note we don't use epochCtx.exitQueueChurn and exitQueueEpoch anymore + validator.exitEpoch = computeExitEpochAndUpdateChurn( + state as CachedBeaconStateElectra, + BigInt(validator.effectiveBalance) + ); } - - // set validator exit epoch and withdrawable epoch - validator.exitEpoch = epochCtx.exitQueueEpoch; - validator.withdrawableEpoch = epochCtx.exitQueueEpoch + config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY; + validator.withdrawableEpoch = validator.exitEpoch + config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY; } diff --git a/packages/state-transition/src/block/processConsolidation.ts b/packages/state-transition/src/block/processConsolidation.ts new file mode 100644 index 000000000000..846b0e2521b4 --- /dev/null +++ b/packages/state-transition/src/block/processConsolidation.ts @@ -0,0 +1,111 @@ +import {toHexString} from "@chainsafe/ssz"; +import {electra, ssz} from "@lodestar/types"; +import {FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} from "@lodestar/params"; +import {verifyConsolidationSignature} from "../signatureSets/index.js"; + +import {CachedBeaconStateElectra} from "../types.js"; +import {getConsolidationChurnLimit, isActiveValidator} from "../util/validator.js"; +import {hasExecutionWithdrawalCredential} from "../util/electra.js"; +import {computeConsolidationEpochAndUpdateChurn} from "../util/epoch.js"; + +export function processConsolidation( + state: CachedBeaconStateElectra, + signedConsolidation: electra.SignedConsolidation +): void { + assertValidConsolidation(state, signedConsolidation); + + // Initiate source validator exit and append pending consolidation + const {sourceIndex, targetIndex} = signedConsolidation.message; + const sourceValidator = state.validators.get(sourceIndex); + + const exitEpoch = computeConsolidationEpochAndUpdateChurn(state, BigInt(sourceValidator.effectiveBalance)); + sourceValidator.exitEpoch = exitEpoch; + sourceValidator.withdrawableEpoch = exitEpoch + state.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY; + + const pendingConsolidation = ssz.electra.PendingConsolidation.toViewDU({ + sourceIndex, + targetIndex, + }); + state.pendingConsolidations.push(pendingConsolidation); +} + +function assertValidConsolidation( + state: CachedBeaconStateElectra, + signedConsolidation: electra.SignedConsolidation +): void { + // If the pending consolidations queue is full, no consolidations are allowed in the block + if (state.pendingConsolidations.length >= PENDING_CONSOLIDATIONS_LIMIT) { + throw new Error("Pending consolidation queue is full"); + } + + // If there is too little available consolidation churn limit, no consolidations are allowed in the block + // assert get_consolidation_churn_limit(state) > MIN_ACTIVATION_BALANCE + if (getConsolidationChurnLimit(state) <= MIN_ACTIVATION_BALANCE) { + throw new Error(`Consolidation churn limit too low. consolidationChurnLimit=${getConsolidationChurnLimit(state)}`); + } + + const consolidation = signedConsolidation.message; + const {sourceIndex, targetIndex} = consolidation; + + // Verify that source != target, so a consolidation cannot be used as an exit. + if (sourceIndex === targetIndex) { + throw new Error( + `Consolidation source and target index cannot be the same: sourceIndex=${sourceIndex} targetIndex=${targetIndex}` + ); + } + + const sourceValidator = state.validators.getReadonly(sourceIndex); + const targetValidator = state.validators.getReadonly(targetIndex); + const currentEpoch = state.epochCtx.epoch; + + // Verify the source and the target are active + if (!isActiveValidator(sourceValidator, currentEpoch)) { + throw new Error(`Consolidation source validator is not active: sourceIndex=${sourceIndex}`); + } + + if (!isActiveValidator(targetValidator, currentEpoch)) { + throw new Error(`Consolidation target validator is not active: targetIndex=${targetIndex}`); + } + + // Verify exits for source and target have not been initiated + if (sourceValidator.exitEpoch !== FAR_FUTURE_EPOCH) { + throw new Error(`Consolidation source validator has initialized exit: sourceIndex=${sourceIndex}`); + } + if (targetValidator.exitEpoch !== FAR_FUTURE_EPOCH) { + throw new Error(`Consolidation target validator has initialized exit: targetIndex=${targetIndex}`); + } + + // Consolidations must specify an epoch when they become valid; they are not valid before then + if (currentEpoch < consolidation.epoch) { + throw new Error( + `Consolidation epoch is after the current epoch: consolidationEpoch=${consolidation.epoch} currentEpoch=${currentEpoch}` + ); + } + + // Verify the source and the target have Execution layer withdrawal credentials + if (!hasExecutionWithdrawalCredential(sourceValidator.withdrawalCredentials)) { + throw new Error( + `Consolidation source validator does not have execution withdrawal credentials: sourceIndex=${sourceIndex}` + ); + } + if (!hasExecutionWithdrawalCredential(targetValidator.withdrawalCredentials)) { + throw new Error( + `Consolidation target validator does not have execution withdrawal credentials: targetIndex=${targetIndex}` + ); + } + + // Verify the same withdrawal address + const sourceWithdrawalAddress = toHexString(sourceValidator.withdrawalCredentials.subarray(12)); + const targetWithdrawalAddress = toHexString(targetValidator.withdrawalCredentials.subarray(12)); + + if (sourceWithdrawalAddress !== targetWithdrawalAddress) { + throw new Error( + `Consolidation source and target withdrawal address are different: source: ${sourceWithdrawalAddress} target: ${targetWithdrawalAddress}` + ); + } + + // Verify consolidation is signed by the source and the target + if (!verifyConsolidationSignature(state, signedConsolidation)) { + throw new Error("Consolidation not valid"); + } +} diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 5a2a892a5c9b..65b3cbfb10fd 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -13,9 +13,17 @@ import { import {DepositData} from "@lodestar/types/lib/phase0/types.js"; import {DepositReceipt} from "@lodestar/types/lib/electra/types.js"; +import {BeaconConfig} from "@lodestar/config"; import {ZERO_HASH} from "../constants/index.js"; -import {computeDomain, computeSigningRoot, increaseBalance} from "../util/index.js"; -import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; +import { + computeDomain, + computeSigningRoot, + hasCompoundingWithdrawalCredential, + hasEth1WithdrawalCredential, + increaseBalance, + switchToCompoundingValidator, +} from "../util/index.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStateElectra} from "../types.js"; /** * Process a Deposit operation. Potentially adds a new validator to the registry. Mutates the validators and balances @@ -58,29 +66,29 @@ export function applyDeposit( const cachedIndex = epochCtx.getValidatorIndex(pubkey); if (cachedIndex === undefined || !Number.isSafeInteger(cachedIndex) || cachedIndex >= validators.length) { - // verify the deposit signature (proof of posession) which is not checked by the deposit contract - const depositMessage = { - pubkey, - withdrawalCredentials, - amount, - }; - // fork-agnostic domain since deposits are valid across forks - const domain = computeDomain(DOMAIN_DEPOSIT, config.GENESIS_FORK_VERSION, ZERO_HASH); - const signingRoot = computeSigningRoot(ssz.phase0.DepositMessage, depositMessage, domain); - try { - // Pubkeys must be checked for group + inf. This must be done only once when the validator deposit is processed - const publicKey = PublicKey.fromBytes(pubkey, true); - const signature = Signature.fromBytes(deposit.data.signature, true); - if (!verify(signingRoot, publicKey, signature)) { - return; - } - } catch (e) { - return; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature + if (isValidDepositSignature(config, pubkey, withdrawalCredentials, amount, deposit.signature)) { + addValidatorToRegistry(fork, state, pubkey, withdrawalCredentials, amount); } - addValidatorToRegistry(fork, state, pubkey, withdrawalCredentials, amount); } else { - // increase balance by deposit amount - increaseBalance(state, cachedIndex, amount); + if (fork < ForkSeq.electra) { + // increase balance by deposit amount right away pre-electra + increaseBalance(state, cachedIndex, amount); + } else if (fork >= ForkSeq.electra) { + const stateElectra = state as CachedBeaconStateElectra; + const pendingBalanceDeposit = ssz.electra.PendingBalanceDeposit.toViewDU({ + index: cachedIndex, + amount: BigInt(amount), + }); + stateElectra.pendingBalanceDeposits.push(pendingBalanceDeposit); + + if ( + hasCompoundingWithdrawalCredential(withdrawalCredentials) && + hasEth1WithdrawalCredential(validators.getReadonly(cachedIndex).withdrawalCredentials) && + isValidDepositSignature(config, pubkey, withdrawalCredentials, amount, deposit.signature) + ) { + switchToCompoundingValidator(stateElectra, cachedIndex); + } + } } } @@ -93,7 +101,8 @@ function addValidatorToRegistry( ): void { const {validators, epochCtx} = state; // add validator and balance entries - const effectiveBalance = Math.min(amount - (amount % EFFECTIVE_BALANCE_INCREMENT), MAX_EFFECTIVE_BALANCE); + const effectiveBalance = + fork < ForkSeq.electra ? Math.min(amount - (amount % EFFECTIVE_BALANCE_INCREMENT), MAX_EFFECTIVE_BALANCE) : 0; validators.push( ssz.phase0.Validator.toViewDU({ pubkey, @@ -106,9 +115,9 @@ function addValidatorToRegistry( slashed: false, }) ); - state.balances.push(amount); const validatorIndex = validators.length - 1; + // TODO Electra: Review this // Updating here is better than updating at once on epoch transition // - Simplify genesis fn applyDeposits(): effectiveBalanceIncrements is populated immediately // - Keep related code together to reduce risk of breaking this cache @@ -128,4 +137,43 @@ function addValidatorToRegistry( stateAltair.previousEpochParticipation.push(0); stateAltair.currentEpochParticipation.push(0); } + + if (fork < ForkSeq.electra) { + state.balances.push(amount); + } else if (fork >= ForkSeq.electra) { + state.balances.push(0); + const stateElectra = state as CachedBeaconStateElectra; + const pendingBalanceDeposit = ssz.electra.PendingBalanceDeposit.toViewDU({ + index: validatorIndex, + amount: BigInt(amount), + }); + stateElectra.pendingBalanceDeposits.push(pendingBalanceDeposit); + } +} + +function isValidDepositSignature( + config: BeaconConfig, + pubkey: Uint8Array, + withdrawalCredentials: Uint8Array, + amount: number, + depositSignature: Uint8Array +): boolean { + // verify the deposit signature (proof of posession) which is not checked by the deposit contract + const depositMessage = { + pubkey, + withdrawalCredentials, + amount, + }; + // fork-agnostic domain since deposits are valid across forks + const domain = computeDomain(DOMAIN_DEPOSIT, config.GENESIS_FORK_VERSION, ZERO_HASH); + const signingRoot = computeSigningRoot(ssz.phase0.DepositMessage, depositMessage, domain); + try { + // Pubkeys must be checked for group + inf. This must be done only once when the validator deposit is processed + const publicKey = PublicKey.fromBytes(pubkey, true); + const signature = Signature.fromBytes(depositSignature, true); + + return verify(signingRoot, publicKey, signature) + } catch (e) { + return false; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature + } } diff --git a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts index cfe719bf57f3..e16fad105aaa 100644 --- a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts +++ b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts @@ -1,67 +1,99 @@ -import {CompositeViewDU} from "@chainsafe/ssz"; -import {electra, ssz} from "@lodestar/types"; -import {ETH1_ADDRESS_WITHDRAWAL_PREFIX, FAR_FUTURE_EPOCH} from "@lodestar/params"; +import {toHexString} from "@chainsafe/ssz"; +import {electra, phase0, ssz} from "@lodestar/types"; +import { + FAR_FUTURE_EPOCH, + MIN_ACTIVATION_BALANCE, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + FULL_EXIT_REQUEST_AMOUNT, + ForkSeq, +} from "@lodestar/params"; -import {isActiveValidator} from "../util/index.js"; import {CachedBeaconStateElectra} from "../types.js"; -import {initiateValidatorExit} from "./index.js"; +import {hasCompoundingWithdrawalCredential, hasExecutionWithdrawalCredential} from "../util/electra.js"; +import {getPendingBalanceToWithdraw, isActiveValidator} from "../util/validator.js"; +import {computeExitEpochAndUpdateChurn} from "../util/epoch.js"; +import {initiateValidatorExit} from "./initiateValidatorExit.js"; -const FULL_EXIT_REQUEST_AMOUNT = 0; -/** - * Process execution layer exit messages and initiate exit incase they belong to a valid active validator - * otherwise silent ignore. - */ export function processExecutionLayerWithdrawalRequest( + fork: ForkSeq, state: CachedBeaconStateElectra, - withdrawalRequest: electra.ExecutionLayerWithdrawalRequest + executionLayerWithdrawalRequest: electra.ExecutionLayerWithdrawalRequest ): void { - const isFullExitRequest = withdrawalRequest.amount === FULL_EXIT_REQUEST_AMOUNT; + const amount = Number(executionLayerWithdrawalRequest.amount); + const {pendingPartialWithdrawals, validators, epochCtx} = state; + // no need to use unfinalized pubkey cache from 6110 as validator won't be active anyway + const {pubkey2index, config} = epochCtx; + const isFullExitRequest = amount === FULL_EXIT_REQUEST_AMOUNT; - if (isFullExitRequest) { - const validator = isValidExecutionLayerExit(state, withdrawalRequest); - if (validator === null) { - return; - } - - initiateValidatorExit(state, validator); - } else { - // partial withdral request add codeblock + // If partial withdrawal queue is full, only full exits are processed + if (pendingPartialWithdrawals.length >= PENDING_PARTIAL_WITHDRAWALS_LIMIT && !isFullExitRequest) { + return; } -} -// TODO electra : add pending withdrawal check before exit -export function isValidExecutionLayerExit( - state: CachedBeaconStateElectra, - exit: electra.ExecutionLayerWithdrawalRequest -): CompositeViewDU | null { - const {config, epochCtx} = state; - const validatorIndex = epochCtx.getValidatorIndex(exit.validatorPubkey); - const validator = validatorIndex !== undefined ? state.validators.getReadonly(validatorIndex) : undefined; - if (validator === undefined) { - return null; + // bail out if validator is not in beacon state + // note that we don't need to check for 6110 unfinalized vals as they won't be eligible for withdraw/exit anyway + const validatorIndex = pubkey2index.get(executionLayerWithdrawalRequest.validatorPubkey); + if (validatorIndex === undefined) { + return; } - const {withdrawalCredentials} = validator; - if (withdrawalCredentials[0] !== ETH1_ADDRESS_WITHDRAWAL_PREFIX) { - return null; + const validator = validators.getReadonly(validatorIndex); + if (!isValidatorEligibleForWithdrawOrExit(validator, executionLayerWithdrawalRequest.sourceAddress, state)) { + return; } - const executionAddress = withdrawalCredentials.subarray(12, 32); - if (Buffer.compare(executionAddress, exit.sourceAddress) !== 0) { - return null; + // TODO Electra: Consider caching pendingPartialWithdrawals + const pendingBalanceToWithdraw = getPendingBalanceToWithdraw(state, validatorIndex); + const validatorBalance = state.balances.get(validatorIndex); + + if (isFullExitRequest) { + // only exit validator if it has no pending withdrawals in the queue + if (pendingBalanceToWithdraw === 0) { + initiateValidatorExit(fork, state, validator); + } + return; } - const currentEpoch = epochCtx.epoch; + // partial withdrawal request + const hasSufficientEffectiveBalance = validator.effectiveBalance >= MIN_ACTIVATION_BALANCE; + const hasExcessBalance = validatorBalance > MIN_ACTIVATION_BALANCE + pendingBalanceToWithdraw; + + // Only allow partial withdrawals with compounding withdrawal credentials if ( - // verify the validator is active + hasCompoundingWithdrawalCredential(validator.withdrawalCredentials) && + hasSufficientEffectiveBalance && + hasExcessBalance + ) { + const amountToWithdraw = BigInt( + Math.min(validatorBalance - MIN_ACTIVATION_BALANCE - pendingBalanceToWithdraw, amount) + ); + const exitQueueEpoch = computeExitEpochAndUpdateChurn(state, amountToWithdraw); + const withdrawableEpoch = exitQueueEpoch + config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY; + + const pendingPartialWithdrawal = ssz.electra.PartialWithdrawal.toViewDU({ + index: validatorIndex, + amount: amountToWithdraw, + withdrawableEpoch, + }); + state.pendingPartialWithdrawals.push(pendingPartialWithdrawal); + } +} + +function isValidatorEligibleForWithdrawOrExit( + validator: phase0.Validator, + sourceAddress: Uint8Array, + state: CachedBeaconStateElectra +): boolean { + const {withdrawalCredentials} = validator; + const addressStr = toHexString(withdrawalCredentials.subarray(12)); + const sourceAddressStr = toHexString(sourceAddress); + const {epoch: currentEpoch, config} = state.epochCtx; + + return ( + hasExecutionWithdrawalCredential(withdrawalCredentials) && + addressStr === sourceAddressStr && isActiveValidator(validator, currentEpoch) && - // verify exit has not been initiated validator.exitEpoch === FAR_FUTURE_EPOCH && - // verify the validator had been active long enough currentEpoch >= validator.activationEpoch + config.SHARD_COMMITTEE_PERIOD - ) { - return validator; - } else { - return null; - } + ); } diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index 228b4eef6fd3..8d65762931e7 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -8,10 +8,11 @@ import {processProposerSlashing} from "./processProposerSlashing.js"; import {processAttesterSlashing} from "./processAttesterSlashing.js"; import {processDeposit} from "./processDeposit.js"; import {processVoluntaryExit} from "./processVoluntaryExit.js"; -import {processExecutionLayerWithdrawalRequest} from "./processExecutionLayerWithdrawalRequest.js"; import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js"; +import {processExecutionLayerWithdrawalRequest} from "./processExecutionLayerWithdrawalRequest.js"; import {processDepositReceipt} from "./processDepositReceipt.js"; import {ProcessBlockOpts} from "./types.js"; +import {processConsolidation} from "./processConsolidation.js"; export { processProposerSlashing, @@ -52,12 +53,7 @@ export function processOperations( } for (const voluntaryExit of body.voluntaryExits) { - processVoluntaryExit(state, voluntaryExit, opts.verifySignatures); - } - if (fork >= ForkSeq.electra) { - for (const elWithdrawalRequest of (body as electra.BeaconBlockBody).executionPayload.withdrawalRequests) { - processExecutionLayerWithdrawalRequest(state as CachedBeaconStateElectra, elWithdrawalRequest); - } + processVoluntaryExit(fork, state, voluntaryExit, opts.verifySignatures); } if (fork >= ForkSeq.capella) { @@ -67,8 +63,19 @@ export function processOperations( } if (fork >= ForkSeq.electra) { - for (const depositReceipt of (body as electra.BeaconBlockBody).executionPayload.depositReceipts) { - processDepositReceipt(fork, state as CachedBeaconStateElectra, depositReceipt); + const stateElectra = state as CachedBeaconStateElectra; + const bodyElectra = body as electra.BeaconBlockBody; + + for (const elWithdrawalRequest of bodyElectra.executionPayload.withdrawalRequests) { + processExecutionLayerWithdrawalRequest(fork, state as CachedBeaconStateElectra, elWithdrawalRequest); + } + + for (const depositReceipt of bodyElectra.executionPayload.depositReceipts) { + processDepositReceipt(fork, stateElectra, depositReceipt); + } + + for (const consolidation of bodyElectra.consolidations) { + processConsolidation(stateElectra, consolidation); } } } diff --git a/packages/state-transition/src/block/processVoluntaryExit.ts b/packages/state-transition/src/block/processVoluntaryExit.ts index 80982623a447..b08aa7800884 100644 --- a/packages/state-transition/src/block/processVoluntaryExit.ts +++ b/packages/state-transition/src/block/processVoluntaryExit.ts @@ -1,7 +1,7 @@ -import {FAR_FUTURE_EPOCH} from "@lodestar/params"; +import {FAR_FUTURE_EPOCH, ForkSeq} from "@lodestar/params"; import {phase0} from "@lodestar/types"; -import {isActiveValidator} from "../util/index.js"; -import {CachedBeaconStateAllForks} from "../types.js"; +import {getPendingBalanceToWithdraw, isActiveValidator} from "../util/index.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; import {verifyVoluntaryExitSignature} from "../signatureSets/index.js"; import {initiateValidatorExit} from "./index.js"; @@ -11,16 +11,21 @@ import {initiateValidatorExit} from "./index.js"; * PERF: Work depends on number of VoluntaryExit per block. On regular networks the average is 0 / block. */ export function processVoluntaryExit( + fork: ForkSeq, state: CachedBeaconStateAllForks, signedVoluntaryExit: phase0.SignedVoluntaryExit, verifySignature = true ): void { - if (!isValidVoluntaryExit(state, signedVoluntaryExit, verifySignature)) { - throw Error("Invalid voluntary exit"); + const isValidExit = + fork >= ForkSeq.electra + ? isValidVoluntaryExitElectra(state as CachedBeaconStateElectra, signedVoluntaryExit, verifySignature) + : isValidVoluntaryExit(state, signedVoluntaryExit, verifySignature); + if (!isValidExit) { + throw Error(`Invalid voluntary exit at forkSeq=${fork}`); } const validator = state.validators.get(signedVoluntaryExit.message.validatorIndex); - initiateValidatorExit(state, validator); + initiateValidatorExit(fork, state, validator); } export function isValidVoluntaryExit( @@ -46,3 +51,16 @@ export function isValidVoluntaryExit( (!verifySignature || verifyVoluntaryExitSignature(state, signedVoluntaryExit)) ); } + +function isValidVoluntaryExitElectra( + state: CachedBeaconStateElectra, + signedVoluntaryExit: phase0.SignedVoluntaryExit, + verifySignature = true +): boolean { + // only exit validator if it has no pending withdrawals in the queue (post-Electra only) + if (getPendingBalanceToWithdraw(state, signedVoluntaryExit.message.validatorIndex) === 0) { + return isValidVoluntaryExit(state, signedVoluntaryExit, verifySignature); + } + + return false; +} diff --git a/packages/state-transition/src/block/processWithdrawals.ts b/packages/state-transition/src/block/processWithdrawals.ts index 9ae4c570e013..50113ef1741a 100644 --- a/packages/state-transition/src/block/processWithdrawals.ts +++ b/packages/state-transition/src/block/processWithdrawals.ts @@ -1,20 +1,30 @@ import {byteArrayEquals} from "@chainsafe/ssz"; import {ssz, capella} from "@lodestar/types"; import { - MAX_EFFECTIVE_BALANCE, MAX_WITHDRAWALS_PER_PAYLOAD, MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP, + ForkSeq, + MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP, + FAR_FUTURE_EPOCH, + MIN_ACTIVATION_BALANCE, } from "@lodestar/params"; import {toRootHex} from "@lodestar/utils"; -import {CachedBeaconStateCapella} from "../types.js"; -import {decreaseBalance, hasEth1WithdrawalCredential, isCapellaPayloadHeader} from "../util/index.js"; +import {CachedBeaconStateCapella, CachedBeaconStateElectra} from "../types.js"; +import { + decreaseBalance, + getValidatorMaxEffectiveBalance, + isCapellaPayloadHeader, + isFullyWithdrawableValidator, + isPartiallyWithdrawableValidator, +} from "../util/index.js"; export function processWithdrawals( - state: CachedBeaconStateCapella, + fork: ForkSeq, + state: CachedBeaconStateCapella | CachedBeaconStateElectra, payload: capella.FullOrBlindedExecutionPayload ): void { - const {withdrawals: expectedWithdrawals} = getExpectedWithdrawals(state); + const {withdrawals: expectedWithdrawals, partialWithdrawalsCount} = getExpectedWithdrawals(fork, state); const numWithdrawals = expectedWithdrawals.length; if (isCapellaPayloadHeader(payload)) { @@ -44,6 +54,11 @@ export function processWithdrawals( decreaseBalance(state, withdrawal.validatorIndex, Number(withdrawal.amount)); } + if (fork >= ForkSeq.electra) { + const stateElectra = state as CachedBeaconStateElectra; + stateElectra.pendingPartialWithdrawals = stateElectra.pendingPartialWithdrawals.sliceFrom(partialWithdrawalsCount); + } + // Update the nextWithdrawalIndex if (expectedWithdrawals.length > 0) { const latestWithdrawal = expectedWithdrawals[expectedWithdrawals.length - 1]; @@ -63,46 +78,80 @@ export function processWithdrawals( } } -export function getExpectedWithdrawals(state: CachedBeaconStateCapella): { +export function getExpectedWithdrawals( + fork: ForkSeq, + state: CachedBeaconStateCapella | CachedBeaconStateElectra +): { withdrawals: capella.Withdrawal[]; sampledValidators: number; + partialWithdrawalsCount: number; } { const epoch = state.epochCtx.epoch; let withdrawalIndex = state.nextWithdrawalIndex; const {validators, balances, nextWithdrawalValidatorIndex} = state; - const bound = Math.min(validators.length, MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP); - - let n = 0; const withdrawals: capella.Withdrawal[] = []; + + if (fork >= ForkSeq.electra) { + const stateElectra = state as CachedBeaconStateElectra; + + for (const withdrawal of stateElectra.pendingPartialWithdrawals.getAllReadonly()) { + if (withdrawal.withdrawableEpoch > epoch || withdrawals.length === MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP) { + break; + } + + const validator = validators.getReadonly(withdrawal.index); + + if ( + validator.exitEpoch === FAR_FUTURE_EPOCH && + validator.effectiveBalance >= MIN_ACTIVATION_BALANCE && + balances.get(withdrawalIndex) > MIN_ACTIVATION_BALANCE + ) { + const balanceOverMinActivationBalance = BigInt(balances.get(withdrawalIndex) - MIN_ACTIVATION_BALANCE); + const withdrawableBalance = + balanceOverMinActivationBalance < withdrawal.amount ? balanceOverMinActivationBalance : withdrawal.amount; + withdrawals.push({ + index: withdrawalIndex, + validatorIndex: withdrawal.index, + address: validator.withdrawalCredentials.subarray(12), + amount: withdrawableBalance, + }); + withdrawalIndex++; + } + } + } + + const partialWithdrawalsCount = withdrawals.length; + const bound = Math.min(validators.length, MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP); + let n = 0; // Just run a bounded loop max iterating over all withdrawals // however breaks out once we have MAX_WITHDRAWALS_PER_PAYLOAD for (n = 0; n < bound; n++) { // Get next validator in turn const validatorIndex = (nextWithdrawalValidatorIndex + n) % validators.length; - // It's most likely for validators to not have set eth1 credentials, than having 0 balance const validator = validators.getReadonly(validatorIndex); - if (!hasEth1WithdrawalCredential(validator.withdrawalCredentials)) { + const balance = balances.get(validatorIndex); + // early skip for balance = 0 as its now more likely that validator has exited/slahed with + // balance zero than not have withdrawal credentials set + if (balance === 0) { continue; } - const balance = balances.get(validatorIndex); - - if (balance > 0 && validator.withdrawableEpoch <= epoch) { + if (isFullyWithdrawableValidator(fork, validator, balance, epoch)) { withdrawals.push({ index: withdrawalIndex, validatorIndex, - address: validator.withdrawalCredentials.slice(12), + address: validator.withdrawalCredentials.subarray(12), amount: BigInt(balance), }); withdrawalIndex++; - } else if (validator.effectiveBalance === MAX_EFFECTIVE_BALANCE && balance > MAX_EFFECTIVE_BALANCE) { + } else if (isPartiallyWithdrawableValidator(fork, validator, balance)) { withdrawals.push({ index: withdrawalIndex, validatorIndex, - address: validator.withdrawalCredentials.slice(12), - amount: BigInt(balance - MAX_EFFECTIVE_BALANCE), + address: validator.withdrawalCredentials.subarray(12), + amount: BigInt(balance - getValidatorMaxEffectiveBalance(validator.withdrawalCredentials)), }); withdrawalIndex++; } @@ -113,5 +162,5 @@ export function getExpectedWithdrawals(state: CachedBeaconStateCapella): { } } - return {withdrawals, sampledValidators: n}; + return {withdrawals, sampledValidators: n, partialWithdrawalsCount}; } diff --git a/packages/state-transition/src/block/slashValidator.ts b/packages/state-transition/src/block/slashValidator.ts index 9f3eb2947644..c4b7d5f848ea 100644 --- a/packages/state-transition/src/block/slashValidator.ts +++ b/packages/state-transition/src/block/slashValidator.ts @@ -6,11 +6,13 @@ import { MIN_SLASHING_PENALTY_QUOTIENT, MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR, MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX, + MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA, PROPOSER_REWARD_QUOTIENT, PROPOSER_WEIGHT, TIMELY_TARGET_FLAG_INDEX, WEIGHT_DENOMINATOR, WHISTLEBLOWER_REWARD_QUOTIENT, + WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA, } from "@lodestar/params"; import {decreaseBalance, increaseBalance} from "../util/index.js"; @@ -31,7 +33,7 @@ export function slashValidator( const validator = state.validators.get(slashedIndex); // TODO: Bellatrix initiateValidatorExit validators.update() with the one below - initiateValidatorExit(state, validator); + initiateValidatorExit(fork, state, validator); validator.slashed = true; validator.withdrawableEpoch = Math.max(validator.withdrawableEpoch, epoch + EPOCHS_PER_SLASHINGS_VECTOR); @@ -41,7 +43,7 @@ export function slashValidator( // state.slashings is initially a Gwei (BigInt) vector, however since Nov 2023 it's converted to UintNum64 (number) vector in the state transition because: // - state.slashings[nextEpoch % EPOCHS_PER_SLASHINGS_VECTOR] is reset per epoch in processSlashingsReset() // - max slashed validators per epoch is SLOTS_PER_EPOCH * MAX_ATTESTER_SLASHINGS * MAX_VALIDATORS_PER_COMMITTEE which is 32 * 2 * 2048 = 131072 on mainnet - // - with that and 32_000_000_000 MAX_EFFECTIVE_BALANCE, it still fits in a number given that Math.floor(Number.MAX_SAFE_INTEGER / 32_000_000_000) = 281474 + // - with that and 32_000_000_000 MAX_EFFECTIVE_BALANCE or 2048_000_000_000 MAX_EFFECTIVE_BALANCE_ELECTRA, it still fits in a number given that Math.floor(Number.MAX_SAFE_INTEGER / 32_000_000_000) = 281474 // - we don't need to compute the total slashings from state.slashings, it's handled by totalSlashingsByIncrement in EpochCache const slashingIndex = epoch % EPOCHS_PER_SLASHINGS_VECTOR; state.slashings.set(slashingIndex, (state.slashings.get(slashingIndex) ?? 0) + effectiveBalance); @@ -52,11 +54,16 @@ export function slashValidator( ? MIN_SLASHING_PENALTY_QUOTIENT : fork === ForkSeq.altair ? MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR - : MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX; + : fork < ForkSeq.electra // no change from bellatrix to deneb + ? MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX + : MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA; decreaseBalance(state, slashedIndex, Math.floor(effectiveBalance / minSlashingPenaltyQuotient)); // apply proposer and whistleblower rewards - const whistleblowerReward = Math.floor(effectiveBalance / WHISTLEBLOWER_REWARD_QUOTIENT); + const whistleblowerReward = + fork < ForkSeq.electra + ? Math.floor(effectiveBalance / WHISTLEBLOWER_REWARD_QUOTIENT) + : Math.floor(effectiveBalance / WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA); const proposerReward = fork === ForkSeq.phase0 ? Math.floor(whistleblowerReward / PROPOSER_REWARD_QUOTIENT) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index a7433e848a44..538f00dd91c7 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -180,6 +180,7 @@ export class EpochCache { * initiateValidatorExit(). This value may vary on each fork of the state. * * NOTE: Changes block to block + * NOTE: No longer used by initiateValidatorExit post-electra */ exitQueueEpoch: Epoch; /** @@ -187,6 +188,7 @@ export class EpochCache { * initiateValidatorExit(). This value may vary on each fork of the state. * * NOTE: Changes block to block + * NOTE: No longer used by initiateValidatorExit post-electra */ exitQueueChurn: number; diff --git a/packages/state-transition/src/cache/epochTransitionCache.ts b/packages/state-transition/src/cache/epochTransitionCache.ts index e6f84de6c62e..280524ec7beb 100644 --- a/packages/state-transition/src/cache/epochTransitionCache.ts +++ b/packages/state-transition/src/cache/epochTransitionCache.ts @@ -1,6 +1,6 @@ import {Epoch, ValidatorIndex} from "@lodestar/types"; import {intDiv} from "@lodestar/utils"; -import {EPOCHS_PER_SLASHINGS_VECTOR, FAR_FUTURE_EPOCH, ForkSeq, MAX_EFFECTIVE_BALANCE} from "@lodestar/params"; +import {EPOCHS_PER_SLASHINGS_VECTOR, FAR_FUTURE_EPOCH, ForkSeq, MIN_ACTIVATION_BALANCE} from "@lodestar/params"; import { hasMarkers, @@ -78,7 +78,7 @@ export interface EpochTransitionCache { /** * Indices of validators that just joined and will be eligible for the active queue. * ``` - * v.activationEligibilityEpoch === FAR_FUTURE_EPOCH && v.effectiveBalance === MAX_EFFECTIVE_BALANCE + * v.activationEligibilityEpoch === FAR_FUTURE_EPOCH && v.effectiveBalance >= MAX_EFFECTIVE_BALANCE * ``` * All validators in indicesEligibleForActivationQueue get activationEligibilityEpoch set. So it can only include * validators that have just joined the registry through a valid full deposit(s). @@ -297,12 +297,12 @@ export function beforeProcessEpoch( // def is_eligible_for_activation_queue(validator: Validator) -> bool: // return ( // validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH - // and validator.effective_balance == MAX_EFFECTIVE_BALANCE + // and validator.effective_balance >= MAX_EFFECTIVE_BALANCE # [Modified in Electra] // ) // ``` if ( validator.activationEligibilityEpoch === FAR_FUTURE_EPOCH && - validator.effectiveBalance === MAX_EFFECTIVE_BALANCE + validator.effectiveBalance >= MIN_ACTIVATION_BALANCE ) { indicesEligibleForActivationQueue.push(i); } diff --git a/packages/state-transition/src/epoch/index.ts b/packages/state-transition/src/epoch/index.ts index b55ebe291fb9..6e736fdae2cc 100644 --- a/packages/state-transition/src/epoch/index.ts +++ b/packages/state-transition/src/epoch/index.ts @@ -11,6 +11,7 @@ import { CachedBeaconStateAltair, CachedBeaconStatePhase0, EpochTransitionCache, + CachedBeaconStateElectra, } from "../types.js"; import {BeaconStateTransitionMetrics} from "../metrics.js"; import {processEffectiveBalanceUpdates} from "./processEffectiveBalanceUpdates.js"; @@ -27,6 +28,8 @@ import {processRewardsAndPenalties} from "./processRewardsAndPenalties.js"; import {processSlashings} from "./processSlashings.js"; import {processSlashingsReset} from "./processSlashingsReset.js"; import {processSyncCommitteeUpdates} from "./processSyncCommitteeUpdates.js"; +import {processPendingBalanceDeposits} from "./processPendingBalanceDeposits.js"; +import {processPendingConsolidations} from "./processPendingConsolidations.js"; // For spec tests export {getRewardsAndPenalties} from "./processRewardsAndPenalties.js"; @@ -45,6 +48,8 @@ export { processParticipationFlagUpdates, processSyncCommitteeUpdates, processHistoricalSummariesUpdate, + processPendingBalanceDeposits, + processPendingConsolidations, }; export {computeUnrealizedCheckpoints} from "./computeUnrealizedCheckpoints.js"; @@ -65,6 +70,8 @@ export enum EpochTransitionStep { processEffectiveBalanceUpdates = "processEffectiveBalanceUpdates", processParticipationFlagUpdates = "processParticipationFlagUpdates", processSyncCommitteeUpdates = "processSyncCommitteeUpdates", + processPendingBalanceDeposits = "processPendingBalanceDeposits", + processPendingConsolidations = "processPendingConsolidations", } export function processEpoch( @@ -76,7 +83,7 @@ export function processEpoch( // state.slashings is initially a Gwei (BigInt) vector, however since Nov 2023 it's converted to UintNum64 (number) vector in the state transition because: // - state.slashings[nextEpoch % EPOCHS_PER_SLASHINGS_VECTOR] is reset per epoch in processSlashingsReset() // - max slashed validators per epoch is SLOTS_PER_EPOCH * MAX_ATTESTER_SLASHINGS * MAX_VALIDATORS_PER_COMMITTEE which is 32 * 2 * 2048 = 131072 on mainnet - // - with that and 32_000_000_000 MAX_EFFECTIVE_BALANCE, it still fits in a number given that Math.floor(Number.MAX_SAFE_INTEGER / 32_000_000_000) = 281474 + // - with that and 32_000_000_000 MAX_EFFECTIVE_BALANCE or 2048_000_000_000 MAX_EFFECTIVE_BALANCE_ELECTRA, it still fits in a number given that Math.floor(Number.MAX_SAFE_INTEGER / 32_000_000_000) = 281474 if (maxValidatorsPerStateSlashing > maxSafeValidators) { throw new Error("Lodestar does not support this network, parameters don't fit number value inside state.slashings"); } @@ -100,7 +107,7 @@ export function processEpoch( // processRewardsAndPenalties(state, cache); { const timer = metrics?.epochTransitionStepTime.startTimer({step: EpochTransitionStep.processRegistryUpdates}); - processRegistryUpdates(state, cache); + processRegistryUpdates(fork, state, cache); timer?.(); } @@ -120,11 +127,30 @@ export function processEpoch( processEth1DataReset(state, cache); + if (fork >= ForkSeq.electra) { + const stateElectra = state as CachedBeaconStateElectra; + { + const timer = metrics?.epochTransitionStepTime.startTimer({ + step: EpochTransitionStep.processPendingBalanceDeposits, + }); + processPendingBalanceDeposits(stateElectra); + timer?.(); + } + + { + const timer = metrics?.epochTransitionStepTime.startTimer({ + step: EpochTransitionStep.processPendingConsolidations, + }); + processPendingConsolidations(stateElectra); + timer?.(); + } + } + { const timer = metrics?.epochTransitionStepTime.startTimer({ step: EpochTransitionStep.processEffectiveBalanceUpdates, }); - processEffectiveBalanceUpdates(state, cache); + processEffectiveBalanceUpdates(fork, state, cache); timer?.(); } diff --git a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts index 5f1df35b7215..e83d2545ef50 100644 --- a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts +++ b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts @@ -5,9 +5,12 @@ import { HYSTERESIS_QUOTIENT, HYSTERESIS_UPWARD_MULTIPLIER, MAX_EFFECTIVE_BALANCE, + MAX_EFFECTIVE_BALANCE_ELECTRA, + MIN_ACTIVATION_BALANCE, TIMELY_TARGET_FLAG_INDEX, } from "@lodestar/params"; import {EpochTransitionCache, CachedBeaconStateAllForks, BeaconStateAltair} from "../types.js"; +import {hasCompoundingWithdrawalCredential} from "../util/electra.js"; /** Same to https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/beacon-chain.md#has_flag */ const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX; @@ -21,7 +24,11 @@ const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX; * - On normal mainnet conditions 0 validators change their effective balance * - In case of big innactivity event a medium portion of validators may have their effectiveBalance updated */ -export function processEffectiveBalanceUpdates(state: CachedBeaconStateAllForks, cache: EpochTransitionCache): void { +export function processEffectiveBalanceUpdates( + fork: ForkSeq, + state: CachedBeaconStateAllForks, + cache: EpochTransitionCache +): void { const HYSTERESIS_INCREMENT = EFFECTIVE_BALANCE_INCREMENT / HYSTERESIS_QUOTIENT; const DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER; const UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER; @@ -42,6 +49,7 @@ export function processEffectiveBalanceUpdates(state: CachedBeaconStateAllForks, // PERF: It's faster to access to get() every single element (4ms) than to convert to regular array then loop (9ms) let effectiveBalanceIncrement = effectiveBalanceIncrements[i]; let effectiveBalance = effectiveBalanceIncrement * EFFECTIVE_BALANCE_INCREMENT; + let effectiveBalanceLimit; if ( // Too big @@ -49,10 +57,20 @@ export function processEffectiveBalanceUpdates(state: CachedBeaconStateAllForks, // Too small. Check effectiveBalance < MAX_EFFECTIVE_BALANCE to prevent unnecessary updates (effectiveBalance < MAX_EFFECTIVE_BALANCE && effectiveBalance < balance - UPWARD_THRESHOLD) ) { - effectiveBalance = Math.min(balance - (balance % EFFECTIVE_BALANCE_INCREMENT), MAX_EFFECTIVE_BALANCE); // Update the state tree // Should happen rarely, so it's fine to update the tree const validator = validators.get(i); + + if (fork < ForkSeq.electra) { + effectiveBalanceLimit = MAX_EFFECTIVE_BALANCE; + } else { + // Electra or after + effectiveBalanceLimit = hasCompoundingWithdrawalCredential(validator.withdrawalCredentials) + ? MAX_EFFECTIVE_BALANCE_ELECTRA + : MIN_ACTIVATION_BALANCE; + } + + effectiveBalance = Math.min(balance - (balance % EFFECTIVE_BALANCE_INCREMENT), effectiveBalanceLimit); validator.effectiveBalance = effectiveBalance; // Also update the fast cached version const newEffectiveBalanceIncrement = Math.floor(effectiveBalance / EFFECTIVE_BALANCE_INCREMENT); diff --git a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts new file mode 100644 index 000000000000..95928d66df2d --- /dev/null +++ b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts @@ -0,0 +1,35 @@ +import {CachedBeaconStateElectra} from "../types.js"; +import {increaseBalance} from "../util/balance.js"; +import {getActivationExitChurnLimit} from "../util/validator.js"; + +/** + * Starting from Electra: + * Process pending balance deposits from state subject to churn limit and depsoitBalanceToConsume. + * For each eligible `deposit`, call `increaseBalance()`. + * Remove the processed deposits from `state.pendingBalanceDeposits`. + * Update `state.depositBalanceToConsume` for the next epoch + */ +export function processPendingBalanceDeposits(state: CachedBeaconStateElectra): void { + const availableForProcessing = state.depositBalanceToConsume + BigInt(getActivationExitChurnLimit(state)); + let processedAmount = 0n; + let nextDepositIndex = 0; + + for (const deposit of state.pendingBalanceDeposits.getAllReadonly()) { + const {amount} = deposit; + if (processedAmount + amount > availableForProcessing) { + break; + } + increaseBalance(state, deposit.index, Number(amount)); + processedAmount = processedAmount + amount; + nextDepositIndex++; + } + + const remainingPendingBalanceDeposits = state.pendingBalanceDeposits.sliceFrom(nextDepositIndex); + state.pendingBalanceDeposits = remainingPendingBalanceDeposits; + + if (remainingPendingBalanceDeposits.length === 0) { + state.depositBalanceToConsume = 0n; + } else { + state.depositBalanceToConsume = availableForProcessing - processedAmount; + } +} diff --git a/packages/state-transition/src/epoch/processPendingConsolidations.ts b/packages/state-transition/src/epoch/processPendingConsolidations.ts new file mode 100644 index 000000000000..e025a454f64e --- /dev/null +++ b/packages/state-transition/src/epoch/processPendingConsolidations.ts @@ -0,0 +1,45 @@ +import {CachedBeaconStateElectra} from "../types.js"; +import {decreaseBalance, increaseBalance} from "../util/balance.js"; +import {getActiveBalance} from "../util/validator.js"; +import {switchToCompoundingValidator} from "../util/electra.js"; + +/** + * Starting from Electra: + * Process every `pendingConsolidation` in `state.pendingConsolidations`. + * Churn limit was applied when enqueueing so we don't care about the limit here + * However we only process consolidations up to current epoch + * + * For each valid `pendingConsolidation`, update withdrawal credential of target + * validator to compounding, decrease balance of source validator and increase balance + * of target validator. + * + * Dequeue all processed consolidations from `state.pendingConsolidation` + * + */ +export function processPendingConsolidations(state: CachedBeaconStateElectra): void { + let nextPendingConsolidation = 0; + + for (const pendingConsolidation of state.pendingConsolidations.getAllReadonly()) { + const {sourceIndex, targetIndex} = pendingConsolidation; + const sourceValidator = state.validators.getReadonly(sourceIndex); + + if (sourceValidator.slashed) { + nextPendingConsolidation++; + continue; + } + + if (sourceValidator.withdrawableEpoch > state.epochCtx.epoch) { + break; + } + // Churn any target excess active balance of target and raise its max + switchToCompoundingValidator(state, targetIndex); + // Move active balance to target. Excess balance is withdrawable. + const activeBalance = getActiveBalance(state, sourceIndex); + decreaseBalance(state, sourceIndex, activeBalance); + increaseBalance(state, targetIndex, activeBalance); + + nextPendingConsolidation++; + } + + state.pendingConsolidations = state.pendingConsolidations.sliceFrom(nextPendingConsolidation); +} diff --git a/packages/state-transition/src/epoch/processRegistryUpdates.ts b/packages/state-transition/src/epoch/processRegistryUpdates.ts index 905e7b567c01..d2e93632dabe 100644 --- a/packages/state-transition/src/epoch/processRegistryUpdates.ts +++ b/packages/state-transition/src/epoch/processRegistryUpdates.ts @@ -1,3 +1,4 @@ +import {ForkSeq} from "@lodestar/params"; import {computeActivationExitEpoch} from "../util/index.js"; import {initiateValidatorExit} from "../block/index.js"; import {EpochTransitionCache, CachedBeaconStateAllForks} from "../types.js"; @@ -16,7 +17,11 @@ import {EpochTransitionCache, CachedBeaconStateAllForks} from "../types.js"; * - indicesEligibleForActivationQueue: 0 * - indicesToEject: 0 */ -export function processRegistryUpdates(state: CachedBeaconStateAllForks, cache: EpochTransitionCache): void { +export function processRegistryUpdates( + fork: ForkSeq, + state: CachedBeaconStateAllForks, + cache: EpochTransitionCache +): void { const {epochCtx} = state; // Get the validators sub tree once for all the loop @@ -28,7 +33,7 @@ export function processRegistryUpdates(state: CachedBeaconStateAllForks, cache: for (const index of cache.indicesToEject) { // set validator exit epoch and withdrawable epoch // TODO: Figure out a way to quickly set properties on the validators tree - initiateValidatorExit(state, validators.get(index)); + initiateValidatorExit(fork, state, validators.get(index)); } // set new activation eligibilities @@ -38,7 +43,10 @@ export function processRegistryUpdates(state: CachedBeaconStateAllForks, cache: const finalityEpoch = state.finalizedCheckpoint.epoch; // this avoids an array allocation compared to `slice(0, epochCtx.activationChurnLimit)` - const len = Math.min(cache.indicesEligibleForActivation.length, epochCtx.activationChurnLimit); + const len = + fork < ForkSeq.electra + ? Math.min(cache.indicesEligibleForActivation.length, epochCtx.activationChurnLimit) + : cache.indicesEligibleForActivation.length; const activationEpoch = computeActivationExitEpoch(cache.currentEpoch); // dequeue validators for activation up to churn limit for (let i = 0; i < len; i++) { diff --git a/packages/state-transition/src/signatureSets/consolidation.ts b/packages/state-transition/src/signatureSets/consolidation.ts new file mode 100644 index 000000000000..0aef47d417a5 --- /dev/null +++ b/packages/state-transition/src/signatureSets/consolidation.ts @@ -0,0 +1,51 @@ +import {DOMAIN_CONSOLIDATION, ForkName} from "@lodestar/params"; +import {electra, ssz} from "@lodestar/types"; + +import { + computeSigningRoot, + createAggregateSignatureSetFromComponents, + ISignatureSet, + verifySignatureSet, +} from "../util/index.js"; +import {CachedBeaconStateElectra} from "../types.js"; + +export function verifyConsolidationSignature( + state: CachedBeaconStateElectra, + signedConsolidation: electra.SignedConsolidation +): boolean { + return verifySignatureSet(getConsolidationSignatureSet(state, signedConsolidation)); +} + +/** + * Extract signatures to allow validating all block signatures at once + */ +export function getConsolidationSignatureSet( + state: CachedBeaconStateElectra, + signedConsolidation: electra.SignedConsolidation +): ISignatureSet { + const {config} = state; + const {index2pubkey} = state.epochCtx; // TODO Electra: Use 6110 pubkey cache + const {sourceIndex, targetIndex} = signedConsolidation.message; + const sourcePubkey = index2pubkey[sourceIndex]; + const targetPubkey = index2pubkey[targetIndex]; + + // signatureFork for signing domain is fixed + const signatureFork = ForkName.phase0; + const domain = config.getDomainAtFork(signatureFork, DOMAIN_CONSOLIDATION); + const signingRoot = computeSigningRoot(ssz.electra.Consolidation, signedConsolidation.message, domain); + + return createAggregateSignatureSetFromComponents( + [sourcePubkey, targetPubkey], + signingRoot, + signedConsolidation.signature + ); +} + +export function getConsolidationSignatureSets( + state: CachedBeaconStateElectra, + signedBlock: electra.SignedBeaconBlock +): ISignatureSet[] { + return signedBlock.message.body.consolidations.map((consolidation) => + getConsolidationSignatureSet(state, consolidation) + ); +} diff --git a/packages/state-transition/src/signatureSets/index.ts b/packages/state-transition/src/signatureSets/index.ts index 983e131e00e6..140b607c0bcb 100644 --- a/packages/state-transition/src/signatureSets/index.ts +++ b/packages/state-transition/src/signatureSets/index.ts @@ -1,7 +1,7 @@ import {ForkSeq} from "@lodestar/params"; -import {SignedBeaconBlock, altair, capella} from "@lodestar/types"; +import {SignedBeaconBlock, altair, capella, electra} from "@lodestar/types"; import {ISignatureSet} from "../util/index.js"; -import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStateElectra} from "../types.js"; import {getSyncCommitteeSignatureSet} from "../block/processSyncCommittee.js"; import {getProposerSlashingsSignatureSets} from "./proposerSlashings.js"; import {getAttesterSlashingsSignatureSets} from "./attesterSlashings.js"; @@ -10,6 +10,7 @@ import {getBlockProposerSignatureSet} from "./proposer.js"; import {getRandaoRevealSignatureSet} from "./randao.js"; import {getVoluntaryExitsSignatureSets} from "./voluntaryExits.js"; import {getBlsToExecutionChangeSignatureSets} from "./blsToExecutionChange.js"; +import {getConsolidationSignatureSets} from "./consolidation.js"; export * from "./attesterSlashings.js"; export * from "./indexedAttestation.js"; @@ -18,6 +19,7 @@ export * from "./proposerSlashings.js"; export * from "./randao.js"; export * from "./voluntaryExits.js"; export * from "./blsToExecutionChange.js"; +export * from "./consolidation.js"; /** * Includes all signatures on the block (except the deposit signatures) for verification. @@ -69,5 +71,15 @@ export function getBlockSignatureSets( } } + if (fork >= ForkSeq.electra) { + const consolidationSignatureSets = getConsolidationSignatureSets( + state as CachedBeaconStateElectra, + signedBlock as electra.SignedBeaconBlock + ); + if (consolidationSignatureSets.length > 0) { + signatureSets.push(...consolidationSignatureSets); + } + } + return signatureSets; } diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index f41c37af94aa..760595c3a86b 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -1,7 +1,12 @@ import {ssz} from "@lodestar/types"; -import {UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; +import {FAR_FUTURE_EPOCH, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateDeneb} from "../types.js"; import {CachedBeaconStateElectra, getCachedBeaconState} from "../cache/stateCache.js"; +import { + hasCompoundingWithdrawalCredential, + queueEntireBalanceAndResetValidator, + queueExcessActiveBalance, +} from "../util/electra.js"; /** * Upgrade a state from Capella to Deneb. @@ -24,6 +29,23 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + const validatorsArr = stateElectra.validators.getAllReadonly(); + + for (let i = 0; i < validatorsArr.length; i++) { + const validator = validatorsArr[i]; + + // [EIP-7251]: add validators that are not yet active to pending balance deposits + if (validator.activationEligibilityEpoch === FAR_FUTURE_EPOCH) { + queueEntireBalanceAndResetValidator(stateElectra, i); + } + + // [EIP-7251]: Ensure early adopters of compounding credentials go through the activation churn + const withdrawalCredential = validator.withdrawalCredentials; + if (hasCompoundingWithdrawalCredential(withdrawalCredential)) { + queueExcessActiveBalance(stateElectra, i); + } + } + // Commit new added fields ViewDU to the root node stateElectra.commit(); // Clear cache to ensure the cache of deneb fields is not used by new ELECTRA fields diff --git a/packages/state-transition/src/util/electra.ts b/packages/state-transition/src/util/electra.ts new file mode 100644 index 000000000000..00c5bb183eb4 --- /dev/null +++ b/packages/state-transition/src/util/electra.ts @@ -0,0 +1,103 @@ +import { + COMPOUNDING_WITHDRAWAL_PREFIX, + FAR_FUTURE_EPOCH, + ForkSeq, + MAX_EFFECTIVE_BALANCE, + MIN_ACTIVATION_BALANCE, +} from "@lodestar/params"; +import {ValidatorIndex, phase0, ssz} from "@lodestar/types"; +import {CachedBeaconStateElectra} from "../types.js"; +import {getValidatorMaxEffectiveBalance} from "./validator.js"; +import {hasEth1WithdrawalCredential} from "./capella.js"; + +type ValidatorInfo = Pick; + +export function hasCompoundingWithdrawalCredential(withdrawalCredentials: Uint8Array): boolean { + return withdrawalCredentials[0] === COMPOUNDING_WITHDRAWAL_PREFIX; +} + +export function hasExecutionWithdrawalCredential(withdrawalCredentials: Uint8Array): boolean { + return ( + hasCompoundingWithdrawalCredential(withdrawalCredentials) || hasEth1WithdrawalCredential(withdrawalCredentials) + ); +} + +export function isFullyWithdrawableValidator( + fork: ForkSeq, + validatorCredential: ValidatorInfo, + balance: number, + epoch: number +): boolean { + const {withdrawableEpoch, withdrawalCredentials: withdrawalCredential} = validatorCredential; + + if (fork < ForkSeq.capella) { + throw new Error(`isFullyWithdrawableValidator not supported at forkSeq=${fork} < ForkSeq.capella`); + } + const hasWithdrawableCredentials = + fork >= ForkSeq.electra + ? hasExecutionWithdrawalCredential(withdrawalCredential) + : hasEth1WithdrawalCredential(withdrawalCredential); + + return hasWithdrawableCredentials && withdrawableEpoch <= epoch && balance > 0; +} + +export function isPartiallyWithdrawableValidator( + fork: ForkSeq, + validatorCredential: ValidatorInfo, + balance: number +): boolean { + const {effectiveBalance, withdrawalCredentials: withdrawalCredential} = validatorCredential; + + if (fork < ForkSeq.capella) { + throw new Error(`isPartiallyWithdrawableValidator not supported at forkSeq=${fork} < ForkSeq.capella`); + } + const hasWithdrawableCredentials = + fork >= ForkSeq.electra + ? hasExecutionWithdrawalCredential(withdrawalCredential) + : hasEth1WithdrawalCredential(withdrawalCredential); + + const validatorMaxEffectiveBalance = + fork >= ForkSeq.electra ? getValidatorMaxEffectiveBalance(withdrawalCredential) : MAX_EFFECTIVE_BALANCE; + const hasMaxEffectiveBalance = effectiveBalance === validatorMaxEffectiveBalance; + const hasExcessBalance = balance > validatorMaxEffectiveBalance; + + return hasWithdrawableCredentials && hasMaxEffectiveBalance && hasExcessBalance; +} + +export function switchToCompoundingValidator(state: CachedBeaconStateElectra, index: ValidatorIndex): void { + const validator = state.validators.get(index); + + if (hasEth1WithdrawalCredential(validator.withdrawalCredentials)) { + validator.withdrawalCredentials[0] = COMPOUNDING_WITHDRAWAL_PREFIX; + queueExcessActiveBalance(state, index); + } +} + +export function queueExcessActiveBalance(state: CachedBeaconStateElectra, index: ValidatorIndex): void { + const balance = state.balances.get(index); + if (balance > MIN_ACTIVATION_BALANCE) { + const excessBalance = balance - MIN_ACTIVATION_BALANCE; + state.balances.set(index, MIN_ACTIVATION_BALANCE); + + const pendingBalanceDeposit = ssz.electra.PendingBalanceDeposit.toViewDU({ + index, + amount: BigInt(excessBalance), + }); + state.pendingBalanceDeposits.push(pendingBalanceDeposit); + } +} + +export function queueEntireBalanceAndResetValidator(state: CachedBeaconStateElectra, index: ValidatorIndex): void { + const balance = state.balances.get(index); + state.balances.set(index, 0); + + const validator = state.validators.get(index); + validator.effectiveBalance = 0; + validator.activationEligibilityEpoch = FAR_FUTURE_EPOCH; + + const pendingBalanceDeposit = ssz.electra.PendingBalanceDeposit.toViewDU({ + index, + amount: BigInt(balance), + }); + state.pendingBalanceDeposits.push(pendingBalanceDeposit); +} diff --git a/packages/state-transition/src/util/epoch.ts b/packages/state-transition/src/util/epoch.ts index ba182f627de0..3ac77556e3cb 100644 --- a/packages/state-transition/src/util/epoch.ts +++ b/packages/state-transition/src/util/epoch.ts @@ -1,5 +1,7 @@ import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, GENESIS_EPOCH, MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params"; import {BeaconState, Epoch, Slot, SyncPeriod} from "@lodestar/types"; +import {CachedBeaconStateElectra} from "../types.js"; +import {getActivationExitChurnLimit, getConsolidationChurnLimit} from "./validator.js"; /** * Return the epoch number at the given slot. @@ -39,6 +41,60 @@ export function computeActivationExitEpoch(epoch: Epoch): Epoch { return epoch + 1 + MAX_SEED_LOOKAHEAD; } +export function computeExitEpochAndUpdateChurn(state: CachedBeaconStateElectra, exitBalance: Gwei): number { + let earliestExitEpoch = Math.max(state.earliestExitEpoch, computeActivationExitEpoch(state.epochCtx.epoch)); + const perEpochChurn = getActivationExitChurnLimit(state); + + // New epoch for exits. + let exitBalanceToConsume = + state.earliestExitEpoch < earliestExitEpoch ? perEpochChurn : Number(state.exitBalanceToConsume); + + // Exit doesn't fit in the current earliest epoch. + if (exitBalance > exitBalanceToConsume) { + const balanceToProcess = Number(exitBalance) - exitBalanceToConsume; + const additionalEpochs = Math.floor((balanceToProcess - 1) / (perEpochChurn + 1)); + earliestExitEpoch += additionalEpochs; + exitBalanceToConsume += additionalEpochs * perEpochChurn; + } + + // Consume the balance and update state variables. + state.exitBalanceToConsume = BigInt(exitBalanceToConsume) - exitBalance; + state.earliestExitEpoch = earliestExitEpoch; + + return state.earliestExitEpoch; +} + +export function computeConsolidationEpochAndUpdateChurn( + state: CachedBeaconStateElectra, + consolidationBalance: Gwei +): number { + let earliestConsolidationEpoch = Math.max( + state.earliestConsolidationEpoch, + computeActivationExitEpoch(state.epochCtx.epoch) + ); + const perEpochConsolidationChurn = getConsolidationChurnLimit(state); + + // New epoch for consolidations + let consolidationBalanceToConsume = + state.earliestConsolidationEpoch < earliestConsolidationEpoch + ? perEpochConsolidationChurn + : Number(state.consolidationBalanceToConsume); + + // Consolidation doesn't fit in the current earliest epoch. + if (consolidationBalance > consolidationBalanceToConsume) { + const balanceToProcess = Number(consolidationBalance) - consolidationBalanceToConsume; + const additionalEpochs = Math.floor((balanceToProcess - 1) / (perEpochConsolidationChurn + 1)); + earliestConsolidationEpoch += additionalEpochs; + consolidationBalanceToConsume += additionalEpochs * perEpochConsolidationChurn; + } + + // Consume the balance and update state variables. + state.consolidationBalanceToConsume = BigInt(consolidationBalanceToConsume) - consolidationBalance; + state.earliestConsolidationEpoch = earliestConsolidationEpoch; + + return state.earliestConsolidationEpoch; +} + /** * Return the current epoch of the given state. */ diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 6c700436d7f6..537edc7f976f 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -185,7 +185,7 @@ export function applyDeposits( validator.effectiveBalance = effectiveBalance; epochCtx.effectiveBalanceIncrementsSet(i, effectiveBalance); - if (validator.effectiveBalance === MAX_EFFECTIVE_BALANCE) { + if (validator.effectiveBalance >= MAX_EFFECTIVE_BALANCE) { validator.activationEligibilityEpoch = GENESIS_EPOCH; validator.activationEpoch = GENESIS_EPOCH; activatedValidatorCount++; diff --git a/packages/state-transition/src/util/index.ts b/packages/state-transition/src/util/index.ts index ba998f65b254..6a839fbe103d 100644 --- a/packages/state-transition/src/util/index.ts +++ b/packages/state-transition/src/util/index.ts @@ -24,3 +24,4 @@ export * from "./syncCommittee.js"; export * from "./validator.js"; export * from "./weakSubjectivity.js"; export * from "./deposit.js"; +export * from "./electra.js"; diff --git a/packages/state-transition/src/util/validator.ts b/packages/state-transition/src/util/validator.ts index 99f1e6fa0b19..0c8c74b2cb03 100644 --- a/packages/state-transition/src/util/validator.ts +++ b/packages/state-transition/src/util/validator.ts @@ -1,8 +1,14 @@ import {Epoch, phase0, ValidatorIndex} from "@lodestar/types"; import {intDiv} from "@lodestar/utils"; import {ChainForkConfig} from "@lodestar/config"; -import {ForkSeq} from "@lodestar/params"; -import {BeaconStateAllForks} from "../types.js"; +import { + EFFECTIVE_BALANCE_INCREMENT, + ForkSeq, + MAX_EFFECTIVE_BALANCE_ELECTRA, + MIN_ACTIVATION_BALANCE, +} from "@lodestar/params"; +import {BeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; +import {hasCompoundingWithdrawalCredential} from "./electra.js"; /** * Check if [[validator]] is active @@ -47,3 +53,48 @@ export function getActivationChurnLimit(config: ChainForkConfig, fork: ForkSeq, export function getChurnLimit(config: ChainForkConfig, activeValidatorCount: number): number { return Math.max(config.MIN_PER_EPOCH_CHURN_LIMIT, intDiv(activeValidatorCount, config.CHURN_LIMIT_QUOTIENT)); } + +/** + * Get combined churn limit of activation-exit and consolidation + */ +export function getBalanceChurnLimit(state: CachedBeaconStateElectra): number { + const churnLimitByTotalActiveBalance = Math.floor( + (state.epochCtx.totalActiveBalanceIncrements / state.config.CHURN_LIMIT_QUOTIENT) * EFFECTIVE_BALANCE_INCREMENT + ); // TODO Electra: verify calculation + + const churn = Math.max(churnLimitByTotalActiveBalance, state.config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA); + + return churn - (churn % EFFECTIVE_BALANCE_INCREMENT); +} + +export function getActivationExitChurnLimit(state: CachedBeaconStateElectra): number { + return Math.min(state.config.MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT, getBalanceChurnLimit(state)); +} + +export function getConsolidationChurnLimit(state: CachedBeaconStateElectra): number { + return getBalanceChurnLimit(state) - getActivationExitChurnLimit(state); +} + +export function getValidatorMaxEffectiveBalance(withdrawalCredentials: Uint8Array): number { + // Compounding withdrawal credential only available since Electra + if (hasCompoundingWithdrawalCredential(withdrawalCredentials)) { + return MAX_EFFECTIVE_BALANCE_ELECTRA; + } else { + return MIN_ACTIVATION_BALANCE; + } +} + +export function getActiveBalance(state: CachedBeaconStateElectra, validatorIndex: ValidatorIndex): number { + const validatorMaxEffectiveBalance = getValidatorMaxEffectiveBalance( + state.validators.getReadonly(validatorIndex).withdrawalCredentials + ); + + return Math.min(state.balances.get(validatorIndex), validatorMaxEffectiveBalance); +} + +export function getPendingBalanceToWithdraw(state: CachedBeaconStateElectra, validatorIndex: ValidatorIndex): number { + return state.pendingPartialWithdrawals + .getAllReadonly() + .filter((item) => item.index === validatorIndex) + .reduce((total, item) => total + Number(item.amount), 0); +} diff --git a/packages/state-transition/test/perf/analyzeEpochs.ts b/packages/state-transition/test/perf/analyzeEpochs.ts index 6f61bc81abbc..deb0861427bf 100644 --- a/packages/state-transition/test/perf/analyzeEpochs.ts +++ b/packages/state-transition/test/perf/analyzeEpochs.ts @@ -152,6 +152,9 @@ async function analyzeEpochs(network: NetworkName, fromEpoch?: number): Promise< // processRegistryUpdates: function of registry updates // processSlashingsAllForks: function of process.indicesToSlash // processSlashingsReset: free + // -- electra + // processPendingBalanceDeposits: - + // processPendingConsolidations: - // -- altair // processInactivityUpdates: - // processParticipationFlagUpdates: - diff --git a/packages/state-transition/test/perf/block/processWithdrawals.test.ts b/packages/state-transition/test/perf/block/processWithdrawals.test.ts index 997f401d32ce..66d624b39bfd 100644 --- a/packages/state-transition/test/perf/block/processWithdrawals.test.ts +++ b/packages/state-transition/test/perf/block/processWithdrawals.test.ts @@ -1,4 +1,5 @@ import {itBench} from "@dapplion/benchmark"; +import {ForkSeq} from "@lodestar/params"; import {CachedBeaconStateCapella} from "../../../src/index.js"; import {getExpectedWithdrawals} from "../../../src/block/processWithdrawals.js"; import {numValidators} from "../util.js"; @@ -9,7 +10,7 @@ import {getExpectedWithdrawalsTestData, WithdrawalOpts} from "../../utils/capell // having BLS withdrawal credential prefix as that validator probe is wasted. // // Best case: -// All Validator have balances > MAX_EFFECTIVE_BALANCE and ETH1 withdrawal credential prefix set +// All Validator have balances > MAX_EFFECTIVE_BALANCE and ETH1 withdrawal credential prefix set // TODO Electra: Not true anymore // // Worst case: // All balances are low enough or withdrawal credential not set @@ -69,7 +70,7 @@ describe("getExpectedWithdrawals", () => { return opts.cache ? state : state.clone(true); }, fn: (state) => { - const {sampledValidators} = getExpectedWithdrawals(state); + const {sampledValidators} = getExpectedWithdrawals(ForkSeq.capella, state); // TODO Electra: Do test for electra if (sampledValidators !== opts.sampled) { throw Error(`Wrong sampledValidators ${sampledValidators} != ${opts.sampled}`); } diff --git a/packages/state-transition/test/unit/block/processWithdrawals.test.ts b/packages/state-transition/test/unit/block/processWithdrawals.test.ts index 2841da635472..7b708d108a7b 100644 --- a/packages/state-transition/test/unit/block/processWithdrawals.test.ts +++ b/packages/state-transition/test/unit/block/processWithdrawals.test.ts @@ -1,4 +1,5 @@ import {describe, it, expect} from "vitest"; +import {ForkSeq} from "@lodestar/params"; import {getExpectedWithdrawals} from "../../../src/block/processWithdrawals.js"; import {numValidators} from "../../perf/util.js"; import {getExpectedWithdrawalsTestData, WithdrawalOpts} from "../../utils/capella.js"; @@ -36,8 +37,9 @@ describe("getExpectedWithdrawals", () => { // Clone true to drop cache const state = beforeValue(() => getExpectedWithdrawalsTestData(vc, opts).clone(true)); + // TODO Electra: Add test for electra it(`getExpectedWithdrawals ${vc} ${caseID}`, () => { - const {sampledValidators, withdrawals} = getExpectedWithdrawals(state.value); + const {sampledValidators, withdrawals} = getExpectedWithdrawals(ForkSeq.capella, state.value); expect(sampledValidators).toBe(opts.sampled); expect(withdrawals.length).toBe(opts.withdrawals); }); diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 53195f30de11..26539dd61365 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -17,6 +17,10 @@ import { MAX_ATTESTATIONS_ELECTRA, MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, } from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; @@ -26,6 +30,8 @@ import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; const { + Epoch, + Gwei, UintNum64, Slot, Root, @@ -148,6 +154,23 @@ export const ExecutionPayloadHeader = new ContainerType( {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} ); +export const Consolidation = new ContainerType( + { + sourceIndex: ValidatorIndex, + targetIndex: ValidatorIndex, + epoch: Epoch, + }, + {typeName: "Consolidation", jsonCase: "eth2"} +); + +export const SignedConsolidation = new ContainerType( + { + message: Consolidation, + signature: BLSSignature, + }, + {typeName: "SignedConsolidation", jsonCase: "eth2"} +); + // We have to preserve Fields ordering while changing the type of ExecutionPayload export const BeaconBlockBody = new ContainerType( { @@ -163,6 +186,7 @@ export const BeaconBlockBody = new ContainerType( executionPayload: ExecutionPayload, // Modified in ELECTRA blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, + consolidations: new ListCompositeType(SignedConsolidation, MAX_CONSOLIDATIONS), // [New in Electra] }, {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); @@ -243,8 +267,32 @@ export const ExecutionPayloadAndBlobsBundle = new ContainerType( {typeName: "ExecutionPayloadAndBlobsBundle", jsonCase: "eth2"} ); -// We don't spread deneb.BeaconState fields since we need to replace -// latestExecutionPayloadHeader and we cannot keep order doing that +export const PendingBalanceDeposit = new ContainerType( + { + index: ValidatorIndex, + amount: Gwei, + }, + {typeName: "PendingBalanceDeposit", jsonCase: "eth2"} +); + +export const PartialWithdrawal = new ContainerType( + { + index: ValidatorIndex, + amount: Gwei, + withdrawableEpoch: Epoch, + }, + {typeName: "PartialWithdrawal", jsonCase: "eth2"} +); + +export const PendingConsolidation = new ContainerType( + { + sourceIndex: ValidatorIndex, + targetIndex: ValidatorIndex, + }, + {typeName: "PendingConsolidation", jsonCase: "eth2"} +); + +// In EIP-7251, we spread deneb fields as new fields are appended at the end export const BeaconState = new ContainerType( { genesisTime: UintNum64, @@ -288,6 +336,14 @@ export const BeaconState = new ContainerType( // Deep history valid from Capella onwards historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, depositReceiptsStartIndex: UintBn64, // New in ELECTRA + depositBalanceToConsume: Gwei, // [New in Electra] + exitBalanceToConsume: Gwei, // [New in Electra] + earliestExitEpoch: Epoch, // [New in Electra] + consolidationBalanceToConsume: Gwei, // [New in Electra] + earliestConsolidationEpoch: Epoch, // [New in Electra] + pendingBalanceDeposits: new ListCompositeType(PendingBalanceDeposit, PENDING_BALANCE_DEPOSITS_LIMIT), // [New in Electra] + pendingPartialWithdrawals: new ListCompositeType(PartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT), // [New in Electra] + pendingConsolidations: new ListCompositeType(PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT), // [New in Electra] }, {typeName: "BeaconState", jsonCase: "eth2"} ); diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index d1d0109e6ae6..4de209b48960 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -42,3 +42,10 @@ export type LightClientUpdate = ValueOf; export type LightClientFinalityUpdate = ValueOf; export type LightClientOptimisticUpdate = ValueOf; export type LightClientStore = ValueOf; + +export type Consolidation = ValueOf; +export type SignedConsolidation = ValueOf; + +export type PendingBalanceDeposit = ValueOf; +export type PartialWithdrawal = ValueOf; +export type PendingConsolidation = ValueOf; diff --git a/packages/types/src/phase0/sszTypes.ts b/packages/types/src/phase0/sszTypes.ts index 9eb2a13e5fae..4a04701b789d 100644 --- a/packages/types/src/phase0/sszTypes.ts +++ b/packages/types/src/phase0/sszTypes.ts @@ -236,7 +236,7 @@ export const RandaoMixes = new VectorCompositeType(Bytes32, EPOCHS_PER_HISTORICA * This is initially a Gwei (BigInt) vector, however since Nov 2023 it's converted to UintNum64 (number) vector in the state transition because: * - state.slashings[nextEpoch % EPOCHS_PER_SLASHINGS_VECTOR] is reset per epoch in processSlashingsReset() * - max slashed validators per epoch is SLOTS_PER_EPOCH * MAX_ATTESTER_SLASHINGS * MAX_VALIDATORS_PER_COMMITTEE which is 32 * 2 * 2048 = 131072 on mainnet - * - with that and 32_000_000_000 MAX_EFFECTIVE_BALANCE, it still fits in a number given that Math.floor(Number.MAX_SAFE_INTEGER / 32_000_000_000) = 281474 + * - with that and 32_000_000_000 MAX_EFFECTIVE_BALANCE or 2048_000_000_000 MAX_EFFECTIVE_BALANCE_ELECTRA, it still fits in a number given that Math.floor(Number.MAX_SAFE_INTEGER / 32_000_000_000) = 281474 * - we don't need to compute the total slashings from state.slashings, it's handled by totalSlashingsByIncrement in EpochCache */ export const Slashings = new VectorBasicType(UintNum64, EPOCHS_PER_SLASHINGS_VECTOR); diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index ff1c8c0fdc25..3a497555361a 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -227,5 +227,16 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Tue, 7 May 2024 22:11:51 +0300 Subject: [PATCH 019/259] feat: beacon node process electra attestations EIP-7549 (#6738) * Process attestations in block * Fix check-types * Address comments --- .../src/chain/blocks/importBlock.ts | 4 +- .../test/spec/presets/fork_choice.test.ts | 5 +- .../src/block/processAttestationPhase0.ts | 60 +++++++++---- .../src/block/processAttestations.ts | 4 +- .../src/block/processAttestationsAltair.ts | 7 +- .../state-transition/src/cache/epochCache.ts | 90 ++++++++++++++++--- .../src/signatureSets/indexedAttestation.ts | 6 +- 7 files changed, 139 insertions(+), 37 deletions(-) diff --git a/packages/beacon-node/src/chain/blocks/importBlock.ts b/packages/beacon-node/src/chain/blocks/importBlock.ts index 360a3f8f5db9..de5ecf607d95 100644 --- a/packages/beacon-node/src/chain/blocks/importBlock.ts +++ b/packages/beacon-node/src/chain/blocks/importBlock.ts @@ -69,6 +69,7 @@ export async function importBlock( const prevFinalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch; const blockDelaySec = (fullyVerifiedBlock.seenTimestampSec - postState.genesisTime) % this.config.SECONDS_PER_SLOT; const recvToValLatency = Date.now() / 1000 - (opts.seenTimestampSec ?? Date.now() / 1000); + const fork = this.config.getForkSeq(blockSlot); // this is just a type assertion since blockinput with dataPromise type will not end up here if (blockInput.type === BlockInputType.dataPromise) { @@ -120,7 +121,8 @@ export async function importBlock( for (const attestation of attestations) { try { - const indexedAttestation = postState.epochCtx.getIndexedAttestation(attestation); + // TODO Electra: figure out how to reuse the attesting indices computed from state transition + const indexedAttestation = postState.epochCtx.getIndexedAttestation(fork, attestation); const {target, beaconBlockRoot} = attestation.data; const attDataRoot = toRootHex(ssz.phase0.AttestationData.hashTreeRoot(indexedAttestation.data)); 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 92862c6cb03b..01adcc77500b 100644 --- a/packages/beacon-node/test/spec/presets/fork_choice.test.ts +++ b/packages/beacon-node/test/spec/presets/fork_choice.test.ts @@ -137,7 +137,10 @@ const forkChoiceTest = if (!attestation) throw Error(`No attestation ${step.attestation}`); const headState = chain.getHeadState(); const attDataRootHex = toHexString(ssz.phase0.AttestationData.hashTreeRoot(attestation.data)); - chain.forkChoice.onAttestation(headState.epochCtx.getIndexedAttestation(attestation), attDataRootHex); + chain.forkChoice.onAttestation( + headState.epochCtx.getIndexedAttestation(ForkSeq[fork], attestation), + attDataRootHex + ); } // attester slashing step diff --git a/packages/state-transition/src/block/processAttestationPhase0.ts b/packages/state-transition/src/block/processAttestationPhase0.ts index 95fc575003ee..c7c6b3b531a8 100644 --- a/packages/state-transition/src/block/processAttestationPhase0.ts +++ b/packages/state-transition/src/block/processAttestationPhase0.ts @@ -1,7 +1,7 @@ -import {Slot, phase0, ssz} from "@lodestar/types"; - -import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH, ForkSeq} from "@lodestar/params"; import {toRootHex} from "@lodestar/utils"; +import {Slot, allForks, electra, phase0, ssz} from "@lodestar/types"; +import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH, ForkSeq} from "@lodestar/params"; +import {assert} from "@lodestar/utils"; import {computeEpochAtSlot} from "../util/index.js"; import {CachedBeaconStatePhase0, CachedBeaconStateAllForks} from "../types.js"; import {isValidIndexedAttestation} from "./index.js"; @@ -51,7 +51,7 @@ export function processAttestationPhase0( state.previousEpochAttestations.push(pendingAttestation); } - if (!isValidIndexedAttestation(state, epochCtx.getIndexedAttestation(attestation), verifySignature)) { + if (!isValidIndexedAttestation(state, epochCtx.getIndexedAttestation(ForkSeq.phase0, attestation), verifySignature)) { throw new Error("Attestation is not valid"); } } @@ -59,19 +59,14 @@ export function processAttestationPhase0( export function validateAttestation( fork: ForkSeq, state: CachedBeaconStateAllForks, - attestation: phase0.Attestation + attestation: allForks.Attestation ): void { const {epochCtx} = state; const slot = state.slot; const data = attestation.data; const computedEpoch = computeEpochAtSlot(data.slot); const committeeCount = epochCtx.getCommitteeCountPerSlot(computedEpoch); - if (!(data.index < committeeCount)) { - throw new Error( - "Attestation committee index not within current committee count: " + - `committeeIndex=${data.index} committeeCount=${committeeCount}` - ); - } + if (!(data.target.epoch === epochCtx.previousShuffling.epoch || data.target.epoch === epochCtx.epoch)) { throw new Error( "Attestation target epoch not in previous or current epoch: " + @@ -93,12 +88,45 @@ export function validateAttestation( ); } - const committee = epochCtx.getBeaconCommittee(data.slot, data.index); - if (attestation.aggregationBits.bitLen !== committee.length) { - throw new Error( - "Attestation aggregation bits length does not match committee length: " + - `aggregationBitsLength=${attestation.aggregationBits.bitLen} committeeLength=${committee.length}` + if (fork >= ForkSeq.electra) { + assert.equal(data.index, 0, `AttestationData.index must be zero: index=${data.index}`); + const attestationElectra = attestation as electra.Attestation; + const committeeBitsLength = attestationElectra.committeeBits.bitLen; + + if (committeeBitsLength > committeeCount) { + throw new Error( + `Attestation committee bits length are longer than number of committees: committeeBitsLength=${committeeBitsLength} numCommittees=${committeeCount}` + ); + } + + // TODO Electra: this should be obsolete soon when the spec switches to committeeIndices + const committeeIndices = attestationElectra.committeeBits.getTrueBitIndexes(); + + // Get total number of attestation participant of every committee specified + const participantCount = committeeIndices + .map((committeeIndex) => epochCtx.getBeaconCommittee(data.slot, committeeIndex).length) + .reduce((acc, committeeSize) => acc + committeeSize, 0); + + assert.equal( + attestationElectra.aggregationBits.bitLen, + participantCount, + `Attestation aggregation bits length does not match total number of committee participant aggregationBitsLength=${attestation.aggregationBits.bitLen} participantCount=${participantCount}` ); + } else { + if (!(data.index < committeeCount)) { + throw new Error( + "Attestation committee index not within current committee count: " + + `committeeIndex=${data.index} committeeCount=${committeeCount}` + ); + } + + const committee = epochCtx.getBeaconCommittee(data.slot, data.index); + if (attestation.aggregationBits.bitLen !== committee.length) { + throw new Error( + "Attestation aggregation bits length does not match committee length: " + + `aggregationBitsLength=${attestation.aggregationBits.bitLen} committeeLength=${committee.length}` + ); + } } } diff --git a/packages/state-transition/src/block/processAttestations.ts b/packages/state-transition/src/block/processAttestations.ts index 2b132fa22e0b..991ba5621905 100644 --- a/packages/state-transition/src/block/processAttestations.ts +++ b/packages/state-transition/src/block/processAttestations.ts @@ -1,4 +1,4 @@ -import {phase0} from "@lodestar/types"; +import {allForks} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../types.js"; import {processAttestationPhase0} from "./processAttestationPhase0.js"; @@ -10,7 +10,7 @@ import {processAttestationsAltair} from "./processAttestationsAltair.js"; export function processAttestations( fork: ForkSeq, state: CachedBeaconStateAllForks, - attestations: phase0.Attestation[], + attestations: allForks.Attestation[], verifySignatures = true ): void { if (fork === ForkSeq.phase0) { diff --git a/packages/state-transition/src/block/processAttestationsAltair.ts b/packages/state-transition/src/block/processAttestationsAltair.ts index e37629712194..48d304c08133 100644 --- a/packages/state-transition/src/block/processAttestationsAltair.ts +++ b/packages/state-transition/src/block/processAttestationsAltair.ts @@ -1,5 +1,5 @@ import {byteArrayEquals} from "@chainsafe/ssz"; -import {Epoch, phase0} from "@lodestar/types"; +import {Epoch, allForks, phase0} from "@lodestar/types"; import {intSqrt} from "@lodestar/utils"; import { @@ -32,7 +32,7 @@ const SLOTS_PER_EPOCH_SQRT = intSqrt(SLOTS_PER_EPOCH); export function processAttestationsAltair( fork: ForkSeq, state: CachedBeaconStateAltair, - attestations: phase0.Attestation[], + attestations: allForks.Attestation[], verifySignature = true ): void { const {epochCtx} = state; @@ -49,8 +49,7 @@ export function processAttestationsAltair( validateAttestation(fork, state, attestation); // Retrieve the validator indices from the attestation participation bitfield - const committeeIndices = epochCtx.getBeaconCommittee(data.slot, data.index); - const attestingIndices = attestation.aggregationBits.intersectValues(committeeIndices); + const attestingIndices = epochCtx.getAttestingIndices(fork, attestation); // this check is done last because its the most expensive (if signature verification is toggled on) // TODO: Why should we verify an indexed attestation that we just created? If it's just for the signature diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 538f00dd91c7..71c3b3d15f1a 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -1,7 +1,17 @@ import {PublicKey} from "@chainsafe/blst"; import * as immutable from "immutable"; import {fromHexString} from "@chainsafe/ssz"; -import {BLSSignature, CommitteeIndex, Epoch, Slot, ValidatorIndex, phase0, SyncPeriod} from "@lodestar/types"; +import { + BLSSignature, + CommitteeIndex, + Epoch, + Slot, + ValidatorIndex, + phase0, + SyncPeriod, + allForks, + electra, +} from "@lodestar/types"; import {createBeaconConfig, BeaconConfig, ChainConfig} from "@lodestar/config"; import { ATTESTATION_SUBNET_COUNT, @@ -651,15 +661,47 @@ export class EpochCache { * Return the beacon committee at slot for index. */ getBeaconCommittee(slot: Slot, index: CommitteeIndex): Uint32Array { + return this.getBeaconCommittees(slot, [index]); + } + + /** + * Return a single Uint32Array representing concatted committees of indices + */ + getBeaconCommittees(slot: Slot, indices: CommitteeIndex[]): Uint32Array { + if (indices.length === 0) { + throw new Error("Attempt to get committees without providing CommitteeIndex"); + } + const slotCommittees = this.getShufflingAtSlot(slot).committees[slot % SLOTS_PER_EPOCH]; - if (index >= slotCommittees.length) { - throw new EpochCacheError({ - code: EpochCacheErrorCode.COMMITTEE_INDEX_OUT_OF_RANGE, - index, - maxIndex: slotCommittees.length, - }); + const committees = []; + + for (const index of indices) { + if (index >= slotCommittees.length) { + throw new EpochCacheError({ + code: EpochCacheErrorCode.COMMITTEE_INDEX_OUT_OF_RANGE, + index, + maxIndex: slotCommittees.length, + }); + } + committees.push(slotCommittees[index]); + } + + // Early return if only one index + if (committees.length === 1) { + return committees[0]; + } + + // Create a new Uint32Array to flatten `committees` + const totalLength = committees.reduce((acc, curr) => acc + curr.length, 0); + const result = new Uint32Array(totalLength); + + let offset = 0; + for (const committee of committees) { + result.set(committee, offset); + offset += committee.length; } - return slotCommittees[index]; + + return result; } getCommitteeCountPerSlot(epoch: Epoch): number { @@ -745,10 +787,9 @@ export class EpochCache { /** * Return the indexed attestation corresponding to ``attestation``. */ - getIndexedAttestation(attestation: phase0.Attestation): phase0.IndexedAttestation { - const {aggregationBits, data} = attestation; - const committeeIndices = this.getBeaconCommittee(data.slot, data.index); - const attestingIndices = aggregationBits.intersectValues(committeeIndices); + getIndexedAttestation(fork: ForkSeq, attestation: allForks.Attestation): allForks.IndexedAttestation { + const {data} = attestation; + const attestingIndices = this.getAttestingIndices(fork, attestation); // sort in-place attestingIndices.sort((a, b) => a - b); @@ -759,6 +800,31 @@ export class EpochCache { }; } + /** + * Return indices of validators who attestested in `attestation` + */ + getAttestingIndices(fork: ForkSeq, attestation: allForks.Attestation): number[] { + if (fork < ForkSeq.electra) { + const {aggregationBits, data} = attestation; + const validatorIndices = this.getBeaconCommittee(data.slot, data.index); + + return aggregationBits.intersectValues(validatorIndices); + } else { + const {aggregationBits, committeeBits, data} = attestation as electra.Attestation; + + // There is a naming conflict on the term `committeeIndices` + // In Lodestar it usually means a list of validator indices of participants in a committee + // In the spec it means a list of committee indices according to committeeBits + // This `committeeIndices` refers to the latter + // TODO Electra: resolve the naming conflicts + const committeeIndices = committeeBits.getTrueBitIndexes(); + + const validatorIndices = this.getBeaconCommittees(data.slot, committeeIndices); + + return aggregationBits.intersectValues(validatorIndices); + } + } + getCommitteeAssignments( epoch: Epoch, requestedValidatorIndices: ValidatorIndex[] diff --git a/packages/state-transition/src/signatureSets/indexedAttestation.ts b/packages/state-transition/src/signatureSets/indexedAttestation.ts index 9ae6627d0b56..d3decaf6406f 100644 --- a/packages/state-transition/src/signatureSets/indexedAttestation.ts +++ b/packages/state-transition/src/signatureSets/indexedAttestation.ts @@ -41,7 +41,11 @@ export function getAttestationsSignatureSets( state: CachedBeaconStateAllForks, signedBlock: SignedBeaconBlock ): ISignatureSet[] { + // TODO: figure how to get attesting indices of an attestation once per block processing return signedBlock.message.body.attestations.map((attestation) => - getIndexedAttestationSignatureSet(state, state.epochCtx.getIndexedAttestation(attestation)) + getIndexedAttestationSignatureSet( + state, + state.epochCtx.getIndexedAttestation(state.epochCtx.config.getForkSeq(signedBlock.message.slot), attestation) + ) ); } From 8e1535058a525345103fd1ce22353aa9d8a8218e Mon Sep 17 00:00:00 2001 From: g11tech Date: Wed, 8 May 2024 16:01:26 +0530 Subject: [PATCH 020/259] feat: handle the EL payload sending data in deposit requests instead of deposit receipts (#6746) --- .../beacon-node/src/execution/engine/types.ts | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 54b3a415ec98..f0701d48c5fc 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -125,7 +125,9 @@ type ExecutionPayloadResponse = ExecutionPayloadRpc | ExecutionPayloadRpcWithVal export type ExecutionPayloadBodyRpc = { transactions: DATA[]; withdrawals: WithdrawalV1[] | null | undefined; - depositReceipts: DepositReceiptV1[] | null | undefined; + // currently there is a discepancy between EL and CL field name references for deposit requests + // its likely CL receipt will be renamed to requests + depositRequests: DepositReceiptV1[] | null | undefined; withdrawalRequests: ExecutionLayerWithdrawalRequestV1[] | null | undefined; }; @@ -155,7 +157,7 @@ export type ExecutionPayloadRpc = { blobGasUsed?: QUANTITY; // DENEB excessBlobGas?: QUANTITY; // DENEB parentBeaconBlockRoot?: QUANTITY; // DENEB - depositReceipts?: DepositReceiptRpc[]; // ELECTRA + depositRequests?: DepositReceiptRpc[]; // ELECTRA withdrawalRequests?: ExecutionLayerWithdrawalRequestRpc[]; // ELECTRA }; @@ -231,10 +233,10 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload payload.excessBlobGas = numToQuantity(excessBlobGas); } - // ELECTRA adds depositReceipts to the ExecutionPayload + // ELECTRA adds depositReceipts/depositRequests to the ExecutionPayload if (ForkSeq[fork] >= ForkSeq.electra) { const {depositReceipts, withdrawalRequests} = data as electra.ExecutionPayload; - payload.depositReceipts = depositReceipts.map(serializeDepositReceipt); + payload.depositRequests = depositReceipts.map(serializeDepositReceipt); payload.withdrawalRequests = withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest); } @@ -324,14 +326,15 @@ export function parseExecutionPayload( } if (ForkSeq[fork] >= ForkSeq.electra) { - const {depositReceipts, withdrawalRequests} = data; + // electra adds depositRequests/depositReceipts + const {depositRequests, withdrawalRequests} = data; // Geth can also reply with null - if (depositReceipts == null) { + if (depositRequests == null) { throw Error( - `depositReceipts missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` + `depositRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` ); } - (executionPayload as electra.ExecutionPayload).depositReceipts = depositReceipts.map(deserializeDepositReceipt); + (executionPayload as electra.ExecutionPayload).depositReceipts = depositRequests.map(deserializeDepositReceipt); if (withdrawalRequests == null) { throw Error( @@ -454,7 +457,7 @@ export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | ? { transactions: data.transactions.map((tran) => dataToBytes(tran, null)), withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null, - depositReceipts: data.depositReceipts ? data.depositReceipts.map(deserializeDepositReceipt) : null, + depositReceipts: data.depositRequests ? data.depositRequests.map(deserializeDepositReceipt) : null, withdrawalRequests: data.withdrawalRequests ? data.withdrawalRequests.map(deserializeExecutionLayerWithdrawalRequest) : null, @@ -467,7 +470,7 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null) ? { transactions: data.transactions.map((tran) => bytesToData(tran)), withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null, - depositReceipts: data.depositReceipts ? data.depositReceipts.map(serializeDepositReceipt) : null, + depositRequests: data.depositReceipts ? data.depositReceipts.map(serializeDepositReceipt) : null, withdrawalRequests: data.withdrawalRequests ? data.withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest) : null, From 84cf3962de6b1cca0789c1070ce2ce3002199c91 Mon Sep 17 00:00:00 2001 From: NC Date: Wed, 8 May 2024 14:00:11 +0300 Subject: [PATCH 021/259] feat: implement EIP-7549 (#6689) * initial commit * lint * Add getAttestingIndices and update getIndexedAttestation * Update gossip validation * Update attestation gossip validation * aggregateAndProof validation * clean up * Validator * Misc * Fix the build erros * feat: get attestations for electra block (#6732) * feat: getAttestationsForBlock() for electra * chore: fix lint * fix: MAX_ATTESTATIONS_PER_GROUP_ELECTRA and address PR comments * chore: unit test aggregateConsolidation * Fix rebase mistake * Address my own comment :) --------- Co-authored-by: Navie Chan * Fix check-types * Address comments --------- Co-authored-by: Nazar Hussain Co-authored-by: tuyennhv Co-authored-by: gajinder --- packages/api/src/beacon/routes/beacon/pool.ts | 66 +++- packages/api/src/beacon/routes/events.ts | 8 +- packages/api/src/beacon/routes/validator.ts | 93 +++-- .../src/api/impl/beacon/pool/index.ts | 4 +- .../src/api/impl/validator/index.ts | 4 +- .../src/chain/blocks/importBlock.ts | 10 +- .../src/chain/errors/attestationError.ts | 12 +- .../opPools/aggregatedAttestationPool.ts | 348 ++++++++++++++---- .../src/chain/opPools/attestationPool.ts | 72 +++- .../beacon-node/src/chain/opPools/opPool.ts | 8 +- .../src/chain/validation/aggregateAndProof.ts | 33 +- .../src/chain/validation/attestation.ts | 50 ++- .../src/chain/validation/attesterSlashing.ts | 2 +- .../src/metrics/validatorMonitor.ts | 2 +- .../src/network/gossip/interface.ts | 10 +- .../beacon-node/src/network/gossip/topic.ts | 11 +- packages/beacon-node/src/network/interface.ts | 2 +- packages/beacon-node/src/network/network.ts | 2 +- .../src/network/processor/gossipHandlers.ts | 17 +- .../test/unit/api/impl/events/events.test.ts | 6 +- .../opPools/aggregatedAttestationPool.test.ts | 87 ++++- .../fork-choice/src/forkChoice/interface.ts | 2 +- .../src/signatureSets/attesterSlashings.ts | 6 +- .../src/signatureSets/index.ts | 6 +- .../validator/src/services/attestation.ts | 6 +- .../validator/src/services/validatorStore.ts | 37 +- packages/validator/src/validator.ts | 1 + .../test/unit/services/attestation.test.ts | 3 + 28 files changed, 718 insertions(+), 190 deletions(-) diff --git a/packages/api/src/beacon/routes/beacon/pool.ts b/packages/api/src/beacon/routes/beacon/pool.ts index f957390131fe..3c390aa41481 100644 --- a/packages/api/src/beacon/routes/beacon/pool.ts +++ b/packages/api/src/beacon/routes/beacon/pool.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; +import {ForkSeq} from "@lodestar/params"; import {phase0, capella, CommitteeIndex, Slot, ssz} from "@lodestar/types"; import {Schema, Endpoint, RouteDefinitions} from "../../../utils/index.js"; import { @@ -12,18 +13,24 @@ import { EmptyRequest, EmptyResponseCodec, EmptyResponseData, + WithVersion, } from "../../../utils/codecs.js"; +import {MetaHeader, VersionCodec, VersionMeta} from "../../../utils/metadata.js"; +import {toForkName} from "../../../utils/fork.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes -const AttestationListType = ArrayOf(ssz.phase0.Attestation); +const AttestationListTypePhase0 = ArrayOf(ssz.phase0.Attestation); +const AttestationListTypeElectra = ArrayOf(ssz.electra.Attestation); const AttesterSlashingListType = ArrayOf(ssz.phase0.AttesterSlashing); const ProposerSlashingListType = ArrayOf(ssz.phase0.ProposerSlashing); const SignedVoluntaryExitListType = ArrayOf(ssz.phase0.SignedVoluntaryExit); const SignedBLSToExecutionChangeListType = ArrayOf(ssz.capella.SignedBLSToExecutionChange); const SyncCommitteeMessageListType = ArrayOf(ssz.altair.SyncCommitteeMessage); -type AttestationList = ValueOf; +type AttestationListPhase0 = ValueOf; +type AttestationListElectra = ValueOf; +type AttestationList = AttestationListPhase0 | AttestationListElectra; type AttesterSlashingList = ValueOf; type ProposerSlashingList = ValueOf; type SignedVoluntaryExitList = ValueOf; @@ -40,7 +47,7 @@ export type Endpoints = { {slot?: Slot; committeeIndex?: CommitteeIndex}, {query: {slot?: number; committee_index?: number}}, AttestationList, - EmptyMeta + VersionMeta >; /** @@ -106,7 +113,7 @@ export type Endpoints = { submitPoolAttestations: Endpoint< "POST", {signedAttestations: AttestationList}, - {body: unknown}, + {body: unknown; headers: {[MetaHeader.Version]: string}}, EmptyResponseData, EmptyMeta >; @@ -172,7 +179,7 @@ export type Endpoints = { >; }; -export function getDefinitions(_config: ChainForkConfig): RouteDefinitions { +export function getDefinitions(config: ChainForkConfig): RouteDefinitions { return { getPoolAttestations: { url: "/eth/v1/beacon/pool/attestations", @@ -183,8 +190,10 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions + ForkSeq[fork] >= ForkSeq.electra ? AttestationListTypeElectra : AttestationListTypePhase0 + ), + meta: VersionCodec, }, }, getPoolAttesterSlashings: { @@ -227,12 +236,47 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({body: AttestationListType.toJson(signedAttestations)}), - parseReqJson: ({body}) => ({signedAttestations: AttestationListType.fromJson(body)}), - writeReqSsz: ({signedAttestations}) => ({body: AttestationListType.serialize(signedAttestations)}), - parseReqSsz: ({body}) => ({signedAttestations: AttestationListType.deserialize(body)}), + writeReqJson: ({signedAttestations}) => { + const fork = config.getForkName(signedAttestations[0].data.slot); + return { + body: + ForkSeq[fork] >= ForkSeq.electra + ? AttestationListTypeElectra.toJson(signedAttestations as AttestationListElectra) + : AttestationListTypePhase0.toJson(signedAttestations as AttestationListPhase0), + headers: {[MetaHeader.Version]: fork}, + }; + }, + parseReqJson: ({body, headers}) => { + const fork = toForkName(headers[MetaHeader.Version]); + return { + signedAttestations: + ForkSeq[fork] >= ForkSeq.electra + ? AttestationListTypeElectra.fromJson(body) + : AttestationListTypePhase0.fromJson(body), + }; + }, + writeReqSsz: ({signedAttestations}) => { + const fork = config.getForkName(signedAttestations[0].data.slot); + return { + body: + ForkSeq[fork] >= ForkSeq.electra + ? AttestationListTypeElectra.serialize(signedAttestations as AttestationListElectra) + : AttestationListTypePhase0.serialize(signedAttestations as AttestationListPhase0), + headers: {[MetaHeader.Version]: fork}, + }; + }, + parseReqSsz: ({body, headers}) => { + const fork = toForkName(headers[MetaHeader.Version]); + return { + signedAttestations: + ForkSeq[fork] >= ForkSeq.electra + ? AttestationListTypeElectra.deserialize(body) + : AttestationListTypePhase0.deserialize(body), + }; + }, schema: { body: Schema.ObjectArray, + headers: {[MetaHeader.Version]: Schema.String}, }, }, resp: EmptyResponseCodec, diff --git a/packages/api/src/beacon/routes/events.ts b/packages/api/src/beacon/routes/events.ts index 23be5e7c2288..04131750dbf2 100644 --- a/packages/api/src/beacon/routes/events.ts +++ b/packages/api/src/beacon/routes/events.ts @@ -104,10 +104,10 @@ export type EventData = { block: RootHex; executionOptimistic: boolean; }; - [EventType.attestation]: phase0.Attestation; + [EventType.attestation]: {version: ForkName; data: allForks.Attestation}; [EventType.voluntaryExit]: phase0.SignedVoluntaryExit; [EventType.proposerSlashing]: phase0.ProposerSlashing; - [EventType.attesterSlashing]: phase0.AttesterSlashing; + [EventType.attesterSlashing]: {version: ForkName; data: allForks.AttesterSlashing}; [EventType.blsToExecutionChange]: capella.SignedBLSToExecutionChange; [EventType.finalizedCheckpoint]: { block: RootHex; @@ -225,10 +225,10 @@ export function getTypeByEvent(): {[K in EventType]: TypeJson} { {jsonCase: "eth2"} ), - [EventType.attestation]: ssz.phase0.Attestation, + [EventType.attestation]: WithVersion((fork) => (ssz.allForks[fork] as allForks.AllForksSSZTypes).Attestation), [EventType.voluntaryExit]: ssz.phase0.SignedVoluntaryExit, [EventType.proposerSlashing]: ssz.phase0.ProposerSlashing, - [EventType.attesterSlashing]: ssz.phase0.AttesterSlashing, + [EventType.attesterSlashing]: WithVersion((fork) => ssz.allForks[fork].AttesterSlashing), [EventType.blsToExecutionChange]: ssz.capella.SignedBLSToExecutionChange, [EventType.finalizedCheckpoint]: new ContainerType( diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index 33161ec789e5..f37ec7b24488 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, fromHexString, toHexString, Type, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; -import {isForkBlobs} from "@lodestar/params"; +import {isForkBlobs, ForkSeq} from "@lodestar/params"; import { altair, BLSSignature, @@ -208,7 +208,8 @@ export const ValidatorIndicesType = ArrayOf(ssz.ValidatorIndex); export const AttesterDutyListType = ArrayOf(AttesterDutyType); export const ProposerDutyListType = ArrayOf(ProposerDutyType); export const SyncDutyListType = ArrayOf(SyncDutyType); -export const SignedAggregateAndProofListType = ArrayOf(ssz.phase0.SignedAggregateAndProof); +export const SignedAggregateAndProofListPhase0Type = ArrayOf(ssz.phase0.SignedAggregateAndProof); +export const SignedAggregateAndProofListElectaType = ArrayOf(ssz.electra.SignedAggregateAndProof); export const SignedContributionAndProofListType = ArrayOf(ssz.altair.SignedContributionAndProof); export const BeaconCommitteeSubscriptionListType = ArrayOf(BeaconCommitteeSubscriptionType); export const SyncCommitteeSubscriptionListType = ArrayOf(SyncCommitteeSubscriptionType); @@ -225,7 +226,9 @@ export type ProposerDuty = ValueOf; export type ProposerDutyList = ValueOf; export type SyncDuty = ValueOf; export type SyncDutyList = ValueOf; -export type SignedAggregateAndProofList = ValueOf; +export type SignedAggregateAndProofListPhase0 = ValueOf; +export type SignedAggregateAndProofListElecta = ValueOf; +export type SignedAggregateAndProofList = SignedAggregateAndProofListPhase0 | SignedAggregateAndProofListElecta; export type SignedContributionAndProofList = ValueOf; export type BeaconCommitteeSubscription = ValueOf; export type BeaconCommitteeSubscriptionList = ValueOf; @@ -406,10 +409,11 @@ export type Endpoints = { /** HashTreeRoot of AttestationData that validator want's aggregated */ attestationDataRoot: Root; slot: Slot; + index: number; }, - {query: {attestation_data_root: string; slot: number}}, - phase0.Attestation, - EmptyMeta + {query: {attestation_data_root: string; slot: number; index: number}}, + allForks.Attestation, + VersionMeta >; /** @@ -419,7 +423,7 @@ export type Endpoints = { publishAggregateAndProofs: Endpoint< "POST", {signedAggregateAndProofs: SignedAggregateAndProofList}, - {body: unknown}, + {body: unknown; headers: {[MetaHeader.Version]: string}}, EmptyResponseData, EmptyMeta >; @@ -536,7 +540,7 @@ export type Endpoints = { >; }; -export function getDefinitions(_config: ChainForkConfig): RouteDefinitions { +export function getDefinitions(config: ChainForkConfig): RouteDefinitions { return { getAttesterDuties: { url: "/eth/v1/validator/duties/attester/{epoch}", @@ -801,33 +805,78 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({ - query: {attestation_data_root: toHexString(attestationDataRoot), slot}, + writeReq: ({attestationDataRoot, slot, index}) => ({ + query: {attestation_data_root: toHexString(attestationDataRoot), slot, index}, + }), + parseReq: ({query}) => ({ + attestationDataRoot: fromHexString(query.attestation_data_root), + slot: query.slot, + index: query.slot, }), - parseReq: ({query}) => ({attestationDataRoot: fromHexString(query.attestation_data_root), slot: query.slot}), schema: { - query: {attestation_data_root: Schema.StringRequired, slot: Schema.UintRequired}, + query: {attestation_data_root: Schema.StringRequired, slot: Schema.UintRequired, index: Schema.UintRequired}, }, }, resp: { - data: ssz.phase0.Attestation, - meta: EmptyMetaCodec, + data: WithVersion((fork) => + ForkSeq[fork] >= ForkSeq.electra ? ssz.electra.Attestation : ssz.phase0.Attestation + ), + meta: VersionCodec, }, }, publishAggregateAndProofs: { url: "/eth/v1/validator/aggregate_and_proofs", method: "POST", req: { - writeReqJson: ({signedAggregateAndProofs}) => ({ - body: SignedAggregateAndProofListType.toJson(signedAggregateAndProofs), - }), - parseReqJson: ({body}) => ({signedAggregateAndProofs: SignedAggregateAndProofListType.fromJson(body)}), - writeReqSsz: ({signedAggregateAndProofs}) => ({ - body: SignedAggregateAndProofListType.serialize(signedAggregateAndProofs), - }), - parseReqSsz: ({body}) => ({signedAggregateAndProofs: SignedAggregateAndProofListType.deserialize(body)}), + writeReqJson: ({signedAggregateAndProofs}) => { + const fork = config.getForkName(signedAggregateAndProofs[0].message.aggregate.data.slot); + return { + body: + ForkSeq[fork] >= ForkSeq.electra + ? SignedAggregateAndProofListElectaType.toJson( + signedAggregateAndProofs as SignedAggregateAndProofListElecta + ) + : SignedAggregateAndProofListPhase0Type.toJson( + signedAggregateAndProofs as SignedAggregateAndProofListPhase0 + ), + headers: {[MetaHeader.Version]: fork}, + }; + }, + parseReqJson: ({body, headers}) => { + const fork = toForkName(headers[MetaHeader.Version]); + return { + signedAggregateAndProofs: + ForkSeq[fork] >= ForkSeq.electra + ? SignedAggregateAndProofListElectaType.fromJson(body) + : SignedAggregateAndProofListPhase0Type.fromJson(body), + }; + }, + writeReqSsz: ({signedAggregateAndProofs}) => { + const fork = config.getForkName(signedAggregateAndProofs[0].message.aggregate.data.slot); + return { + body: + ForkSeq[fork] >= ForkSeq.electra + ? SignedAggregateAndProofListElectaType.serialize( + signedAggregateAndProofs as SignedAggregateAndProofListElecta + ) + : SignedAggregateAndProofListPhase0Type.serialize( + signedAggregateAndProofs as SignedAggregateAndProofListPhase0 + ), + headers: {[MetaHeader.Version]: fork}, + }; + }, + parseReqSsz: ({body, headers}) => { + const fork = toForkName(headers[MetaHeader.Version]); + return { + signedAggregateAndProofs: + ForkSeq[fork] >= ForkSeq.electra + ? SignedAggregateAndProofListElectaType.deserialize(body) + : SignedAggregateAndProofListPhase0Type.deserialize(body), + }; + }, schema: { body: Schema.ObjectArray, + headers: {[MetaHeader.Version]: Schema.String}, }, }, resp: EmptyResponseCodec, diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index 8372b84db3b1..77f6b24f28af 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -1,7 +1,7 @@ import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; import {Epoch, ssz} from "@lodestar/types"; -import {SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; +import {ForkName, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; import {validateApiAttestation} from "../../../../chain/validation/index.js"; import {validateApiAttesterSlashing} from "../../../../chain/validation/attesterSlashing.js"; import {validateApiProposerSlashing} from "../../../../chain/validation/proposerSlashing.js"; @@ -78,7 +78,7 @@ export function getBeaconPoolApi({ metrics?.opPool.attestationPoolInsertOutcome.inc({insertOutcome}); } - chain.emitter.emit(routes.events.EventType.attestation, attestation); + chain.emitter.emit(routes.events.EventType.attestation, {data: attestation, version: ForkName.phase0}); const sentPeers = await network.publishBeaconAttestation(attestation, subnet); metrics?.onPoolSubmitUnaggregatedAttestation(seenTimestampSec, indexedAttestation, subnet, sentPeers); diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index ca0fe1ac95a2..63f860e7a193 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -814,6 +814,7 @@ export function getValidatorApi( const attEpoch = computeEpochAtSlot(slot); const headBlockRootHex = chain.forkChoice.getHead().blockRoot; const headBlockRoot = fromHex(headBlockRootHex); + const fork = config.getForkSeq(slot); const beaconBlockRoot = slot >= headSlot @@ -845,7 +846,7 @@ export function getValidatorApi( return { data: { slot, - index: committeeIndex, + index: fork >= ForkSeq.electra ? 0 : committeeIndex, beaconBlockRoot, source: attEpochState.currentJustifiedCheckpoint, target: {epoch: attEpoch, root: targetRoot}, @@ -1087,6 +1088,7 @@ export function getValidatorApi( return { data: aggregate, + version: config.getForkName(slot), }; }, diff --git a/packages/beacon-node/src/chain/blocks/importBlock.ts b/packages/beacon-node/src/chain/blocks/importBlock.ts index de5ecf607d95..fa862a2fb31e 100644 --- a/packages/beacon-node/src/chain/blocks/importBlock.ts +++ b/packages/beacon-node/src/chain/blocks/importBlock.ts @@ -409,12 +409,18 @@ export async function importBlock( } if (this.emitter.listenerCount(routes.events.EventType.attestation)) { for (const attestation of block.message.body.attestations) { - this.emitter.emit(routes.events.EventType.attestation, attestation); + this.emitter.emit(routes.events.EventType.attestation, { + version: this.config.getForkName(blockSlot), + data: attestation, + }); } } if (this.emitter.listenerCount(routes.events.EventType.attesterSlashing)) { for (const attesterSlashing of block.message.body.attesterSlashings) { - this.emitter.emit(routes.events.EventType.attesterSlashing, attesterSlashing); + this.emitter.emit(routes.events.EventType.attesterSlashing, { + version: this.config.getForkName(blockSlot), + data: attesterSlashing, + }); } } if (this.emitter.listenerCount(routes.events.EventType.proposerSlashing)) { diff --git a/packages/beacon-node/src/chain/errors/attestationError.ts b/packages/beacon-node/src/chain/errors/attestationError.ts index fa0635bc0115..d53a6f99682d 100644 --- a/packages/beacon-node/src/chain/errors/attestationError.ts +++ b/packages/beacon-node/src/chain/errors/attestationError.ts @@ -127,6 +127,14 @@ export enum AttestationErrorCode { INVALID_SERIALIZED_BYTES = "ATTESTATION_ERROR_INVALID_SERIALIZED_BYTES", /** Too many skipped slots. */ TOO_MANY_SKIPPED_SLOTS = "ATTESTATION_ERROR_TOO_MANY_SKIPPED_SLOTS", + /** + * Electra: The aggregated attestation doesn't have only one committee bit set. + */ + NOT_EXACTLY_ONE_COMMITTEE_BIT_SET = "ATTESTATION_ERROR_NOT_EXACTLY_ONE_COMMITTEE_BIT_SET", + /** + * Electra: Invalid attestationData index: is non-zero + */ + NON_ZERO_ATTESTATION_DATA_INDEX = "ATTESTATION_ERROR_NON_ZERO_ATTESTATION_DATA_INDEX", } export type AttestationErrorType = @@ -160,7 +168,9 @@ export type AttestationErrorType = | {code: AttestationErrorCode.INVALID_AGGREGATOR} | {code: AttestationErrorCode.INVALID_INDEXED_ATTESTATION} | {code: AttestationErrorCode.INVALID_SERIALIZED_BYTES} - | {code: AttestationErrorCode.TOO_MANY_SKIPPED_SLOTS; headBlockSlot: Slot; attestationSlot: Slot}; + | {code: AttestationErrorCode.TOO_MANY_SKIPPED_SLOTS; headBlockSlot: Slot; attestationSlot: Slot} + | {code: AttestationErrorCode.NOT_EXACTLY_ONE_COMMITTEE_BIT_SET} + | {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX}; export class AttestationError extends GossipActionError { getMetadata(): Record { diff --git a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts index 8277732ea1d5..d5368bcfe4fe 100644 --- a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts @@ -1,6 +1,26 @@ import {aggregateSignatures} from "@chainsafe/blst"; -import {ForkName, ForkSeq, MAX_ATTESTATIONS, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {phase0, Epoch, Slot, ssz, ValidatorIndex, RootHex} from "@lodestar/types"; +import {Signature} from "@chainsafe/bls/types"; +import {BitArray, toHexString} from "@chainsafe/ssz"; +import { + ForkName, + ForkSeq, + MAX_ATTESTATIONS, + MAX_ATTESTATIONS_ELECTRA, + MAX_COMMITTEES_PER_SLOT, + MIN_ATTESTATION_INCLUSION_DELAY, + SLOTS_PER_EPOCH, +} from "@lodestar/params"; +import { + phase0, + Epoch, + Slot, + ssz, + ValidatorIndex, + RootHex, + allForks, + electra, + isElectraAttestation, +} from "@lodestar/types"; import { CachedBeaconStateAllForks, CachedBeaconStatePhase0, @@ -19,13 +39,24 @@ type DataRootHex = string; type CommitteeIndex = number; -type AttestationWithScore = {attestation: phase0.Attestation; score: number}; +// for pre-electra +type AttestationWithScore = {attestation: allForks.Attestation; score: number}; +/** + * for electra, this is to consolidate aggregated attestations of the same attestation data into a single attestation to be included in block + * note that this is local definition in this file and it's NOT validator consolidation + */ +export type AttestationsConsolidation = { + byCommittee: Map; + attData: phase0.AttestationData; + totalNotSeenCount: number; + score: number; +}; /** - * This function returns not seen participation for a given epoch and committee. + * This function returns not seen participation for a given epoch and slot and committe index. * Return null if all validators are seen or no info to check. */ -type GetNotSeenValidatorsFn = (epoch: Epoch, committee: Uint32Array) => Set | null; +type GetNotSeenValidatorsFn = (epoch: Epoch, slot: Slot, committeeIndex: number) => Set | null; type ValidateAttestationDataFn = (attData: phase0.AttestationData) => boolean; @@ -38,14 +69,21 @@ type ValidateAttestationDataFn = (attData: phase0.AttestationData) => boolean; const MAX_RETAINED_ATTESTATIONS_PER_GROUP = 4; /** - * On mainnet, each slot has 64 committees, and each block has 128 attestations max so in average + * Pre-electra, each slot has 64 committees, and each block has 128 attestations max so in average * we get 2 attestation per groups. * Starting from Jan 2024, we have a performance issue getting attestations for a block. Based on the - * fact that lot of groups will have only 1 attestation since it's full of participation increase this number + * fact that lot of groups will have only 1 full participation attestation, increase this number * a bit higher than average. This also help decrease number of slots to search for attestations. */ const MAX_ATTESTATIONS_PER_GROUP = 3; +/** + * For electra, each block has up to 8 aggregated attestations, assuming there are 3 for the "best" + * attestation data, there are still 5 for other attestation data so this constant is still good. + * We should separate to 2 constant based on conditions of different networks + */ +const MAX_ATTESTATIONS_PER_GROUP_ELECTRA = 3; + /** * Maintain a pool of aggregated attestations. Attestations can be retrieved for inclusion in a block * or api. The returned attestations are aggregated to maximise the number of validators that can be @@ -53,20 +91,25 @@ const MAX_ATTESTATIONS_PER_GROUP = 3; * Note that we want to remove attestations with attesters that were included in the chain. */ export class AggregatedAttestationPool { - private readonly attestationGroupByDataHashByIndexBySlot = new MapDef< + /** + * post electra, different committees could have the same AttData and we have to consolidate attestations of the same + * data to be included in block, so we should group by data before index + * // TODO: make sure it does not affect performance for pre electra forks + */ + private readonly attestationGroupByIndexByDataHexBySlot = new MapDef< Slot, - Map> - >(() => new Map>()); + Map> + >(() => new Map>()); private lowestPermissibleSlot = 0; /** For metrics to track size of the pool */ getAttestationCount(): {attestationCount: number; attestationDataCount: number} { let attestationCount = 0; let attestationDataCount = 0; - for (const attestationGroupByDataByIndex of this.attestationGroupByDataHashByIndexBySlot.values()) { - for (const attestationGroupByData of attestationGroupByDataByIndex.values()) { - attestationDataCount += attestationGroupByData.size; - for (const attestationGroup of attestationGroupByData.values()) { + for (const attestationGroupByIndexByDataHex of this.attestationGroupByIndexByDataHexBySlot.values()) { + for (const attestationGroupByIndex of attestationGroupByIndexByDataHex.values()) { + attestationDataCount += attestationGroupByIndex.size; + for (const attestationGroup of attestationGroupByIndex.values()) { attestationCount += attestationGroup.getAttestationCount(); } } @@ -75,7 +118,7 @@ export class AggregatedAttestationPool { } add( - attestation: phase0.Attestation, + attestation: allForks.Attestation, dataRootHex: RootHex, attestingIndicesCount: number, committee: Uint32Array @@ -88,16 +131,24 @@ export class AggregatedAttestationPool { return InsertOutcome.Old; } - const attestationGroupByDataHashByIndex = this.attestationGroupByDataHashByIndexBySlot.getOrDefault(slot); - let attestationGroupByDataHash = attestationGroupByDataHashByIndex.get(attestation.data.index); - if (!attestationGroupByDataHash) { - attestationGroupByDataHash = new Map(); - attestationGroupByDataHashByIndex.set(attestation.data.index, attestationGroupByDataHash); + const attestationGroupByIndexByDataHash = this.attestationGroupByIndexByDataHexBySlot.getOrDefault(slot); + let attestationGroupByIndex = attestationGroupByIndexByDataHash.get(dataRootHex); + if (!attestationGroupByIndex) { + attestationGroupByIndex = new Map(); + attestationGroupByIndexByDataHash.set(dataRootHex, attestationGroupByIndex); + } + const committeeIndex = isElectraAttestation(attestation) + ? // this attestation is added to pool after validation + attestation.committeeBits.getSingleTrueBit() + : attestation.data.index; + if (committeeIndex === null) { + // this should not happen because attestation should be validated before reaching this + throw Error(`Invalid attestation slot=${slot} committeeIndex=${committeeIndex}`); } - let attestationGroup = attestationGroupByDataHash.get(dataRootHex); + let attestationGroup = attestationGroupByIndex.get(committeeIndex); if (!attestationGroup) { attestationGroup = new MatchingDataAttestationGroup(committee, attestation.data); - attestationGroupByDataHash.set(dataRootHex, attestationGroup); + attestationGroupByIndex.set(committeeIndex, attestationGroup); } return attestationGroup.add({ @@ -109,14 +160,25 @@ export class AggregatedAttestationPool { /** Remove attestations which are too old to be included in a block. */ prune(clockSlot: Slot): void { // Only retain SLOTS_PER_EPOCH slots - pruneBySlot(this.attestationGroupByDataHashByIndexBySlot, clockSlot, SLOTS_PER_EPOCH); + pruneBySlot(this.attestationGroupByIndexByDataHexBySlot, clockSlot, SLOTS_PER_EPOCH); this.lowestPermissibleSlot = Math.max(clockSlot - SLOTS_PER_EPOCH, 0); } + getAttestationsForBlock( + fork: ForkName, + forkChoice: IForkChoice, + state: CachedBeaconStateAllForks + ): allForks.Attestation[] { + const forkSeq = ForkSeq[fork]; + return forkSeq >= ForkSeq.electra + ? this.getAttestationsForBlockElectra(fork, forkChoice, state) + : this.getAttestationsForBlockPreElectra(fork, forkChoice, state); + } + /** - * Get attestations to be included in a block. Returns $MAX_ATTESTATIONS items + * Get attestations to be included in a block pre-electra. Returns up to $MAX_ATTESTATIONS items */ - getAttestationsForBlock( + getAttestationsForBlockPreElectra( fork: ForkName, forkChoice: IForkChoice, state: CachedBeaconStateAllForks @@ -130,14 +192,14 @@ export class AggregatedAttestationPool { const attestationsByScore: AttestationWithScore[] = []; - const slots = Array.from(this.attestationGroupByDataHashByIndexBySlot.keys()).sort((a, b) => b - a); + const slots = Array.from(this.attestationGroupByIndexByDataHexBySlot.keys()).sort((a, b) => b - a); let minScore = Number.MAX_SAFE_INTEGER; let slotCount = 0; slot: for (const slot of slots) { slotCount++; - const attestationGroupByDataHashByIndex = this.attestationGroupByDataHashByIndexBySlot.get(slot); + const attestationGroupByIndexByDataHash = this.attestationGroupByIndexByDataHexBySlot.get(slot); // should not happen - if (!attestationGroupByDataHashByIndex) { + if (!attestationGroupByIndexByDataHash) { throw Error(`No aggregated attestation pool for slot=${slot}`); } @@ -158,35 +220,25 @@ export class AggregatedAttestationPool { } const slotDelta = stateSlot - slot; - const shuffling = state.epochCtx.getShufflingAtEpoch(epoch); - const slotCommittees = shuffling.committees[slot % SLOTS_PER_EPOCH]; - for (const [committeeIndex, attestationGroupByData] of attestationGroupByDataHashByIndex.entries()) { - // all attestations will be validated against the state in next step so we can get committee from the state - // this is an improvement to save the notSeenValidatorsFn call for the same slot/index instead of the same attestation data - if (committeeIndex > slotCommittees.length) { - // invalid index, should not happen - continue; - } - - const committee = slotCommittees[committeeIndex]; - const notSeenAttestingIndices = notSeenValidatorsFn(epoch, committee); - if (notSeenAttestingIndices === null || notSeenAttestingIndices.size === 0) { - continue; - } + for (const attestationGroupByIndex of attestationGroupByIndexByDataHash.values()) { + for (const [committeeIndex, attestationGroup] of attestationGroupByIndex.entries()) { + const notSeenAttestingIndices = notSeenValidatorsFn(epoch, slot, committeeIndex); + if (notSeenAttestingIndices === null || notSeenAttestingIndices.size === 0) { + continue; + } - if ( - slotCount > 2 && - attestationsByScore.length >= MAX_ATTESTATIONS && - notSeenAttestingIndices.size / slotDelta < minScore - ) { - // after 2 slots, there are a good chance that we have 2 * MAX_ATTESTATIONS attestations and break the for loop early - // if not, we may have to scan all slots in the pool - // if we have enough attestations and the max possible score is lower than scores of `attestationsByScore`, we should skip - // otherwise it takes time to check attestation, add it and remove it later after the sort by score - continue; - } + if ( + slotCount > 2 && + attestationsByScore.length >= MAX_ATTESTATIONS && + notSeenAttestingIndices.size / slotDelta < minScore + ) { + // after 2 slots, there are a good chance that we have 2 * MAX_ATTESTATIONS attestations and break the for loop early + // if not, we may have to scan all slots in the pool + // if we have enough attestations and the max possible score is lower than scores of `attestationsByScore`, we should skip + // otherwise it takes time to check attestation, add it and remove it later after the sort by score + continue; + } - for (const attestationGroup of attestationGroupByData.values()) { if (!validateAttestationDataFn(attestationGroup.data)) { continue; } @@ -199,6 +251,7 @@ export class AggregatedAttestationPool { // IF they have to be validated, do it only with one attestation per group since same data // The committeeCountPerSlot can be precomputed once per slot for (const {attestation, notSeenAttesterCount} of attestationGroup.getAttestationsForBlock( + fork, notSeenAttestingIndices )) { const score = notSeenAttesterCount / slotDelta; @@ -231,23 +284,134 @@ export class AggregatedAttestationPool { return attestationsForBlock; } + /** + * Get attestations to be included in an electra block. Returns up to $MAX_ATTESTATIONS_ELECTRA items + */ + getAttestationsForBlockElectra( + fork: ForkName, + forkChoice: IForkChoice, + state: CachedBeaconStateAllForks + ): electra.Attestation[] { + const stateSlot = state.slot; + const stateEpoch = state.epochCtx.epoch; + const statePrevEpoch = stateEpoch - 1; + + const notSeenValidatorsFn = getNotSeenValidatorsFn(state); + const validateAttestationDataFn = getValidateAttestationDataFn(forkChoice, state); + + const slots = Array.from(this.attestationGroupByIndexByDataHexBySlot.keys()).sort((a, b) => b - a); + const consolidations: AttestationsConsolidation[] = []; + let minScore = Number.MAX_SAFE_INTEGER; + let slotCount = 0; + slot: for (const slot of slots) { + slotCount++; + const attestationGroupByIndexByDataHash = this.attestationGroupByIndexByDataHexBySlot.get(slot); + // should not happen + if (!attestationGroupByIndexByDataHash) { + throw Error(`No aggregated attestation pool for slot=${slot}`); + } + + const epoch = computeEpochAtSlot(slot); + // validateAttestation condition: Attestation target epoch not in previous or current epoch + if (!(epoch === stateEpoch || epoch === statePrevEpoch)) { + continue; // Invalid attestations + } + // validateAttestation condition: Attestation slot not within inclusion window + if (!(slot + MIN_ATTESTATION_INCLUSION_DELAY <= stateSlot)) { + continue; // Invalid attestations + } + + const slotDelta = stateSlot - slot; + // CommitteeIndex 0 1 2 ... Consolidation + // Attestations att00 --- att10 --- att20 --- 0 (att 00 10 20) + // att01 --- - --- att21 --- 1 (att 01 __ 21) + // - --- - --- att22 --- 2 (att __ __ 22) + for (const attestationGroupByIndex of attestationGroupByIndexByDataHash.values()) { + // sameAttDataCons could be up to MAX_ATTESTATIONS_PER_GROUP_ELECTRA + const sameAttDataCons: AttestationsConsolidation[] = []; + for (const [committeeIndex, attestationGroup] of attestationGroupByIndex.entries()) { + const notSeenAttestingIndices = notSeenValidatorsFn(epoch, slot, committeeIndex); + if (notSeenAttestingIndices === null || notSeenAttestingIndices.size === 0) { + continue; + } + + if ( + slotCount > 2 && + consolidations.length >= MAX_ATTESTATIONS_ELECTRA && + notSeenAttestingIndices.size / slotDelta < minScore + ) { + // after 2 slots, there are a good chance that we have 2 * MAX_ATTESTATIONS_ELECTRA attestations and break the for loop early + // if not, we may have to scan all slots in the pool + // if we have enough attestations and the max possible score is lower than scores of `attestationsByScore`, we should skip + // otherwise it takes time to check attestation, add it and remove it later after the sort by score + continue; + } + + if (!validateAttestationDataFn(attestationGroup.data)) { + continue; + } + + // TODO: Is it necessary to validateAttestation for: + // - Attestation committee index not within current committee count + // - Attestation aggregation bits length does not match committee length + // + // These properties should not change after being validate in gossip + // IF they have to be validated, do it only with one attestation per group since same data + // The committeeCountPerSlot can be precomputed once per slot + for (const [i, attestationNonParticipation] of attestationGroup + .getAttestationsForBlock(fork, notSeenAttestingIndices) + .entries()) { + if (sameAttDataCons[i] === undefined) { + sameAttDataCons[i] = { + byCommittee: new Map(), + attData: attestationNonParticipation.attestation.data, + totalNotSeenCount: 0, + // only update score after we have full data + score: 0, + }; + } + sameAttDataCons[i].byCommittee.set(committeeIndex, attestationNonParticipation); + sameAttDataCons[i].totalNotSeenCount += attestationNonParticipation.notSeenAttesterCount; + } + for (const consolidation of sameAttDataCons) { + const score = consolidation.totalNotSeenCount / slotDelta; + if (score < minScore) { + minScore = score; + } + consolidations.push({...consolidation, score}); + // Stop accumulating attestations there are enough that may have good scoring + if (consolidations.length >= MAX_ATTESTATIONS_ELECTRA * 2) { + break slot; + } + } + } + } + } + + const sortedConsolidationsByScore = consolidations + .sort((a, b) => b.score - a.score) + .slice(0, MAX_ATTESTATIONS_ELECTRA); + // on chain aggregation is expensive, only do it after all + return sortedConsolidationsByScore.map(aggregateConsolidation); + } + /** * Get all attestations optionally filtered by `attestation.data.slot` * @param bySlot slot to filter, `bySlot === attestation.data.slot` */ - getAll(bySlot?: Slot): phase0.Attestation[] { - let attestationGroupsArr: Map[]; + getAll(bySlot?: Slot): allForks.Attestation[] { + let attestationGroupsArr: Map[]; if (bySlot === undefined) { - attestationGroupsArr = Array.from(this.attestationGroupByDataHashByIndexBySlot.values()).flatMap((byIndex) => + attestationGroupsArr = Array.from(this.attestationGroupByIndexByDataHexBySlot.values()).flatMap((byIndex) => Array.from(byIndex.values()) ); } else { - const attestationGroupsByIndex = this.attestationGroupByDataHashByIndexBySlot.get(bySlot); + const attestationGroupsByIndex = this.attestationGroupByIndexByDataHexBySlot.get(bySlot); if (!attestationGroupsByIndex) throw Error(`No attestations for slot ${bySlot}`); attestationGroupsArr = Array.from(attestationGroupsByIndex.values()); } - const attestations: phase0.Attestation[] = []; + const attestations: allForks.Attestation[] = []; for (const attestationGroups of attestationGroupsArr) { for (const attestationGroup of attestationGroups.values()) { attestations.push(...attestationGroup.getAttestations()); @@ -258,12 +422,12 @@ export class AggregatedAttestationPool { } interface AttestationWithIndex { - attestation: phase0.Attestation; + attestation: allForks.Attestation; trueBitsCount: number; } type AttestationNonParticipant = { - attestation: phase0.Attestation; + attestation: allForks.Attestation; // this is <= attestingIndices.count since some attesters may be seen by the chain // this is only updated and used in removeBySeenValidators function notSeenAttesterCount: number; @@ -345,8 +509,9 @@ export class MatchingDataAttestationGroup { * @param notSeenAttestingIndices not seen attestting indices, i.e. indices in the same committee * @returns an array of AttestationNonParticipant */ - getAttestationsForBlock(notSeenAttestingIndices: Set): AttestationNonParticipant[] { + getAttestationsForBlock(fork: ForkName, notSeenAttestingIndices: Set): AttestationNonParticipant[] { const attestations: AttestationNonParticipant[] = []; + const forkSeq = ForkSeq[fork]; for (const {attestation} of this.attestations) { let notSeenAttesterCount = 0; const {aggregationBits} = attestation; @@ -356,22 +521,22 @@ export class MatchingDataAttestationGroup { } } - if (notSeenAttesterCount > 0) { + // if fork >= electra, should return electra-only attestations + if (notSeenAttesterCount > 0 && (forkSeq < ForkSeq.electra || isElectraAttestation(attestation))) { attestations.push({attestation, notSeenAttesterCount}); } } - if (attestations.length <= MAX_ATTESTATIONS_PER_GROUP) { + const maxAttestation = forkSeq >= ForkSeq.electra ? MAX_ATTESTATIONS_PER_GROUP_ELECTRA : MAX_ATTESTATIONS_PER_GROUP; + if (attestations.length <= maxAttestation) { return attestations; } else { - return attestations - .sort((a, b) => b.notSeenAttesterCount - a.notSeenAttesterCount) - .slice(0, MAX_ATTESTATIONS_PER_GROUP); + return attestations.sort((a, b) => b.notSeenAttesterCount - a.notSeenAttesterCount).slice(0, maxAttestation); } } /** Get attestations for API. */ - getAttestations(): phase0.Attestation[] { + getAttestations(): allForks.Attestation[] { return this.attestations.map((attestation) => attestation.attestation); } } @@ -385,6 +550,34 @@ export function aggregateInto(attestation1: AttestationWithIndex, attestation2: attestation1.attestation.signature = aggregateSignatures([signature1, signature2]).toBytes(); } +/** + * Electra and after: Block proposer consolidates attestations with the same + * attestation data from different committee into a single attestation + * https://github.com/ethereum/consensus-specs/blob/aba6345776aa876dad368cab27fbbb23fae20455/specs/_features/eip7549/validator.md?plain=1#L39 + */ +export function aggregateConsolidation({byCommittee, attData}: AttestationsConsolidation): electra.Attestation { + const committeeBits = BitArray.fromBitLen(MAX_COMMITTEES_PER_SLOT); + // TODO: can we improve this? + let aggregationBits: boolean[] = []; + const signatures: Signature[] = []; + const sortedCommittees = Array.from(byCommittee.keys()).sort((a, b) => a - b); + for (const committeeIndex of sortedCommittees) { + const attestationNonParticipation = byCommittee.get(committeeIndex); + if (attestationNonParticipation !== undefined) { + const {attestation} = attestationNonParticipation; + committeeBits.set(committeeIndex, true); + aggregationBits = [...aggregationBits, ...attestation.aggregationBits.toBoolArray()]; + signatures.push(signatureFromBytesNoCheck(attestation.signature)); + } + } + return { + aggregationBits: BitArray.fromBoolArray(aggregationBits), + data: attData, + committeeBits, + signature: aggregateSignatures(signatures).toBytes(), + }; +} + /** * Pre-compute participation from a CachedBeaconStateAllForks, for use to check if an attestation's committee * has already attested or not. @@ -407,12 +600,13 @@ export function getNotSeenValidatorsFn(state: CachedBeaconStateAllForks): GetNot state ); - return (epoch: Epoch, committee: Uint32Array) => { + return (epoch: Epoch, slot: Slot, committeeIndex: number) => { const participants = epoch === stateEpoch ? currentEpochParticipants : epoch === stateEpoch - 1 ? previousEpochParticipants : null; if (participants === null) { return null; } + const committee = state.epochCtx.getBeaconCommittee(slot, committeeIndex); const notSeenAttestingIndices = new Set(); for (const [i, validatorIndex] of committee.entries()) { @@ -434,22 +628,32 @@ export function getNotSeenValidatorsFn(state: CachedBeaconStateAllForks): GetNot const previousParticipation = altairState.previousEpochParticipation.getAll(); const currentParticipation = altairState.currentEpochParticipation.getAll(); const stateEpoch = computeEpochAtSlot(state.slot); + // this function could be called multiple times with same slot + committeeIndex + const cachedNotSeenValidators = new Map>(); - return (epoch: Epoch, committee: Uint32Array) => { + return (epoch: Epoch, slot: Slot, committeeIndex: number) => { const participationStatus = epoch === stateEpoch ? currentParticipation : epoch === stateEpoch - 1 ? previousParticipation : null; if (participationStatus === null) { return null; } + const cacheKey = slot + "_" + committeeIndex; + let notSeenAttestingIndices = cachedNotSeenValidators.get(cacheKey); + if (notSeenAttestingIndices != null) { + // if all validators are seen then return null, we don't need to check for any attestations of same committee again + return notSeenAttestingIndices.size === 0 ? null : notSeenAttestingIndices; + } - const notSeenAttestingIndices = new Set(); + const committee = state.epochCtx.getBeaconCommittee(slot, committeeIndex); + notSeenAttestingIndices = new Set(); for (const [i, validatorIndex] of committee.entries()) { // no need to check flagIsTimelySource as if validator is not seen, it's participation status is 0 if (participationStatus[validatorIndex] === 0) { notSeenAttestingIndices.add(i); } } + cachedNotSeenValidators.set(cacheKey, notSeenAttestingIndices); // if all validators are seen then return null, we don't need to check for any attestations of same committee again return notSeenAttestingIndices.size === 0 ? null : notSeenAttestingIndices; }; diff --git a/packages/beacon-node/src/chain/opPools/attestationPool.ts b/packages/beacon-node/src/chain/opPools/attestationPool.ts index 2b511598f9a4..9db73cf4a013 100644 --- a/packages/beacon-node/src/chain/opPools/attestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/attestationPool.ts @@ -1,6 +1,6 @@ import {BitArray} from "@chainsafe/ssz"; import {Signature, aggregateSignatures} from "@chainsafe/blst"; -import {phase0, Slot, RootHex} from "@lodestar/types"; +import {Slot, RootHex, allForks} from "@lodestar/types"; import {MapDef} from "@lodestar/utils"; import {IClock} from "../../util/clock.js"; import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js"; @@ -22,12 +22,16 @@ const SLOTS_RETAINED = 3; */ const MAX_ATTESTATIONS_PER_SLOT = 16_384; -type AggregateFast = { - data: phase0.Attestation["data"]; +type AggregateFastPhase0 = { + data: allForks.Attestation["data"]; aggregationBits: BitArray; signature: Signature; }; +type AggregateFastElectra = AggregateFastPhase0 & {committeeBits: BitArray}; + +type AggregateFast = AggregateFastPhase0 | AggregateFastElectra; + /** Hex string of DataRoot `TODO` */ type DataRootHex = string; @@ -92,7 +96,7 @@ export class AttestationPool { * - Valid committeeIndex * - Valid data */ - add(attestation: phase0.Attestation, attDataRootHex: RootHex): InsertOutcome { + add(attestation: allForks.Attestation, attDataRootHex: RootHex): InsertOutcome { const slot = attestation.data.slot; const lowestPermissibleSlot = this.lowestPermissibleSlot; @@ -127,7 +131,7 @@ export class AttestationPool { /** * For validator API to get an aggregate */ - getAggregate(slot: Slot, dataRootHex: RootHex): phase0.Attestation | null { + getAggregate(slot: Slot, dataRootHex: RootHex): allForks.Attestation | null { const aggregate = this.attestationByRootBySlot.get(slot)?.get(dataRootHex); if (!aggregate) { // TODO: Add metric for missing aggregates @@ -151,8 +155,8 @@ export class AttestationPool { * Get all attestations optionally filtered by `attestation.data.slot` * @param bySlot slot to filter, `bySlot === attestation.data.slot` */ - getAll(bySlot?: Slot): phase0.Attestation[] { - const attestations: phase0.Attestation[] = []; + getAll(bySlot?: Slot): allForks.Attestation[] { + const attestations: allForks.Attestation[] = []; const aggregateByRoots = bySlot === undefined @@ -177,7 +181,7 @@ export class AttestationPool { /** * Aggregate a new contribution into `aggregate` mutating it */ -function aggregateAttestationInto(aggregate: AggregateFast, attestation: phase0.Attestation): InsertOutcome { +function aggregateAttestationInto(aggregate: AggregateFast, attestation: allForks.Attestation): InsertOutcome { const bitIndex = attestation.aggregationBits.getSingleTrueBit(); // Should never happen, attestations are verified against this exact condition before @@ -185,6 +189,26 @@ function aggregateAttestationInto(aggregate: AggregateFast, attestation: phase0. throw Error("Invalid attestation not exactly one bit set"); } + if ("committeeBits" in attestation && !("committeeBits" in aggregate)) { + throw Error("Attempt to aggregate electra attestation into phase0 attestation"); + } + + if (!("committeeBits" in attestation) && "committeeBits" in aggregate) { + throw Error("Attempt to aggregate phase0 attestation into electra attestation"); + } + + if ("committeeBits" in attestation) { + // We assume attestation.committeeBits should already be validated in api and gossip handler and should be non-null + const attestationCommitteeIndex = attestation.committeeBits.getSingleTrueBit(); + const aggregateCommitteeIndex = (aggregate as AggregateFastElectra).committeeBits.getSingleTrueBit(); + + if (attestationCommitteeIndex !== aggregateCommitteeIndex) { + throw Error( + `Committee index mismatched: attestation ${attestationCommitteeIndex} aggregate ${aggregateCommitteeIndex}` + ); + } + } + if (aggregate.aggregationBits.get(bitIndex) === true) { return InsertOutcome.AlreadyKnown; } @@ -197,7 +221,16 @@ function aggregateAttestationInto(aggregate: AggregateFast, attestation: phase0. /** * Format `contribution` into an efficient `aggregate` to add more contributions in with aggregateContributionInto() */ -function attestationToAggregate(attestation: phase0.Attestation): AggregateFast { +function attestationToAggregate(attestation: allForks.Attestation): AggregateFast { + if ("committeeBits" in attestation) { + return { + data: attestation.data, + // clone because it will be mutated + aggregationBits: attestation.aggregationBits.clone(), + committeeBits: attestation.committeeBits, + signature: signatureFromBytesNoCheck(attestation.signature), + }; + } return { data: attestation.data, // clone because it will be mutated @@ -209,10 +242,19 @@ function attestationToAggregate(attestation: phase0.Attestation): AggregateFast /** * Unwrap AggregateFast to phase0.Attestation */ -function fastToAttestation(aggFast: AggregateFast): phase0.Attestation { - return { - data: aggFast.data, - aggregationBits: aggFast.aggregationBits, - signature: aggFast.signature.toBytes(), - }; +function fastToAttestation(aggFast: AggregateFast): allForks.Attestation { + if ("committeeBits" in aggFast) { + return { + data: aggFast.data, + aggregationBits: aggFast.aggregationBits, + committeeBits: aggFast.committeeBits, + signature: aggFast.signature.toBytes(), + }; + } else { + return { + data: aggFast.data, + aggregationBits: aggFast.aggregationBits, + signature: aggFast.signature.toBytes(), + }; + } } diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index a991a6e8630a..8eb3cebcffdb 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -14,6 +14,7 @@ import { BLS_WITHDRAWAL_PREFIX, MAX_ATTESTER_SLASHINGS, ForkSeq, + MAX_ATTESTER_SLASHINGS_ELECTRA, } from "@lodestar/params"; import {Epoch, phase0, capella, ssz, ValidatorIndex, SignedBeaconBlock} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; @@ -174,7 +175,7 @@ export class OpPool { blockType: BlockType, metrics: Metrics | null ): [ - phase0.AttesterSlashing[], + allForks.AttesterSlashing[], phase0.ProposerSlashing[], phase0.SignedVoluntaryExit[], capella.SignedBLSToExecutionChange[], @@ -208,7 +209,8 @@ export class OpPool { }); const endAttesterSlashings = stepsMetrics?.startTimer(); - const attesterSlashings: phase0.AttesterSlashing[] = []; + const attesterSlashings: allForks.AttesterSlashing[] = []; + const maxAttesterSlashing = stateFork >= ForkSeq.electra ? MAX_ATTESTER_SLASHINGS_ELECTRA : MAX_ATTESTER_SLASHINGS; attesterSlashing: for (const attesterSlashing of this.attesterSlashings.values()) { /** Indices slashable in this attester slashing */ const slashableIndices = new Set(); @@ -223,7 +225,7 @@ export class OpPool { if (isSlashableAtEpoch(validator, stateEpoch)) { slashableIndices.add(index); } - if (attesterSlashings.length >= MAX_ATTESTER_SLASHINGS) { + if (attesterSlashings.length >= maxAttesterSlashing) { break attesterSlashing; } } diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 3c32ffe1a9ec..d55b4e300232 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -1,5 +1,5 @@ -import {ForkName} from "@lodestar/params"; -import {phase0, RootHex, ssz} from "@lodestar/types"; +import {ForkName, ForkSeq} from "@lodestar/params"; +import {allForks, electra, phase0, RootHex, ssz} from "@lodestar/types"; import { computeEpochAtSlot, isAggregatorFromCommitteeLength, @@ -20,7 +20,7 @@ import { } from "./attestation.js"; export type AggregateAndProofValidationResult = { - indexedAttestation: phase0.IndexedAttestation; + indexedAttestation: allForks.IndexedAttestation; committeeIndices: Uint32Array; attDataRootHex: RootHex; }; @@ -41,7 +41,7 @@ export async function validateApiAggregateAndProof( export async function validateGossipAggregateAndProof( fork: ForkName, chain: IBeaconChain, - signedAggregateAndProof: phase0.SignedAggregateAndProof, + signedAggregateAndProof: allForks.SignedAggregateAndProof, serializedData: Uint8Array ): Promise { return validateAggregateAndProof(fork, chain, signedAggregateAndProof, serializedData); @@ -50,7 +50,7 @@ export async function validateGossipAggregateAndProof( async function validateAggregateAndProof( fork: ForkName, chain: IBeaconChain, - signedAggregateAndProof: phase0.SignedAggregateAndProof, + signedAggregateAndProof: allForks.SignedAggregateAndProof, serializedData: Uint8Array | null = null, opts: {skipValidationKnownAttesters: boolean; prioritizeBls: boolean} = { skipValidationKnownAttesters: false, @@ -74,7 +74,21 @@ async function validateAggregateAndProof( const attDataBase64 = serializedData ? getAttDataBase64FromSignedAggregateAndProofSerialized(serializedData) : null; const cachedAttData = attDataBase64 ? chain.seenAttestationDatas.get(attSlot, attDataBase64) : null; - const attIndex = attData.index; + let attIndex; + if (ForkSeq[fork] >= ForkSeq.electra) { + attIndex = (aggregate as electra.Attestation).committeeBits.getSingleTrueBit(); + // [REJECT] len(committee_indices) == 1, where committee_indices = get_committee_indices(aggregate) + if (attIndex === null) { + throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NOT_EXACTLY_ONE_COMMITTEE_BIT_SET}); + } + // [REJECT] aggregate.data.index == 0 + if (attData.index === 0) { + throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX}); + } + } else { + attIndex = attData.index; + } + const attEpoch = computeEpochAtSlot(attSlot); const attTarget = attData.target; const targetEpoch = attTarget.epoch; @@ -163,11 +177,16 @@ async function validateAggregateAndProof( throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS}); } const attestingIndices = aggregate.aggregationBits.intersectValues(committeeIndices); - const indexedAttestation: phase0.IndexedAttestation = { + + const indexedAttestationContent = { attestingIndices, data: attData, signature: aggregate.signature, }; + const indexedAttestation = + ForkSeq[fork] >= ForkSeq.electra + ? (indexedAttestationContent as electra.IndexedAttestation) + : (indexedAttestationContent as phase0.IndexedAttestation); // TODO: Check this before regen // [REJECT] The attestation has participants -- that is, diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index a66b95b782e4..813f9a25fc2d 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -1,4 +1,4 @@ -import {phase0, Epoch, Root, Slot, RootHex, ssz} from "@lodestar/types"; +import {phase0, Epoch, Root, Slot, RootHex, ssz, allForks, electra} from "@lodestar/types"; import {ProtoBlock} from "@lodestar/fork-choice"; import {ATTESTATION_SUBNET_COUNT, SLOTS_PER_EPOCH, ForkName, ForkSeq, DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; import { @@ -20,6 +20,7 @@ import { AttDataBase64, getAggregationBitsFromAttestationSerialized, getAttDataBase64FromAttestationSerialized, + getCommitteeBitsFromAttestationSerialized, getSignatureFromAttestationSerialized, } from "../../util/sszBytes.js"; import {AttestationDataCacheEntry} from "../seenCache/seenAttestationData.js"; @@ -34,8 +35,8 @@ export type BatchResult = { }; export type AttestationValidationResult = { - attestation: phase0.Attestation; - indexedAttestation: phase0.IndexedAttestation; + attestation: allForks.Attestation; + indexedAttestation: allForks.IndexedAttestation; subnet: number; attDataRootHex: RootHex; }; @@ -43,7 +44,7 @@ export type AttestationValidationResult = { export type AttestationOrBytes = ApiAttestation | GossipAttestation; /** attestation from api */ -export type ApiAttestation = {attestation: phase0.Attestation; serializedData: null}; +export type ApiAttestation = {attestation: phase0.Attestation; serializedData: null}; // TODO Electra: add new attestation type /** attestation from gossip */ export type GossipAttestation = { @@ -248,7 +249,7 @@ async function validateGossipAttestationNoSignatureCheck( // Run the checks that happen before an indexed attestation is constructed. let attestationOrCache: - | {attestation: phase0.Attestation; cache: null} + | {attestation: allForks.Attestation; cache: null} | {attestation: null; cache: AttestationDataCacheEntry; serializedData: Uint8Array}; let attDataBase64: AttDataBase64 | null = null; if (attestationOrBytes.serializedData) { @@ -260,7 +261,7 @@ async function validateGossipAttestationNoSignatureCheck( attestationOrBytes.attDataBase64 ?? getAttDataBase64FromAttestationSerialized(attestationOrBytes.serializedData); const cachedAttData = attDataBase64 !== null ? chain.seenAttestationDatas.get(attSlot, attDataBase64) : null; if (cachedAttData === null) { - const attestation = sszDeserializeAttestation(attestationOrBytes.serializedData); + const attestation = sszDeserializeAttestation(fork, attestationOrBytes.serializedData); // only deserialize on the first AttestationData that's not cached attestationOrCache = {attestation, cache: null}; } else { @@ -276,11 +277,34 @@ async function validateGossipAttestationNoSignatureCheck( ? attestationOrCache.attestation.data : attestationOrCache.cache.attestationData; const attSlot = attData.slot; - const attIndex = attData.index; const attEpoch = computeEpochAtSlot(attSlot); const attTarget = attData.target; const targetEpoch = attTarget.epoch; + let attIndex; + if (ForkSeq[fork] >= ForkSeq.electra) { + const committeeBits = attestationOrCache.attestation + ? (attestationOrCache.attestation as electra.Attestation).committeeBits + : getCommitteeBitsFromAttestationSerialized(attestationOrCache.serializedData); + + if (committeeBits === null) { + throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.INVALID_SERIALIZED_BYTES}); + } + + attIndex = committeeBits.getSingleTrueBit(); + // [REJECT] len(committee_indices) == 1, where committee_indices = get_committee_indices(aggregate) + if (attIndex === null) { + throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NOT_EXACTLY_ONE_COMMITTEE_BIT_SET}); + } + + // [REJECT] aggregate.data.index == 0 + if (attData.index === 0) { + throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX}); + } + } else { + attIndex = attData.index; + } + chain.metrics?.gossipAttestation.attestationSlotToClockSlot.observe( {caller: RegenCaller.validateGossipAttestation}, chain.clock.currentSlot - attSlot @@ -452,13 +476,17 @@ async function validateGossipAttestationNoSignatureCheck( } // no signature check, leave that for step1 - const indexedAttestation: phase0.IndexedAttestation = { + const indexedAttestationContent = { attestingIndices, data: attData, signature, }; + const indexedAttestation = + ForkSeq[fork] >= ForkSeq.electra + ? (indexedAttestationContent as electra.IndexedAttestation) + : (indexedAttestationContent as phase0.IndexedAttestation); - const attestation: phase0.Attestation = attestationOrCache.attestation + const attestation: allForks.Attestation = attestationOrCache.attestation ? attestationOrCache.attestation : { aggregationBits, @@ -698,6 +726,10 @@ function verifyAttestationTargetRoot(headBlock: ProtoBlock, targetRoot: Root, at } } +/** + * Get a list of indices of validators in the given committee + * attestationIndex - Index of the committee in shuffling.committees + */ export function getCommitteeIndices( shuffling: EpochShuffling, attestationSlot: Slot, diff --git a/packages/beacon-node/src/chain/validation/attesterSlashing.ts b/packages/beacon-node/src/chain/validation/attesterSlashing.ts index 818812526fb3..11a499c9bb53 100644 --- a/packages/beacon-node/src/chain/validation/attesterSlashing.ts +++ b/packages/beacon-node/src/chain/validation/attesterSlashing.ts @@ -9,7 +9,7 @@ import {AttesterSlashingError, AttesterSlashingErrorCode, GossipAction} from ".. export async function validateApiAttesterSlashing( chain: IBeaconChain, - attesterSlashing: phase0.AttesterSlashing + attesterSlashing: phase0.AttesterSlashing // TODO Electra: Handle electra.AttesterSlashing ): Promise { const prioritizeBls = true; return validateAttesterSlashing(chain, attesterSlashing, prioritizeBls); diff --git a/packages/beacon-node/src/metrics/validatorMonitor.ts b/packages/beacon-node/src/metrics/validatorMonitor.ts index 5492f57edc02..a443bf761c93 100644 --- a/packages/beacon-node/src/metrics/validatorMonitor.ts +++ b/packages/beacon-node/src/metrics/validatorMonitor.ts @@ -13,7 +13,7 @@ import {BeaconBlock, RootHex, altair, deneb} from "@lodestar/types"; import {ChainConfig, ChainForkConfig} from "@lodestar/config"; import {ForkSeq, INTERVALS_PER_SLOT, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params"; import {Epoch, Slot, ValidatorIndex} from "@lodestar/types"; -import {IndexedAttestation, SignedAggregateAndProof} from "@lodestar/types/phase0"; +import {IndexedAttestation, SignedAggregateAndProof} from "@lodestar/types/allForks"; import {GENESIS_SLOT} from "../constants/constants.js"; import {LodestarMetrics} from "./metrics/lodestar.js"; diff --git a/packages/beacon-node/src/network/gossip/interface.ts b/packages/beacon-node/src/network/gossip/interface.ts index 25a871b4e2a0..649bfd455387 100644 --- a/packages/beacon-node/src/network/gossip/interface.ts +++ b/packages/beacon-node/src/network/gossip/interface.ts @@ -80,8 +80,8 @@ export type SSZTypeOfGossipTopic = T extends {type: infer export type GossipTypeMap = { [GossipType.beacon_block]: SignedBeaconBlock; [GossipType.blob_sidecar]: deneb.BlobSidecar; - [GossipType.beacon_aggregate_and_proof]: phase0.SignedAggregateAndProof; - [GossipType.beacon_attestation]: phase0.Attestation; + [GossipType.beacon_aggregate_and_proof]: allForks.SignedAggregateAndProof; + [GossipType.beacon_attestation]: allForks.Attestation; [GossipType.voluntary_exit]: phase0.SignedVoluntaryExit; [GossipType.proposer_slashing]: phase0.ProposerSlashing; [GossipType.attester_slashing]: phase0.AttesterSlashing; @@ -95,8 +95,10 @@ export type GossipTypeMap = { export type GossipFnByType = { [GossipType.beacon_block]: (signedBlock: SignedBeaconBlock) => Promise | void; [GossipType.blob_sidecar]: (blobSidecar: deneb.BlobSidecar) => Promise | void; - [GossipType.beacon_aggregate_and_proof]: (aggregateAndProof: phase0.SignedAggregateAndProof) => Promise | void; - [GossipType.beacon_attestation]: (attestation: phase0.Attestation) => Promise | void; + [GossipType.beacon_aggregate_and_proof]: ( + aggregateAndProof: allForks.SignedAggregateAndProof + ) => Promise | void; + [GossipType.beacon_attestation]: (attestation: allForks.Attestation) => Promise | void; [GossipType.voluntary_exit]: (voluntaryExit: phase0.SignedVoluntaryExit) => Promise | void; [GossipType.proposer_slashing]: (proposerSlashing: phase0.ProposerSlashing) => Promise | void; [GossipType.attester_slashing]: (attesterSlashing: phase0.AttesterSlashing) => Promise | void; diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index 4923b71e6887..ffbad28cd936 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -1,4 +1,4 @@ -import {phase0, ssz, sszTypesFor} from "@lodestar/types"; +import {ssz, sszTypesFor} from "@lodestar/types"; import {ForkDigestContext} from "@lodestar/config"; import { ATTESTATION_SUBNET_COUNT, @@ -87,9 +87,9 @@ export function getGossipSSZType(topic: GossipTopic) { case GossipType.blob_sidecar: return ssz.deneb.BlobSidecar; case GossipType.beacon_aggregate_and_proof: - return ssz.phase0.SignedAggregateAndProof; + return ssz.allForks[topic.fork].SignedAggregateAndProof; case GossipType.beacon_attestation: - return ssz.phase0.Attestation; + return ssz.allForks[topic.fork].Attestation; case GossipType.proposer_slashing: return ssz.phase0.ProposerSlashing; case GossipType.attester_slashing: @@ -128,9 +128,10 @@ export function sszDeserialize(topic: T, serializedData: /** * Deserialize a gossip serialized data into an Attestation object. */ -export function sszDeserializeAttestation(serializedData: Uint8Array): phase0.Attestation { +export function sszDeserializeAttestation(fork: ForkName, serializedData: Uint8Array): allForks.Attestation { + const sszType = ssz.allForks[fork].Attestation; try { - return ssz.phase0.Attestation.deserialize(serializedData); + return sszType.deserialize(serializedData); } catch (e) { throw new GossipActionError(GossipAction.REJECT, {code: GossipErrorCode.INVALID_SERIALIZED_BYTES_ERROR_CODE}); } diff --git a/packages/beacon-node/src/network/interface.ts b/packages/beacon-node/src/network/interface.ts index 5012650e229a..4fd1235fe91a 100644 --- a/packages/beacon-node/src/network/interface.ts +++ b/packages/beacon-node/src/network/interface.ts @@ -71,7 +71,7 @@ export interface INetwork extends INetworkCorePublic { // Gossip publishBeaconBlock(signedBlock: SignedBeaconBlock): Promise; publishBlobSidecar(blobSidecar: deneb.BlobSidecar): Promise; - publishBeaconAggregateAndProof(aggregateAndProof: phase0.SignedAggregateAndProof): Promise; + publishBeaconAggregateAndProof(aggregateAndProof: allForks.SignedAggregateAndProof): Promise; publishBeaconAttestation(attestation: phase0.Attestation, subnet: number): Promise; publishVoluntaryExit(voluntaryExit: phase0.SignedVoluntaryExit): Promise; publishBlsToExecutionChange(blsToExecutionChange: capella.SignedBLSToExecutionChange): Promise; diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 52b9d85c0064..f9550d4c0ec2 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -316,7 +316,7 @@ export class Network implements INetwork { }); } - async publishBeaconAggregateAndProof(aggregateAndProof: phase0.SignedAggregateAndProof): Promise { + async publishBeaconAggregateAndProof(aggregateAndProof: allForks.SignedAggregateAndProof): Promise { const fork = this.config.getForkName(aggregateAndProof.message.aggregate.data.slot); return this.publishGossip( {type: GossipType.beacon_aggregate_and_proof, fork}, diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index 6f64148b87e2..57697ba2643f 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -421,7 +421,11 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler validationResult = await validateGossipAggregateAndProof(fork, chain, signedAggregateAndProof, serializedData); } catch (e) { if (e instanceof AttestationError && e.action === GossipAction.REJECT) { - chain.persistInvalidSszValue(ssz.phase0.SignedAggregateAndProof, signedAggregateAndProof, "gossip_reject"); + chain.persistInvalidSszValue( + ssz.allForks[fork].SignedAggregateAndProof, + signedAggregateAndProof, + "gossip_reject" + ); } throw e; } @@ -450,7 +454,10 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler } } - chain.emitter.emit(routes.events.EventType.attestation, signedAggregateAndProof.message.aggregate); + chain.emitter.emit(routes.events.EventType.attestation, { + version: fork, + data: signedAggregateAndProof.message.aggregate, + }); }, [GossipType.beacon_attestation]: async ({ gossipData, @@ -502,7 +509,7 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler } } - chain.emitter.emit(routes.events.EventType.attestation, attestation); + chain.emitter.emit(routes.events.EventType.attestation, {version: fork, data: attestation}); }, [GossipType.attester_slashing]: async ({ @@ -522,7 +529,7 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler logger.error("Error adding attesterSlashing to pool", {}, e as Error); } - chain.emitter.emit(routes.events.EventType.attesterSlashing, attesterSlashing); + chain.emitter.emit(routes.events.EventType.attesterSlashing, {version: topic.fork, data: attesterSlashing}); }, [GossipType.proposer_slashing]: async ({ @@ -710,7 +717,7 @@ function getBatchHandlers(modules: ValidatorFnsModules, options: GossipHandlerOp } } - chain.emitter.emit(routes.events.EventType.attestation, attestation); + chain.emitter.emit(routes.events.EventType.attestation, {version: fork, data: attestation}); } if (batchableBls) { diff --git a/packages/beacon-node/test/unit/api/impl/events/events.test.ts b/packages/beacon-node/test/unit/api/impl/events/events.test.ts index e031c3ac9958..b1f85b5e6e44 100644 --- a/packages/beacon-node/test/unit/api/impl/events/events.test.ts +++ b/packages/beacon-node/test/unit/api/impl/events/events.test.ts @@ -2,6 +2,7 @@ import {describe, it, expect, beforeEach, afterEach, vi, MockedObject} from "vit import {routes} from "@lodestar/api"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; +import {ForkName} from "@lodestar/params"; import {BeaconChain, ChainEventEmitter, HeadEventData} from "../../../../../src/chain/index.js"; import {getEventsApi} from "../../../../../src/api/impl/events/index.js"; import {ZERO_HASH_HEX} from "../../../../../src/constants/constants.js"; @@ -66,7 +67,10 @@ describe("Events api impl", function () { it("should ignore not sent topics", async function () { const events = getEvents([routes.events.EventType.head]); - chainEventEmmitter.emit(routes.events.EventType.attestation, ssz.phase0.Attestation.defaultValue()); + chainEventEmmitter.emit(routes.events.EventType.attestation, { + version: ForkName.phase0, + data: ssz.phase0.Attestation.defaultValue(), + }); chainEventEmmitter.emit(routes.events.EventType.head, headEventData); expect(events).toHaveLength(1); diff --git a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts index 800984fa84bc..57b5d6fad00f 100644 --- a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts @@ -2,13 +2,21 @@ import {BitArray, fromHexString, toHexString} from "@chainsafe/ssz"; import {describe, it, expect, beforeEach, beforeAll, afterEach, vi} from "vitest"; import {SecretKey, Signature, fastAggregateVerify} from "@chainsafe/blst"; import {CachedBeaconStateAllForks, newFilledArray} from "@lodestar/state-transition"; -import {FAR_FUTURE_EPOCH, ForkName, MAX_EFFECTIVE_BALANCE, SLOTS_PER_EPOCH} from "@lodestar/params"; +import { + FAR_FUTURE_EPOCH, + ForkName, + MAX_COMMITTEES_PER_SLOT, + MAX_EFFECTIVE_BALANCE, + SLOTS_PER_EPOCH, +} from "@lodestar/params"; import {ssz, phase0} from "@lodestar/types"; import {CachedBeaconStateAltair} from "@lodestar/state-transition/src/types.js"; import {MockedForkChoice, getMockedForkChoice} from "../../../mocks/mockedBeaconChain.js"; import { + aggregateConsolidation, AggregatedAttestationPool, aggregateInto, + AttestationsConsolidation, getNotSeenValidatorsFn, MatchingDataAttestationGroup, } from "../../../../src/chain/opPools/aggregatedAttestationPool.js"; @@ -80,11 +88,11 @@ describe("AggregatedAttestationPool", function () { vi.clearAllMocks(); }); - it("getParticipationFn", () => { + it("getNotSeenValidatorsFn", () => { // previousEpochParticipation and currentEpochParticipation is created inside generateCachedState // 0 and 1 are fully participated const notSeenValidatorFn = getNotSeenValidatorsFn(altairState); - const participation = notSeenValidatorFn(currentEpoch, committee); + const participation = notSeenValidatorFn(currentEpoch, currentSlot, committeeIndex); // seen attesting indices are 0, 1 => not seen are 2, 3 expect(participation).toEqual( // { @@ -279,6 +287,7 @@ describe("MatchingDataAttestationGroup.getAttestationsForBlock", () => { } } const attestationsForBlock = attestationGroup.getAttestationsForBlock( + ForkName.phase0, // notSeenValidatorIndices, notSeenAttestingIndices ); @@ -320,3 +329,75 @@ describe("MatchingDataAttestationGroup aggregateInto", function () { ); }); }); + +describe("aggregateConsolidation", function () { + const sk0 = bls.SecretKey.fromBytes(Buffer.alloc(32, 1)); + const sk1 = bls.SecretKey.fromBytes(Buffer.alloc(32, 2)); + const sk2 = bls.SecretKey.fromBytes(Buffer.alloc(32, 3)); + const skArr = [sk0, sk1, sk2]; + const testCases: { + name: string; + committeeIndices: number[]; + aggregationBitsArr: Array[]; + expectedAggregationBits: Array; + expectedCommitteeBits: Array; + }[] = [ + // note that bit index starts from the right + { + name: "test case 0", + committeeIndices: [0, 1, 2], + aggregationBitsArr: [[0b111], [0b011], [0b111]], + expectedAggregationBits: [0b11011111, 0b1], + expectedCommitteeBits: [true, true, true, false], + }, + { + name: "test case 1", + committeeIndices: [2, 3, 1], + aggregationBitsArr: [[0b100], [0b010], [0b001]], + expectedAggregationBits: [0b10100001, 0b0], + expectedCommitteeBits: [false, true, true, true], + }, + ]; + for (const { + name, + committeeIndices, + aggregationBitsArr, + expectedAggregationBits, + expectedCommitteeBits, + } of testCases) { + it(name, () => { + const attData = ssz.phase0.AttestationData.defaultValue(); + const consolidation: AttestationsConsolidation = { + byCommittee: new Map(), + attData: attData, + totalNotSeenCount: 0, + score: 0, + }; + // to simplify, instead of signing the signingRoot, just sign the attData root + const sigArr = skArr.map((sk) => sk.sign(ssz.phase0.AttestationData.hashTreeRoot(attData))); + const attestationSeed = ssz.electra.Attestation.defaultValue(); + for (let i = 0; i < committeeIndices.length; i++) { + const committeeIndex = committeeIndices[i]; + const commiteeBits = BitArray.fromBoolArray( + Array.from({length: MAX_COMMITTEES_PER_SLOT}, (_, i) => i === committeeIndex) + ); + const aggAttestation = { + ...attestationSeed, + aggregationBits: new BitArray(new Uint8Array(aggregationBitsArr[i]), 3), + committeeBits: commiteeBits, + signature: sigArr[i].toBytes(), + }; + consolidation.byCommittee.set(committeeIndex, { + attestation: aggAttestation, + notSeenAttesterCount: aggregationBitsArr[i].filter((item) => item).length, + }); + } + + const finalAttestation = aggregateConsolidation(consolidation); + expect(finalAttestation.aggregationBits.uint8Array).toEqual(new Uint8Array(expectedAggregationBits)); + expect(finalAttestation.committeeBits.toBoolArray()).toEqual(expectedCommitteeBits); + expect(finalAttestation.data).toEqual(attData); + expect(finalAttestation.signature).toEqual(bls.Signature.aggregate(sigArr).toBytes()); + }); + } +}); diff --git a/packages/fork-choice/src/forkChoice/interface.ts b/packages/fork-choice/src/forkChoice/interface.ts index d0629c2125cc..c9d1aa627b03 100644 --- a/packages/fork-choice/src/forkChoice/interface.ts +++ b/packages/fork-choice/src/forkChoice/interface.ts @@ -156,7 +156,7 @@ export interface IForkChoice { * The supplied `attestation` **must** pass the `in_valid_indexed_attestation` function as it * will not be run here. */ - onAttestation(attestation: phase0.IndexedAttestation, attDataRoot: string, forceImport?: boolean): void; + onAttestation(attestation: allForks.IndexedAttestation, attDataRoot: string, forceImport?: boolean): void; /** * Register attester slashing in order not to consider their votes in `getHead` * diff --git a/packages/state-transition/src/signatureSets/attesterSlashings.ts b/packages/state-transition/src/signatureSets/attesterSlashings.ts index 256582afe368..10e7a1991e4f 100644 --- a/packages/state-transition/src/signatureSets/attesterSlashings.ts +++ b/packages/state-transition/src/signatureSets/attesterSlashings.ts @@ -1,4 +1,4 @@ -import {SignedBeaconBlock, phase0, ssz} from "@lodestar/types"; +import {SignedBeaconBlock, ssz} from "@lodestar/types"; import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; import {computeSigningRoot, computeStartSlotAtEpoch, ISignatureSet, SignatureSetType} from "../util/index.js"; import {CachedBeaconStateAllForks} from "../types.js"; @@ -16,7 +16,7 @@ export function getAttesterSlashingsSignatureSets( /** Get signature sets from a single AttesterSlashing object */ export function getAttesterSlashingSignatureSets( state: CachedBeaconStateAllForks, - attesterSlashing: phase0.AttesterSlashing + attesterSlashing: allForks.AttesterSlashing ): ISignatureSet[] { return [attesterSlashing.attestation1, attesterSlashing.attestation2].map((attestation) => getIndexedAttestationBigintSignatureSet(state, attestation) @@ -25,7 +25,7 @@ export function getAttesterSlashingSignatureSets( export function getIndexedAttestationBigintSignatureSet( state: CachedBeaconStateAllForks, - indexedAttestation: phase0.IndexedAttestationBigint + indexedAttestation: allForks.IndexedAttestationBigint ): ISignatureSet { const slot = computeStartSlotAtEpoch(Number(indexedAttestation.data.target.epoch as bigint)); const domain = state.config.getDomain(state.slot, DOMAIN_BEACON_ATTESTER, slot); diff --git a/packages/state-transition/src/signatureSets/index.ts b/packages/state-transition/src/signatureSets/index.ts index 140b607c0bcb..5f063235735c 100644 --- a/packages/state-transition/src/signatureSets/index.ts +++ b/packages/state-transition/src/signatureSets/index.ts @@ -33,6 +33,9 @@ export function getBlockSignatureSets( skipProposerSignature?: boolean; } ): ISignatureSet[] { + // fork based validations + const fork = state.config.getForkSeq(signedBlock.message.slot); + const signatureSets = [ getRandaoRevealSignatureSet(state, signedBlock.message), ...getProposerSlashingsSignatureSets(state, signedBlock), @@ -45,9 +48,6 @@ export function getBlockSignatureSets( signatureSets.push(getBlockProposerSignatureSet(state, signedBlock)); } - // fork based validations - const fork = state.config.getForkSeq(signedBlock.message.slot); - // Only after altair fork, validate tSyncCommitteeSignature if (fork >= ForkSeq.altair) { const syncCommitteeSignatureSet = getSyncCommitteeSignatureSet( diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index 9191b251a6de..31eb9e662e8c 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -1,8 +1,9 @@ import {toHexString} from "@chainsafe/ssz"; -import {BLSSignature, phase0, Slot, ssz} from "@lodestar/types"; +import {allForks, BLSSignature, phase0, Slot, ssz} from "@lodestar/types"; import {computeEpochAtSlot, isAggregatorFromCommitteeLength} from "@lodestar/state-transition"; import {sleep} from "@lodestar/utils"; import {ApiClient, routes} from "@lodestar/api"; +import {ChainForkConfig} from "@lodestar/config"; import {IClock, LoggerVc} from "../util/index.js"; import {PubkeyHex} from "../types.js"; import {Metrics} from "../metrics.js"; @@ -43,6 +44,7 @@ export class AttestationService { chainHeadTracker: ChainHeaderTracker, syncingStatusTracker: SyncingStatusTracker, private readonly metrics: Metrics | null, + private readonly config: ChainForkConfig, private readonly opts?: AttestationServiceOpts ) { this.dutiesService = new AttestationDutiesService( @@ -271,7 +273,7 @@ export class AttestationService { const aggregate = res.value(); this.metrics?.numParticipantsInAggregate.observe(aggregate.aggregationBits.getTrueBitIndexes().length); - const signedAggregateAndProofs: phase0.SignedAggregateAndProof[] = []; + const signedAggregateAndProofs: allForks.SignedAggregateAndProof[] = []; await Promise.all( duties.map(async ({duty, selectionProof}) => { diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index 53299463ad2f..4678f6188382 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -19,6 +19,7 @@ import { DOMAIN_SYNC_COMMITTEE, DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF, DOMAIN_APPLICATION_BUILDER, + ForkSeq, } from "@lodestar/params"; import { altair, @@ -27,6 +28,7 @@ import { BlindedBeaconBlock, BLSPubkey, BLSSignature, + electra, Epoch, phase0, Root, @@ -493,7 +495,7 @@ export class ValidatorStore { duty: routes.validator.AttesterDuty, attestationData: phase0.AttestationData, currentEpoch: Epoch - ): Promise { + ): Promise { // Make sure the target epoch is not higher than the current epoch to avoid potential attacks. if (attestationData.target.epoch > currentEpoch) { throw Error( @@ -525,21 +527,30 @@ export class ValidatorStore { data: attestationData, }; - return { - aggregationBits: BitArray.fromSingleBit(duty.committeeLength, duty.validatorCommitteeIndex), - data: attestationData, - signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage), - }; + if (this.config.getForkSeq(duty.slot) >= ForkSeq.electra) { + return { + aggregationBits: BitArray.fromSingleBit(duty.committeeLength, duty.validatorCommitteeIndex), + data: attestationData, + committeeBits: BitArray.fromSingleBit(duty.committeesAtSlot, duty.committeeIndex), + signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage), + } as electra.Attestation; + } else { + return { + aggregationBits: BitArray.fromSingleBit(duty.committeeLength, duty.validatorCommitteeIndex), + data: attestationData, + signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage), + } as phase0.Attestation; + } } async signAggregateAndProof( duty: routes.validator.AttesterDuty, selectionProof: BLSSignature, - aggregate: phase0.Attestation - ): Promise { + aggregate: allForks.Attestation + ): Promise { this.validateAttestationDuty(duty, aggregate.data); - const aggregateAndProof: phase0.AggregateAndProof = { + const aggregateAndProof: allForks.AggregateAndProof = { aggregate, aggregatorIndex: duty.validatorIndex, selectionProof, @@ -547,7 +558,10 @@ export class ValidatorStore { const signingSlot = aggregate.data.slot; const domain = this.config.getDomain(signingSlot, DOMAIN_AGGREGATE_AND_PROOF); - const signingRoot = computeSigningRoot(ssz.phase0.AggregateAndProof, aggregateAndProof, domain); + const signingRoot = + this.config.getForkSeq(duty.slot) >= ForkSeq.electra + ? computeSigningRoot(ssz.electra.AggregateAndProof, aggregateAndProof, domain) + : computeSigningRoot(ssz.phase0.AggregateAndProof, aggregateAndProof, domain); const signableMessage: SignableMessage = { type: SignableMessageType.AGGREGATE_AND_PROOF, @@ -788,6 +802,9 @@ export class ValidatorStore { `Inconsistent duties during signing: duty.committeeIndex ${duty.committeeIndex} != att.committeeIndex ${data.index}` ); } + if (this.config.getForkSeq(duty.slot) >= ForkSeq.electra && data.index !== 0) { + throw Error(`Attestataion data index must be 0 post electra: index ${data.index}`); + } } private assertDoppelgangerSafe(pubKey: PubkeyHex | BLSPubkey): void { diff --git a/packages/validator/src/validator.ts b/packages/validator/src/validator.ts index 1732f54ababf..8ec8f3330af2 100644 --- a/packages/validator/src/validator.ts +++ b/packages/validator/src/validator.ts @@ -241,6 +241,7 @@ export class Validator { chainHeaderTracker, syncingStatusTracker, metrics, + config, { afterBlockDelaySlotFraction: opts.afterBlockDelaySlotFraction, disableAttestationGrouping: opts.disableAttestationGrouping || opts.distributed, diff --git a/packages/validator/test/unit/services/attestation.test.ts b/packages/validator/test/unit/services/attestation.test.ts index 11779ee496b3..f02b15f38853 100644 --- a/packages/validator/test/unit/services/attestation.test.ts +++ b/packages/validator/test/unit/services/attestation.test.ts @@ -3,6 +3,8 @@ import {toHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; import {ssz} from "@lodestar/types"; import {routes} from "@lodestar/api"; +import {createChainForkConfig} from "@lodestar/config"; +import {config} from "@lodestar/config/default"; import {AttestationService, AttestationServiceOpts} from "../../../src/services/attestation.js"; import {AttDutyAndProof} from "../../../src/services/attestationDuties.js"; import {ValidatorStore} from "../../../src/services/validatorStore.js"; @@ -68,6 +70,7 @@ describe("AttestationService", function () { chainHeadTracker, syncingStatusTracker, null, + createChainForkConfig(config), opts ); From 09e751077b1c8217fad31c9c220c575e147203d6 Mon Sep 17 00:00:00 2001 From: twoeths Date: Wed, 8 May 2024 18:09:39 +0700 Subject: [PATCH 022/259] fix: attestation pool for electra (#6744) * feat: attestationPool to group by slot by data root by committee index for electra * fix: gossip validation and assert.notNull() util * fix: remove light-client stats.html * fix: lint and check-types --- packages/api/src/beacon/routes/validator.ts | 16 +-- .../api/test/unit/beacon/testData/events.ts | 98 ++++++++++--------- .../test/unit/beacon/testData/validator.ts | 4 +- .../src/api/impl/beacon/pool/index.ts | 3 +- .../src/api/impl/validator/index.ts | 11 ++- .../opPools/aggregatedAttestationPool.ts | 8 +- .../src/chain/opPools/attestationPool.ts | 79 ++++++--------- .../src/chain/validation/aggregateAndProof.ts | 2 +- .../src/chain/validation/attestation.ts | 4 +- .../test/perf/epoch/epochAltair.test.ts | 4 +- .../test/perf/epoch/epochCapella.test.ts | 4 +- .../test/perf/epoch/epochPhase0.test.ts | 4 +- .../processEffectiveBalanceUpdates.test.ts | 3 +- .../perf/epoch/processRegistryUpdates.test.ts | 3 +- packages/utils/src/assert.ts | 12 +++ packages/utils/test/unit/assert.test.ts | 12 ++- .../validator/src/services/attestation.ts | 8 +- .../validator/src/services/validatorStore.ts | 3 +- 18 files changed, 149 insertions(+), 129 deletions(-) diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index f37ec7b24488..8c8355f63d07 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -409,9 +409,9 @@ export type Endpoints = { /** HashTreeRoot of AttestationData that validator want's aggregated */ attestationDataRoot: Root; slot: Slot; - index: number; + committeeIndex: number; }, - {query: {attestation_data_root: string; slot: number; index: number}}, + {query: {attestation_data_root: string; slot: number; committeeIndex: number}}, allForks.Attestation, VersionMeta >; @@ -805,16 +805,20 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ - query: {attestation_data_root: toHexString(attestationDataRoot), slot, index}, + writeReq: ({attestationDataRoot, slot, committeeIndex}) => ({ + query: {attestation_data_root: toHexString(attestationDataRoot), slot, committeeIndex}, }), parseReq: ({query}) => ({ attestationDataRoot: fromHexString(query.attestation_data_root), slot: query.slot, - index: query.slot, + committeeIndex: query.slot, }), schema: { - query: {attestation_data_root: Schema.StringRequired, slot: Schema.UintRequired, index: Schema.UintRequired}, + query: { + attestation_data_root: Schema.StringRequired, + slot: Schema.UintRequired, + committeeIndex: Schema.UintRequired, + }, }, }, resp: { diff --git a/packages/api/test/unit/beacon/testData/events.ts b/packages/api/test/unit/beacon/testData/events.ts index 8a7610a26836..7966d0ea3b8a 100644 --- a/packages/api/test/unit/beacon/testData/events.ts +++ b/packages/api/test/unit/beacon/testData/events.ts @@ -31,18 +31,21 @@ export const eventTestData: EventData = { block: "0x9a2fefd2fdb57f74993c7780ea5b9030d2897b615b89f808011ca5aebed54eaf", executionOptimistic: false, }, - [EventType.attestation]: ssz.phase0.Attestation.fromJson({ - aggregation_bits: "0x01", - signature: - "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", - data: { - slot: "1", - index: "1", - beacon_block_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", - source: {epoch: "1", root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}, - target: {epoch: "1", root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}, - }, - }), + [EventType.attestation]: { + version: ForkName.altair, + data: ssz.phase0.Attestation.fromJson({ + aggregation_bits: "0x01", + signature: + "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + data: { + slot: "1", + index: "1", + beacon_block_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + source: {epoch: "1", root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}, + target: {epoch: "1", root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}, + }, + }), + }, [EventType.voluntaryExit]: ssz.phase0.SignedVoluntaryExit.fromJson({ message: {epoch: "1", validator_index: "1"}, signature: @@ -72,44 +75,47 @@ export const eventTestData: EventData = { "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, }), - [EventType.attesterSlashing]: ssz.phase0.AttesterSlashing.fromJson({ - attestation_1: { - attesting_indices: ["0", "1"], - data: { - slot: "0", - index: "0", - beacon_block_root: "0x0000000000000000000000000000000000000000000000000000000000000000", - source: { - epoch: "0", - root: "0x0000000000000000000000000000000000000000000000000000000000000000", - }, - target: { - epoch: "0", - root: "0x0000000000000000000000000000000000000000000000000000000000000000", + [EventType.attesterSlashing]: { + version: ForkName.altair, + data: ssz.phase0.AttesterSlashing.fromJson({ + attestation_1: { + attesting_indices: ["0", "1"], + data: { + slot: "0", + index: "0", + beacon_block_root: "0x0000000000000000000000000000000000000000000000000000000000000000", + source: { + epoch: "0", + root: "0x0000000000000000000000000000000000000000000000000000000000000000", + }, + target: { + epoch: "0", + root: "0x0000000000000000000000000000000000000000000000000000000000000000", + }, }, + signature: + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, - signature: - "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - }, - attestation_2: { - attesting_indices: ["0", "1"], - data: { - slot: "0", - index: "0", - beacon_block_root: "0x0000000000000000000000000000000000000000000000000000000000000000", - source: { - epoch: "0", - root: "0x0000000000000000000000000000000000000000000000000000000000000000", - }, - target: { - epoch: "0", - root: "0x0000000000000000000000000000000000000000000000000000000000000000", + attestation_2: { + attesting_indices: ["0", "1"], + data: { + slot: "0", + index: "0", + beacon_block_root: "0x0000000000000000000000000000000000000000000000000000000000000000", + source: { + epoch: "0", + root: "0x0000000000000000000000000000000000000000000000000000000000000000", + }, + target: { + epoch: "0", + root: "0x0000000000000000000000000000000000000000000000000000000000000000", + }, }, + signature: + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, - signature: - "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - }, - }), + }), + }, [EventType.blsToExecutionChange]: ssz.capella.SignedBLSToExecutionChange.fromJson({ message: { validator_index: "1", diff --git a/packages/api/test/unit/beacon/testData/validator.ts b/packages/api/test/unit/beacon/testData/validator.ts index 11fd7dd26425..5f82d4a818b0 100644 --- a/packages/api/test/unit/beacon/testData/validator.ts +++ b/packages/api/test/unit/beacon/testData/validator.ts @@ -99,8 +99,8 @@ export const testData: GenericServerTestCases = { res: {data: ssz.altair.SyncCommitteeContribution.defaultValue()}, }, getAggregatedAttestation: { - args: {attestationDataRoot: ZERO_HASH, slot: 32000}, - res: {data: ssz.phase0.Attestation.defaultValue()}, + args: {attestationDataRoot: ZERO_HASH, slot: 32000, index: 2}, + res: {data: ssz.phase0.Attestation.defaultValue(), meta: {version: ForkName.phase0}}, }, publishAggregateAndProofs: { args: {signedAggregateAndProofs: [ssz.phase0.SignedAggregateAndProof.defaultValue()]}, diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index 77f6b24f28af..3f594fa4c3ae 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -27,12 +27,13 @@ export function getBeaconPoolApi({ async getPoolAttestations({slot, committeeIndex}) { // Already filtered by slot let attestations = chain.aggregatedAttestationPool.getAll(slot); + const fork = chain.config.getForkName(slot ?? attestations[0].data.slot) ?? ForkName.phase0; if (committeeIndex !== undefined) { attestations = attestations.filter((attestation) => committeeIndex === attestation.data.index); } - return {data: attestations}; + return {data: attestations, meta: {version: fork}}; }, async getPoolAttesterSlashings() { diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 63f860e7a193..856b301d7a21 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -1072,23 +1072,26 @@ export function getValidatorApi( }; }, - async getAggregatedAttestation({attestationDataRoot, slot}) { + async getAggregatedAttestation({attestationDataRoot, slot, committeeIndex}) { notWhileSyncing(); await waitForSlot(slot); // Must never request for a future slot > currentSlot const dataRootHex = toRootHex(attestationDataRoot); - const aggregate = chain.attestationPool.getAggregate(slot, dataRootHex); + const aggregate = chain.attestationPool.getAggregate(slot, committeeIndex, dataRootHex); if (!aggregate) { - throw new ApiError(404, `No aggregated attestation for slot=${slot}, dataRoot=${dataRootHex}`); + throw new ApiError( + 404, + `No aggregated attestation for slot=${slot} committeeIndex=${committeeIndex}, dataRoot=${dataRootHex}` + ); } metrics?.production.producedAggregateParticipants.observe(aggregate.aggregationBits.getTrueBitIndexes().length); return { data: aggregate, - version: config.getForkName(slot), + meta: {version: config.getForkName(slot)}, }; }, diff --git a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts index d5368bcfe4fe..31d461766947 100644 --- a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts @@ -30,7 +30,7 @@ import { getBlockRootAtSlot, } from "@lodestar/state-transition"; import {IForkChoice, EpochDifference} from "@lodestar/fork-choice"; -import {MapDef, toRootHex} from "@lodestar/utils"; +import {MapDef, toRootHex, assert} from "@lodestar/utils"; import {intersectUint8Arrays, IntersectResult} from "../../util/bitArray.js"; import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; import {InsertOutcome} from "./types.js"; @@ -141,10 +141,8 @@ export class AggregatedAttestationPool { ? // this attestation is added to pool after validation attestation.committeeBits.getSingleTrueBit() : attestation.data.index; - if (committeeIndex === null) { - // this should not happen because attestation should be validated before reaching this - throw Error(`Invalid attestation slot=${slot} committeeIndex=${committeeIndex}`); - } + // this should not happen because attestation should be validated before reaching this + assert.notNull(committeeIndex, "Committee index should not be null in aggregated attestation pool"); let attestationGroup = attestationGroupByIndex.get(committeeIndex); if (!attestationGroup) { attestationGroup = new MatchingDataAttestationGroup(committee, attestation.data); diff --git a/packages/beacon-node/src/chain/opPools/attestationPool.ts b/packages/beacon-node/src/chain/opPools/attestationPool.ts index 9db73cf4a013..a9286ac4949a 100644 --- a/packages/beacon-node/src/chain/opPools/attestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/attestationPool.ts @@ -1,7 +1,7 @@ import {BitArray} from "@chainsafe/ssz"; import {Signature, aggregateSignatures} from "@chainsafe/blst"; -import {Slot, RootHex, allForks} from "@lodestar/types"; -import {MapDef} from "@lodestar/utils"; +import {Slot, RootHex, allForks, isElectraAttestation} from "@lodestar/types"; +import {MapDef, assert} from "@lodestar/utils"; import {IClock} from "../../util/clock.js"; import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js"; import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; @@ -35,6 +35,8 @@ type AggregateFast = AggregateFastPhase0 | AggregateFastElectra; /** Hex string of DataRoot `TODO` */ type DataRootHex = string; +type CommitteeIndex = number; + /** * A pool of `Attestation` that is specially designed to store "unaggregated" attestations from * the native aggregation scheme. @@ -59,8 +61,8 @@ type DataRootHex = string; * receives and it can be triggered manually. */ export class AttestationPool { - private readonly attestationByRootBySlot = new MapDef>( - () => new Map() + private readonly attestationByRootBySlot = new MapDef>>( + () => new Map>() ); private lowestPermissibleSlot = 0; @@ -116,14 +118,26 @@ export class AttestationPool { throw new OpPoolError({code: OpPoolErrorCode.REACHED_MAX_PER_SLOT}); } + const committeeIndex = isElectraAttestation(attestation) + ? // this attestation is added to pool after validation + attestation.committeeBits.getSingleTrueBit() + : attestation.data.index; + // this should not happen because attestation should be validated before reaching this + assert.notNull(committeeIndex, "Committee index should not be null in attestation pool"); + // Pre-aggregate the contribution with existing items - const aggregate = aggregateByRoot.get(attDataRootHex); + let aggregateByIndex = aggregateByRoot.get(attDataRootHex); + if (aggregateByIndex === undefined) { + aggregateByIndex = new Map(); + aggregateByRoot.set(attDataRootHex, aggregateByIndex); + } + const aggregate = aggregateByIndex.get(committeeIndex); if (aggregate) { // Aggregate mutating return aggregateAttestationInto(aggregate, attestation); } else { // Create new aggregate - aggregateByRoot.set(attDataRootHex, attestationToAggregate(attestation)); + aggregateByIndex.set(committeeIndex, attestationToAggregate(attestation)); return InsertOutcome.NewData; } } @@ -131,8 +145,8 @@ export class AttestationPool { /** * For validator API to get an aggregate */ - getAggregate(slot: Slot, dataRootHex: RootHex): allForks.Attestation | null { - const aggregate = this.attestationByRootBySlot.get(slot)?.get(dataRootHex); + getAggregate(slot: Slot, committeeIndex: CommitteeIndex, dataRootHex: RootHex): allForks.Attestation | null { + const aggregate = this.attestationByRootBySlot.get(slot)?.get(dataRootHex)?.get(committeeIndex); if (!aggregate) { // TODO: Add metric for missing aggregates return null; @@ -165,8 +179,10 @@ export class AttestationPool { for (const aggregateByRoot of aggregateByRoots) { if (aggregateByRoot) { - for (const aggFast of aggregateByRoot.values()) { - attestations.push(fastToAttestation(aggFast)); + for (const aggFastByIndex of aggregateByRoot.values()) { + for (const aggFast of aggFastByIndex.values()) { + attestations.push(fastToAttestation(aggFast)); + } } } } @@ -179,35 +195,13 @@ export class AttestationPool { // - Insert attestations coming from gossip and API /** - * Aggregate a new contribution into `aggregate` mutating it + * Aggregate a new attestation into `aggregate` mutating it */ function aggregateAttestationInto(aggregate: AggregateFast, attestation: allForks.Attestation): InsertOutcome { const bitIndex = attestation.aggregationBits.getSingleTrueBit(); // Should never happen, attestations are verified against this exact condition before - if (bitIndex === null) { - throw Error("Invalid attestation not exactly one bit set"); - } - - if ("committeeBits" in attestation && !("committeeBits" in aggregate)) { - throw Error("Attempt to aggregate electra attestation into phase0 attestation"); - } - - if (!("committeeBits" in attestation) && "committeeBits" in aggregate) { - throw Error("Attempt to aggregate phase0 attestation into electra attestation"); - } - - if ("committeeBits" in attestation) { - // We assume attestation.committeeBits should already be validated in api and gossip handler and should be non-null - const attestationCommitteeIndex = attestation.committeeBits.getSingleTrueBit(); - const aggregateCommitteeIndex = (aggregate as AggregateFastElectra).committeeBits.getSingleTrueBit(); - - if (attestationCommitteeIndex !== aggregateCommitteeIndex) { - throw Error( - `Committee index mismatched: attestation ${attestationCommitteeIndex} aggregate ${aggregateCommitteeIndex}` - ); - } - } + assert.notNull(bitIndex, "Invalid attestation in pool, not exactly one bit set"); if (aggregate.aggregationBits.get(bitIndex) === true) { return InsertOutcome.AlreadyKnown; @@ -222,7 +216,7 @@ function aggregateAttestationInto(aggregate: AggregateFast, attestation: allFork * Format `contribution` into an efficient `aggregate` to add more contributions in with aggregateContributionInto() */ function attestationToAggregate(attestation: allForks.Attestation): AggregateFast { - if ("committeeBits" in attestation) { + if (isElectraAttestation(attestation)) { return { data: attestation.data, // clone because it will be mutated @@ -243,18 +237,5 @@ function attestationToAggregate(attestation: allForks.Attestation): AggregateFas * Unwrap AggregateFast to phase0.Attestation */ function fastToAttestation(aggFast: AggregateFast): allForks.Attestation { - if ("committeeBits" in aggFast) { - return { - data: aggFast.data, - aggregationBits: aggFast.aggregationBits, - committeeBits: aggFast.committeeBits, - signature: aggFast.signature.toBytes(), - }; - } else { - return { - data: aggFast.data, - aggregationBits: aggFast.aggregationBits, - signature: aggFast.signature.toBytes(), - }; - } + return {...aggFast, signature: aggFast.signature.toBytes()}; } diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index d55b4e300232..c2ecb95907e9 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -82,7 +82,7 @@ async function validateAggregateAndProof( throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NOT_EXACTLY_ONE_COMMITTEE_BIT_SET}); } // [REJECT] aggregate.data.index == 0 - if (attData.index === 0) { + if (attData.index !== 0) { throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX}); } } else { diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index 813f9a25fc2d..046e1180309c 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -44,7 +44,7 @@ export type AttestationValidationResult = { export type AttestationOrBytes = ApiAttestation | GossipAttestation; /** attestation from api */ -export type ApiAttestation = {attestation: phase0.Attestation; serializedData: null}; // TODO Electra: add new attestation type +export type ApiAttestation = {attestation: phase0.Attestation; serializedData: null}; /** attestation from gossip */ export type GossipAttestation = { @@ -298,7 +298,7 @@ async function validateGossipAttestationNoSignatureCheck( } // [REJECT] aggregate.data.index == 0 - if (attData.index === 0) { + if (attData.index !== 0) { throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX}); } } else { diff --git a/packages/state-transition/test/perf/epoch/epochAltair.test.ts b/packages/state-transition/test/perf/epoch/epochAltair.test.ts index 273353d8632b..6c43151cc137 100644 --- a/packages/state-transition/test/perf/epoch/epochAltair.test.ts +++ b/packages/state-transition/test/perf/epoch/epochAltair.test.ts @@ -120,7 +120,7 @@ function benchmarkAltairEpochSteps(stateOg: LazyValue itBench({ id: `${stateId} - altair processRegistryUpdates`, beforeEach: () => stateOg.value.clone(), - fn: (state) => processRegistryUpdates(state, cache.value), + fn: (state) => processRegistryUpdates(ForkSeq.altair, state, cache.value), }); // TODO: Needs a better state to test with, current does not include enough actions: 39.985 us/op @@ -141,7 +141,7 @@ function benchmarkAltairEpochSteps(stateOg: LazyValue itBench({ id: `${stateId} - altair processEffectiveBalanceUpdates`, beforeEach: () => stateOg.value.clone(), - fn: (state) => processEffectiveBalanceUpdates(state, cache.value), + fn: (state) => processEffectiveBalanceUpdates(ForkSeq.altair, state, cache.value), }); itBench({ diff --git a/packages/state-transition/test/perf/epoch/epochCapella.test.ts b/packages/state-transition/test/perf/epoch/epochCapella.test.ts index eeaf8bfc5400..5b8300df3f18 100644 --- a/packages/state-transition/test/perf/epoch/epochCapella.test.ts +++ b/packages/state-transition/test/perf/epoch/epochCapella.test.ts @@ -99,7 +99,7 @@ function benchmarkAltairEpochSteps(stateOg: LazyValue itBench({ id: `${stateId} - capella processRegistryUpdates`, beforeEach: () => stateOg.value.clone(), - fn: (state) => processRegistryUpdates(state, cache.value), + fn: (state) => processRegistryUpdates(ForkSeq.capella, state, cache.value), }); // TODO: Needs a better state to test with, current does not include enough actions: 39.985 us/op @@ -120,7 +120,7 @@ function benchmarkAltairEpochSteps(stateOg: LazyValue itBench({ id: `${stateId} - capella processEffectiveBalanceUpdates`, beforeEach: () => stateOg.value.clone(), - fn: (state) => processEffectiveBalanceUpdates(state, cache.value), + fn: (state) => processEffectiveBalanceUpdates(ForkSeq.capella, state, cache.value), }); itBench({ diff --git a/packages/state-transition/test/perf/epoch/epochPhase0.test.ts b/packages/state-transition/test/perf/epoch/epochPhase0.test.ts index 4e43634b1669..411577878102 100644 --- a/packages/state-transition/test/perf/epoch/epochPhase0.test.ts +++ b/packages/state-transition/test/perf/epoch/epochPhase0.test.ts @@ -102,7 +102,7 @@ function benchmarkPhase0EpochSteps(stateOg: LazyValue itBench({ id: `${stateId} - phase0 processRegistryUpdates`, beforeEach: () => stateOg.value.clone(), - fn: (state) => processRegistryUpdates(state, cache.value), + fn: (state) => processRegistryUpdates(ForkSeq.phase0, state, cache.value), }); // TODO: Needs a better state to test with, current does not include enough actions: 39.985 us/op @@ -123,7 +123,7 @@ function benchmarkPhase0EpochSteps(stateOg: LazyValue itBench({ id: `${stateId} - phase0 processEffectiveBalanceUpdates`, beforeEach: () => stateOg.value.clone(), - fn: (state) => processEffectiveBalanceUpdates(state, cache.value), + fn: (state) => processEffectiveBalanceUpdates(ForkSeq.phase0, state, cache.value), }); itBench({ diff --git a/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts b/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts index 0fb1d448142f..d94daac9e59b 100644 --- a/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts +++ b/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts @@ -1,6 +1,7 @@ import {itBench} from "@dapplion/benchmark"; import {ssz} from "@lodestar/types"; import {config} from "@lodestar/config/default"; +import {ForkSeq} from "@lodestar/params"; import {beforeProcessEpoch, CachedBeaconStateAllForks, EpochTransitionCache} from "../../../src/index.js"; import {processEffectiveBalanceUpdates} from "../../../src/epoch/processEffectiveBalanceUpdates.js"; import {numValidators} from "../util.js"; @@ -35,7 +36,7 @@ describe("phase0 processEffectiveBalanceUpdates", () => { minRuns: 5, // Worst case is very slow before: () => getEffectiveBalanceTestData(vc, changeRatio), beforeEach: ({state, cache}) => ({state: state.clone(), cache}), - fn: ({state, cache}) => processEffectiveBalanceUpdates(state, cache), + fn: ({state, cache}) => processEffectiveBalanceUpdates(ForkSeq.phase0, state, cache), }); } }); diff --git a/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts b/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts index ccfd2405a665..2d57de44f8ee 100644 --- a/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts +++ b/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts @@ -1,4 +1,5 @@ import {itBench} from "@dapplion/benchmark"; +import {ForkSeq} from "@lodestar/params"; import {beforeProcessEpoch, CachedBeaconStateAllForks, EpochTransitionCache} from "../../../src/index.js"; import {processRegistryUpdates} from "../../../src/epoch/processRegistryUpdates.js"; import {generatePerfTestCachedStatePhase0, numValidators} from "../util.js"; @@ -62,7 +63,7 @@ describe("phase0 processRegistryUpdates", () => { noThreshold: notTrack, before: () => getRegistryUpdatesTestData(vc, lengths), beforeEach: async ({state, cache}) => ({state: state.clone(), cache}), - fn: ({state, cache}) => processRegistryUpdates(state, cache), + fn: ({state, cache}) => processRegistryUpdates(ForkSeq.phase0, state, cache), }); } }); diff --git a/packages/utils/src/assert.ts b/packages/utils/src/assert.ts index aa86161cca44..91612b0e6407 100644 --- a/packages/utils/src/assert.ts +++ b/packages/utils/src/assert.ts @@ -21,6 +21,18 @@ export const assert = { } }, + /** + * Assert not null + * ``` + * actual !== null + * ``` + */ + notNull(actual: T | null, message?: string): asserts actual is T { + if (!(actual !== null)) { + throw new AssertionError(`${message || "Expected value to be not null"}`); + } + }, + /** * Assert less than or equal * ```js diff --git a/packages/utils/test/unit/assert.test.ts b/packages/utils/test/unit/assert.test.ts index 0555bcbd01a0..3b413efa11be 100644 --- a/packages/utils/test/unit/assert.test.ts +++ b/packages/utils/test/unit/assert.test.ts @@ -20,8 +20,18 @@ describe("assert", () => { }); }); + describe("notNull with custom message", () => { + it("Should not throw error with not null value", () => { + expect(() => assert.notNull(0)).not.toThrow(); + expect(() => assert.notNull("")).not.toThrow(); + }); + it("Should throw with null value", () => { + expect(() => assert.notNull(null, "something must not be null")).toThrow("something must not be null"); + }); + }); + const cases: { - op: keyof Omit; + op: keyof Omit; args: [number, number]; ok: boolean; }[] = [ diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index 31eb9e662e8c..a0cf8e8768e7 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -139,7 +139,7 @@ export class AttestationService { // Then download, sign and publish a `SignedAggregateAndProof` for each // validator that is elected to aggregate for this `slot` and `committeeIndex`. - await this.produceAndPublishAggregates(attestation, dutiesSameCommittee); + await this.produceAndPublishAggregates(attestation, index, dutiesSameCommittee); } private async runAttestationTasksGrouped( @@ -165,7 +165,7 @@ export class AttestationService { await Promise.all( Array.from(dutiesByCommitteeIndex.entries()).map(([index, dutiesSameCommittee]) => { const attestationData: phase0.AttestationData = {...attestationNoCommittee, index}; - return this.produceAndPublishAggregates(attestationData, dutiesSameCommittee); + return this.produceAndPublishAggregates(attestationData, index, dutiesSameCommittee); }) ); } @@ -256,9 +256,10 @@ export class AttestationService { */ private async produceAndPublishAggregates( attestation: phase0.AttestationData, + committeeIndex: number, duties: AttDutyAndProof[] ): Promise { - const logCtx = {slot: attestation.slot, index: attestation.index}; + const logCtx = {slot: attestation.slot, index: committeeIndex}; // No validator is aggregator, skip if (duties.every(({selectionProof}) => selectionProof === null)) { @@ -269,6 +270,7 @@ export class AttestationService { const res = await this.api.validator.getAggregatedAttestation({ attestationDataRoot: ssz.phase0.AttestationData.hashTreeRoot(attestation), slot: attestation.slot, + committeeIndex, }); const aggregate = res.value(); this.metrics?.numParticipantsInAggregate.observe(aggregate.aggregationBits.getTrueBitIndexes().length); diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index 4678f6188382..a807c27569eb 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -20,6 +20,7 @@ import { DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF, DOMAIN_APPLICATION_BUILDER, ForkSeq, + MAX_COMMITTEES_PER_SLOT, } from "@lodestar/params"; import { altair, @@ -531,7 +532,7 @@ export class ValidatorStore { return { aggregationBits: BitArray.fromSingleBit(duty.committeeLength, duty.validatorCommitteeIndex), data: attestationData, - committeeBits: BitArray.fromSingleBit(duty.committeesAtSlot, duty.committeeIndex), + committeeBits: BitArray.fromSingleBit(MAX_COMMITTEES_PER_SLOT, duty.committeeIndex), signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage), } as electra.Attestation; } else { From 08932765a785e060f207eba7b764f3c8fcd9590b Mon Sep 17 00:00:00 2001 From: g11tech Date: Wed, 8 May 2024 17:11:08 +0530 Subject: [PATCH 023/259] feat: update engineapi endpoints to v4 (#6747) --- packages/beacon-node/src/execution/engine/http.ts | 6 +++--- packages/beacon-node/src/execution/engine/mock.ts | 4 ++-- packages/beacon-node/src/execution/engine/types.ts | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index ac3402852c35..10a805e26d66 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -199,7 +199,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { ): Promise { const method = ForkSeq[fork] >= ForkSeq.electra - ? "engine_newPayloadV6110" + ? "engine_newPayloadV4" : ForkSeq[fork] >= ForkSeq.deneb ? "engine_newPayloadV3" : ForkSeq[fork] >= ForkSeq.capella @@ -220,7 +220,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { const serializedVersionedHashes = serializeVersionedHashes(versionedHashes); const parentBeaconBlockRoot = serializeBeaconBlockRoot(parentBlockRoot); - const method = ForkSeq[fork] >= ForkSeq.electra ? "engine_newPayloadV6110" : "engine_newPayloadV3"; + const method = ForkSeq[fork] >= ForkSeq.electra ? "engine_newPayloadV4" : "engine_newPayloadV3"; engineRequest = { method, params: [serializedExecutionPayload, serializedVersionedHashes, parentBeaconBlockRoot], @@ -395,7 +395,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { }> { const method = ForkSeq[fork] >= ForkSeq.electra - ? "engine_getPayloadV6110" + ? "engine_getPayloadV4" : ForkSeq[fork] >= ForkSeq.deneb ? "engine_getPayloadV3" : ForkSeq[fork] >= ForkSeq.capella diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index 5a50f1697de9..4cff2a8d00f4 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -89,14 +89,14 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { engine_newPayloadV1: this.notifyNewPayload.bind(this), engine_newPayloadV2: this.notifyNewPayload.bind(this), engine_newPayloadV3: this.notifyNewPayload.bind(this), - engine_newPayloadV6110: this.notifyNewPayload.bind(this), + engine_newPayloadV4: this.notifyNewPayload.bind(this), engine_forkchoiceUpdatedV1: this.notifyForkchoiceUpdate.bind(this), engine_forkchoiceUpdatedV2: this.notifyForkchoiceUpdate.bind(this), engine_forkchoiceUpdatedV3: this.notifyForkchoiceUpdate.bind(this), engine_getPayloadV1: this.getPayload.bind(this), engine_getPayloadV2: this.getPayload.bind(this), engine_getPayloadV3: this.getPayload.bind(this), - engine_getPayloadV6110: this.getPayload.bind(this), + engine_getPayloadV4: this.getPayload.bind(this), engine_getPayloadBodiesByHashV1: this.getPayloadBodiesByHash.bind(this), engine_getPayloadBodiesByRangeV1: this.getPayloadBodiesByRange.bind(this), engine_getClientVersionV1: this.getClientVersionV1.bind(this), diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index f0701d48c5fc..49b34ea97086 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -28,7 +28,7 @@ export type EngineApiRpcParamTypes = { engine_newPayloadV1: [ExecutionPayloadRpc]; engine_newPayloadV2: [ExecutionPayloadRpc]; engine_newPayloadV3: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; - engine_newPayloadV6110: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; + engine_newPayloadV4: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; /** * 1. Object - Payload validity status with respect to the consensus rules: * - blockHash: DATA, 32 Bytes - block hash value of the payload @@ -52,7 +52,7 @@ export type EngineApiRpcParamTypes = { engine_getPayloadV1: [QUANTITY]; engine_getPayloadV2: [QUANTITY]; engine_getPayloadV3: [QUANTITY]; - engine_getPayloadV6110: [QUANTITY]; + engine_getPayloadV4: [QUANTITY]; /** * 1. Array of DATA - Array of block_hash field values of the ExecutionPayload structure @@ -85,7 +85,7 @@ export type EngineApiRpcReturnTypes = { engine_newPayloadV1: PayloadStatus; engine_newPayloadV2: PayloadStatus; engine_newPayloadV3: PayloadStatus; - engine_newPayloadV6110: PayloadStatus; + engine_newPayloadV4: PayloadStatus; engine_forkchoiceUpdatedV1: { payloadStatus: PayloadStatus; payloadId: QUANTITY | null; @@ -104,7 +104,7 @@ export type EngineApiRpcReturnTypes = { engine_getPayloadV1: ExecutionPayloadRpc; engine_getPayloadV2: ExecutionPayloadResponse; engine_getPayloadV3: ExecutionPayloadResponse; - engine_getPayloadV6110: ExecutionPayloadResponse; + engine_getPayloadV4: ExecutionPayloadResponse; engine_getPayloadBodiesByHashV1: (ExecutionPayloadBodyRpc | null)[]; From 2b0ec1255b2a9a560ef07f346460942f7450ea9a Mon Sep 17 00:00:00 2001 From: NC Date: Wed, 8 May 2024 18:12:36 +0300 Subject: [PATCH 024/259] feat: rename deposit receipt to deposit request for Pectra (#6748) * Rename receipt to request * Remove stats.html --- packages/beacon-node/src/chain/chain.ts | 2 +- .../src/eth1/eth1DepositDataTracker.ts | 4 +- .../src/execution/engine/interface.ts | 4 +- .../src/execution/engine/payloadIdCache.ts | 2 +- .../beacon-node/src/execution/engine/types.ts | 40 +++++++++---------- .../test/sim/electra-interop.test.ts | 28 ++++++------- .../test/spec/presets/operations.test.ts | 6 +-- .../test/unit/executionEngine/http.test.ts | 8 ++-- packages/beacon-node/test/utils/state.ts | 2 +- packages/light-client/src/spec/utils.ts | 8 ++-- .../src/block/processDeposit.ts | 6 +-- ...sitReceipt.ts => processDepositRequest.ts} | 10 ++--- .../src/block/processOperations.ts | 8 ++-- .../src/slot/upgradeStateToElectra.ts | 6 +-- packages/state-transition/src/util/deposit.ts | 4 +- .../state-transition/src/util/execution.ts | 4 +- packages/state-transition/src/util/genesis.ts | 2 +- .../test/unit/util/deposit.test.ts | 4 +- packages/types/src/electra/sszTypes.ts | 12 +++--- packages/types/src/electra/types.ts | 4 +- 20 files changed, 82 insertions(+), 82 deletions(-) rename packages/state-transition/src/block/{processDepositReceipt.ts => processDepositRequest.ts} (55%) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 9f67857fe530..9f30936305f0 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -1147,7 +1147,7 @@ export class BeaconChain implements IBeaconChain { // Will resolve this later // if (cpEpoch >= (this.config.ELECTRA_FORK_EPOCH ?? Infinity)) { // // finalizedState can be safely casted to Electra state since cp is already post-Electra - // if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateElectra).depositReceiptsStartIndex) { + // if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateElectra).depositRequestsStartIndex) { // // Signal eth1 to stop polling eth1Data // this.eth1.stopPollingEth1Data(); // } diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index c0b3ab35a73a..d0578718f29f 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -129,9 +129,9 @@ export class Eth1DepositDataTracker { async getEth1DataAndDeposits(state: CachedBeaconStateAllForks): Promise { if ( state.epochCtx.isAfterElectra() && - state.eth1DepositIndex >= (state as CachedBeaconStateElectra).depositReceiptsStartIndex + state.eth1DepositIndex >= (state as CachedBeaconStateElectra).depositRequestsStartIndex ) { - // No need to poll eth1Data since Electra deprecates the mechanism after depositReceiptsStartIndex is reached + // No need to poll eth1Data since Electra deprecates the mechanism after depositRequestsStartIndex is reached return {eth1Data: state.eth1Data, deposits: []}; } const eth1Data = this.forcedEth1DataVote ?? (await this.getEth1Data(state)); diff --git a/packages/beacon-node/src/execution/engine/interface.ts b/packages/beacon-node/src/execution/engine/interface.ts index 91a8ce1cffe3..c2e44901afbb 100644 --- a/packages/beacon-node/src/execution/engine/interface.ts +++ b/packages/beacon-node/src/execution/engine/interface.ts @@ -3,10 +3,10 @@ import {KZGCommitment, Blob, KZGProof} from "@lodestar/types/deneb"; import {Root, RootHex, capella, Wei, ExecutionPayload} from "@lodestar/types"; import {DATA} from "../../eth1/provider/utils.js"; -import {PayloadIdCache, PayloadId, WithdrawalV1, DepositReceiptV1} from "./payloadIdCache.js"; +import {PayloadIdCache, PayloadId, WithdrawalV1, DepositRequestV1} from "./payloadIdCache.js"; import {ExecutionPayloadBody} from "./types.js"; -export {PayloadIdCache, type PayloadId, type WithdrawalV1, type DepositReceiptV1}; +export {PayloadIdCache, type PayloadId, type WithdrawalV1, type DepositRequestV1}; export enum ExecutionPayloadStatus { /** given payload is valid */ diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index b5fe3d33e267..f79c28582459 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -18,7 +18,7 @@ export type WithdrawalV1 = { amount: QUANTITY; }; -export type DepositReceiptV1 = { +export type DepositRequestV1 = { pubkey: DATA; withdrawalCredentials: DATA; amount: QUANTITY; diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 49b34ea97086..3c1da820a610 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -17,7 +17,7 @@ import { quantityToBigint, } from "../../eth1/provider/utils.js"; import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js"; -import {WithdrawalV1, DepositReceiptV1, ExecutionLayerWithdrawalRequestV1} from "./payloadIdCache.js"; +import {WithdrawalV1, DepositRequestV1, ExecutionLayerWithdrawalRequestV1} from "./payloadIdCache.js"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -127,14 +127,14 @@ export type ExecutionPayloadBodyRpc = { withdrawals: WithdrawalV1[] | null | undefined; // currently there is a discepancy between EL and CL field name references for deposit requests // its likely CL receipt will be renamed to requests - depositRequests: DepositReceiptV1[] | null | undefined; + depositRequests: DepositRequestV1[] | null | undefined; withdrawalRequests: ExecutionLayerWithdrawalRequestV1[] | null | undefined; }; export type ExecutionPayloadBody = { transactions: bellatrix.Transaction[]; withdrawals: capella.Withdrawals | null; - depositReceipts: electra.DepositReceipts | null; + depositRequests: electra.DepositRequests | null; withdrawalRequests: electra.ExecutionLayerWithdrawalRequests | null; }; @@ -157,7 +157,7 @@ export type ExecutionPayloadRpc = { blobGasUsed?: QUANTITY; // DENEB excessBlobGas?: QUANTITY; // DENEB parentBeaconBlockRoot?: QUANTITY; // DENEB - depositRequests?: DepositReceiptRpc[]; // ELECTRA + depositRequests?: DepositRequestRpc[]; // ELECTRA withdrawalRequests?: ExecutionLayerWithdrawalRequestRpc[]; // ELECTRA }; @@ -168,7 +168,7 @@ export type WithdrawalRpc = { amount: QUANTITY; }; -export type DepositReceiptRpc = DepositReceiptV1; +export type DepositRequestRpc = DepositRequestV1; export type ExecutionLayerWithdrawalRequestRpc = ExecutionLayerWithdrawalRequestV1; export type VersionedHashesRpc = DATA[]; @@ -233,10 +233,10 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload payload.excessBlobGas = numToQuantity(excessBlobGas); } - // ELECTRA adds depositReceipts/depositRequests to the ExecutionPayload + // ELECTRA adds depositRequests/depositRequests to the ExecutionPayload if (ForkSeq[fork] >= ForkSeq.electra) { - const {depositReceipts, withdrawalRequests} = data as electra.ExecutionPayload; - payload.depositRequests = depositReceipts.map(serializeDepositReceipt); + const {depositRequests, withdrawalRequests} = data as electra.ExecutionPayload; + payload.depositRequests = depositRequests.map(serializeDepositRequest); payload.withdrawalRequests = withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest); } @@ -326,7 +326,7 @@ export function parseExecutionPayload( } if (ForkSeq[fork] >= ForkSeq.electra) { - // electra adds depositRequests/depositReceipts + // electra adds depositRequests/depositRequests const {depositRequests, withdrawalRequests} = data; // Geth can also reply with null if (depositRequests == null) { @@ -334,7 +334,7 @@ export function parseExecutionPayload( `depositRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` ); } - (executionPayload as electra.ExecutionPayload).depositReceipts = depositRequests.map(deserializeDepositReceipt); + (executionPayload as electra.ExecutionPayload).depositRequests = depositRequests.map(deserializeDepositRequest); if (withdrawalRequests == null) { throw Error( @@ -412,24 +412,24 @@ export function deserializeWithdrawal(serialized: WithdrawalRpc): capella.Withdr } as capella.Withdrawal; } -export function serializeDepositReceipt(depositReceipt: electra.DepositReceipt): DepositReceiptRpc { +export function serializeDepositRequest(depositRequest: electra.DepositRequest): DepositRequestRpc { return { - pubkey: bytesToData(depositReceipt.pubkey), - withdrawalCredentials: bytesToData(depositReceipt.withdrawalCredentials), - amount: numToQuantity(depositReceipt.amount), - signature: bytesToData(depositReceipt.signature), - index: numToQuantity(depositReceipt.index), + pubkey: bytesToData(depositRequest.pubkey), + withdrawalCredentials: bytesToData(depositRequest.withdrawalCredentials), + amount: numToQuantity(depositRequest.amount), + signature: bytesToData(depositRequest.signature), + index: numToQuantity(depositRequest.index), }; } -export function deserializeDepositReceipt(serialized: DepositReceiptRpc): electra.DepositReceipt { +export function deserializeDepositRequest(serialized: DepositRequestRpc): electra.DepositRequest { return { pubkey: dataToBytes(serialized.pubkey, 48), withdrawalCredentials: dataToBytes(serialized.withdrawalCredentials, 32), amount: quantityToNum(serialized.amount), signature: dataToBytes(serialized.signature, 96), index: quantityToNum(serialized.index), - } as electra.DepositReceipt; + } as electra.DepositRequest; } export function serializeExecutionLayerWithdrawalRequest( @@ -457,7 +457,7 @@ export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | ? { transactions: data.transactions.map((tran) => dataToBytes(tran, null)), withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null, - depositReceipts: data.depositRequests ? data.depositRequests.map(deserializeDepositReceipt) : null, + depositRequests: data.depositRequests ? data.depositRequests.map(deserializeDepositRequest) : null, withdrawalRequests: data.withdrawalRequests ? data.withdrawalRequests.map(deserializeExecutionLayerWithdrawalRequest) : null, @@ -470,7 +470,7 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null) ? { transactions: data.transactions.map((tran) => bytesToData(tran)), withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null, - depositRequests: data.depositReceipts ? data.depositReceipts.map(serializeDepositReceipt) : null, + depositRequests: data.depositRequests ? data.depositRequests.map(serializeDepositRequest) : null, withdrawalRequests: data.withdrawalRequests ? data.withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest) : null, diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index 29483b249c85..c503052a74f4 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -72,7 +72,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { } }); - it("Send and get payloads with depositReceipts to/from EL", async () => { + it("Send and get payloads with depositRequests to/from EL", async () => { const {elClient, tearDownCallBack} = await runEL( {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "electra.tmpl"}, {...elRunOptions, ttd: BigInt(0)}, @@ -111,7 +111,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { // 2. Send raw deposit transaction A and B. tx A is to be imported via newPayload, tx B is to be included in payload via getPayload const depositTransactionA = "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; - const depositReceiptA = { + const depositRequestA = { amount: 32000000000, index: 0, pubkey: dataToBytes( @@ -127,7 +127,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { const depositTransactionB = "0x02f9021c8217de018459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120a18b4c7cab0afa273ea9504904521ea8421a4e32740b7611bd3d5095ca99f0cb0000000000000000000000000000000000000000000000000000000000000030a5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca00000000000000000000000000000000000000000000000000000000000000609561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1c001a0644e0a763a34b4bfb9f56a677857b57fcf15e3db57e2f57060e92084f75f3d82a018ba8eaacbd8e6f6917675b1d0362b12ca82850ca8ef9c010430760c2b2e0cb5"; - const depositReceiptB = { + const depositRequestB = { amount: 32000000000, index: 1, pubkey: dataToBytes( @@ -168,7 +168,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { excessBlobGas: 0n, transactions: [dataToBytes(depositTransactionA, null)], withdrawals: [], - depositReceipts: [depositReceiptA], + depositRequests: [depositRequestA], blockNumber: 1, blockHash: dataToBytes(newPayloadBlockHash, 32), receiptsRoot: dataToBytes("0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9", 32), @@ -205,7 +205,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { ); if (!payloadId2) throw Error("InvalidPayloadId"); - // 5. Get the payload. Check depositReceipts field contains deposit + // 5. Get the payload. Check depositRequests field contains deposit // Wait a bit first for besu to pick up tx from the tx pool. await sleep(1000); const payloadAndBlockValue = await executionEngine.getPayload(ForkName.electra, payloadId2); @@ -221,16 +221,16 @@ describe("executionEngine / ExecutionEngineHttp", function () { } } - if (payload.depositReceipts.length !== 1) { - throw Error(`Number of depositReceipts mismatched. Expected: 1, actual: ${payload.depositReceipts.length}`); + if (payload.depositRequests.length !== 1) { + throw Error(`Number of depositRequests mismatched. Expected: 1, actual: ${payload.depositRequests.length}`); } - const actualDepositReceipt = payload.depositReceipts[0]; + const actualDepositRequest = payload.depositRequests[0]; assert.deepStrictEqual( - actualDepositReceipt, - depositReceiptB, - `Deposit receipts mismatched. Expected: ${JSON.stringify(depositReceiptB)}, actual: ${JSON.stringify( - actualDepositReceipt + actualDepositRequest, + depositRequestB, + `Deposit receipts mismatched. Expected: ${JSON.stringify(depositRequestB)}, actual: ${JSON.stringify( + actualDepositRequest )}` ); }); @@ -432,8 +432,8 @@ describe("executionEngine / ExecutionEngineHttp", function () { throw Error("Historical validator length for epoch 1 or 2 is not dropped properly"); } - if (headState.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { - throw Error("state.depositReceiptsStartIndex is not set upon processing new deposit receipt"); + if (headState.depositRequestsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + throw Error("state.depositRequestsStartIndex is not set upon processing new deposit receipt"); } // wait for 1 slot to print current epoch stats diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index 9b8214a88c0a..c674c1dd18f9 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -57,9 +57,9 @@ const operationFns: Record> = blockFns.processDeposit(fork, state, testCase.deposit); }, - deposit_receipt: (state, testCase: {deposit_receipt: electra.DepositReceipt}) => { + deposit_receipt: (state, testCase: {deposit_receipt: electra.DepositRequest}) => { const fork = state.config.getForkSeq(state.slot); - blockFns.processDepositReceipt(fork, state as CachedBeaconStateElectra, testCase.deposit_receipt); + blockFns.processDepositRequest(fork, state as CachedBeaconStateElectra, testCase.deposit_receipt); }, proposer_slashing: (state, testCase: {proposer_slashing: phase0.ProposerSlashing}) => { @@ -127,7 +127,7 @@ const operations: TestRunnerFn = (fork, block: ssz[fork].BeaconBlock, body: ssz[fork].BeaconBlockBody, deposit: ssz.phase0.Deposit, - deposit_receipt: ssz.electra.DepositReceipt, + deposit_receipt: ssz.electra.DepositRequest, proposer_slashing: ssz.phase0.ProposerSlashing, voluntary_exit: ssz.phase0.SignedVoluntaryExit, // Altair diff --git a/packages/beacon-node/test/unit/executionEngine/http.test.ts b/packages/beacon-node/test/unit/executionEngine/http.test.ts index 842f39a5ff90..2cc08c8c78d2 100644 --- a/packages/beacon-node/test/unit/executionEngine/http.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/http.test.ts @@ -193,7 +193,7 @@ describe("ExecutionEngine / http", () => { amount: "0x7b", }, ], - depositReceipts: null, // depositReceipts is null pre-electra + depositRequests: null, // depositRequests is null pre-electra withdrawalRequests: null, }, null, // null returned for missing blocks @@ -203,7 +203,7 @@ describe("ExecutionEngine / http", () => { "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", ], withdrawals: null, // withdrawals is null pre-capella - depositReceipts: null, // depositReceipts is null pre-electra + depositRequests: null, // depositRequests is null pre-electra withdrawalRequests: null, }, ], @@ -252,7 +252,7 @@ describe("ExecutionEngine / http", () => { amount: "0x7b", }, ], - depositReceipts: null, // depositReceipts is null pre-electra + depositRequests: null, // depositRequests is null pre-electra withdrawalRequests: null, }, null, // null returned for missing blocks @@ -262,7 +262,7 @@ describe("ExecutionEngine / http", () => { "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", ], withdrawals: null, // withdrawals is null pre-capella - depositReceipts: null, // depositReceipts is null pre-electra + depositRequests: null, // depositRequests is null pre-electra withdrawalRequests: null, }, ], diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index ad4dd4b88dac..bb55adca1eb0 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -97,7 +97,7 @@ export function generateState( if (forkSeq >= ForkSeq.electra) { const stateElectra = state as electra.BeaconState; - stateElectra.depositReceiptsStartIndex = 2023n; + stateElectra.depositRequestsStartIndex = 2023n; stateElectra.latestExecutionPayloadHeader = ssz.electra.ExecutionPayloadHeader.defaultValue(); } diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 1b460dd39cf2..679371a54d6c 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -115,9 +115,9 @@ export function upgradeLightClientHeader( // eslint-disable-next-line no-fallthrough case ForkName.electra: - (upgradedHeader as LightClientHeader).execution.depositReceiptsRoot = - ssz.electra.LightClientHeader.fields.execution.fields.depositReceiptsRoot.defaultValue(); - (upgradedHeader as electra.LightClientHeader).execution.withdrawalRequestsRoot = + (upgradedHeader as LightClientHeader).execution.depositRequestsRoot = + ssz.electra.LightClientHeader.fields.execution.fields.depositRequestsRoot.defaultValue(); + (upgradedHeader as LightClientHeader).execution.withdrawalRequestsRoot = ssz.electra.LightClientHeader.fields.execution.fields.withdrawalRequestsRoot.defaultValue(); // Break if no further upgrades is required else fall through @@ -157,7 +157,7 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: LightC if (epoch < config.ELECTRA_FORK_EPOCH) { if ( - (header as LightClientHeader).execution.depositReceiptsRoot !== undefined || + (header as LightClientHeader).execution.depositRequestsRoot !== undefined || (header as LightClientHeader).execution.withdrawalRequestsRoot !== undefined ) { return false; diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 65b3cbfb10fd..bc140b864ad9 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -12,7 +12,7 @@ import { } from "@lodestar/params"; import {DepositData} from "@lodestar/types/lib/phase0/types.js"; -import {DepositReceipt} from "@lodestar/types/lib/electra/types.js"; +import {DepositRequest} from "@lodestar/types/lib/electra/types.js"; import {BeaconConfig} from "@lodestar/config"; import {ZERO_HASH} from "../constants/index.js"; import { @@ -53,13 +53,13 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, /** * Adds a new validator into the registry. Or increase balance if already exist. - * Follows applyDeposit() in consensus spec. Will be used by processDeposit() and processDepositReceipt() + * Follows applyDeposit() in consensus spec. Will be used by processDeposit() and processDepositRequest() * */ export function applyDeposit( fork: ForkSeq, state: CachedBeaconStateAllForks, - deposit: DepositData | DepositReceipt + deposit: DepositData | DepositRequest ): void { const {config, validators, epochCtx} = state; const {pubkey, withdrawalCredentials, amount} = deposit; diff --git a/packages/state-transition/src/block/processDepositReceipt.ts b/packages/state-transition/src/block/processDepositRequest.ts similarity index 55% rename from packages/state-transition/src/block/processDepositReceipt.ts rename to packages/state-transition/src/block/processDepositRequest.ts index 140e38d634fd..ca6fe4206188 100644 --- a/packages/state-transition/src/block/processDepositReceipt.ts +++ b/packages/state-transition/src/block/processDepositRequest.ts @@ -4,14 +4,14 @@ import {ForkSeq, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateElectra} from "../types.js"; import {applyDeposit} from "./processDeposit.js"; -export function processDepositReceipt( +export function processDepositRequest( fork: ForkSeq, state: CachedBeaconStateElectra, - depositReceipt: electra.DepositReceipt + depositRequest: electra.DepositRequest ): void { - if (state.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { - state.depositReceiptsStartIndex = BigInt(depositReceipt.index); + if (state.depositRequestsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + state.depositRequestsStartIndex = BigInt(depositRequest.index); } - applyDeposit(fork, state, depositReceipt); + applyDeposit(fork, state, depositRequest); } diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index 8d65762931e7..3ddc3668e487 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -10,7 +10,7 @@ import {processDeposit} from "./processDeposit.js"; import {processVoluntaryExit} from "./processVoluntaryExit.js"; import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js"; import {processExecutionLayerWithdrawalRequest} from "./processExecutionLayerWithdrawalRequest.js"; -import {processDepositReceipt} from "./processDepositReceipt.js"; +import {processDepositRequest} from "./processDepositRequest.js"; import {ProcessBlockOpts} from "./types.js"; import {processConsolidation} from "./processConsolidation.js"; @@ -22,7 +22,7 @@ export { processVoluntaryExit, processExecutionLayerWithdrawalRequest, processBlsToExecutionChange, - processDepositReceipt, + processDepositRequest, }; export function processOperations( @@ -70,8 +70,8 @@ export function processOperations( processExecutionLayerWithdrawalRequest(fork, state as CachedBeaconStateElectra, elWithdrawalRequest); } - for (const depositReceipt of bodyElectra.executionPayload.depositReceipts) { - processDepositReceipt(fork, stateElectra, depositReceipt); + for (const depositRequest of bodyElectra.executionPayload.depositRequests) { + processDepositRequest(fork, stateElectra, depositRequest); } for (const consolidation of bodyElectra.consolidations) { diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 760595c3a86b..a6bc6c331e11 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -25,9 +25,9 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache epoch: stateDeneb.epochCtx.epoch, }); - // latestExecutionPayloadHeader's depositReceiptsRoot and withdrawalRequestsRoot set to zeros by default - // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX - stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + // latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default + // default value of depositRequestsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX + stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; const validatorsArr = stateElectra.validators.getAllReadonly(); diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index 493099fdd982..e8ef93c515d2 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -9,9 +9,9 @@ export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: // eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64 // since the result lies within upper and lower bound of UintNum64 const eth1DataIndexLimit: UintNum64 = - eth1DataToUse.depositCount < electraState.depositReceiptsStartIndex + eth1DataToUse.depositCount < electraState.depositRequestsStartIndex ? eth1DataToUse.depositCount - : Number(electraState.depositReceiptsStartIndex); + : Number(electraState.depositRequestsStartIndex); if (state.eth1DepositIndex < eth1DataIndexLimit) { return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index c7f0ec2f395c..2c55dc61a502 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -172,8 +172,8 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio } if (fork >= ForkSeq.electra) { - (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositReceiptsRoot = - ssz.electra.DepositReceipts.hashTreeRoot((payload as electra.ExecutionPayload).depositReceipts); + (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositRequestsRoot = + ssz.electra.DepositRequests.hashTreeRoot((payload as electra.ExecutionPayload).depositRequests); (bellatrixPayloadFields as electra.ExecutionPayloadHeader).withdrawalRequestsRoot = ssz.electra.ExecutionLayerWithdrawalRequests.hashTreeRoot( (payload as electra.ExecutionPayload).withdrawalRequests diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 537edc7f976f..d5f4c577711f 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -293,7 +293,7 @@ export function initializeBeaconStateFromEth1( stateElectra.latestExecutionPayloadHeader = (executionPayloadHeader as CompositeViewDU) ?? ssz.electra.ExecutionPayloadHeader.defaultViewDU(); - stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; } state.commit(); diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts index e8f7f7a86af8..677a15724ece 100644 --- a/packages/state-transition/test/unit/util/deposit.test.ts +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -43,7 +43,7 @@ describe("getEth1DepositCount", () => { throw Error("Not a post-Electra state"); } - postElectraState.depositReceiptsStartIndex = 1000n; + postElectraState.depositRequestsStartIndex = 1000n; postElectraState.eth1Data.depositCount = 995; // 1. Should get less than MAX_DEPOSIT @@ -77,7 +77,7 @@ describe("getEth1DepositCount", () => { throw Error("Not a post-Electra state"); } - postElectraState.depositReceiptsStartIndex = 1000n; + postElectraState.depositRequestsStartIndex = 1000n; postElectraState.eth1Data.depositCount = 1005; // Before eth1DepositIndex reaching the start index diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 26539dd61365..246c731d8382 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -110,7 +110,7 @@ export const SignedAggregateAndProof = new ContainerType( {typeName: "SignedAggregateAndProof", jsonCase: "eth2"} ); -export const DepositReceipt = new ContainerType( +export const DepositRequest = new ContainerType( { pubkey: BLSPubkey, withdrawalCredentials: Bytes32, @@ -118,10 +118,10 @@ export const DepositReceipt = new ContainerType( signature: BLSSignature, index: DepositIndex, }, - {typeName: "DepositReceipt", jsonCase: "eth2"} + {typeName: "DepositRequest", jsonCase: "eth2"} ); -export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); +export const DepositRequests = new ListCompositeType(DepositRequest, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); export const ExecutionLayerWithdrawalRequest = new ContainerType( { @@ -139,7 +139,7 @@ export const ExecutionLayerWithdrawalRequests = new ListCompositeType( export const ExecutionPayload = new ContainerType( { ...denebSsz.ExecutionPayload.fields, - depositReceipts: DepositReceipts, // New in ELECTRA + depositRequests: DepositRequests, // New in ELECTRA withdrawalRequests: ExecutionLayerWithdrawalRequests, // New in ELECTRA }, {typeName: "ExecutionPayload", jsonCase: "eth2"} @@ -148,7 +148,7 @@ export const ExecutionPayload = new ContainerType( export const ExecutionPayloadHeader = new ContainerType( { ...denebSsz.ExecutionPayloadHeader.fields, - depositReceiptsRoot: Root, // New in ELECTRA + depositRequestsRoot: Root, // New in ELECTRA withdrawalRequestsRoot: Root, // New in ELECTRA }, {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} @@ -335,7 +335,7 @@ export const BeaconState = new ContainerType( nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex, // Deep history valid from Capella onwards historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, - depositReceiptsStartIndex: UintBn64, // New in ELECTRA + depositRequestsStartIndex: UintBn64, // New in ELECTRA depositBalanceToConsume: Gwei, // [New in Electra] exitBalanceToConsume: Gwei, // [New in Electra] earliestExitEpoch: Epoch, // [New in Electra] diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index 4de209b48960..53b95e95525c 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -9,8 +9,8 @@ export type AttesterSlashing = ValueOf; export type AggregateAndProof = ValueOf; export type SignedAggregateAndProof = ValueOf; -export type DepositReceipt = ValueOf; -export type DepositReceipts = ValueOf; +export type DepositRequest = ValueOf; +export type DepositRequests = ValueOf; export type ExecutionLayerWithdrawalRequest = ValueOf; export type ExecutionLayerWithdrawalRequests = ValueOf; From 3cf76cb5e446890d4adee8dca158ec0d93de1699 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Wed, 8 May 2024 17:14:44 +0200 Subject: [PATCH 025/259] test: enable spec tests related to eip-7549 (#6741) * initial commit * Update gossip validation * Update attestation gossip validation * aggregateAndProof validation * Extend spec runner to be more flexible * Add missing state attributes for electra * Fix ss data types for electra spec * Make the spec runner more flexible * Fix the bug in process attestation * Update the sepc test version * clean up * Misc * Fix the build erros * feat: get attestations for electra block (#6732) * feat: getAttestationsForBlock() for electra * chore: fix lint * fix: MAX_ATTESTATIONS_PER_GROUP_ELECTRA and address PR comments * chore: unit test aggregateConsolidation * Fix rebase mistake * Address my own comment :) --------- Co-authored-by: Navie Chan * Fix check-types * Address comments * Fix the build erros * Extend spec runner to be more flexible * Add missing state attributes for electra * Fix ss data types for electra spec * Make the spec runner more flexible * Fix the bug in process attestation * Update the sepc test version * Fix rebase issue * Update committee index count check --------- Co-authored-by: NC Co-authored-by: Navie Chan Co-authored-by: tuyennhv --- .../test/spec/presets/operations.test.ts | 4 +-- .../test/spec/specTestVersioning.ts | 2 +- .../test/spec/utils/specTestIterator.ts | 27 +++++++++++++------ .../src/block/processAttestationPhase0.ts | 19 +++++++------ packages/types/src/electra/sszTypes.ts | 20 +++++++------- 5 files changed, 43 insertions(+), 29 deletions(-) diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index c674c1dd18f9..ca215f1e197c 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -122,8 +122,8 @@ const operations: TestRunnerFn = (fork, sszTypes: { pre: ssz[fork].BeaconState, post: ssz[fork].BeaconState, - attestation: ssz.phase0.Attestation, - attester_slashing: ssz.phase0.AttesterSlashing, + attestation: fork === ForkName.electra ? ssz.electra.Attestation : ssz.phase0.Attestation, + attester_slashing: fork === ForkName.electra ? ssz.electra.AttesterSlashing : ssz.phase0.AttesterSlashing, block: ssz[fork].BeaconBlock, body: ssz[fork].BeaconBlockBody, deposit: ssz.phase0.Deposit, diff --git a/packages/beacon-node/test/spec/specTestVersioning.ts b/packages/beacon-node/test/spec/specTestVersioning.ts index 06b02ab5304e..9195532379a0 100644 --- a/packages/beacon-node/test/spec/specTestVersioning.ts +++ b/packages/beacon-node/test/spec/specTestVersioning.ts @@ -15,7 +15,7 @@ import {DownloadTestsOptions} from "@lodestar/spec-test-util/downloadTests"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const ethereumConsensusSpecsTests: DownloadTestsOptions = { - specVersion: "v1.5.0-alpha.1", + specVersion: "v1.5.0-alpha.2", // Target directory is the host package root: 'packages/*/spec-tests' outputDir: path.join(__dirname, "../../spec-tests"), specTestsRepoUrl: "https://github.com/ethereum/consensus-spec-tests", diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index 88d7cbdea9e6..b99bc281cf50 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -14,7 +14,8 @@ const ARTIFACT_FILENAMES = new Set([ ]); export interface SkipOpts { - skippedPrefixes?: string[]; + skippedTestSuites?: RegExp[]; + skippedTests?: RegExp[]; skippedForks?: string[]; skippedRunners?: string[]; skippedHandlers?: string[]; @@ -57,14 +58,17 @@ const coveredTestRunners = [ // ], // ``` export const defaultSkipOpts: SkipOpts = { - skippedForks: ["electra", "eip7594"], + skippedForks: ["eip7594"], // TODO: capella // BeaconBlockBody proof in lightclient is the new addition in v1.3.0-rc.2-hotfix // Skip them for now to enable subsequently - skippedPrefixes: [ - "capella/light_client/single_merkle_proof/BeaconBlockBody", - "deneb/light_client/single_merkle_proof/BeaconBlockBody", + skippedTestSuites: [ + /^capella\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, + /^deneb\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, + // /^electra\/(?!operations\/attestations)(?!operations\/attester_slashing)/, + /^electra\/(?!operations\/attestation)/, ], + skippedTests: [], skippedRunners: ["merkle_proof", "networking"], }; @@ -100,7 +104,10 @@ export function specTestIterator( opts: SkipOpts = defaultSkipOpts ): void { for (const forkStr of readdirSyncSpec(configDirpath)) { - if (opts?.skippedForks?.includes(forkStr)) { + if ( + opts?.skippedForks?.includes(forkStr) || + (process.env.SPEC_FILTER_FORK && forkStr !== process.env.SPEC_FILTER_FORK) + ) { continue; } const fork = forkStr as ForkName; @@ -134,7 +141,7 @@ export function specTestIterator( for (const testSuite of readdirSyncSpec(testHandlerDirpath)) { const testId = `${fork}/${testRunnerName}/${testHandler}/${testSuite}`; - if (opts?.skippedPrefixes?.some((skippedPrefix) => testId.startsWith(skippedPrefix))) { + if (opts?.skippedTestSuites?.some((skippedMatch) => testId.match(skippedMatch))) { displaySkipTest(testId); } else if (fork === undefined) { displayFailTest(testId, `Unknown fork ${forkStr}`); @@ -150,7 +157,11 @@ export function specTestIterator( // Generic testRunner else { const {testFunction, options} = testRunner.fn(fork, testHandler, testSuite); - + if (opts.skippedTests && options.shouldSkip === undefined) { + options.shouldSkip = (_testCase: any, name: string, _index: number): boolean => { + return opts?.skippedTests?.some((skippedMatch) => name.match(skippedMatch)) ?? false; + }; + } describeDirectorySpecTest(testId, testSuiteDirpath, testFunction, options); } } diff --git a/packages/state-transition/src/block/processAttestationPhase0.ts b/packages/state-transition/src/block/processAttestationPhase0.ts index c7c6b3b531a8..3bb5b71fa267 100644 --- a/packages/state-transition/src/block/processAttestationPhase0.ts +++ b/packages/state-transition/src/block/processAttestationPhase0.ts @@ -91,17 +91,20 @@ export function validateAttestation( if (fork >= ForkSeq.electra) { assert.equal(data.index, 0, `AttestationData.index must be zero: index=${data.index}`); const attestationElectra = attestation as electra.Attestation; - const committeeBitsLength = attestationElectra.committeeBits.bitLen; - - if (committeeBitsLength > committeeCount) { - throw new Error( - `Attestation committee bits length are longer than number of committees: committeeBitsLength=${committeeBitsLength} numCommittees=${committeeCount}` - ); - } - // TODO Electra: this should be obsolete soon when the spec switches to committeeIndices const committeeIndices = attestationElectra.committeeBits.getTrueBitIndexes(); + if (committeeIndices.length === 0) { + throw Error("Attestation should have at least one committee bit set"); + } else { + const lastCommitteeIndex = committeeIndices[committeeIndices.length - 1]; + if (lastCommitteeIndex >= committeeCount) { + throw new Error( + `Attestation committee index exceeds committee count: lastCommitteeIndex=${lastCommitteeIndex} numCommittees=${committeeCount}` + ); + } + } + // Get total number of attestation participant of every committee specified const participantCount = committeeIndices .map((committeeIndex) => epochCtx.getBeaconCommittee(data.slot, committeeIndex).length) diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 246c731d8382..ee8d2702c65d 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -19,8 +19,8 @@ import { MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, MAX_CONSOLIDATIONS, PENDING_BALANCE_DEPOSITS_LIMIT, - PENDING_CONSOLIDATIONS_LIMIT, PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, } from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; @@ -335,15 +335,15 @@ export const BeaconState = new ContainerType( nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex, // Deep history valid from Capella onwards historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, - depositRequestsStartIndex: UintBn64, // New in ELECTRA - depositBalanceToConsume: Gwei, // [New in Electra] - exitBalanceToConsume: Gwei, // [New in Electra] - earliestExitEpoch: Epoch, // [New in Electra] - consolidationBalanceToConsume: Gwei, // [New in Electra] - earliestConsolidationEpoch: Epoch, // [New in Electra] - pendingBalanceDeposits: new ListCompositeType(PendingBalanceDeposit, PENDING_BALANCE_DEPOSITS_LIMIT), // [New in Electra] - pendingPartialWithdrawals: new ListCompositeType(PartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT), // [New in Electra] - pendingConsolidations: new ListCompositeType(PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT), // [New in Electra] + depositRequestsStartIndex: UintBn64, // New in ELECTRA:EIP6110 + depositBalanceToConsume: Gwei, // New in Electra:EIP7251 + exitBalanceToConsume: Gwei, // New in Electra:EIP7251 + earliestExitEpoch: Epoch, // New in Electra:EIP7251 + consolidationBalanceToConsume: Gwei, // New in Electra:EIP7251 + earliestConsolidationEpoch: Epoch, // New in Electra:EIP7251 + pendingBalanceDeposits: new ListCompositeType(PendingBalanceDeposit, Number(PENDING_BALANCE_DEPOSITS_LIMIT)), // new in electra:eip7251 + pendingPartialWithdrawals: new ListCompositeType(PartialWithdrawal, Number(PENDING_PARTIAL_WITHDRAWALS_LIMIT)), // New in Electra:EIP7251 + pendingConsolidations: new ListCompositeType(PendingConsolidation, Number(PENDING_CONSOLIDATIONS_LIMIT)), // new in electra:eip7251 }, {typeName: "BeaconState", jsonCase: "eth2"} ); From a0fff8f4ebd0e0abed455ddf93192e95f6310ab5 Mon Sep 17 00:00:00 2001 From: NC Date: Wed, 8 May 2024 18:37:14 +0300 Subject: [PATCH 026/259] fix: fix e2e test in electra-fork (#6751) Update spec version --- packages/params/test/e2e/ensure-config-is-synced.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/params/test/e2e/ensure-config-is-synced.test.ts b/packages/params/test/e2e/ensure-config-is-synced.test.ts index 06fb4bae000c..515d8f44a710 100644 --- a/packages/params/test/e2e/ensure-config-is-synced.test.ts +++ b/packages/params/test/e2e/ensure-config-is-synced.test.ts @@ -8,7 +8,7 @@ import {loadConfigYaml} from "../yaml.js"; // Not e2e, but slow. Run with e2e tests /** https://github.com/ethereum/consensus-specs/releases */ -const specConfigCommit = "v1.4.0-beta.5"; +const specConfigCommit = "v1.5.0-alpha.2"; describe("Ensure config is synced", function () { vi.setConfig({testTimeout: 60 * 1000}); From 15b7cdf8f9cd6ebd79a8e88abbce89f74c38075b Mon Sep 17 00:00:00 2001 From: g11tech Date: Thu, 9 May 2024 00:55:18 +0530 Subject: [PATCH 027/259] feat: get the basic integration working with the ethereumjs electra build (#6752) --- .../el-interop/ethereumjsdocker/electra.tmpl | 94 +++++++++++++++++++ .../test/sim/electra-interop.test.ts | 65 +++++++------ 2 files changed, 126 insertions(+), 33 deletions(-) create mode 100644 packages/beacon-node/test/scripts/el-interop/ethereumjsdocker/electra.tmpl diff --git a/packages/beacon-node/test/scripts/el-interop/ethereumjsdocker/electra.tmpl b/packages/beacon-node/test/scripts/el-interop/ethereumjsdocker/electra.tmpl new file mode 100644 index 000000000000..d557d505c649 --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/ethereumjsdocker/electra.tmpl @@ -0,0 +1,94 @@ +{ +"config": { +"chainId":1, +"homesteadBlock":0, +"eip150Block":0, +"eip155Block":0, +"eip158Block":0, +"byzantiumBlock":0, +"constantinopleBlock":0, +"petersburgBlock":0, +"istanbulBlock":0, +"muirGlacierBlock":0, +"berlinBlock":0, +"londonBlock":0, +"shanghaiTime":0, +"cancunTime": 0, +"pragueTime": 0, +"clique": { +"blockperiodseconds": 5, +"epochlength": 30000 +}, +"terminalTotalDifficulty":${TTD} +}, +"nonce":"0x42", +"timestamp":"0x0", +"extraData":"0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", +"gasLimit":"0x1C9C380", +"difficulty":"0x400000000", +"mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", +"coinbase":"0x0000000000000000000000000000000000000000", +"alloc":{ + "0x610adc49ecd66cbf176a8247ebd59096c031bd9f": { + "balance": "0x6d6172697573766477000000" + }, + "0xa4664C40AACeBD82A2Db79f0ea36C06Bc6A19Adb": { + "balance": "1000000000000000000000000000" + }, + "0x00000000219ab540356cBB839Cbe05303d7705Fa": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a2646970667358221220dceca8706b29e917dacf25fceef95acac8d90d765ac926663ce4096195952b6164736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + }, + "0x25a219378dad9b3503c8268c9ca836a52427a4fb": { + "balance": "0", + "nonce": "1", + "code": "0x60203611603157600143035f35116029575f356120000143116029576120005f3506545f5260205ff35b5f5f5260205ff35b5f5ffd00" + }, + "0x00A3ca265EBcb825B45F985A16CEFB49958cE017": { + "balance": "0", + "nonce": "1", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": + "0x000000000000000000000000000000000000000000000000000000000000049d" + } + } +}, +"number":"0x0", +"gasUsed":"0x0", +"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", +"baseFeePerGas":"0x7" +} \ No newline at end of file diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index c503052a74f4..78010ff364ad 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -28,9 +28,7 @@ import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; // NOTE: How to run -// DEV_RUN=true EL_BINARY_DIR=naviechan/besu:v6110 EL_SCRIPT_DIR=besudocker yarn vitest --run test/sim/electra-interop.test.ts -// or -// DEV_RUN=true EL_BINARY_DIR=/Volumes/fast_boi/navie/Documents/workspace/besu/build/install/besu/bin EL_SCRIPT_DIR=besu yarn vitest --run test/sim/electra-interop.test.ts +// DEV_RUN=true EL_BINARY_DIR=ethpandaops/ethereumjs:master-0e06ddf EL_SCRIPT_DIR=ethereumjsdocker yarn vitest --run test/sim/electra-interop.test.ts // ``` /* eslint-disable no-console, @typescript-eslint/naming-convention */ @@ -110,35 +108,35 @@ describe("executionEngine / ExecutionEngineHttp", function () { // 2. Send raw deposit transaction A and B. tx A is to be imported via newPayload, tx B is to be included in payload via getPayload const depositTransactionA = - "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; + "0x02f90213018080648401c9c3809400000000219ab540356cbb839cbe05303d7705fa8901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001208cd4e5a69709cf8ee5b1b73d6efbf3f33bcac92fb7e4ce62b2467542fb50a72d0000000000000000000000000000000000000000000000000000000000000030ac842878bb70009552a4cfcad801d6e659c50bd50d7d03306790cb455ce7363c5b6972f0159d170f625a99b2064dbefc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020010000000000000000000000818ccb1c4eda80270b04d6df822b1e72dd83c3030000000000000000000000000000000000000000000000000000000000000060a747f75c72d0cf0d2b52504c7385b516f0523e2f0842416399f42b4aee5c6384a5674f6426b1cc3d0827886fa9b909e616f5c9f61f986013ed2b9bf37071cbae951136265b549f44e3c8e26233c0433e9124b7fd0dc86e82f9fedfc0a179d769c080a067c9857d27a42f8fde4d5cf2d6c324af94469ac93ec867eacdd9002e1297835fa07927224866e03d51fb1ae94390e7aec453cad8df9e048892e98f945178eab254"; const depositRequestA = { amount: 32000000000, index: 0, pubkey: dataToBytes( - "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9", + "0xac842878bb70009552a4cfcad801d6e659c50bd50d7d03306790cb455ce7363c5b6972f0159d170f625a99b2064dbefc", 48 ), signature: dataToBytes( - "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9", + "0xa747f75c72d0cf0d2b52504c7385b516f0523e2f0842416399f42b4aee5c6384a5674f6426b1cc3d0827886fa9b909e616f5c9f61f986013ed2b9bf37071cbae951136265b549f44e3c8e26233c0433e9124b7fd0dc86e82f9fedfc0a179d769", 96 ), - withdrawalCredentials: dataToBytes("0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2", 32), + withdrawalCredentials: dataToBytes("0x010000000000000000000000818ccb1c4eda80270b04d6df822b1e72dd83c303", 32), }; const depositTransactionB = - "0x02f9021c8217de018459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120a18b4c7cab0afa273ea9504904521ea8421a4e32740b7611bd3d5095ca99f0cb0000000000000000000000000000000000000000000000000000000000000030a5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca00000000000000000000000000000000000000000000000000000000000000609561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1c001a0644e0a763a34b4bfb9f56a677857b57fcf15e3db57e2f57060e92084f75f3d82a018ba8eaacbd8e6f6917675b1d0362b12ca82850ca8ef9c010430760c2b2e0cb5"; + "0x02f90213010180648401c9c3809400000000219ab540356cbb839cbe05303d7705fa8901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120a7ec6a3459bf9389265f62abbdffcd0ef20924bd03e4856d3b964edf565bd8e80000000000000000000000000000000000000000000000000000000000000030a5290ddb9abd6a7fb8bac3414c6c7ff093a18ff297c1eada20464de388b14aafa505bfc98847ca7e6f7ca3aa9d4ca769000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020010000000000000000000000da628fed218cbe3a9e684a9f51c49dd63a229a1d000000000000000000000000000000000000000000000000000000000000006080e12262f94795ce3453f17eea2dd44843ff7977d303b192c1d2a4ce0dbebc8856c398d6445cbf244ba9e99307ead1e30b2544a5e9693cdd5196a33c46e2dd8a8b83afc8278c1ea79cd5c13cac2b96a62257b3636787d0f1e0f881c50a4667ddc080a0b653aad27e504d4fcd19b7c317ffbd2a26a81d6ac14ecea6a891a63dcf7816dfa02953273b4cddc93b2a9ba21aaeb0db988cb1086319dd0b91f79bc101adfe32e4"; const depositRequestB = { amount: 32000000000, index: 1, pubkey: dataToBytes( - "0xa5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b", + "0xa5290ddb9abd6a7fb8bac3414c6c7ff093a18ff297c1eada20464de388b14aafa505bfc98847ca7e6f7ca3aa9d4ca769", 48 ), signature: dataToBytes( - "0x9561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1", + "0x80e12262f94795ce3453f17eea2dd44843ff7977d303b192c1d2a4ce0dbebc8856c398d6445cbf244ba9e99307ead1e30b2544a5e9693cdd5196a33c46e2dd8a8b83afc8278c1ea79cd5c13cac2b96a62257b3636787d0f1e0f881c50a4667dd", 96 ), - withdrawalCredentials: dataToBytes("0x001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca", 32), + withdrawalCredentials: dataToBytes("0x010000000000000000000000da628fed218cbe3a9e684a9f51c49dd63a229a1d", 32), }; sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e: Error) => { @@ -150,18 +148,18 @@ describe("executionEngine / ExecutionEngineHttp", function () { }); // 3. Import new payload with tx A and deposit receipt A - const newPayloadBlockHash = "0xfd1189e6ea0814b7d40d4e50b31ae5feabbb2acff39399457bbdda7cb5ccd490"; + const newPayloadBlockHash = "0x4cec1852552239cf78e8bd2db35ff9396acb6b40c3ce486e6e3028bc75c9faec"; const newPayload = { - parentHash: dataToBytes("0x26118cf71453320edcebbc4ebb34af5b578087a32385b80108bf691fa23efc42", 32), + parentHash: dataToBytes("0xeb86e5aca89ea5477a6e169a389efbbe7e5a3d5f5c5296bcde3a4b032ea9bae8", 32), feeRecipient: dataToBytes("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 20), - stateRoot: dataToBytes("0x14208ac0e218167936e220b72d5d5887a963cb858ea2f2d268518f014a3da3fa", 32), + stateRoot: dataToBytes("0x686ce0478cabce79b298712fefee4aefd2fac1ab4a4813936d2c1ccca788bbc3", 32), logsBloom: dataToBytes( - "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", + "0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", 256 ), prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), gasLimit: 30000000, - gasUsed: 84846, + gasUsed: 84714, timestamp: 16, extraData: dataToBytes("0x", 0), baseFeePerGas: 7n, @@ -171,7 +169,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { depositRequests: [depositRequestA], blockNumber: 1, blockHash: dataToBytes(newPayloadBlockHash, 32), - receiptsRoot: dataToBytes("0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9", 32), + receiptsRoot: dataToBytes("0x0b67bea29f17eeb290685e01e9a2e4cd77a83471d9985a8ce27997a7ed3ee3f8", 32), blobGasUsed: 0n, withdrawalRequests: [], }; @@ -235,21 +233,22 @@ describe("executionEngine / ExecutionEngineHttp", function () { ); }); - it("Post-merge, run for a few blocks", async function () { - console.log("\n\nPost-merge, run for a few blocks\n\n"); - const {elClient, tearDownCallBack} = await runEL( - {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "electra.tmpl"}, - {...elRunOptions, ttd: BigInt(0)}, - controller.signal - ); - afterEachCallbacks.push(() => tearDownCallBack()); - - await runNodeWithEL({ - elClient, - electraEpoch: 0, - testName: "post-merge", - }); - }); + // TODO: get this post merge run working + // it("Post-merge, run for a few blocks", async function () { + // console.log("\n\nPost-merge, run for a few blocks\n\n"); + // const {elClient, tearDownCallBack} = await runEL( + // {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "electra.tmpl"}, + // {...elRunOptions, ttd: BigInt(0)}, + // controller.signal + // ); + // afterEachCallbacks.push(() => tearDownCallBack()); + + // await runNodeWithEL({ + // elClient, + // electraEpoch: 0, + // testName: "post-merge", + // }); + // }); /** * Want to test two things: @@ -364,7 +363,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { // send raw tx at slot 1 const depositTransaction = - "0x02f9021e8217de8085012a05f20085019254d380830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120ef950826b191ebea0bbafa92a2c6bffa8239c6f456d92891ce2852b8360f0d30000000000000000000000000000000000000000000000000000000000000003095e4f91aea91a9e00387fad9d60997cff6cbf68d42d1b6629a7b248cdef255f94a2a2381e5d4125273fe42da5f7aa0e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b6c06e65228046268aa918baf78e072c25e65aa0bcf258cefcac3371c47df81bc4d43ca942f5fc28f9a563e925fd9c5010bc8c300add3faf3af0d61fabaaf03694020feaafb03e47c1bc4fcf082684c7ed3f7d5839d1722214b24f95ad2b226cc080a0be1161617492e4ca2fcb89edcadf5e71e8cac0d6447d18cfde9b55e5a8412417a07ec8c47dd484036c745049bb2e2980d44e38d4dacac50dc4a14a2f23c52f2e5f"; + "0x02f90213018080648401c9c3809400000000219ab540356cbb839cbe05303d7705fa8901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001208cd4e5a69709cf8ee5b1b73d6efbf3f33bcac92fb7e4ce62b2467542fb50a72d0000000000000000000000000000000000000000000000000000000000000030ac842878bb70009552a4cfcad801d6e659c50bd50d7d03306790cb455ce7363c5b6972f0159d170f625a99b2064dbefc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020010000000000000000000000818ccb1c4eda80270b04d6df822b1e72dd83c3030000000000000000000000000000000000000000000000000000000000000060a747f75c72d0cf0d2b52504c7385b516f0523e2f0842416399f42b4aee5c6384a5674f6426b1cc3d0827886fa9b909e616f5c9f61f986013ed2b9bf37071cbae951136265b549f44e3c8e26233c0433e9124b7fd0dc86e82f9fedfc0a179d769c080a067c9857d27a42f8fde4d5cf2d6c324af94469ac93ec867eacdd9002e1297835fa07927224866e03d51fb1ae94390e7aec453cad8df9e048892e98f945178eab254"; sendRawTransactionBig(ethRpcUrl, depositTransaction, `${dataPath}/deposit.json`).catch((e: Error) => { loggerNodeA.error("Fail to send raw deposit transaction", undefined, e); }); From 9f599f38a9b42cc44e5dec8ffc4401466654e840 Mon Sep 17 00:00:00 2001 From: g11tech Date: Thu, 9 May 2024 22:29:39 +0530 Subject: [PATCH 028/259] feat: apply some fixes and hacks to get the single node devnet working with fork transition (#6754) --- .../chain/produceBlock/produceBlockBody.ts | 5 ++ .../src/slot/upgradeStateToElectra.ts | 74 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index ba560d5a7ff0..53f59850b647 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -17,6 +17,7 @@ import { BlindedBeaconBlockBody, BlindedBeaconBlock, sszTypesFor, + electra, } from "@lodestar/types"; import { CachedBeaconStateAllForks, @@ -342,6 +343,10 @@ export async function produceBlockBody( } } + if (ForkSeq[fork] >= ForkSeq.electra) { + (blockBody as electra.BeaconBlockBody).consolidations = []; + } + Object.assign(logMeta, {executionPayloadValue}); this.logger.verbose("Produced beacon block body", logMeta); diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index a6bc6c331e11..121425265b50 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -14,6 +14,80 @@ import { export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): CachedBeaconStateElectra { const {config} = stateDeneb; + ssz.deneb.BeaconState.commitViewDU(stateDeneb); + const stateElectraCloned = stateDeneb; + + const stateElectraView = ssz.electra.BeaconState.defaultViewDU(); + stateElectraView.genesisTime = stateElectraCloned.genesisTime; + stateElectraView.genesisValidatorsRoot = stateElectraCloned.genesisValidatorsRoot; + stateElectraView.slot = stateElectraCloned.slot; + stateElectraView.fork = ssz.phase0.Fork.toViewDU({ + previousVersion: stateDeneb.fork.currentVersion, + currentVersion: config.ELECTRA_FORK_VERSION, + epoch: stateDeneb.epochCtx.epoch, + }); + stateElectraView.latestBlockHeader = stateElectraCloned.latestBlockHeader; + stateElectraView.blockRoots = stateElectraCloned.blockRoots; + stateElectraView.stateRoots = stateElectraCloned.stateRoots; + stateElectraView.historicalRoots = stateElectraCloned.historicalRoots; + stateElectraView.eth1Data = stateElectraCloned.eth1Data; + stateElectraView.eth1DataVotes = stateElectraCloned.eth1DataVotes; + stateElectraView.eth1DepositIndex = stateElectraCloned.eth1DepositIndex; + stateElectraView.validators = stateElectraCloned.validators; + stateElectraView.balances = stateElectraCloned.balances; + stateElectraView.randaoMixes = stateElectraCloned.randaoMixes; + stateElectraView.slashings = stateElectraCloned.slashings; + stateElectraView.previousEpochParticipation = stateElectraCloned.previousEpochParticipation; + stateElectraView.currentEpochParticipation = stateElectraCloned.currentEpochParticipation; + stateElectraView.justificationBits = stateElectraCloned.justificationBits; + stateElectraView.previousJustifiedCheckpoint = stateElectraCloned.previousJustifiedCheckpoint; + stateElectraView.currentJustifiedCheckpoint = stateElectraCloned.currentJustifiedCheckpoint; + stateElectraView.finalizedCheckpoint = stateElectraCloned.finalizedCheckpoint; + stateElectraView.inactivityScores = stateElectraCloned.inactivityScores; + stateElectraView.currentSyncCommittee = stateElectraCloned.currentSyncCommittee; + stateElectraView.nextSyncCommittee = stateElectraCloned.nextSyncCommittee; + stateElectraView.latestExecutionPayloadHeader = ssz.electra.BeaconState.fields.latestExecutionPayloadHeader.toViewDU({ + ...stateElectraCloned.latestExecutionPayloadHeader.toValue(), + depositRequestsRoot: ssz.Root.defaultValue(), + withdrawalRequestsRoot: ssz.Root.defaultValue(), + }); + stateElectraView.nextWithdrawalIndex = stateDeneb.nextWithdrawalIndex; + stateElectraView.nextWithdrawalValidatorIndex = stateDeneb.nextWithdrawalValidatorIndex; + stateElectraView.historicalSummaries = stateElectraCloned.historicalSummaries; + + // latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default + // default value of depositRequestsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX + stateElectraView.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + + const validatorsArr = stateElectraView.validators.getAllReadonly(); + + for (let i = 0; i < validatorsArr.length; i++) { + const validator = validatorsArr[i]; + + // [EIP-7251]: add validators that are not yet active to pending balance deposits + if (validator.activationEligibilityEpoch === FAR_FUTURE_EPOCH) { + queueEntireBalanceAndResetValidator(stateElectraView as CachedBeaconStateElectra, i); + } + + // [EIP-7251]: Ensure early adopters of compounding credentials go through the activation churn + const withdrawalCredential = validator.withdrawalCredentials; + if (hasCompoundingWithdrawalCredential(withdrawalCredential)) { + queueExcessActiveBalance(stateElectraView as CachedBeaconStateElectra, i); + } + } + + const stateElectra = getCachedBeaconState(stateElectraView, stateDeneb); + // Commit new added fields ViewDU to the root node + stateElectra.commit(); + // Clear cache to ensure the cache of deneb fields is not used by new ELECTRA fields + stateElectra["clearCache"](); + + return stateElectra; +} + +export function upgradeStateToElectraOriginal(stateDeneb: CachedBeaconStateDeneb): CachedBeaconStateElectra { + const {config} = stateDeneb; + const stateElectraNode = ssz.deneb.BeaconState.commitViewDU(stateDeneb); const stateElectraView = ssz.electra.BeaconState.getViewDU(stateElectraNode); From c34eac700460d036aed302f8ac5d40cb6fdadfb7 Mon Sep 17 00:00:00 2001 From: twoeths Date: Fri, 10 May 2024 17:52:08 +0700 Subject: [PATCH 029/259] fix: get aggregate and proofs signature sets (#6757) fix: get signature for SignedAggregateAndProof based on fork --- .../validation/signatureSets/aggregateAndProof.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts index 59787341cfb9..411f33f68e66 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts @@ -1,7 +1,7 @@ -import {PublicKey} from "@chainsafe/blst"; -import {DOMAIN_AGGREGATE_AND_PROOF} from "@lodestar/params"; -import {ssz} from "@lodestar/types"; -import {Epoch, phase0} from "@lodestar/types"; +import type {PublicKey} from "@chainsafe/bls/types"; +import {DOMAIN_AGGREGATE_AND_PROOF, ForkSeq} from "@lodestar/params"; +import {allForks, ssz} from "@lodestar/types"; +import {Epoch} from "@lodestar/types"; import { computeSigningRoot, computeStartSlotAtEpoch, @@ -13,7 +13,7 @@ import {BeaconConfig} from "@lodestar/config"; export function getAggregateAndProofSigningRoot( config: BeaconConfig, epoch: Epoch, - aggregateAndProof: phase0.SignedAggregateAndProof + aggregateAndProof: allForks.SignedAggregateAndProof ): Uint8Array { // previously, we call `const aggregatorDomain = state.config.getDomain(state.slot, DOMAIN_AGGREGATE_AND_PROOF, slot);` // at fork boundary, it's required to dial to target epoch https://github.com/ChainSafe/lodestar/blob/v1.11.3/packages/beacon-node/src/chain/validation/attestation.ts#L573 @@ -21,14 +21,15 @@ export function getAggregateAndProofSigningRoot( const slot = computeStartSlotAtEpoch(epoch); const fork = config.getForkName(slot); const aggregatorDomain = config.getDomainAtFork(fork, DOMAIN_AGGREGATE_AND_PROOF); - return computeSigningRoot(ssz.phase0.AggregateAndProof, aggregateAndProof.message, aggregatorDomain); + const sszType = ForkSeq[fork] >= ForkSeq.electra ? ssz.electra.AggregateAndProof : ssz.phase0.AggregateAndProof; + return computeSigningRoot(sszType, aggregateAndProof.message, aggregatorDomain); } export function getAggregateAndProofSignatureSet( config: BeaconConfig, epoch: Epoch, aggregator: PublicKey, - aggregateAndProof: phase0.SignedAggregateAndProof + aggregateAndProof: allForks.SignedAggregateAndProof ): ISignatureSet { return createSingleSignatureSetFromComponents( aggregator, From 81e76820c6957279ae96e01e3fabfb19d2e06cec Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Sat, 11 May 2024 00:01:42 +0200 Subject: [PATCH 030/259] test(spec): fix attestors slashing specs for electra fork (#6758) * Fix attester slashing specs for electra * Remove unused import * Add code comment * Update the expression * Update the fork check --- packages/beacon-node/test/spec/utils/specTestIterator.ts | 3 +-- .../src/block/isValidIndexedAttestation.ts | 8 ++++++-- packages/state-transition/src/util/epoch.ts | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index b99bc281cf50..393983bb8a56 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -65,8 +65,7 @@ export const defaultSkipOpts: SkipOpts = { skippedTestSuites: [ /^capella\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, /^deneb\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, - // /^electra\/(?!operations\/attestations)(?!operations\/attester_slashing)/, - /^electra\/(?!operations\/attestation)/, + /^electra\/(?!operations\/attestations)(?!operations\/attester_slashing)/, ], skippedTests: [], skippedRunners: ["merkle_proof", "networking"], diff --git a/packages/state-transition/src/block/isValidIndexedAttestation.ts b/packages/state-transition/src/block/isValidIndexedAttestation.ts index e3965b97ee73..33d92a208260 100644 --- a/packages/state-transition/src/block/isValidIndexedAttestation.ts +++ b/packages/state-transition/src/block/isValidIndexedAttestation.ts @@ -1,4 +1,4 @@ -import {MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; +import {ForkSeq, MAX_COMMITTEES_PER_SLOT, MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; import {phase0} from "@lodestar/types"; import {CachedBeaconStateAllForks} from "../types.js"; import {verifySignatureSet} from "../util/index.js"; @@ -44,7 +44,11 @@ export function isValidIndexedAttestationBigint( */ export function isValidIndexedAttestationIndices(state: CachedBeaconStateAllForks, indices: number[]): boolean { // verify max number of indices - if (!(indices.length > 0 && indices.length <= MAX_VALIDATORS_PER_COMMITTEE)) { + const maxIndices = + state.config.getForkSeq(state.slot) >= ForkSeq.electra + ? MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT + : MAX_VALIDATORS_PER_COMMITTEE; + if (!(indices.length > 0 && indices.length <= maxIndices)) { return false; } diff --git a/packages/state-transition/src/util/epoch.ts b/packages/state-transition/src/util/epoch.ts index 3ac77556e3cb..67837780dca9 100644 --- a/packages/state-transition/src/util/epoch.ts +++ b/packages/state-transition/src/util/epoch.ts @@ -52,7 +52,7 @@ export function computeExitEpochAndUpdateChurn(state: CachedBeaconStateElectra, // Exit doesn't fit in the current earliest epoch. if (exitBalance > exitBalanceToConsume) { const balanceToProcess = Number(exitBalance) - exitBalanceToConsume; - const additionalEpochs = Math.floor((balanceToProcess - 1) / (perEpochChurn + 1)); + const additionalEpochs = Math.floor((balanceToProcess - 1) / perEpochChurn) + 1; earliestExitEpoch += additionalEpochs; exitBalanceToConsume += additionalEpochs * perEpochChurn; } From f2be31798f96dd104d9bfaa9d9e0b420e6714cfe Mon Sep 17 00:00:00 2001 From: g11tech Date: Mon, 13 May 2024 14:02:31 +0530 Subject: [PATCH 031/259] chore: fix types and lint (#6750) * chore: fix types and lint * fx * type and lint fix --- .../src/api/impl/config/constants.ts | 10 +++++++ .../test/sim/electra-interop.test.ts | 30 +++++++++---------- .../spec/presets/epoch_processing.test.ts | 10 +++++-- .../test/spec/presets/operations.test.ts | 3 +- packages/types/src/electra/index.ts | 5 ++-- 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/packages/beacon-node/src/api/impl/config/constants.ts b/packages/beacon-node/src/api/impl/config/constants.ts index 87ffce91b4d9..b5f810157581 100644 --- a/packages/beacon-node/src/api/impl/config/constants.ts +++ b/packages/beacon-node/src/api/impl/config/constants.ts @@ -36,6 +36,10 @@ import { SYNC_COMMITTEE_SUBNET_COUNT, BLOB_TX_TYPE, VERSIONED_HASH_VERSION_KZG, + COMPOUNDING_WITHDRAWAL_PREFIX, + DOMAIN_CONSOLIDATION, + UNSET_DEPOSIT_RECEIPTS_START_INDEX, + FULL_EXIT_REQUEST_AMOUNT, } from "@lodestar/params"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -57,6 +61,7 @@ export const specConstants = { // ## Withdrawal prefixes BLS_WITHDRAWAL_PREFIX, ETH1_ADDRESS_WITHDRAWAL_PREFIX, + COMPOUNDING_WITHDRAWAL_PREFIX, // ## Domain types DOMAIN_BEACON_PROPOSER, DOMAIN_BEACON_ATTESTER, @@ -66,6 +71,7 @@ export const specConstants = { DOMAIN_SELECTION_PROOF, DOMAIN_AGGREGATE_AND_PROOF, DOMAIN_APPLICATION_BUILDER, + DOMAIN_CONSOLIDATION, // phase0/validator.md TARGET_AGGREGATORS_PER_COMMITTEE, @@ -100,4 +106,8 @@ export const specConstants = { // Deneb types BLOB_TX_TYPE, VERSIONED_HASH_VERSION_KZG, + + // electra + UNSET_DEPOSIT_RECEIPTS_START_INDEX, + FULL_EXIT_REQUEST_AMOUNT, }; diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index 78010ff364ad..2dfa5ee0f77c 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -234,21 +234,21 @@ describe("executionEngine / ExecutionEngineHttp", function () { }); // TODO: get this post merge run working - // it("Post-merge, run for a few blocks", async function () { - // console.log("\n\nPost-merge, run for a few blocks\n\n"); - // const {elClient, tearDownCallBack} = await runEL( - // {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "electra.tmpl"}, - // {...elRunOptions, ttd: BigInt(0)}, - // controller.signal - // ); - // afterEachCallbacks.push(() => tearDownCallBack()); - - // await runNodeWithEL({ - // elClient, - // electraEpoch: 0, - // testName: "post-merge", - // }); - // }); + it.skip("Post-merge, run for a few blocks", async function () { + console.log("\n\nPost-merge, run for a few blocks\n\n"); + const {elClient, tearDownCallBack} = await runEL( + {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "electra.tmpl"}, + {...elRunOptions, ttd: BigInt(0)}, + controller.signal + ); + afterEachCallbacks.push(() => tearDownCallBack()); + + await runNodeWithEL({ + elClient, + electraEpoch: 0, + testName: "post-merge", + }); + }); /** * Want to test two things: diff --git a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts index a244762143f3..b089863fdad3 100644 --- a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts +++ b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts @@ -22,7 +22,10 @@ export type EpochTransitionFn = (state: CachedBeaconStateAllForks, epochTransiti /* eslint-disable @typescript-eslint/naming-convention */ const epochTransitionFns: Record = { - effective_balance_updates: epochFns.processEffectiveBalanceUpdates, + effective_balance_updates: (state, epochTransitionCache) => { + const fork = state.config.getForkSeq(state.slot); + epochFns.processEffectiveBalanceUpdates(fork, state, epochTransitionCache); + }, eth1_data_reset: epochFns.processEth1DataReset, historical_roots_update: epochFns.processHistoricalRootsUpdate, inactivity_updates: epochFns.processInactivityUpdates as EpochTransitionFn, @@ -30,7 +33,10 @@ const epochTransitionFns: Record = { participation_flag_updates: epochFns.processParticipationFlagUpdates as EpochTransitionFn, participation_record_updates: epochFns.processParticipationRecordUpdates as EpochTransitionFn, randao_mixes_reset: epochFns.processRandaoMixesReset, - registry_updates: epochFns.processRegistryUpdates, + registry_updates: (state, epochTransitionCache) => { + const fork = state.config.getForkSeq(state.slot); + epochFns.processRegistryUpdates(fork, state, epochTransitionCache); + }, rewards_and_penalties: epochFns.processRewardsAndPenalties, slashings: epochFns.processSlashings, slashings_reset: epochFns.processSlashingsReset, diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index ca215f1e197c..99d0e578d244 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -71,7 +71,8 @@ const operationFns: Record> = sync_aggregate_random: sync_aggregate, voluntary_exit: (state, testCase: {voluntary_exit: phase0.SignedVoluntaryExit}) => { - blockFns.processVoluntaryExit(state, testCase.voluntary_exit); + const fork = state.config.getForkSeq(state.slot); + blockFns.processVoluntaryExit(fork, state, testCase.voluntary_exit); }, execution_payload: (state, testCase: {body: bellatrix.BeaconBlockBody; execution: {execution_valid: boolean}}) => { diff --git a/packages/types/src/electra/index.ts b/packages/types/src/electra/index.ts index 7856cd729620..981b2015e02a 100644 --- a/packages/types/src/electra/index.ts +++ b/packages/types/src/electra/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}; From 6393d0a67360b79171a0c334f7b5fb1bac78a58b Mon Sep 17 00:00:00 2001 From: NC Date: Tue, 14 May 2024 05:52:02 +0300 Subject: [PATCH 032/259] fix: fix electra genesis spec test (#6764) * process pending deposit from eth1 * Fix the genesis params * fix * Fix * clean up --------- Co-authored-by: Nazar Hussain --- .../beacon-node/src/chain/genesis/genesis.ts | 8 ++++- packages/state-transition/src/util/genesis.ts | 29 ++++++++++++++----- packages/types/src/electra/sszTypes.ts | 7 ++++- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/packages/beacon-node/src/chain/genesis/genesis.ts b/packages/beacon-node/src/chain/genesis/genesis.ts index 979476c69530..5efd352357eb 100644 --- a/packages/beacon-node/src/chain/genesis/genesis.ts +++ b/packages/beacon-node/src/chain/genesis/genesis.ts @@ -174,7 +174,13 @@ export class GenesisBuilder implements IGenesisBuilder { }; }); - const {activatedValidatorCount} = applyDeposits(this.config, this.state, newDeposits, this.depositTree); + const {activatedValidatorCount} = applyDeposits( + this.config.getForkSeq(this.state.slot), + this.config, + this.state, + newDeposits, + this.depositTree + ); this.activatedValidatorCount += activatedValidatorCount; // TODO: If necessary persist deposits here to this.db.depositData, this.db.depositDataRoot diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index d5f4c577711f..ca894fd5b4e5 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -4,6 +4,7 @@ import { EFFECTIVE_BALANCE_INCREMENT, EPOCHS_PER_HISTORICAL_VECTOR, ForkName, + ForkSeq, GENESIS_EPOCH, GENESIS_SLOT, MAX_EFFECTIVE_BALANCE, @@ -11,10 +12,11 @@ import { } from "@lodestar/params"; import {Bytes32, phase0, Root, ssz, TimeSeconds} from "@lodestar/types"; -import {CachedBeaconStateAllForks, BeaconStateAllForks} from "../types.js"; +import {CachedBeaconStateAllForks, BeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; import {createCachedBeaconState} from "../cache/stateCache.js"; import {EpochCacheImmutableData} from "../cache/epochCache.js"; import {processDeposit} from "../block/processDeposit.js"; +import {increaseBalance} from "../index.js"; import {computeEpochAtSlot} from "./epoch.js"; import {getActiveValidatorIndices} from "./validator.js"; import {getTemporaryBlockHeader} from "./blockRoot.js"; @@ -127,6 +129,7 @@ export function applyTimestamp(config: ChainForkConfig, state: CachedBeaconState * @returns active validator indices */ export function applyDeposits( + fork: ForkSeq, config: ChainForkConfig, state: CachedBeaconStateAllForks, newDeposits: phase0.Deposit[], @@ -164,6 +167,16 @@ export function applyDeposits( processDeposit(fork, state, deposit); } + // Process deposit balance updates + if (fork >= ForkSeq.electra) { + const stateElectra = state as CachedBeaconStateElectra; + stateElectra.commit(); + for (const {index: validatorIndex, amount} of stateElectra.pendingBalanceDeposits.getAllReadonly()) { + increaseBalance(state, validatorIndex, Number(amount)); + } + stateElectra.pendingBalanceDeposits = ssz.electra.PendingBalanceDeposits.defaultViewDU(); + } + // Process activations const {epochCtx} = state; const balancesArr = state.balances.getAll(); @@ -226,6 +239,8 @@ export function initializeBeaconStateFromEth1( getTemporaryBlockHeader(config, config.getForkTypes(GENESIS_SLOT).BeaconBlock.defaultValue()) ); + const fork = config.getForkSeq(GENESIS_SLOT); + // We need a CachedBeaconState to run processDeposit() which uses various caches. // However at this point the state's syncCommittees are not known. // This function can be called by: @@ -240,13 +255,13 @@ export function initializeBeaconStateFromEth1( applyEth1BlockHash(state, eth1BlockHash); // Process deposits - applyDeposits(config, state, deposits, fullDepositDataRootList); + applyDeposits(fork, config, state, deposits, fullDepositDataRootList); // Commit before reading all validators in `getActiveValidatorIndices()` state.commit(); const activeValidatorIndices = getActiveValidatorIndices(state, computeEpochAtSlot(GENESIS_SLOT)); - if (GENESIS_SLOT >= config.ALTAIR_FORK_EPOCH) { + if (fork >= ForkSeq.altair) { const {syncCommittee} = getNextSyncCommittee( state, activeValidatorIndices, @@ -259,7 +274,7 @@ export function initializeBeaconStateFromEth1( stateAltair.nextSyncCommittee = ssz.altair.SyncCommittee.toViewDU(syncCommittee); } - if (GENESIS_SLOT >= config.BELLATRIX_FORK_EPOCH) { + if (fork >= ForkSeq.bellatrix) { const stateBellatrix = state as CompositeViewDU; stateBellatrix.fork.previousVersion = config.BELLATRIX_FORK_VERSION; stateBellatrix.fork.currentVersion = config.BELLATRIX_FORK_VERSION; @@ -268,7 +283,7 @@ export function initializeBeaconStateFromEth1( ssz.bellatrix.ExecutionPayloadHeader.defaultViewDU(); } - if (GENESIS_SLOT >= config.CAPELLA_FORK_EPOCH) { + if (fork >= ForkSeq.capella) { const stateCapella = state as CompositeViewDU; stateCapella.fork.previousVersion = config.CAPELLA_FORK_VERSION; stateCapella.fork.currentVersion = config.CAPELLA_FORK_VERSION; @@ -277,7 +292,7 @@ export function initializeBeaconStateFromEth1( ssz.capella.ExecutionPayloadHeader.defaultViewDU(); } - if (GENESIS_SLOT >= config.DENEB_FORK_EPOCH) { + if (fork >= ForkSeq.deneb) { const stateDeneb = state as CompositeViewDU; stateDeneb.fork.previousVersion = config.DENEB_FORK_VERSION; stateDeneb.fork.currentVersion = config.DENEB_FORK_VERSION; @@ -286,7 +301,7 @@ export function initializeBeaconStateFromEth1( ssz.deneb.ExecutionPayloadHeader.defaultViewDU(); } - if (GENESIS_SLOT >= config.ELECTRA_FORK_EPOCH) { + if (fork >= ForkSeq.electra) { const stateElectra = state as CompositeViewDU; stateElectra.fork.previousVersion = config.ELECTRA_FORK_VERSION; stateElectra.fork.currentVersion = config.ELECTRA_FORK_VERSION; diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index ee8d2702c65d..d3d9843e63f1 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -275,6 +275,11 @@ export const PendingBalanceDeposit = new ContainerType( {typeName: "PendingBalanceDeposit", jsonCase: "eth2"} ); +export const PendingBalanceDeposits = new ListCompositeType( + PendingBalanceDeposit, + Number(PENDING_BALANCE_DEPOSITS_LIMIT) +); + export const PartialWithdrawal = new ContainerType( { index: ValidatorIndex, @@ -341,7 +346,7 @@ export const BeaconState = new ContainerType( earliestExitEpoch: Epoch, // New in Electra:EIP7251 consolidationBalanceToConsume: Gwei, // New in Electra:EIP7251 earliestConsolidationEpoch: Epoch, // New in Electra:EIP7251 - pendingBalanceDeposits: new ListCompositeType(PendingBalanceDeposit, Number(PENDING_BALANCE_DEPOSITS_LIMIT)), // new in electra:eip7251 + pendingBalanceDeposits: PendingBalanceDeposits, // new in electra:eip7251 pendingPartialWithdrawals: new ListCompositeType(PartialWithdrawal, Number(PENDING_PARTIAL_WITHDRAWALS_LIMIT)), // New in Electra:EIP7251 pendingConsolidations: new ListCompositeType(PendingConsolidation, Number(PENDING_CONSOLIDATIONS_LIMIT)), // new in electra:eip7251 }, From 55567db67ea185c46cb7c4b20df6d3846f14403b Mon Sep 17 00:00:00 2001 From: NC Date: Tue, 14 May 2024 06:39:55 +0300 Subject: [PATCH 033/259] feat: support missing electra spec test (#6765) Add spec test --- .../test/spec/presets/epoch_processing.test.ts | 2 ++ .../test/spec/presets/operations.test.ts | 17 +++++++++++++++++ .../src/block/processOperations.ts | 1 + 3 files changed, 20 insertions(+) diff --git a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts index b089863fdad3..f159612e416c 100644 --- a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts +++ b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts @@ -42,6 +42,8 @@ const epochTransitionFns: Record = { slashings_reset: epochFns.processSlashingsReset, sync_committee_updates: epochFns.processSyncCommitteeUpdates as EpochTransitionFn, historical_summaries_update: epochFns.processHistoricalSummariesUpdate as EpochTransitionFn, + pending_balance_deposits: epochFns.processPendingBalanceDeposits as EpochTransitionFn, + pending_consolidations: epochFns.processPendingConsolidations as EpochTransitionFn, }; /** diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index 99d0e578d244..fe70c091aa5a 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -91,6 +91,21 @@ const operationFns: Record> = withdrawals: (state, testCase: {execution_payload: capella.ExecutionPayload}) => { blockFns.processWithdrawals(ForkSeq.capella, state as CachedBeaconStateCapella, testCase.execution_payload); }, + + consolidation: (state, testCase: {consolidation: electra.SignedConsolidation}) => { + blockFns.processConsolidation(state as CachedBeaconStateElectra, testCase.consolidation); + }, + + execution_layer_withdrawal_request: ( + state, + testCase: {execution_layer_withdrawal_request: electra.ExecutionLayerWithdrawalRequest} + ) => { + blockFns.processExecutionLayerWithdrawalRequest( + ForkSeq.electra, + state as CachedBeaconStateElectra, + testCase.execution_layer_withdrawal_request + ); + }, }; export type BlockProcessFn = (state: T, testCase: any) => void; @@ -140,6 +155,8 @@ const operations: TestRunnerFn = (fork, : ssz.bellatrix.ExecutionPayload, // Capella address_change: ssz.capella.SignedBLSToExecutionChange, + consolidation: ssz.electra.SignedConsolidation, + execution_layer_withdrawal_request: ssz.electra.ExecutionLayerWithdrawalRequest, }, shouldError: (testCase) => testCase.post === undefined, getExpected: (testCase) => testCase.post, diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index 3ddc3668e487..a2bd691337ad 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -23,6 +23,7 @@ export { processExecutionLayerWithdrawalRequest, processBlsToExecutionChange, processDepositRequest, + processConsolidation, }; export function processOperations( From 81080166624cb68314c60d8e32f1e4e3185ffe07 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 14 May 2024 10:37:56 +0300 Subject: [PATCH 034/259] test: fix ssz types in fork_choice spec tests (#6767) --- packages/beacon-node/test/spec/presets/fork_choice.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 01adcc77500b..9f8d5c727879 100644 --- a/packages/beacon-node/test/spec/presets/fork_choice.test.ts +++ b/packages/beacon-node/test/spec/presets/fork_choice.test.ts @@ -343,8 +343,8 @@ const forkChoiceTest = [BLOCK_FILE_NAME]: ssz[fork].SignedBeaconBlock, [BLOBS_FILE_NAME]: ssz.deneb.Blobs, [POW_BLOCK_FILE_NAME]: ssz.bellatrix.PowBlock, - [ATTESTATION_FILE_NAME]: ssz.phase0.Attestation, - [ATTESTER_SLASHING_FILE_NAME]: ssz.phase0.AttesterSlashing, + [ATTESTATION_FILE_NAME]: ssz.allForks[fork].Attestation, + [ATTESTER_SLASHING_FILE_NAME]: ssz.allForks[fork].AttesterSlashing, }, mapToTestCase: (t: Record) => { // t has input file name as key From 52be86eeaef54165ba38ad0c6c46bd04dd0f4fb2 Mon Sep 17 00:00:00 2001 From: Julien Date: Tue, 14 May 2024 00:50:29 -0700 Subject: [PATCH 035/259] chore: update EffectiveBalanceIncrements type (#6763) * chore: update EffectiveBalanceIncrements type * chore: remove now irrelevant tests --- .../src/cache/effectiveBalanceIncrements.ts | 13 ++-- .../state-transition/src/cache/epochCache.ts | 8 +-- packages/state-transition/src/util/balance.ts | 4 +- .../test/memory/effectiveBalanceIncrements.ts | 62 ------------------- .../perf/dataStructures/arrayish.memory.ts | 54 ---------------- .../test/perf/dataStructures/arrayish.test.ts | 43 ------------- .../effectiveBalanceIncrements.test.ts | 32 ---------- 7 files changed, 12 insertions(+), 204 deletions(-) delete mode 100644 packages/state-transition/test/memory/effectiveBalanceIncrements.ts delete mode 100644 packages/state-transition/test/perf/dataStructures/effectiveBalanceIncrements.test.ts diff --git a/packages/state-transition/src/cache/effectiveBalanceIncrements.ts b/packages/state-transition/src/cache/effectiveBalanceIncrements.ts index a82eb0300432..bd72b333a03c 100644 --- a/packages/state-transition/src/cache/effectiveBalanceIncrements.ts +++ b/packages/state-transition/src/cache/effectiveBalanceIncrements.ts @@ -3,18 +3,17 @@ import {BeaconStateAllForks} from "../types.js"; /** * Alias to allow easier refactoring. - * TODO: Estimate the risk of future proof of MAX_EFFECTIVE_BALANCE_INCREMENT < 255 */ -export type EffectiveBalanceIncrements = Uint8Array; +export type EffectiveBalanceIncrements = Uint16Array; -/** Helper to prevent re-writting tests downstream if we change Uint8Array to number[] */ +/** Helper to prevent re-writting tests downstream if we change Uint16Array to number[] */ export function getEffectiveBalanceIncrementsZeroed(len: number): EffectiveBalanceIncrements { - return new Uint8Array(len); + return new Uint16Array(len); } /** * effectiveBalanceIncrements length will always be equal or greater than validatorCount. The - * getEffectiveBalanceIncrementsByteLen() modulo is used to reduce the frequency at which its Uint8Array is recreated. + * getEffectiveBalanceIncrementsByteLen() modulo is used to reduce the frequency at which its Uint16Array is recreated. * if effectiveBalanceIncrements has length greater than validatorCount it's not a problem since those values would * never be accessed. */ @@ -22,7 +21,7 @@ export function getEffectiveBalanceIncrementsWithLen(validatorCount: number): Ef // TODO: Research what's the best number to minimize both memory cost and copy costs const byteLen = 1024 * Math.ceil(validatorCount / 1024); - return new Uint8Array(byteLen); + return new Uint16Array(byteLen); } /** @@ -32,7 +31,7 @@ export function getEffectiveBalanceIncrementsWithLen(validatorCount: number): Ef */ export function getEffectiveBalanceIncrements(state: BeaconStateAllForks): EffectiveBalanceIncrements { const validatorsArr = state.validators.getAllReadonlyValues(); - const effectiveBalanceIncrements = new Uint8Array(validatorsArr.length); + const effectiveBalanceIncrements = new Uint16Array(validatorsArr.length); for (let i = 0; i < validatorsArr.length; i++) { effectiveBalanceIncrements[i] = Math.floor(validatorsArr[i].effectiveBalance / EFFECTIVE_BALANCE_INCREMENT); } diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 71c3b3d15f1a..dbcacec0062d 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -653,8 +653,8 @@ export class EpochCache { beforeEpochTransition(): void { // Clone (copy) before being mutated in processEffectiveBalanceUpdates - // NOTE: Force to use Uint8Array.slice (copy) instead of Buffer.call (not copy) - this.effectiveBalanceIncrements = Uint8Array.prototype.slice.call(this.effectiveBalanceIncrements, 0); + // NOTE: Force to use Uint16Array.slice (copy) instead of Buffer.call (not copy) + this.effectiveBalanceIncrements = Uint16Array.prototype.slice.call(this.effectiveBalanceIncrements, 0); } /** @@ -1048,13 +1048,13 @@ export class EpochCache { const newLength = index >= this.effectiveBalanceIncrements.length ? index + 1 : this.effectiveBalanceIncrements.length; const effectiveBalanceIncrements = this.effectiveBalanceIncrements; - this.effectiveBalanceIncrements = new Uint8Array(newLength); + this.effectiveBalanceIncrements = new Uint16Array(newLength); this.effectiveBalanceIncrements.set(effectiveBalanceIncrements, 0); } else { if (index >= this.effectiveBalanceIncrements.length) { // Clone and extend effectiveBalanceIncrements const effectiveBalanceIncrements = this.effectiveBalanceIncrements; - this.effectiveBalanceIncrements = new Uint8Array(getEffectiveBalanceIncrementsByteLen(index + 1)); + this.effectiveBalanceIncrements = new Uint16Array(getEffectiveBalanceIncrementsByteLen(index + 1)); this.effectiveBalanceIncrements.set(effectiveBalanceIncrements, 0); } } diff --git a/packages/state-transition/src/util/balance.ts b/packages/state-transition/src/util/balance.ts index e305c745ab72..e9b7a06e4130 100644 --- a/packages/state-transition/src/util/balance.ts +++ b/packages/state-transition/src/util/balance.ts @@ -56,8 +56,8 @@ export function getEffectiveBalanceIncrementsZeroInactive( const validatorCount = justifiedState.validators.length; const {effectiveBalanceIncrements} = justifiedState.epochCtx; // Slice up to `validatorCount` since it won't be mutated, nor accessed beyond `validatorCount` - // NOTE: Force to use Uint8Array.slice (copy) instead of Buffer.call (not copy) - const effectiveBalanceIncrementsZeroInactive = Uint8Array.prototype.slice.call( + // NOTE: Force to use Uint16Array.slice (copy) instead of Buffer.call (not copy) + const effectiveBalanceIncrementsZeroInactive = Uint16Array.prototype.slice.call( effectiveBalanceIncrements, 0, validatorCount diff --git a/packages/state-transition/test/memory/effectiveBalanceIncrements.ts b/packages/state-transition/test/memory/effectiveBalanceIncrements.ts deleted file mode 100644 index f1c603b85657..000000000000 --- a/packages/state-transition/test/memory/effectiveBalanceIncrements.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {MutableVector} from "@chainsafe/persistent-ts"; -import {testRunnerMemory} from "@lodestar/beacon-node/test/memory/testRunnerMemory"; -import {newZeroedArray} from "../../src/index.js"; - -// Results in Linux Feb 2022 -// -// EffectiveBalanceIncrements Uint8Array 300000 - 299873.5 bytes / instance -// EffectiveBalanceIncrements array 300000 - 2400093.1 bytes / instance -// EffectiveBalanceIncrements MutableVector 300000 - 4380557.0 bytes / instance -// EffectiveBalanceIncrements MutableVector 300000 cloned 10 - 4399575.0 bytes / instance -// -// With MutableVector, break even at 14 instances of Uint8Array -// 4380557 / 299873 = 14 - -const vc = 300_000; -const cloneTimes = 10; - -testRunnerMemoryBpi([ - { - id: `EffectiveBalanceIncrements Uint8Array ${vc}`, - getInstance: () => new Uint8Array(vc), - }, - { - id: `EffectiveBalanceIncrements array ${vc}`, - getInstance: () => newZeroedArray(vc), - }, - { - id: `EffectiveBalanceIncrements MutableVector ${vc}`, - getInstance: () => MutableVector.from(newZeroedArray(vc)), - }, - { - id: `EffectiveBalanceIncrements MutableVector ${vc} cloned ${cloneTimes}`, - getInstance: () => { - const mv = MutableVector.from(newZeroedArray(vc)); - const mvs = [mv]; - for (let i = 0; i < cloneTimes; i++) { - const mvc = mv.clone(); - mvc.push(0); - mvs.push(mvc); - } - return mvs; - }, - }, -]); - -/** - * Test bytes per instance in different representations of raw binary data - */ -function testRunnerMemoryBpi(testCases: {getInstance: (bytes: number) => unknown; id: string}[]): void { - const longestId = Math.max(...testCases.map(({id}) => id.length)); - - for (const {id, getInstance} of testCases) { - const bpi = testRunnerMemory({ - getInstance, - convergeFactor: 1 / 100, - sampleEvery: 5, - }); - - // eslint-disable-next-line no-console - console.log(`${id.padEnd(longestId)} - ${bpi.toFixed(1)} bytes / instance`); - } -} diff --git a/packages/state-transition/test/perf/dataStructures/arrayish.memory.ts b/packages/state-transition/test/perf/dataStructures/arrayish.memory.ts index 1f4141912627..7e10f447181f 100644 --- a/packages/state-transition/test/perf/dataStructures/arrayish.memory.ts +++ b/packages/state-transition/test/perf/dataStructures/arrayish.memory.ts @@ -1,5 +1,3 @@ -import {MutableVector} from "@chainsafe/persistent-ts"; - const refs: any[] = []; const xs: number[] = []; const arrayBuffersArr: number[] = []; @@ -23,7 +21,6 @@ const size = 100; const testType = TestType.Set; let arrayNumGlobal: number[] | null = null; -let mutableVectorGlobal: MutableVector | null = null; for (let i = 0; i < 1e8; i++) { switch (testType as TestType) { @@ -65,49 +62,6 @@ for (let i = 0; i < 1e8; i++) { break; } - // size | 100 | 1000 | 10000 | - // ---- | ------ | ------ | ------ | - // rssM | 1817.4 | 15518. | 154335 | - case TestType.MutableVector: { - const items = createArray(size); - const mutableVector = MutableVector.from(items); - refs.push(mutableVector); - break; - } - - // size | 100 | 1000 | - // ---- | ------ | ------ | - // rssM | 58.68 | 55.89 | - case TestType.MutableVectorClone: { - if (!mutableVectorGlobal) { - const items = createArray(size); - mutableVectorGlobal = MutableVector.from(items); - } - refs.push(mutableVectorGlobal.clone()); - break; - } - - // Grid of size / changes, all values = rssM in bytes - // | 100 | 1000 | 10000 | - // ----- | ------ | ------ | ------ | - // 1 | 793.45 | 801.53 | 1137.9 | - // 10 | 803.98 | 802.36 | 1144.9 | - // 100 | 1573.2 | 1826.4 | 2172.0 | - // 1000 | - | 11250. | 11886. | - // 10000 | - | - | 111365 | - case TestType.MutableVectorCloneAndMutate: { - if (!mutableVectorGlobal) { - const items = createArray(size); - mutableVectorGlobal = MutableVector.from(items); - } - const newArr = mutableVectorGlobal.clone(); - for (let j = 0; j < 10000; j++) { - newArr.set(j, i); - } - refs.push(newArr); - break; - } - // size | 100 | 1000 | // ---- | ------ | ------ | // rssM | 2646.8 | 20855. | @@ -161,14 +115,6 @@ for (let i = 0; i < 1e8; i++) { } } -function createArray(n: number): number[] { - const items: number[] = []; - for (let i = 0; i < n; i++) { - items.push(i); - } - return items; -} - /** * From https://github.com/simple-statistics/simple-statistics/blob/d0d177baf74976a2421638bce98ab028c5afb537/src/linear_regression.js * diff --git a/packages/state-transition/test/perf/dataStructures/arrayish.test.ts b/packages/state-transition/test/perf/dataStructures/arrayish.test.ts index 59162b6eecca..5b6af0d989b6 100644 --- a/packages/state-transition/test/perf/dataStructures/arrayish.test.ts +++ b/packages/state-transition/test/perf/dataStructures/arrayish.test.ts @@ -1,6 +1,5 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {LeafNode, toGindex, Tree, zeroNode} from "@chainsafe/persistent-merkle-tree"; -import {MutableVector} from "@chainsafe/persistent-ts"; // Understand the cost of each array-ish data structure to: // - Get one element @@ -99,48 +98,6 @@ describe("Tree (persistent-merkle-tree)", () => { } }); -describe("MutableVector", () => { - // Don't track regressions in CI - setBenchOpts({noThreshold: true}); - - let items: number[]; - let mutableVector: MutableVector; - - before(function () { - items = createArray(n); - mutableVector = MutableVector.from(items); - }); - - itBench(`MutableVector ${n} create`, () => { - MutableVector.from(items); - }); - - itBench({id: `MutableVector ${n} get(${ih})`, runsFactor}, () => { - for (let i = 0; i < runsFactor; i++) mutableVector.get(ih - i); - }); - - itBench({id: `MutableVector ${n} set(${ih})`, runsFactor}, () => { - for (let i = 0; i < runsFactor; i++) mutableVector.set(ih - i, 10000000); - }); - - itBench(`MutableVector ${n} toArray()`, () => { - mutableVector.toArray(); - }); - - itBench(`MutableVector ${n} iterate all - toArray() + loop`, () => { - const mvArr = mutableVector.toArray(); - for (let i = 0; i < n; i++) { - mvArr[i]; - } - }); - - itBench(`MutableVector ${n} iterate all - get(i)`, () => { - for (let i = 0; i < n; i++) { - mutableVector.get(i); - } - }); -}); - describe("Array", () => { // Don't track regressions in CI setBenchOpts({noThreshold: true}); diff --git a/packages/state-transition/test/perf/dataStructures/effectiveBalanceIncrements.test.ts b/packages/state-transition/test/perf/dataStructures/effectiveBalanceIncrements.test.ts deleted file mode 100644 index 13c2d982e86b..000000000000 --- a/packages/state-transition/test/perf/dataStructures/effectiveBalanceIncrements.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {itBench, setBenchOpts} from "@dapplion/benchmark"; -import {MutableVector} from "@chainsafe/persistent-ts"; -import {newZeroedArray} from "../../../src/index.js"; - -describe("effectiveBalanceIncrements", () => { - setBenchOpts({noThreshold: true}); - - const vc = 300_000; - const uint8Array = new Uint8Array(vc); - const mv = MutableVector.from(newZeroedArray(vc)); - - itBench(`effectiveBalanceIncrements clone Uint8Array ${vc}`, () => { - uint8Array.slice(0); - }); - - itBench(`effectiveBalanceIncrements clone MutableVector ${vc}`, () => { - mv.clone(); - }); - - itBench(`effectiveBalanceIncrements rw all Uint8Array ${vc}`, () => { - for (let i = 0; i < vc; i++) { - uint8Array[i]++; - } - }); - - itBench(`effectiveBalanceIncrements rw all MutableVector ${vc}`, () => { - for (let i = 0; i < vc; i++) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - mv.set(i, mv.get(i)! + 1); - } - }); -}); From 9bd982cbfad3744c1c040c5d154a8898df52bece Mon Sep 17 00:00:00 2001 From: Navie Chan Date: Tue, 14 May 2024 11:37:56 +0300 Subject: [PATCH 036/259] Fix ssz_static --- packages/beacon-node/src/chain/chain.ts | 2 +- .../src/eth1/eth1DepositDataTracker.ts | 4 +-- .../beacon-node/src/execution/engine/types.ts | 6 ++-- .../test/sim/electra-interop.test.ts | 4 +-- .../test/spec/presets/ssz_static.test.ts | 1 + packages/beacon-node/test/utils/state.ts | 2 +- packages/light-client/src/spec/utils.ts | 6 ++-- packages/params/src/index.ts | 4 +++ .../src/block/processDepositRequest.ts | 4 +-- .../processExecutionLayerWithdrawalRequest.ts | 2 +- .../src/block/processOperations.ts | 2 +- .../src/slot/upgradeStateToElectra.ts | 14 +++++----- packages/state-transition/src/util/deposit.ts | 4 +-- .../state-transition/src/util/execution.ts | 4 +-- packages/state-transition/src/util/genesis.ts | 2 +- .../test/unit/util/deposit.test.ts | 4 +-- packages/types/src/electra/sszTypes.ts | 28 ++++++++++--------- packages/types/src/electra/types.ts | 6 ++-- 18 files changed, 53 insertions(+), 46 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 9f30936305f0..9f67857fe530 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -1147,7 +1147,7 @@ export class BeaconChain implements IBeaconChain { // Will resolve this later // if (cpEpoch >= (this.config.ELECTRA_FORK_EPOCH ?? Infinity)) { // // finalizedState can be safely casted to Electra state since cp is already post-Electra - // if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateElectra).depositRequestsStartIndex) { + // if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateElectra).depositReceiptsStartIndex) { // // Signal eth1 to stop polling eth1Data // this.eth1.stopPollingEth1Data(); // } diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index d0578718f29f..c0b3ab35a73a 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -129,9 +129,9 @@ export class Eth1DepositDataTracker { async getEth1DataAndDeposits(state: CachedBeaconStateAllForks): Promise { if ( state.epochCtx.isAfterElectra() && - state.eth1DepositIndex >= (state as CachedBeaconStateElectra).depositRequestsStartIndex + state.eth1DepositIndex >= (state as CachedBeaconStateElectra).depositReceiptsStartIndex ) { - // No need to poll eth1Data since Electra deprecates the mechanism after depositRequestsStartIndex is reached + // No need to poll eth1Data since Electra deprecates the mechanism after depositReceiptsStartIndex is reached return {eth1Data: state.eth1Data, deposits: []}; } const eth1Data = this.forcedEth1DataVote ?? (await this.getEth1Data(state)); diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 3c1da820a610..de744d56d6cd 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -235,8 +235,8 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload // ELECTRA adds depositRequests/depositRequests to the ExecutionPayload if (ForkSeq[fork] >= ForkSeq.electra) { - const {depositRequests, withdrawalRequests} = data as electra.ExecutionPayload; - payload.depositRequests = depositRequests.map(serializeDepositRequest); + const {depositReceipts, withdrawalRequests} = data as electra.ExecutionPayload; + payload.depositRequests = depositReceipts.map(serializeDepositRequest); payload.withdrawalRequests = withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest); } @@ -334,7 +334,7 @@ export function parseExecutionPayload( `depositRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` ); } - (executionPayload as electra.ExecutionPayload).depositRequests = depositRequests.map(deserializeDepositRequest); + (executionPayload as electra.ExecutionPayload).depositReceipts = depositRequests.map(deserializeDepositRequest); if (withdrawalRequests == null) { throw Error( diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index 2dfa5ee0f77c..37bed1f7b843 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -431,8 +431,8 @@ describe("executionEngine / ExecutionEngineHttp", function () { throw Error("Historical validator length for epoch 1 or 2 is not dropped properly"); } - if (headState.depositRequestsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { - throw Error("state.depositRequestsStartIndex is not set upon processing new deposit receipt"); + if (headState.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + throw Error("state.depositReceiptsStartIndex is not set upon processing new deposit receipt"); } // wait for 1 slot to print current epoch stats diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index d81b47ecf587..cca6bb57c308 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -45,6 +45,7 @@ const sszStatic = /* eslint-disable @typescript-eslint/strict-boolean-expressions */ const sszType = (sszTypesFor(fork) as Types)[typeName] || + (ssz.electra as Types)[typeName] || (ssz.deneb as Types)[typeName] || (ssz.capella as Types)[typeName] || (ssz.bellatrix as Types)[typeName] || diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index bb55adca1eb0..ad4dd4b88dac 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -97,7 +97,7 @@ export function generateState( if (forkSeq >= ForkSeq.electra) { const stateElectra = state as electra.BeaconState; - stateElectra.depositRequestsStartIndex = 2023n; + stateElectra.depositReceiptsStartIndex = 2023n; stateElectra.latestExecutionPayloadHeader = ssz.electra.ExecutionPayloadHeader.defaultValue(); } diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 679371a54d6c..b1145860833f 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -115,8 +115,8 @@ export function upgradeLightClientHeader( // eslint-disable-next-line no-fallthrough case ForkName.electra: - (upgradedHeader as LightClientHeader).execution.depositRequestsRoot = - ssz.electra.LightClientHeader.fields.execution.fields.depositRequestsRoot.defaultValue(); + (upgradedHeader as LightClientHeader).execution.depositReceiptsRoot = + ssz.electra.LightClientHeader.fields.execution.fields.depositReceiptsRoot.defaultValue(); (upgradedHeader as LightClientHeader).execution.withdrawalRequestsRoot = ssz.electra.LightClientHeader.fields.execution.fields.withdrawalRequestsRoot.defaultValue(); @@ -157,7 +157,7 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: LightC if (epoch < config.ELECTRA_FORK_EPOCH) { if ( - (header as LightClientHeader).execution.depositRequestsRoot !== undefined || + (header as LightClientHeader).execution.depositReceiptsRoot !== undefined || (header as LightClientHeader).execution.withdrawalRequestsRoot !== undefined ) { return false; diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index c1d3f1bc1981..20439568156e 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -264,3 +264,7 @@ export const BLOBSIDECAR_FIXED_SIZE = ACTIVE_PRESET === PresetName.minimal ? 131 // Electra Misc export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = 2n ** 64n - 1n; export const FULL_EXIT_REQUEST_AMOUNT = 0; +export const NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA = 87; +export const NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA = 6; +export const FINALIZED_ROOT_DEPTH_ELECTRA = 7; +export const FINALIZED_ROOT_INDEX_ELECTRA = 169; \ No newline at end of file diff --git a/packages/state-transition/src/block/processDepositRequest.ts b/packages/state-transition/src/block/processDepositRequest.ts index ca6fe4206188..d5525f3cd544 100644 --- a/packages/state-transition/src/block/processDepositRequest.ts +++ b/packages/state-transition/src/block/processDepositRequest.ts @@ -9,8 +9,8 @@ export function processDepositRequest( state: CachedBeaconStateElectra, depositRequest: electra.DepositRequest ): void { - if (state.depositRequestsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { - state.depositRequestsStartIndex = BigInt(depositRequest.index); + if (state.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + state.depositReceiptsStartIndex = BigInt(depositRequest.index); } applyDeposit(fork, state, depositRequest); diff --git a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts index e16fad105aaa..1b795789cb77 100644 --- a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts +++ b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts @@ -70,7 +70,7 @@ export function processExecutionLayerWithdrawalRequest( const exitQueueEpoch = computeExitEpochAndUpdateChurn(state, amountToWithdraw); const withdrawableEpoch = exitQueueEpoch + config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY; - const pendingPartialWithdrawal = ssz.electra.PartialWithdrawal.toViewDU({ + const pendingPartialWithdrawal = ssz.electra.PendingPartialWithdrawal.toViewDU({ index: validatorIndex, amount: amountToWithdraw, withdrawableEpoch, diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index a2bd691337ad..86672a6572e9 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -71,7 +71,7 @@ export function processOperations( processExecutionLayerWithdrawalRequest(fork, state as CachedBeaconStateElectra, elWithdrawalRequest); } - for (const depositRequest of bodyElectra.executionPayload.depositRequests) { + for (const depositRequest of bodyElectra.executionPayload.depositReceipts) { processDepositRequest(fork, stateElectra, depositRequest); } diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 121425265b50..417c3cd717c1 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -48,16 +48,16 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache stateElectraView.nextSyncCommittee = stateElectraCloned.nextSyncCommittee; stateElectraView.latestExecutionPayloadHeader = ssz.electra.BeaconState.fields.latestExecutionPayloadHeader.toViewDU({ ...stateElectraCloned.latestExecutionPayloadHeader.toValue(), - depositRequestsRoot: ssz.Root.defaultValue(), + depositReceiptsRoot: ssz.Root.defaultValue(), withdrawalRequestsRoot: ssz.Root.defaultValue(), }); stateElectraView.nextWithdrawalIndex = stateDeneb.nextWithdrawalIndex; stateElectraView.nextWithdrawalValidatorIndex = stateDeneb.nextWithdrawalValidatorIndex; stateElectraView.historicalSummaries = stateElectraCloned.historicalSummaries; - // latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default - // default value of depositRequestsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX - stateElectraView.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + // latestExecutionPayloadHeader's depositReceiptsRoot and withdrawalRequestsRoot set to zeros by default + // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX + stateElectraView.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; const validatorsArr = stateElectraView.validators.getAllReadonly(); @@ -99,9 +99,9 @@ export function upgradeStateToElectraOriginal(stateDeneb: CachedBeaconStateDeneb epoch: stateDeneb.epochCtx.epoch, }); - // latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default - // default value of depositRequestsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX - stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + // latestExecutionPayloadHeader's depositReceiptsRoot and withdrawalRequestsRoot set to zeros by default + // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX + stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; const validatorsArr = stateElectra.validators.getAllReadonly(); diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index e8ef93c515d2..493099fdd982 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -9,9 +9,9 @@ export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: // eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64 // since the result lies within upper and lower bound of UintNum64 const eth1DataIndexLimit: UintNum64 = - eth1DataToUse.depositCount < electraState.depositRequestsStartIndex + eth1DataToUse.depositCount < electraState.depositReceiptsStartIndex ? eth1DataToUse.depositCount - : Number(electraState.depositRequestsStartIndex); + : Number(electraState.depositReceiptsStartIndex); if (state.eth1DepositIndex < eth1DataIndexLimit) { return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index 2c55dc61a502..c7f0ec2f395c 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -172,8 +172,8 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio } if (fork >= ForkSeq.electra) { - (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositRequestsRoot = - ssz.electra.DepositRequests.hashTreeRoot((payload as electra.ExecutionPayload).depositRequests); + (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositReceiptsRoot = + ssz.electra.DepositReceipts.hashTreeRoot((payload as electra.ExecutionPayload).depositReceipts); (bellatrixPayloadFields as electra.ExecutionPayloadHeader).withdrawalRequestsRoot = ssz.electra.ExecutionLayerWithdrawalRequests.hashTreeRoot( (payload as electra.ExecutionPayload).withdrawalRequests diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index ca894fd5b4e5..e1003dca1946 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -308,7 +308,7 @@ export function initializeBeaconStateFromEth1( stateElectra.latestExecutionPayloadHeader = (executionPayloadHeader as CompositeViewDU) ?? ssz.electra.ExecutionPayloadHeader.defaultViewDU(); - stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; } state.commit(); diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts index 677a15724ece..e8f7f7a86af8 100644 --- a/packages/state-transition/test/unit/util/deposit.test.ts +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -43,7 +43,7 @@ describe("getEth1DepositCount", () => { throw Error("Not a post-Electra state"); } - postElectraState.depositRequestsStartIndex = 1000n; + postElectraState.depositReceiptsStartIndex = 1000n; postElectraState.eth1Data.depositCount = 995; // 1. Should get less than MAX_DEPOSIT @@ -77,7 +77,7 @@ describe("getEth1DepositCount", () => { throw Error("Not a post-Electra state"); } - postElectraState.depositRequestsStartIndex = 1000n; + postElectraState.depositReceiptsStartIndex = 1000n; postElectraState.eth1Data.depositCount = 1005; // Before eth1DepositIndex reaching the start index diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index d3d9843e63f1..b2191215eb2c 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -21,6 +21,8 @@ import { PENDING_BALANCE_DEPOSITS_LIMIT, PENDING_PARTIAL_WITHDRAWALS_LIMIT, PENDING_CONSOLIDATIONS_LIMIT, + FINALIZED_ROOT_DEPTH_ELECTRA, + NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, } from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; @@ -110,7 +112,7 @@ export const SignedAggregateAndProof = new ContainerType( {typeName: "SignedAggregateAndProof", jsonCase: "eth2"} ); -export const DepositRequest = new ContainerType( +export const DepositReceipt = new ContainerType( { pubkey: BLSPubkey, withdrawalCredentials: Bytes32, @@ -118,10 +120,10 @@ export const DepositRequest = new ContainerType( signature: BLSSignature, index: DepositIndex, }, - {typeName: "DepositRequest", jsonCase: "eth2"} + {typeName: "DepositReceipt", jsonCase: "eth2"} ); -export const DepositRequests = new ListCompositeType(DepositRequest, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); +export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); export const ExecutionLayerWithdrawalRequest = new ContainerType( { @@ -139,7 +141,7 @@ export const ExecutionLayerWithdrawalRequests = new ListCompositeType( export const ExecutionPayload = new ContainerType( { ...denebSsz.ExecutionPayload.fields, - depositRequests: DepositRequests, // New in ELECTRA + depositReceipts: DepositReceipts, // New in ELECTRA withdrawalRequests: ExecutionLayerWithdrawalRequests, // New in ELECTRA }, {typeName: "ExecutionPayload", jsonCase: "eth2"} @@ -148,7 +150,7 @@ export const ExecutionPayload = new ContainerType( export const ExecutionPayloadHeader = new ContainerType( { ...denebSsz.ExecutionPayloadHeader.fields, - depositRequestsRoot: Root, // New in ELECTRA + depositReceiptsRoot: Root, // New in ELECTRA withdrawalRequestsRoot: Root, // New in ELECTRA }, {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} @@ -280,13 +282,13 @@ export const PendingBalanceDeposits = new ListCompositeType( Number(PENDING_BALANCE_DEPOSITS_LIMIT) ); -export const PartialWithdrawal = new ContainerType( +export const PendingPartialWithdrawal = new ContainerType( { index: ValidatorIndex, amount: Gwei, withdrawableEpoch: Epoch, }, - {typeName: "PartialWithdrawal", jsonCase: "eth2"} + {typeName: "PendingPartialWithdrawal", jsonCase: "eth2"} ); export const PendingConsolidation = new ContainerType( @@ -340,14 +342,14 @@ export const BeaconState = new ContainerType( nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex, // Deep history valid from Capella onwards historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, - depositRequestsStartIndex: UintBn64, // New in ELECTRA:EIP6110 + depositReceiptsStartIndex: UintBn64, // New in ELECTRA:EIP6110 depositBalanceToConsume: Gwei, // New in Electra:EIP7251 exitBalanceToConsume: Gwei, // New in Electra:EIP7251 earliestExitEpoch: Epoch, // New in Electra:EIP7251 consolidationBalanceToConsume: Gwei, // New in Electra:EIP7251 earliestConsolidationEpoch: Epoch, // New in Electra:EIP7251 pendingBalanceDeposits: PendingBalanceDeposits, // new in electra:eip7251 - pendingPartialWithdrawals: new ListCompositeType(PartialWithdrawal, Number(PENDING_PARTIAL_WITHDRAWALS_LIMIT)), // New in Electra:EIP7251 + pendingPartialWithdrawals: new ListCompositeType(PendingPartialWithdrawal, Number(PENDING_PARTIAL_WITHDRAWALS_LIMIT)), // New in Electra:EIP7251 pendingConsolidations: new ListCompositeType(PendingConsolidation, Number(PENDING_CONSOLIDATIONS_LIMIT)), // new in electra:eip7251 }, {typeName: "BeaconState", jsonCase: "eth2"} @@ -366,7 +368,7 @@ export const LightClientBootstrap = new ContainerType( { header: LightClientHeader, currentSyncCommittee: altairSsz.SyncCommittee, - currentSyncCommitteeBranch: altairSsz.LightClientBootstrap.fields.currentSyncCommitteeBranch, + currentSyncCommitteeBranch: new VectorCompositeType(Bytes32, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA), }, {typeName: "LightClientBootstrap", jsonCase: "eth2"} ); @@ -375,9 +377,9 @@ export const LightClientUpdate = new ContainerType( { attestedHeader: LightClientHeader, nextSyncCommittee: altairSsz.SyncCommittee, - nextSyncCommitteeBranch: altairSsz.LightClientUpdate.fields.nextSyncCommitteeBranch, + nextSyncCommitteeBranch: new VectorCompositeType(Bytes32, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA), finalizedHeader: LightClientHeader, - finalityBranch: altairSsz.LightClientUpdate.fields.finalityBranch, + finalityBranch: new VectorCompositeType(Bytes32, FINALIZED_ROOT_DEPTH_ELECTRA), syncAggregate: altairSsz.SyncAggregate, signatureSlot: Slot, }, @@ -388,7 +390,7 @@ export const LightClientFinalityUpdate = new ContainerType( { attestedHeader: LightClientHeader, finalizedHeader: LightClientHeader, - finalityBranch: altairSsz.LightClientFinalityUpdate.fields.finalityBranch, + finalityBranch: new VectorCompositeType(Bytes32, FINALIZED_ROOT_DEPTH_ELECTRA), syncAggregate: altairSsz.SyncAggregate, signatureSlot: Slot, }, diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index 53b95e95525c..fc95ecde562d 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -9,8 +9,8 @@ export type AttesterSlashing = ValueOf; export type AggregateAndProof = ValueOf; export type SignedAggregateAndProof = ValueOf; -export type DepositRequest = ValueOf; -export type DepositRequests = ValueOf; +export type DepositRequest = ValueOf; +export type DepositRequests = ValueOf; export type ExecutionLayerWithdrawalRequest = ValueOf; export type ExecutionLayerWithdrawalRequests = ValueOf; @@ -47,5 +47,5 @@ export type Consolidation = ValueOf; export type SignedConsolidation = ValueOf; export type PendingBalanceDeposit = ValueOf; -export type PartialWithdrawal = ValueOf; +export type PendingPartialWithdrawal = ValueOf; export type PendingConsolidation = ValueOf; From dc2a197827bec78fd6110e7be49fbebcb7a3345f Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Tue, 14 May 2024 04:42:06 -0400 Subject: [PATCH 037/259] fix: inline sourcemaps to help with debugging (#6768) --- vite.base.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/vite.base.config.ts b/vite.base.config.ts index 65e1bad01500..f9030d9edb7f 100644 --- a/vite.base.config.ts +++ b/vite.base.config.ts @@ -40,6 +40,7 @@ export function getBaseViteConfig( esbuild: { banner, legalComments: "none", + sourcemap: "inline", }, build: { // "modules" refer to ['es2020', 'edge88', 'firefox78', 'chrome87', 'safari14'] From 3e6990ae2044f467930e0436673198e80bb661b6 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Tue, 14 May 2024 11:46:01 +0200 Subject: [PATCH 038/259] fix: additional epoch calculation logic for consolidation churn (#6770) Fix the chunk limit logic --- packages/state-transition/src/util/epoch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/state-transition/src/util/epoch.ts b/packages/state-transition/src/util/epoch.ts index 67837780dca9..b9b911137fd9 100644 --- a/packages/state-transition/src/util/epoch.ts +++ b/packages/state-transition/src/util/epoch.ts @@ -83,7 +83,7 @@ export function computeConsolidationEpochAndUpdateChurn( // Consolidation doesn't fit in the current earliest epoch. if (consolidationBalance > consolidationBalanceToConsume) { const balanceToProcess = Number(consolidationBalance) - consolidationBalanceToConsume; - const additionalEpochs = Math.floor((balanceToProcess - 1) / (perEpochConsolidationChurn + 1)); + const additionalEpochs = Math.floor((balanceToProcess - 1) / perEpochConsolidationChurn) + 1; earliestConsolidationEpoch += additionalEpochs; consolidationBalanceToConsume += additionalEpochs * perEpochConsolidationChurn; } From bd1bb6cb2f4124ca181ec5706c6505b9903ed9ec Mon Sep 17 00:00:00 2001 From: twoeths Date: Tue, 14 May 2024 12:56:01 +0300 Subject: [PATCH 039/259] fix: electra fork transition spec tests (#6769) * fix: electra fork transition * fix: merge issue * chore: remove unwanted change --- .../src/slot/upgradeStateToElectra.ts | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 417c3cd717c1..72255ccddee3 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -1,4 +1,4 @@ -import {ssz} from "@lodestar/types"; +import {Epoch, ValidatorIndex, ssz} from "@lodestar/types"; import {FAR_FUTURE_EPOCH, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateDeneb} from "../types.js"; import {CachedBeaconStateElectra, getCachedBeaconState} from "../cache/stateCache.js"; @@ -7,6 +7,8 @@ import { queueEntireBalanceAndResetValidator, queueExcessActiveBalance, } from "../util/electra.js"; +import {computeActivationExitEpoch} from "../util/epoch.js"; +import {getActivationExitChurnLimit, getConsolidationChurnLimit} from "../util/validator.js"; /** * Upgrade a state from Capella to Deneb. @@ -58,17 +60,52 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache // latestExecutionPayloadHeader's depositReceiptsRoot and withdrawalRequestsRoot set to zeros by default // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX stateElectraView.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + stateElectraView.depositBalanceToConsume = BigInt(0); + stateElectraView.exitBalanceToConsume = BigInt(0); const validatorsArr = stateElectraView.validators.getAllReadonly(); + const exitEpochs: Epoch[] = []; + + // [EIP-7251]: add validators that are not yet active to pending balance deposits + const preActivation: ValidatorIndex[] = []; + for (let validatorIndex = 0; validatorIndex < validatorsArr.length; validatorIndex++) { + const {activationEpoch, exitEpoch} = validatorsArr[validatorIndex]; + if (activationEpoch === FAR_FUTURE_EPOCH) { + preActivation.push(validatorIndex); + } + if (exitEpoch !== FAR_FUTURE_EPOCH) { + exitEpochs.push(exitEpoch); + } + } + + const currentEpochPre = stateDeneb.epochCtx.epoch; + + if (exitEpochs.length === 0) { + exitEpochs.push(currentEpochPre); + } + stateElectraView.earliestExitEpoch = Math.max(...exitEpochs) + 1; + stateElectraView.consolidationBalanceToConsume = BigInt(0); + stateElectraView.earliestConsolidationEpoch = computeActivationExitEpoch(currentEpochPre); + // stateElectraView.pendingBalanceDeposits = ssz.electra.PendingBalanceDeposits.defaultViewDU(); + // pendingBalanceDeposits, pendingPartialWithdrawals, pendingConsolidations are default values + // TODO-electra: can we improve this? + stateElectraView.commit(); + const tmpElectraState = getCachedBeaconState(stateElectraView, stateDeneb); + stateElectraView.exitBalanceToConsume = BigInt(getActivationExitChurnLimit(tmpElectraState)); + stateElectraView.consolidationBalanceToConsume = BigInt(getConsolidationChurnLimit(tmpElectraState)); + + preActivation.sort((i0, i1) => { + const res = validatorsArr[i0].activationEligibilityEpoch - validatorsArr[i1].activationEligibilityEpoch; + return res !== 0 ? res : i0 - i1; + }); + + for (const validatorIndex of preActivation) { + queueEntireBalanceAndResetValidator(stateElectraView as CachedBeaconStateElectra, validatorIndex); + } for (let i = 0; i < validatorsArr.length; i++) { const validator = validatorsArr[i]; - // [EIP-7251]: add validators that are not yet active to pending balance deposits - if (validator.activationEligibilityEpoch === FAR_FUTURE_EPOCH) { - queueEntireBalanceAndResetValidator(stateElectraView as CachedBeaconStateElectra, i); - } - // [EIP-7251]: Ensure early adopters of compounding credentials go through the activation churn const withdrawalCredential = validator.withdrawalCredentials; if (hasCompoundingWithdrawalCredential(withdrawalCredential)) { From f0eab386df4daad9fbd562d6f8c5cbf021647403 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 14 May 2024 14:50:01 +0300 Subject: [PATCH 040/259] test: fix ssz_static spec tests for all forks (#6771) --- .../beacon-node/test/spec/presets/operations.test.ts | 7 ++++--- .../beacon-node/test/spec/presets/ssz_static.test.ts | 5 +++++ packages/params/src/index.ts | 2 +- packages/types/src/electra/sszTypes.ts | 11 ++++------- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index fe70c091aa5a..de8a32a6056a 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -138,12 +138,12 @@ const operations: TestRunnerFn = (fork, sszTypes: { pre: ssz[fork].BeaconState, post: ssz[fork].BeaconState, - attestation: fork === ForkName.electra ? ssz.electra.Attestation : ssz.phase0.Attestation, - attester_slashing: fork === ForkName.electra ? ssz.electra.AttesterSlashing : ssz.phase0.AttesterSlashing, + attestation: ssz.allForks[fork].Attestation, + attester_slashing: ssz.allForks[fork].AttesterSlashing, block: ssz[fork].BeaconBlock, body: ssz[fork].BeaconBlockBody, deposit: ssz.phase0.Deposit, - deposit_receipt: ssz.electra.DepositRequest, + deposit_receipt: ssz.electra.DepositReceipt, proposer_slashing: ssz.phase0.ProposerSlashing, voluntary_exit: ssz.phase0.SignedVoluntaryExit, // Altair @@ -155,6 +155,7 @@ const operations: TestRunnerFn = (fork, : ssz.bellatrix.ExecutionPayload, // Capella address_change: ssz.capella.SignedBLSToExecutionChange, + // Electra consolidation: ssz.electra.SignedConsolidation, execution_layer_withdrawal_request: ssz.electra.ExecutionLayerWithdrawalRequest, }, diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index cca6bb57c308..ad828d5b5bb9 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -2,8 +2,13 @@ import fs from "node:fs"; import path from "node:path"; import {it, vi} from "vitest"; import {Type} from "@chainsafe/ssz"; +<<<<<<< HEAD import {ssz, sszTypesFor} from "@lodestar/types"; import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; +======= +import {ssz} from "@lodestar/types"; +import {ACTIVE_PRESET, ForkName, ForkLightClient, ForkExecution} from "@lodestar/params"; +>>>>>>> 82d0692d63d (test: fix ssz_static spec tests for all forks (#6771)) import {replaceUintTypeWithUintBigintType} from "../utils/replaceUintTypeWithUintBigintType.js"; import {parseSszStaticTestcase} from "../utils/sszTestCaseParser.js"; import {runValidSszTest} from "../utils/runValidSszTest.js"; diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 20439568156e..0c2e3b34794b 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -267,4 +267,4 @@ export const FULL_EXIT_REQUEST_AMOUNT = 0; export const NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA = 87; export const NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA = 6; export const FINALIZED_ROOT_DEPTH_ELECTRA = 7; -export const FINALIZED_ROOT_INDEX_ELECTRA = 169; \ No newline at end of file +export const FINALIZED_ROOT_INDEX_ELECTRA = 169; diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index b2191215eb2c..0aa2872c3a73 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -277,10 +277,7 @@ export const PendingBalanceDeposit = new ContainerType( {typeName: "PendingBalanceDeposit", jsonCase: "eth2"} ); -export const PendingBalanceDeposits = new ListCompositeType( - PendingBalanceDeposit, - Number(PENDING_BALANCE_DEPOSITS_LIMIT) -); +export const PendingBalanceDeposits = new ListCompositeType(PendingBalanceDeposit, PENDING_BALANCE_DEPOSITS_LIMIT); export const PendingPartialWithdrawal = new ContainerType( { @@ -348,9 +345,9 @@ export const BeaconState = new ContainerType( earliestExitEpoch: Epoch, // New in Electra:EIP7251 consolidationBalanceToConsume: Gwei, // New in Electra:EIP7251 earliestConsolidationEpoch: Epoch, // New in Electra:EIP7251 - pendingBalanceDeposits: PendingBalanceDeposits, // new in electra:eip7251 - pendingPartialWithdrawals: new ListCompositeType(PendingPartialWithdrawal, Number(PENDING_PARTIAL_WITHDRAWALS_LIMIT)), // New in Electra:EIP7251 - pendingConsolidations: new ListCompositeType(PendingConsolidation, Number(PENDING_CONSOLIDATIONS_LIMIT)), // new in electra:eip7251 + pendingBalanceDeposits: PendingBalanceDeposits, // New in Electra:EIP7251 + pendingPartialWithdrawals: new ListCompositeType(PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT), // New in Electra:EIP7251 + pendingConsolidations: new ListCompositeType(PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT), // New in Electra:EIP7251 }, {typeName: "BeaconState", jsonCase: "eth2"} ); From 65b6827a8c68ed9401694015b4ca4994fc2b5a5a Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Tue, 14 May 2024 14:11:00 +0200 Subject: [PATCH 041/259] chore(spec): remove the skip specs for electra (#6772) Remove the skip spec for electra --- packages/beacon-node/test/spec/utils/specTestIterator.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index 393983bb8a56..63fe0cc10442 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -65,7 +65,6 @@ export const defaultSkipOpts: SkipOpts = { skippedTestSuites: [ /^capella\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, /^deneb\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, - /^electra\/(?!operations\/attestations)(?!operations\/attester_slashing)/, ], skippedTests: [], skippedRunners: ["merkle_proof", "networking"], From 7f2a77a5349177f799bd5b71e9889d8bbc59775a Mon Sep 17 00:00:00 2001 From: NC Date: Tue, 14 May 2024 15:26:36 +0300 Subject: [PATCH 042/259] fix: use mutable validator object (#6774) Use mutable validator object --- .../src/block/processExecutionLayerWithdrawalRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts index 1b795789cb77..e02129a09d05 100644 --- a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts +++ b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts @@ -37,7 +37,7 @@ export function processExecutionLayerWithdrawalRequest( return; } - const validator = validators.getReadonly(validatorIndex); + const validator = validators.get(validatorIndex); if (!isValidatorEligibleForWithdrawOrExit(validator, executionLayerWithdrawalRequest.sourceAddress, state)) { return; } From 486a7667ea40d841bc5ce3a5863df3a2a2884dff Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Tue, 14 May 2024 11:42:28 -0400 Subject: [PATCH 043/259] test: fix balance spec tests (#6777) * fix: remove epochCache.balances and invalid MAX_EFFECTIVE_BALANCE check * fix: update rewardsAndPenalties balance updates * docs: add comment to check epochTransitionCache --- .../src/epoch/processEffectiveBalanceUpdates.ts | 7 +++++-- .../src/epoch/processRewardsAndPenalties.ts | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts index e83d2545ef50..f4fae6e41d4f 100644 --- a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts +++ b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts @@ -41,7 +41,10 @@ export function processEffectiveBalanceUpdates( // epochTransitionCache.balances is set in processRewardsAndPenalties(), so it's recycled here for performance. // It defaults to `state.balances.getAll()` to make Typescript happy and for spec tests - const balances = cache.balances ?? state.balances.getAll(); + const balances = state.balances.getAll(); + + // TODO: (@matthewkeil) This was causing additional failures but should not. Check the EpochTransitionCache for why + // const balances = cache.balances ?? state.balances.getAll(); for (let i = 0, len = balances.length; i < len; i++) { const balance = balances[i]; @@ -55,7 +58,7 @@ export function processEffectiveBalanceUpdates( // Too big effectiveBalance > balance + DOWNWARD_THRESHOLD || // Too small. Check effectiveBalance < MAX_EFFECTIVE_BALANCE to prevent unnecessary updates - (effectiveBalance < MAX_EFFECTIVE_BALANCE && effectiveBalance < balance - UPWARD_THRESHOLD) + effectiveBalance + UPWARD_THRESHOLD < balance ) { // Update the state tree // Should happen rarely, so it's fine to update the tree diff --git a/packages/state-transition/src/epoch/processRewardsAndPenalties.ts b/packages/state-transition/src/epoch/processRewardsAndPenalties.ts index 61680b81002a..041655d75825 100644 --- a/packages/state-transition/src/epoch/processRewardsAndPenalties.ts +++ b/packages/state-transition/src/epoch/processRewardsAndPenalties.ts @@ -28,7 +28,8 @@ export function processRewardsAndPenalties( const balances = state.balances.getAll(); for (let i = 0, len = rewards.length; i < len; i++) { - balances[i] += rewards[i] - penalties[i] - (slashingPenalties[i] ?? 0); + const result = balances[i] + rewards[i] - penalties[i] - (slashingPenalties[i] ?? 0) + balances[i] = Math.max(result, 0); } // important: do not change state one balance at a time. Set them all at once, constructing the tree in one go From f82b355b55cdae81e1066cad2045c0b1b5a02f26 Mon Sep 17 00:00:00 2001 From: NC Date: Tue, 14 May 2024 22:15:17 +0300 Subject: [PATCH 044/259] fix: effective balance cache is not in sync with validator effective balance (#6780) Update eb cache at fork transition --- packages/state-transition/src/util/electra.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/state-transition/src/util/electra.ts b/packages/state-transition/src/util/electra.ts index 00c5bb183eb4..53f53aaf8d61 100644 --- a/packages/state-transition/src/util/electra.ts +++ b/packages/state-transition/src/util/electra.ts @@ -93,6 +93,7 @@ export function queueEntireBalanceAndResetValidator(state: CachedBeaconStateElec const validator = state.validators.get(index); validator.effectiveBalance = 0; + state.epochCtx.effectiveBalanceIncrementsSet(index, 0); validator.activationEligibilityEpoch = FAR_FUTURE_EPOCH; const pendingBalanceDeposit = ssz.electra.PendingBalanceDeposit.toViewDU({ From 1d57ac79ac7d6c6c14968101497791d80d4fb595 Mon Sep 17 00:00:00 2001 From: NC Date: Thu, 16 May 2024 11:05:01 +0300 Subject: [PATCH 045/259] fix: make electra-fork passes lint and check-types (#6785) fix lint and check-types --- packages/beacon-node/test/sim/electra-interop.test.ts | 6 +++--- packages/fork-choice/test/perf/forkChoice/util.ts | 2 +- .../fork-choice/test/unit/forkChoice/forkChoice.test.ts | 6 +++--- .../test/unit/forkChoice/getProposerHead.test.ts | 6 +++--- .../fork-choice/test/unit/protoArray/computeDeltas.test.ts | 2 +- .../src/epoch/processRewardsAndPenalties.ts | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index 37bed1f7b843..962e0aa5dea9 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -219,11 +219,11 @@ describe("executionEngine / ExecutionEngineHttp", function () { } } - if (payload.depositRequests.length !== 1) { - throw Error(`Number of depositRequests mismatched. Expected: 1, actual: ${payload.depositRequests.length}`); + if (payload.depositReceipts.length !== 1) { + throw Error(`Number of depositRequests mismatched. Expected: 1, actual: ${payload.depositReceipts.length}`); } - const actualDepositRequest = payload.depositRequests[0]; + const actualDepositRequest = payload.depositReceipts[0]; assert.deepStrictEqual( actualDepositRequest, depositRequestB, diff --git a/packages/fork-choice/test/perf/forkChoice/util.ts b/packages/fork-choice/test/perf/forkChoice/util.ts index dbd049e257c1..6c04ac817fb2 100644 --- a/packages/fork-choice/test/perf/forkChoice/util.ts +++ b/packages/fork-choice/test/perf/forkChoice/util.ts @@ -41,7 +41,7 @@ export function initializeForkChoice(opts: Opts): ForkChoice { genesisSlot ); - const balances = new Uint8Array(Array.from({length: opts.initialValidatorCount}, () => 32)); + const balances = new Uint16Array(Array.from({length: opts.initialValidatorCount}, () => 32)); const fcStore: IForkChoiceStore = { currentSlot: genesisSlot, diff --git a/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts b/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts index fcb7376cffa8..40988a0e4a71 100644 --- a/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts @@ -52,16 +52,16 @@ describe("Forkchoice", function () { currentSlot: genesisSlot + 1, justified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(finalizedRoot), rootHex: finalizedRoot}, - balances: new Uint8Array([32]), + balances: new Uint16Array([32]), totalBalance: 32, }, unrealizedJustified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(finalizedRoot), rootHex: finalizedRoot}, - balances: new Uint8Array([32]), + balances: new Uint16Array([32]), }, finalizedCheckpoint: {epoch: genesisEpoch, root: fromHexString(finalizedRoot), rootHex: finalizedRoot}, unrealizedFinalizedCheckpoint: {epoch: genesisEpoch, root: fromHexString(finalizedRoot), rootHex: finalizedRoot}, - justifiedBalancesGetter: () => new Uint8Array([32]), + justifiedBalancesGetter: () => new Uint16Array([32]), equivocatingIndices: new Set(), }; diff --git a/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts b/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts index cc14b5b57b92..f603a4069b83 100644 --- a/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts @@ -102,12 +102,12 @@ describe("Forkchoice / GetProposerHead", function () { currentSlot: genesisSlot + 1, justified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(genesisBlock.blockRoot), rootHex: genesisBlock.blockRoot}, - balances: new Uint8Array(Array(32).fill(150)), + balances: new Uint16Array(Array(32).fill(150)), totalBalance: 32 * 150, }, unrealizedJustified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(genesisBlock.blockRoot), rootHex: genesisBlock.blockRoot}, - balances: new Uint8Array(Array(32).fill(150)), + balances: new Uint16Array(Array(32).fill(150)), }, finalizedCheckpoint: { epoch: genesisEpoch, @@ -119,7 +119,7 @@ describe("Forkchoice / GetProposerHead", function () { root: fromHexString(genesisBlock.blockRoot), rootHex: genesisBlock.blockRoot, }, - justifiedBalancesGetter: () => new Uint8Array(Array(32).fill(150)), + justifiedBalancesGetter: () => new Uint16Array(Array(32).fill(150)), equivocatingIndices: new Set(), }; diff --git a/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts b/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts index fde551d43cda..4428807bd13d 100644 --- a/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts +++ b/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts @@ -253,7 +253,7 @@ describe("computeDeltas", () => { nextEpoch: 0, })); - const balances = new Uint8Array([firstBalance, secondBalance]); + const balances = new Uint16Array([firstBalance, secondBalance]); // 1st validator is part of an attester slashing const equivocatingIndices = new Set([0]); let deltas = computeDeltas(indices.size, votes, balances, balances, equivocatingIndices); diff --git a/packages/state-transition/src/epoch/processRewardsAndPenalties.ts b/packages/state-transition/src/epoch/processRewardsAndPenalties.ts index 041655d75825..6c5d5aa3cb5a 100644 --- a/packages/state-transition/src/epoch/processRewardsAndPenalties.ts +++ b/packages/state-transition/src/epoch/processRewardsAndPenalties.ts @@ -28,7 +28,7 @@ export function processRewardsAndPenalties( const balances = state.balances.getAll(); for (let i = 0, len = rewards.length; i < len; i++) { - const result = balances[i] + rewards[i] - penalties[i] - (slashingPenalties[i] ?? 0) + const result = balances[i] + rewards[i] - penalties[i] - (slashingPenalties[i] ?? 0); balances[i] = Math.max(result, 0); } From edc396ee334acc6d4c0e5b9f624944c085d9b000 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 16 May 2024 11:54:51 +0300 Subject: [PATCH 046/259] fix: update data format of WithdrawalRequestV1 (#6789) --- packages/beacon-node/src/execution/engine/payloadIdCache.ts | 2 +- packages/beacon-node/src/execution/engine/types.ts | 4 ++-- .../src/block/processExecutionLayerWithdrawalRequest.ts | 2 +- packages/types/src/electra/sszTypes.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index f79c28582459..35a50e97cfb3 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -28,7 +28,7 @@ export type DepositRequestV1 = { export type ExecutionLayerWithdrawalRequestV1 = { sourceAddress: DATA; - validatorPubkey: DATA; + validatorPublicKey: DATA; amount: QUANTITY; }; diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index de744d56d6cd..c7b0aefd07ad 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -437,7 +437,7 @@ export function serializeExecutionLayerWithdrawalRequest( ): ExecutionLayerWithdrawalRequestRpc { return { sourceAddress: bytesToData(withdrawalRequest.sourceAddress), - validatorPubkey: bytesToData(withdrawalRequest.validatorPubkey), + validatorPublicKey: bytesToData(withdrawalRequest.validatorPublicKey), amount: numToQuantity(withdrawalRequest.amount), }; } @@ -447,7 +447,7 @@ export function deserializeExecutionLayerWithdrawalRequest( ): electra.ExecutionLayerWithdrawalRequest { return { sourceAddress: dataToBytes(withdrawalRequest.sourceAddress, 20), - validatorPubkey: dataToBytes(withdrawalRequest.validatorPubkey, 48), + validatorPublicKey: dataToBytes(withdrawalRequest.validatorPublicKey, 48), amount: quantityToNum(withdrawalRequest.amount), }; } diff --git a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts index e02129a09d05..935acd522da1 100644 --- a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts +++ b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts @@ -32,7 +32,7 @@ export function processExecutionLayerWithdrawalRequest( // bail out if validator is not in beacon state // note that we don't need to check for 6110 unfinalized vals as they won't be eligible for withdraw/exit anyway - const validatorIndex = pubkey2index.get(executionLayerWithdrawalRequest.validatorPubkey); + const validatorIndex = pubkey2index.get(executionLayerWithdrawalRequest.validatorPublicKey); if (validatorIndex === undefined) { return; } diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 0aa2872c3a73..3596bdbce5bf 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -128,7 +128,7 @@ export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT export const ExecutionLayerWithdrawalRequest = new ContainerType( { sourceAddress: ExecutionAddress, - validatorPubkey: BLSPubkey, + validatorPublicKey: BLSPubkey, amount: UintNum64, }, {typeName: "ExecutionLayerWithdrawalRequest", jsonCase: "eth2"} From 943c91393c475e38b86373ec753d9a1f8aa2397e Mon Sep 17 00:00:00 2001 From: NC Date: Thu, 16 May 2024 12:53:29 +0300 Subject: [PATCH 047/259] fix: publish attestations with non-zero committee index (#6790) Fix publishing att with non-zero comm index --- packages/validator/src/services/attestation.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index a0cf8e8768e7..f4aeeab15260 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -159,12 +159,13 @@ export class AttestationService { this.metrics?.attesterStepCallProduceAggregate.observe(this.clock.secFromSlot(slot + 2 / 3)); const dutiesByCommitteeIndex = groupAttDutiesByCommitteeIndex(dutiesAll); + const isAfterElectra = computeEpochAtSlot(slot) >= this.config.ELECTRA_FORK_EPOCH; // Then download, sign and publish a `SignedAggregateAndProof` for each // validator that is elected to aggregate for this `slot` and `committeeIndex`. await Promise.all( Array.from(dutiesByCommitteeIndex.entries()).map(([index, dutiesSameCommittee]) => { - const attestationData: phase0.AttestationData = {...attestationNoCommittee, index}; + const attestationData: phase0.AttestationData = {...attestationNoCommittee, index: isAfterElectra ? 0 : index}; return this.produceAndPublishAggregates(attestationData, index, dutiesSameCommittee); }) ); @@ -195,10 +196,11 @@ export class AttestationService { const signedAttestations: phase0.Attestation[] = []; const headRootHex = toHexString(attestationNoCommittee.beaconBlockRoot); const currentEpoch = computeEpochAtSlot(slot); + const isAfterElectra = currentEpoch >= this.config.ELECTRA_FORK_EPOCH; await Promise.all( duties.map(async ({duty}) => { - const index = duty.committeeIndex; + const index = isAfterElectra ? 0 : duty.committeeIndex; const attestationData: phase0.AttestationData = {...attestationNoCommittee, index}; const logCtxValidator = {slot, index, head: headRootHex, validatorIndex: duty.validatorIndex}; From 7a50b6ff14d8b6c4d9295ff5bc2dbc8110aad8b3 Mon Sep 17 00:00:00 2001 From: NC Date: Thu, 16 May 2024 15:08:22 +0300 Subject: [PATCH 048/259] fix: validator monitor summaries should not render during epoch 0 (#6791) Skip render summary at epoch 0 --- packages/beacon-node/src/metrics/validatorMonitor.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/metrics/validatorMonitor.ts b/packages/beacon-node/src/metrics/validatorMonitor.ts index a443bf761c93..6331c5dca550 100644 --- a/packages/beacon-node/src/metrics/validatorMonitor.ts +++ b/packages/beacon-node/src/metrics/validatorMonitor.ts @@ -644,7 +644,14 @@ export function createValidatorMonitor( } // Compute summaries of previous epoch attestation performance - const prevEpoch = Math.max(0, computeEpochAtSlot(headState.slot) - 1); + const prevEpoch = computeEpochAtSlot(headState.slot) - 1; + + // During the end of first epoch, the prev epoch with be -1 + // Skip this as there is no attestation and block proposal summary in epoch -1 + if (prevEpoch === -1) { + return; + } + const rootCache = new RootHexCache(headState); if (config.getForkSeq(headState.slot) >= ForkSeq.altair) { From d490b41a3cec9eeace7c4e78de22612652e46238 Mon Sep 17 00:00:00 2001 From: NC Date: Thu, 16 May 2024 15:11:37 +0300 Subject: [PATCH 049/259] fix: attestation duty validation (#6792) * fix attestation duty validation * Update packages/validator/src/services/validatorStore.ts Co-authored-by: twoeths * Update packages/validator/src/services/validatorStore.ts --------- Co-authored-by: twoeths Co-authored-by: Cayman --- packages/validator/src/services/validatorStore.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index a807c27569eb..62ebe339bff9 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -798,11 +798,18 @@ export class ValidatorStore { if (duty.slot !== data.slot) { throw Error(`Inconsistent duties during signing: duty.slot ${duty.slot} != att.slot ${data.slot}`); } - if (duty.committeeIndex != data.index) { + + const isAfterElectra = computeEpochAtSlot(duty.slot) >= this.config.ELECTRA_FORK_EPOCH; + if (!isAfterElectra && duty.committeeIndex != data.index) { throw Error( `Inconsistent duties during signing: duty.committeeIndex ${duty.committeeIndex} != att.committeeIndex ${data.index}` ); } + if (isAfterElectra && data.index !== 0) { + throw Error( + `Non-zero committee index post-electra during signing: att.committeeIndex ${data.index}` + ); + } if (this.config.getForkSeq(duty.slot) >= ForkSeq.electra && data.index !== 0) { throw Error(`Attestataion data index must be 0 post electra: index ${data.index}`); } From 296ce19a3b81cf9a0b27c2d8007e16683136301a Mon Sep 17 00:00:00 2001 From: Cayman Date: Thu, 16 May 2024 08:12:40 -0400 Subject: [PATCH 050/259] fix: align BeaconBlockBody and BlindedBeaconBlockBody (#6782) * fix: align BeaconBlockBody and BlindedBeaconBlockBody * Remove type hacks in test --------- Co-authored-by: Nico Flaig --- packages/types/src/electra/sszTypes.ts | 1 + packages/types/test/unit/blinded.test.ts | 35 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 packages/types/test/unit/blinded.test.ts diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 3596bdbce5bf..0a0c0f6aeefb 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -223,6 +223,7 @@ export const BlindedBeaconBlockBody = new ContainerType( executionPayloadHeader: ExecutionPayloadHeader, // Modified in ELECTRA blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, + consolidations: new ListCompositeType(SignedConsolidation, MAX_CONSOLIDATIONS), // [New in Electra] }, {typeName: "BlindedBeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); diff --git a/packages/types/test/unit/blinded.test.ts b/packages/types/test/unit/blinded.test.ts new file mode 100644 index 000000000000..77005f1defc2 --- /dev/null +++ b/packages/types/test/unit/blinded.test.ts @@ -0,0 +1,35 @@ +import {describe, it, expect} from "vitest"; +import {ForkName, isForkExecution} from "@lodestar/params"; +import {ssz} from "../../src/index.js"; + +describe("blinded data structures", function () { + it("should have the same number of fields as non-blinded", () => { + const blindedTypes = [ + {a: "BlindedBeaconBlockBody" as const, b: "BeaconBlockBody" as const}, + {a: "ExecutionPayloadHeader" as const, b: "ExecutionPayload" as const}, + ]; + + for (const {a, b} of blindedTypes) { + for (const fork of Object.keys(ssz.allForks) as ForkName[]) { + if (!isForkExecution(fork)) { + continue; + } + + const blindedType = ssz[fork][a]; + if (blindedType === undefined) { + expect.fail(`fork: ${fork}, type ${a} is undefined`); + } + + const type = ssz[fork][b]; + if (type === undefined) { + expect.fail(`fork: ${fork}, type ${b} is undefined`); + } + + expect(Object.keys(blindedType.fields).length).toBeWithMessage( + Object.keys(type.fields).length, + `fork: ${fork}, types ${a} and ${b} have different number of fields` + ); + } + } + }); +}); From 7b76bfc18160347c5fd3bf65632b976b2cd053b7 Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 16 May 2024 05:17:49 -0700 Subject: [PATCH 051/259] test: improve ssz tests consistency (#6776) * test: improve ssz tests consistency * chore: address comments --- .../test/spec/presets/ssz_static.test.ts | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index ad828d5b5bb9..e4c5a1914827 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import path from "node:path"; -import {it, vi} from "vitest"; +import {expect, it, vi} from "vitest"; import {Type} from "@chainsafe/ssz"; <<<<<<< HEAD import {ssz, sszTypesFor} from "@lodestar/types"; @@ -56,23 +56,26 @@ const sszStatic = (ssz.bellatrix as Types)[typeName] || (ssz.altair as Types)[typeName] || (ssz.phase0 as Types)[typeName]; - if (!sszType) { - throw Error(`No type for ${typeName}`); - } - const sszTypeNoUint = replaceUintTypeWithUintBigintType(sszType); + if (!sszType) { + expect.fail( + `Missing SSZ type definition for ${typeName}; this will prevent associated ssz_static tests to be executed` + ); + } else { + const sszTypeNoUint = replaceUintTypeWithUintBigintType(sszType); - for (const testCase of fs.readdirSync(testSuiteDirpath)) { - // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts - it(testCase, function () { - // Mainnet must deal with big full states and hash each one multiple times - if (ACTIVE_PRESET === "mainnet") { - vi.setConfig({testTimeout: 30 * 1000}); - } + for (const testCase of fs.readdirSync(testSuiteDirpath)) { + // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts + it(testCase, function () { + // Mainnet must deal with big full states and hash each one multiple times + if (ACTIVE_PRESET === "mainnet") { + vi.setConfig({testTimeout: 30 * 1000}); + } - const testData = parseSszStaticTestcase(path.join(testSuiteDirpath, testCase)); - runValidSszTest(sszTypeNoUint, testData); - }); + const testData = parseSszStaticTestcase(path.join(testSuiteDirpath, testCase)); + runValidSszTest(sszTypeNoUint, testData); + }); + } } }; From dbd6a498a2b2cd960d2945131258ff73d46b5b7d Mon Sep 17 00:00:00 2001 From: twoeths Date: Thu, 16 May 2024 21:09:28 +0300 Subject: [PATCH 052/259] fix: batch validation for electra attestations (#6788) --- .../src/api/impl/beacon/pool/index.ts | 4 +- .../src/chain/opPools/attestationPool.ts | 29 ++-- .../chain/seenCache/seenAttestationData.ts | 24 ++-- .../src/chain/validation/aggregateAndProof.ts | 2 +- .../src/chain/validation/attestation.ts | 134 +++++++++++------- .../src/network/processor/gossipHandlers.ts | 12 +- .../network/processor/gossipQueues/index.ts | 8 +- .../network/processor/gossipQueues/indexed.ts | 1 + packages/beacon-node/src/util/sszBytes.ts | 30 +++- .../perf/chain/validation/attestation.test.ts | 6 +- .../attestation/validateAttestation.test.ts | 26 ++-- .../test/unit/util/sszBytes.test.ts | 6 +- .../validator/src/services/attestation.ts | 4 +- .../validator/src/services/validatorStore.ts | 2 +- 14 files changed, 179 insertions(+), 109 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index 3f594fa4c3ae..19c11362c910 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -66,7 +66,7 @@ export function getBeaconPoolApi({ // when a validator is configured with multiple beacon node urls, this attestation data may come from another beacon node // and the block hasn't been in our forkchoice since we haven't seen / processing that block // see https://github.com/ChainSafe/lodestar/issues/5098 - const {indexedAttestation, subnet, attDataRootHex} = await validateGossipFnRetryUnknownRoot( + const {indexedAttestation, subnet, attDataRootHex, committeeIndex} = await validateGossipFnRetryUnknownRoot( validateFn, network, chain, @@ -75,7 +75,7 @@ export function getBeaconPoolApi({ ); if (network.shouldAggregate(subnet, slot)) { - const insertOutcome = chain.attestationPool.add(attestation, attDataRootHex); + const insertOutcome = chain.attestationPool.add(committeeIndex, attestation, attDataRootHex); metrics?.opPool.attestationPoolInsertOutcome.inc({insertOutcome}); } diff --git a/packages/beacon-node/src/chain/opPools/attestationPool.ts b/packages/beacon-node/src/chain/opPools/attestationPool.ts index a9286ac4949a..dfb3bc7348a2 100644 --- a/packages/beacon-node/src/chain/opPools/attestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/attestationPool.ts @@ -61,9 +61,10 @@ type CommitteeIndex = number; * receives and it can be triggered manually. */ export class AttestationPool { - private readonly attestationByRootBySlot = new MapDef>>( - () => new Map>() - ); + private readonly aggregateByIndexByRootBySlot = new MapDef< + Slot, + Map> + >(() => new Map>()); private lowestPermissibleSlot = 0; constructor( @@ -75,8 +76,10 @@ export class AttestationPool { /** Returns current count of pre-aggregated attestations with unique data */ getAttestationCount(): number { let attestationCount = 0; - for (const attestationByRoot of this.attestationByRootBySlot.values()) { - attestationCount += attestationByRoot.size; + for (const attestationByIndexByRoot of this.aggregateByIndexByRootBySlot.values()) { + for (const attestationByIndex of attestationByIndexByRoot.values()) { + attestationCount += attestationByIndex.size; + } } return attestationCount; } @@ -98,7 +101,7 @@ export class AttestationPool { * - Valid committeeIndex * - Valid data */ - add(attestation: allForks.Attestation, attDataRootHex: RootHex): InsertOutcome { + add(committeeIndex: CommitteeIndex, attestation: allForks.Attestation, attDataRootHex: RootHex): InsertOutcome { const slot = attestation.data.slot; const lowestPermissibleSlot = this.lowestPermissibleSlot; @@ -113,15 +116,11 @@ export class AttestationPool { } // Limit object per slot - const aggregateByRoot = this.attestationByRootBySlot.getOrDefault(slot); + const aggregateByRoot = this.aggregateByIndexByRootBySlot.getOrDefault(slot); if (aggregateByRoot.size >= MAX_ATTESTATIONS_PER_SLOT) { throw new OpPoolError({code: OpPoolErrorCode.REACHED_MAX_PER_SLOT}); } - const committeeIndex = isElectraAttestation(attestation) - ? // this attestation is added to pool after validation - attestation.committeeBits.getSingleTrueBit() - : attestation.data.index; // this should not happen because attestation should be validated before reaching this assert.notNull(committeeIndex, "Committee index should not be null in attestation pool"); @@ -146,7 +145,7 @@ export class AttestationPool { * For validator API to get an aggregate */ getAggregate(slot: Slot, committeeIndex: CommitteeIndex, dataRootHex: RootHex): allForks.Attestation | null { - const aggregate = this.attestationByRootBySlot.get(slot)?.get(dataRootHex)?.get(committeeIndex); + const aggregate = this.aggregateByIndexByRootBySlot.get(slot)?.get(dataRootHex)?.get(committeeIndex); if (!aggregate) { // TODO: Add metric for missing aggregates return null; @@ -160,7 +159,7 @@ export class AttestationPool { * By default, not interested in attestations in old slots, we only preaggregate attestations for the current slot. */ prune(clockSlot: Slot): void { - pruneBySlot(this.attestationByRootBySlot, clockSlot, SLOTS_RETAINED); + pruneBySlot(this.aggregateByIndexByRootBySlot, clockSlot, SLOTS_RETAINED); // by default preaggregateSlotDistance is 0, i.e only accept attestations in the same clock slot. this.lowestPermissibleSlot = Math.max(clockSlot - this.preaggregateSlotDistance, 0); } @@ -174,8 +173,8 @@ export class AttestationPool { const aggregateByRoots = bySlot === undefined - ? Array.from(this.attestationByRootBySlot.values()) - : [this.attestationByRootBySlot.get(bySlot)]; + ? Array.from(this.aggregateByIndexByRootBySlot.values()) + : [this.aggregateByIndexByRootBySlot.get(bySlot)]; for (const aggregateByRoot of aggregateByRoots) { if (aggregateByRoot) { diff --git a/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts b/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts index 9312f3b517a7..17343e386fd7 100644 --- a/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts +++ b/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts @@ -1,12 +1,16 @@ -import {phase0, RootHex, Slot} from "@lodestar/types"; +import {BitArray} from "@chainsafe/ssz"; +import {CommitteeIndex, phase0, RootHex, Slot} from "@lodestar/types"; import {MapDef} from "@lodestar/utils"; import {Metrics} from "../../metrics/metrics.js"; -import {AttDataBase64} from "../../util/sszBytes.js"; +import {SeenAttDataKey} from "../../util/sszBytes.js"; import {InsertOutcome} from "../opPools/types.js"; export type AttestationDataCacheEntry = { // part of shuffling data, so this does not take memory - committeeIndices: Uint32Array; + committeeValidatorIndices: Uint32Array; + // undefined for phase0 Attestation + committeeBits?: BitArray; + committeeIndex: CommitteeIndex; // IndexedAttestationData signing root, 32 bytes signingRoot: Uint8Array; // to be consumed by forkchoice and oppool @@ -38,12 +42,14 @@ const DEFAULT_MAX_CACHE_SIZE_PER_SLOT = 200; const DEFAULT_CACHE_SLOT_DISTANCE = 2; /** + * Cached seen AttestationData to improve gossip validation. For Electra, this still take into account attestationIndex + * even through it is moved outside of AttestationData. * As of April 2023, validating gossip attestation takes ~12% of cpu time for a node subscribing to all subnets on mainnet. * Having this cache help saves a lot of cpu time since most of the gossip attestations are on the same slot. */ export class SeenAttestationDatas { - private cacheEntryByAttDataBase64BySlot = new MapDef>( - () => new Map() + private cacheEntryByAttDataBase64BySlot = new MapDef>( + () => new Map() ); private lowestPermissibleSlot = 0; @@ -57,14 +63,14 @@ export class SeenAttestationDatas { } // TODO: Move InsertOutcome type definition to a common place - add(slot: Slot, attDataBase64: AttDataBase64, cacheEntry: AttestationDataCacheEntry): InsertOutcome { + add(slot: Slot, attDataKey: SeenAttDataKey, cacheEntry: AttestationDataCacheEntry): InsertOutcome { if (slot < this.lowestPermissibleSlot) { this.metrics?.seenCache.attestationData.reject.inc({reason: RejectReason.too_old}); return InsertOutcome.Old; } const cacheEntryByAttDataBase64 = this.cacheEntryByAttDataBase64BySlot.getOrDefault(slot); - if (cacheEntryByAttDataBase64.has(attDataBase64)) { + if (cacheEntryByAttDataBase64.has(attDataKey)) { this.metrics?.seenCache.attestationData.reject.inc({reason: RejectReason.already_known}); return InsertOutcome.AlreadyKnown; } @@ -74,11 +80,11 @@ export class SeenAttestationDatas { return InsertOutcome.ReachLimit; } - cacheEntryByAttDataBase64.set(attDataBase64, cacheEntry); + cacheEntryByAttDataBase64.set(attDataKey, cacheEntry); return InsertOutcome.NewData; } - get(slot: Slot, attDataBase64: AttDataBase64): AttestationDataCacheEntry | null { + get(slot: Slot, attDataBase64: SeenAttDataKey): AttestationDataCacheEntry | null { const cacheEntryByAttDataBase64 = this.cacheEntryByAttDataBase64BySlot.get(slot); const cacheEntry = cacheEntryByAttDataBase64?.get(attDataBase64); if (cacheEntry) { diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index c2ecb95907e9..6cb4bb435cf4 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -168,7 +168,7 @@ async function validateAggregateAndProof( // [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 + ? cachedAttData.committeeValidatorIndices : getCommitteeIndices(shuffling, attSlot, attIndex); // [REJECT] The number of aggregation bits matches the committee size diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index 046e1180309c..1876d9a3d883 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -1,4 +1,16 @@ -import {phase0, Epoch, Root, Slot, RootHex, ssz, allForks, electra} from "@lodestar/types"; +import {BitArray} from "@chainsafe/ssz"; +import { + phase0, + Epoch, + Root, + Slot, + RootHex, + ssz, + allForks, + electra, + isElectraAttestation, + CommitteeIndex, +} from "@lodestar/types"; import {ProtoBlock} from "@lodestar/fork-choice"; import {ATTESTATION_SUBNET_COUNT, SLOTS_PER_EPOCH, ForkName, ForkSeq, DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; import { @@ -17,10 +29,9 @@ import {AttestationError, AttestationErrorCode, GossipAction} from "../errors/in import {MAXIMUM_GOSSIP_CLOCK_DISPARITY_SEC} from "../../constants/index.js"; import {RegenCaller} from "../regen/index.js"; import { - AttDataBase64, + SeenAttDataKey, getAggregationBitsFromAttestationSerialized, - getAttDataBase64FromAttestationSerialized, - getCommitteeBitsFromAttestationSerialized, + getSeenAttDataKey, getSignatureFromAttestationSerialized, } from "../../util/sszBytes.js"; import {AttestationDataCacheEntry} from "../seenCache/seenAttestationData.js"; @@ -39,12 +50,13 @@ export type AttestationValidationResult = { indexedAttestation: allForks.IndexedAttestation; subnet: number; attDataRootHex: RootHex; + committeeIndex: CommitteeIndex; }; export type AttestationOrBytes = ApiAttestation | GossipAttestation; /** attestation from api */ -export type ApiAttestation = {attestation: phase0.Attestation; serializedData: null}; +export type ApiAttestation = {attestation: allForks.Attestation; serializedData: null}; /** attestation from gossip */ export type GossipAttestation = { @@ -52,7 +64,9 @@ export type GossipAttestation = { serializedData: Uint8Array; // available in NetworkProcessor since we check for unknown block root attestations attSlot: Slot; - attDataBase64?: string | null; + // for old LIFO linear gossip queue we don't have attDataBase64 + // for indexed gossip queue we have attDataBase64 + seenAttestationKey?: SeenAttDataKey | null; }; export type Step0Result = AttestationValidationResult & { @@ -83,7 +97,7 @@ export async function validateGossipAttestation( export async function validateGossipAttestationsSameAttData( fork: ForkName, chain: IBeaconChain, - attestationOrBytesArr: AttestationOrBytes[], + attestationOrBytesArr: GossipAttestation[], subnet: number, // for unit test, consumers do not need to pass this step0ValidationFn = validateGossipAttestationNoSignatureCheck @@ -251,15 +265,16 @@ async function validateGossipAttestationNoSignatureCheck( let attestationOrCache: | {attestation: allForks.Attestation; cache: null} | {attestation: null; cache: AttestationDataCacheEntry; serializedData: Uint8Array}; - let attDataBase64: AttDataBase64 | null = null; + let attDataKey: SeenAttDataKey | null = null; if (attestationOrBytes.serializedData) { // gossip const attSlot = attestationOrBytes.attSlot; - // for old LIFO linear gossip queue we don't have attDataBase64 - // for indexed gossip queue we have attDataBase64 - attDataBase64 = - attestationOrBytes.attDataBase64 ?? getAttDataBase64FromAttestationSerialized(attestationOrBytes.serializedData); - const cachedAttData = attDataBase64 !== null ? chain.seenAttestationDatas.get(attSlot, attDataBase64) : null; + attDataKey = + // we always have seenAttestationKey from the IndexedGossipQueue, getSeenAttDataKey() just for backward + // compatible in case beaconAttestationBatchValidation is false + // TODO: remove beaconAttestationBatchValidation flag since the batch attestation is stable + attestationOrBytes.seenAttestationKey ?? getSeenAttDataKey(ForkSeq[fork], attestationOrBytes.serializedData); + const cachedAttData = attDataKey !== null ? chain.seenAttestationDatas.get(attSlot, attDataKey) : null; if (cachedAttData === null) { const attestation = sszDeserializeAttestation(fork, attestationOrBytes.serializedData); // only deserialize on the first AttestationData that's not cached @@ -269,7 +284,7 @@ async function validateGossipAttestationNoSignatureCheck( } } else { // api - attDataBase64 = null; + attDataKey = null; attestationOrCache = {attestation: attestationOrBytes.attestation, cache: null}; } @@ -280,29 +295,33 @@ async function validateGossipAttestationNoSignatureCheck( const attEpoch = computeEpochAtSlot(attSlot); const attTarget = attData.target; const targetEpoch = attTarget.epoch; + let committeeIndex; + if (attestationOrCache.attestation) { + if (isElectraAttestation(attestationOrCache.attestation)) { + // api or first time validation of a gossip attestation + const {committeeBits} = attestationOrCache.attestation; + // throw in both in case of undefined and null + if (committeeBits == null) { + throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.INVALID_SERIALIZED_BYTES}); + } - let attIndex; - if (ForkSeq[fork] >= ForkSeq.electra) { - const committeeBits = attestationOrCache.attestation - ? (attestationOrCache.attestation as electra.Attestation).committeeBits - : getCommitteeBitsFromAttestationSerialized(attestationOrCache.serializedData); - - if (committeeBits === null) { - throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.INVALID_SERIALIZED_BYTES}); - } - - attIndex = committeeBits.getSingleTrueBit(); - // [REJECT] len(committee_indices) == 1, where committee_indices = get_committee_indices(aggregate) - if (attIndex === null) { - throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NOT_EXACTLY_ONE_COMMITTEE_BIT_SET}); - } + committeeIndex = committeeBits.getSingleTrueBit(); + // [REJECT] len(committee_indices) == 1, where committee_indices = get_committee_indices(aggregate) + if (committeeIndex === null) { + throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NOT_EXACTLY_ONE_COMMITTEE_BIT_SET}); + } - // [REJECT] aggregate.data.index == 0 - if (attData.index !== 0) { - throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX}); + // [REJECT] aggregate.data.index == 0 + if (attData.index !== 0) { + throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX}); + } + } else { + // phase0 attestation + committeeIndex = attData.index; } } else { - attIndex = attData.index; + // found a seen AttestationData + committeeIndex = attestationOrCache.cache.committeeIndex; } chain.metrics?.gossipAttestation.attestationSlotToClockSlot.observe( @@ -343,11 +362,11 @@ async function validateGossipAttestationNoSignatureCheck( }); } - let committeeIndices: Uint32Array; + let committeeValidatorIndices: Uint32Array; let getSigningRoot: () => Uint8Array; let expectedSubnet: number; if (attestationOrCache.cache) { - committeeIndices = attestationOrCache.cache.committeeIndices; + committeeValidatorIndices = attestationOrCache.cache.committeeValidatorIndices; const signingRoot = attestationOrCache.cache.signingRoot; getSigningRoot = () => signingRoot; expectedSubnet = attestationOrCache.cache.subnet; @@ -389,17 +408,17 @@ async function validateGossipAttestationNoSignatureCheck( // [REJECT] The committee index is within the expected range // -- i.e. data.index < get_committee_count_per_slot(state, data.target.epoch) - committeeIndices = getCommitteeIndices(shuffling, attSlot, attIndex); + committeeValidatorIndices = getCommitteeIndices(shuffling, attSlot, committeeIndex); getSigningRoot = () => getAttestationDataSigningRoot(chain.config, attData); - expectedSubnet = computeSubnetForSlot(shuffling, attSlot, attIndex); + expectedSubnet = computeSubnetForSlot(shuffling, attSlot, committeeIndex); } - const validatorIndex = committeeIndices[bitIndex]; + const validatorIndex = committeeValidatorIndices[bitIndex]; // [REJECT] The number of aggregation bits matches the committee size // -- i.e. len(attestation.aggregation_bits) == len(get_beacon_committee(state, data.slot, data.index)). // > TODO: Is this necessary? Lighthouse does not do this check. - if (aggregationBits.bitLen !== committeeIndices.length) { + if (aggregationBits.bitLen !== committeeValidatorIndices.length) { throw new AttestationError(GossipAction.REJECT, { code: AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS, }); @@ -445,6 +464,7 @@ async function validateGossipAttestationNoSignatureCheck( }); } + let committeeBits: BitArray | undefined = undefined; if (attestationOrCache.cache) { // there could be up to 6% of cpu time to compute signing root if we don't clone the signature set signatureSet = createSingleSignatureSetFromComponents( @@ -453,6 +473,7 @@ async function validateGossipAttestationNoSignatureCheck( signature ); attDataRootHex = attestationOrCache.cache.attDataRootHex; + committeeBits = attestationOrCache.cache.committeeBits; } else { signatureSet = createSingleSignatureSetFromComponents( chain.index2pubkey[validatorIndex], @@ -462,9 +483,15 @@ async function validateGossipAttestationNoSignatureCheck( // add cached attestation data before verifying signature attDataRootHex = toRootHex(ssz.phase0.AttestationData.hashTreeRoot(attData)); - if (attDataBase64) { - chain.seenAttestationDatas.add(attSlot, attDataBase64, { - committeeIndices, + // if attestation is phase0 the committeeBits is undefined anyway + committeeBits = isElectraAttestation(attestationOrCache.attestation) + ? attestationOrCache.attestation.committeeBits.clone() + : undefined; + if (attDataKey) { + chain.seenAttestationDatas.add(attSlot, attDataKey, { + committeeValidatorIndices, + committeeBits, + committeeIndex, signingRoot: signatureSet.signingRoot, subnet: expectedSubnet, // precompute this to be used in forkchoice @@ -486,14 +513,21 @@ async function validateGossipAttestationNoSignatureCheck( ? (indexedAttestationContent as electra.IndexedAttestation) : (indexedAttestationContent as phase0.IndexedAttestation); - const attestation: allForks.Attestation = attestationOrCache.attestation - ? attestationOrCache.attestation - : { - aggregationBits, - data: attData, - signature, - }; - return {attestation, indexedAttestation, subnet: expectedSubnet, attDataRootHex, signatureSet, validatorIndex}; + const attestation: allForks.Attestation = attestationOrCache.attestation ?? { + aggregationBits, + data: attData, + committeeBits, + signature, + }; + return { + attestation, + indexedAttestation, + subnet: expectedSubnet, + attDataRootHex, + signatureSet, + validatorIndex, + committeeIndex, + }; } /** diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index 57697ba2643f..3f2d6368928d 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -37,8 +37,8 @@ import { AggregateAndProofValidationResult, validateGossipAttestationsSameAttData, validateGossipAttestation, - AttestationOrBytes, AttestationValidationResult, + GossipAttestation, } from "../../chain/validation/index.js"; import {NetworkEvent, NetworkEventBus} from "../events.js"; import {PeerAction} from "../peers/index.js"; @@ -487,14 +487,14 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler } // Handler - const {indexedAttestation, attDataRootHex, attestation} = validationResult; + const {indexedAttestation, attDataRootHex, attestation, committeeIndex} = validationResult; metrics?.registerGossipUnaggregatedAttestation(seenTimestampSec, indexedAttestation); try { // Node may be subscribe to extra subnets (long-lived random subnets). For those, validate the messages // but don't add to attestation pool, to save CPU and RAM if (aggregatorTracker.shouldAggregate(subnet, indexedAttestation.data.slot)) { - const insertOutcome = chain.attestationPool.add(attestation, attDataRootHex); + const insertOutcome = chain.attestationPool.add(committeeIndex, attestation, attDataRootHex); metrics?.opPool.attestationPoolInsertOutcome.inc({insertOutcome}); } } catch (e) { @@ -679,7 +679,7 @@ function getBatchHandlers(modules: ValidatorFnsModules, options: GossipHandlerOp serializedData: param.gossipData.serializedData, attSlot: param.gossipData.msgSlot, attDataBase64: param.gossipData.indexed, - })) as AttestationOrBytes[]; + })) as GossipAttestation[]; const {results: validationResults, batchableBls} = await validateGossipAttestationsSameAttData( fork, chain, @@ -695,14 +695,14 @@ function getBatchHandlers(modules: ValidatorFnsModules, options: GossipHandlerOp results.push(null); // Handler - const {indexedAttestation, attDataRootHex, attestation} = validationResult.result; + const {indexedAttestation, attDataRootHex, attestation, committeeIndex} = validationResult.result; metrics?.registerGossipUnaggregatedAttestation(gossipHandlerParams[i].seenTimestampSec, indexedAttestation); try { // Node may be subscribe to extra subnets (long-lived random subnets). For those, validate the messages // but don't add to attestation pool, to save CPU and RAM if (aggregatorTracker.shouldAggregate(subnet, indexedAttestation.data.slot)) { - const insertOutcome = chain.attestationPool.add(attestation, attDataRootHex); + const insertOutcome = chain.attestationPool.add(committeeIndex, attestation, attDataRootHex); metrics?.opPool.attestationPoolInsertOutcome.inc({insertOutcome}); } } catch (e) { diff --git a/packages/beacon-node/src/network/processor/gossipQueues/index.ts b/packages/beacon-node/src/network/processor/gossipQueues/index.ts index 366b23b30679..b38ee74279ca 100644 --- a/packages/beacon-node/src/network/processor/gossipQueues/index.ts +++ b/packages/beacon-node/src/network/processor/gossipQueues/index.ts @@ -1,7 +1,8 @@ import {mapValues} from "@lodestar/utils"; +import {ForkSeq} from "@lodestar/params"; import {GossipType} from "../../gossip/interface.js"; import {PendingGossipsubMessage} from "../types.js"; -import {getAttDataBase64FromAttestationSerialized} from "../../../util/sszBytes.js"; +import {getSeenAttDataKey} from "../../../util/sszBytes.js"; import {LinearGossipQueue} from "./linear.js"; import { DropType, @@ -86,7 +87,10 @@ const indexedGossipQueueOpts: { } = { [GossipType.beacon_attestation]: { maxLength: 24576, - indexFn: (item: PendingGossipsubMessage) => getAttDataBase64FromAttestationSerialized(item.msg.data), + indexFn: (item: PendingGossipsubMessage) => { + const {topic, msg} = item; + return getSeenAttDataKey(ForkSeq[topic.fork], msg.data); + }, minChunkSize: MIN_SIGNATURE_SETS_TO_BATCH_VERIFY, maxChunkSize: MAX_GOSSIP_ATTESTATION_BATCH_SIZE, }, diff --git a/packages/beacon-node/src/network/processor/gossipQueues/indexed.ts b/packages/beacon-node/src/network/processor/gossipQueues/indexed.ts index 4e29a52173f0..8edba7dfaadb 100644 --- a/packages/beacon-node/src/network/processor/gossipQueues/indexed.ts +++ b/packages/beacon-node/src/network/processor/gossipQueues/indexed.ts @@ -84,6 +84,7 @@ export class IndexedGossipQueueMinSize= ForkSeq.electra ? getSeenAttDataKeyElectra(data) : getSeenAttDataKeyPhase0(data); +} + +/** + * Extract attestation data + committeeBits base64 from electra attestation serialized bytes. + * Return null if data is not long enough to extract attestation data. + */ +export function getSeenAttDataKeyElectra(electraAttestationBytes: Uint8Array): AttDataCommitteeBitsBase64 | null { + const startIndex = VARIABLE_FIELD_OFFSET; + const seenKeyLength = ATTESTATION_DATA_SIZE + COMMITTEE_BITS_SIZE; + + if (electraAttestationBytes.length < startIndex + seenKeyLength) { + return null; + } + + return Buffer.from(electraAttestationBytes.subarray(startIndex, startIndex + seenKeyLength)).toString("base64"); +} + +/** + * Extract attestation data base64 from phase0 attestation serialized bytes. * Return null if data is not long enough to extract attestation data. */ -export function getAttDataBase64FromAttestationSerialized(data: Uint8Array): AttDataBase64 | null { +export function getSeenAttDataKeyPhase0(data: Uint8Array): AttDataBase64 | null { if (data.length < VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE) { return null; } diff --git a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts index 5fce9a342509..8f462609c063 100644 --- a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts +++ b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts @@ -5,7 +5,7 @@ import {ssz} from "@lodestar/types"; import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../state-transition/test/perf/util.js"; import {validateAttestation, validateGossipAttestationsSameAttData} from "../../../../src/chain/validation/index.js"; import {getAttestationValidData} from "../../../utils/validationData/attestation.js"; -import {getAttDataBase64FromAttestationSerialized} from "../../../../src/util/sszBytes.js"; +import {getSeenAttDataKeyPhase0} from "../../../../src/util/sszBytes.js"; describe("validate gossip attestation", () => { setBenchOpts({ @@ -42,7 +42,7 @@ describe("validate gossip attestation", () => { attestation: null, serializedData, attSlot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, subnet0 ); @@ -67,7 +67,7 @@ describe("validate gossip attestation", () => { attestation: null, serializedData, attSlot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + attDataBase64: getSeenAttDataKeyPhase0(serializedData), }; }); diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts index 56aab699f4f7..c7d9dc775c85 100644 --- a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts @@ -12,7 +12,7 @@ import { validateApiAttestation, validateAttestation, } from "../../../../../src/chain/validation/index.js"; -import {getAttDataBase64FromAttestationSerialized} from "../../../../../src/util/sszBytes.js"; +import {getSeenAttDataKeyPhase0} from "../../../../../src/util/sszBytes.js"; import {memoOnce} from "../../../../utils/cache.js"; import {expectRejectedWithLodestarError} from "../../../../utils/errors.js"; import {AttestationValidDataOpts, getAttestationValidData} from "../../../../utils/validationData/attestation.js"; @@ -52,7 +52,7 @@ describe("validateAttestation", () => { const {chain, subnet} = getValidData(); await expectGossipError( chain, - {attestation: null, serializedData: Buffer.alloc(0), attSlot: 0, attDataBase64: "invalid"}, + {attestation: null, serializedData: Buffer.alloc(0), attSlot: 0, seenAttestationDataKey: "invalid"}, subnet, GossipErrorCode.INVALID_SERIALIZED_BYTES_ERROR_CODE ); @@ -72,7 +72,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.BAD_TARGET_EPOCH @@ -91,7 +91,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.PAST_SLOT @@ -110,7 +110,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.FUTURE_SLOT @@ -135,7 +135,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET @@ -155,7 +155,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET @@ -179,7 +179,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT @@ -199,7 +199,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.INVALID_TARGET_ROOT @@ -226,7 +226,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS @@ -245,7 +245,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, invalidSubnet, AttestationErrorCode.INVALID_SUBNET_ID @@ -265,7 +265,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.ATTESTATION_ALREADY_KNOWN @@ -287,7 +287,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.INVALID_SIGNATURE diff --git a/packages/beacon-node/test/unit/util/sszBytes.test.ts b/packages/beacon-node/test/unit/util/sszBytes.test.ts index dd1b5aa747bf..0c768bb3fbb3 100644 --- a/packages/beacon-node/test/unit/util/sszBytes.test.ts +++ b/packages/beacon-node/test/unit/util/sszBytes.test.ts @@ -4,7 +4,7 @@ import {allForks, deneb, Epoch, isElectraAttestation, phase0, RootHex, Slot, ssz import {fromHex, toHex} from "@lodestar/utils"; import {ForkName, MAX_COMMITTEES_PER_SLOT} from "@lodestar/params"; import { - getAttDataBase64FromAttestationSerialized, + getSeenAttDataKeyPhase0, getAttDataBase64FromSignedAggregateAndProofSerialized, getAggregationBitsFromAttestationSerialized, getBlockRootFromAttestationSerialized, @@ -62,7 +62,7 @@ describe("attestation SSZ serialized picking", () => { } const attDataBase64 = ssz.phase0.AttestationData.serialize(attestation.data); - expect(getAttDataBase64FromAttestationSerialized(bytes)).toBe(Buffer.from(attDataBase64).toString("base64")); + expect(getSeenAttDataKeyPhase0(bytes)).toBe(Buffer.from(attDataBase64).toString("base64")); }); } @@ -83,7 +83,7 @@ describe("attestation SSZ serialized picking", () => { it("getAttDataBase64FromAttestationSerialized - invalid data", () => { const invalidAttDataBase64DataSizes = [0, 4, 100, 128, 131]; for (const size of invalidAttDataBase64DataSizes) { - expect(getAttDataBase64FromAttestationSerialized(Buffer.alloc(size))).toBeNull(); + expect(getSeenAttDataKeyPhase0(Buffer.alloc(size))).toBeNull(); } }); diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index f4aeeab15260..51fff4096282 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -1,5 +1,5 @@ import {toHexString} from "@chainsafe/ssz"; -import {allForks, BLSSignature, phase0, Slot, ssz} from "@lodestar/types"; +import {allForks, BLSSignature, electra, isElectraAttestation, phase0, Slot, ssz} from "@lodestar/types"; import {computeEpochAtSlot, isAggregatorFromCommitteeLength} from "@lodestar/state-transition"; import {sleep} from "@lodestar/utils"; import {ApiClient, routes} from "@lodestar/api"; @@ -193,7 +193,7 @@ export class AttestationService { attestationNoCommittee: phase0.AttestationData, duties: AttDutyAndProof[] ): Promise { - const signedAttestations: phase0.Attestation[] = []; + const signedAttestations: allForks.Attestation[] = []; const headRootHex = toHexString(attestationNoCommittee.beaconBlockRoot); const currentEpoch = computeEpochAtSlot(slot); const isAfterElectra = currentEpoch >= this.config.ELECTRA_FORK_EPOCH; diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index 62ebe339bff9..ee40e80d811a 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -534,7 +534,7 @@ export class ValidatorStore { data: attestationData, committeeBits: BitArray.fromSingleBit(MAX_COMMITTEES_PER_SLOT, duty.committeeIndex), signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage), - } as electra.Attestation; + }; } else { return { aggregationBits: BitArray.fromSingleBit(duty.committeeLength, duty.validatorCommitteeIndex), From 9db912a6e68fe4de596ecba7be22a28f793ba127 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 16 May 2024 21:23:52 +0300 Subject: [PATCH 053/259] fix: update withdrawal request container to match consensus spec (#6797) --- packages/beacon-node/src/execution/engine/types.ts | 4 ++-- .../src/block/processExecutionLayerWithdrawalRequest.ts | 2 +- packages/types/src/electra/sszTypes.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index c7b0aefd07ad..8fcca29a026c 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -437,7 +437,7 @@ export function serializeExecutionLayerWithdrawalRequest( ): ExecutionLayerWithdrawalRequestRpc { return { sourceAddress: bytesToData(withdrawalRequest.sourceAddress), - validatorPublicKey: bytesToData(withdrawalRequest.validatorPublicKey), + validatorPublicKey: bytesToData(withdrawalRequest.validatorPubkey), amount: numToQuantity(withdrawalRequest.amount), }; } @@ -447,7 +447,7 @@ export function deserializeExecutionLayerWithdrawalRequest( ): electra.ExecutionLayerWithdrawalRequest { return { sourceAddress: dataToBytes(withdrawalRequest.sourceAddress, 20), - validatorPublicKey: dataToBytes(withdrawalRequest.validatorPublicKey, 48), + validatorPubkey: dataToBytes(withdrawalRequest.validatorPublicKey, 48), amount: quantityToNum(withdrawalRequest.amount), }; } diff --git a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts index 935acd522da1..e02129a09d05 100644 --- a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts +++ b/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts @@ -32,7 +32,7 @@ export function processExecutionLayerWithdrawalRequest( // bail out if validator is not in beacon state // note that we don't need to check for 6110 unfinalized vals as they won't be eligible for withdraw/exit anyway - const validatorIndex = pubkey2index.get(executionLayerWithdrawalRequest.validatorPublicKey); + const validatorIndex = pubkey2index.get(executionLayerWithdrawalRequest.validatorPubkey); if (validatorIndex === undefined) { return; } diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 0a0c0f6aeefb..a8249156c7b9 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -128,7 +128,7 @@ export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT export const ExecutionLayerWithdrawalRequest = new ContainerType( { sourceAddress: ExecutionAddress, - validatorPublicKey: BLSPubkey, + validatorPubkey: BLSPubkey, amount: UintNum64, }, {typeName: "ExecutionLayerWithdrawalRequest", jsonCase: "eth2"} From 23868c66c74d2833698fd4b36f22a6be708a0190 Mon Sep 17 00:00:00 2001 From: twoeths Date: Fri, 17 May 2024 18:47:58 +0300 Subject: [PATCH 054/259] fix: get seen AttData key from SignedAggregateAndProof electra (#6802) * fix: get seen AttData key from SignedAggregateAndProof electra * chore: revert the naming change to COMMITTEE_BITS_SIZE and add comment * fix: add toBase64() util --- .../src/chain/validation/aggregateAndProof.ts | 10 ++- packages/beacon-node/src/util/sszBytes.ts | 43 ++++++++-- .../test/unit/util/sszBytes.test.ts | 86 +++++++++++++++++-- 3 files changed, 121 insertions(+), 18 deletions(-) diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 6cb4bb435cf4..176c90a665ac 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -9,7 +9,9 @@ import {toRootHex} from "@lodestar/utils"; import {IBeaconChain} from ".."; import {AttestationError, AttestationErrorCode, GossipAction} from "../errors/index.js"; import {RegenCaller} from "../regen/index.js"; -import {getAttDataBase64FromSignedAggregateAndProofSerialized} from "../../util/sszBytes.js"; +import { + getSeenAttDataKeyFromSignedAggregateAndProof, +} from "../../util/sszBytes.js"; import {getSelectionProofSignatureSet, getAggregateAndProofSignatureSet} from "./signatureSets/index.js"; import { getAttestationDataSigningRoot, @@ -71,8 +73,10 @@ async function validateAggregateAndProof( const attData = aggregate.data; const attSlot = attData.slot; - const attDataBase64 = serializedData ? getAttDataBase64FromSignedAggregateAndProofSerialized(serializedData) : null; - const cachedAttData = attDataBase64 ? chain.seenAttestationDatas.get(attSlot, attDataBase64) : null; + const seenAttDataKey = serializedData + ? getSeenAttDataKeyFromSignedAggregateAndProof(ForkSeq[fork], serializedData) + : null; + const cachedAttData = seenAttDataKey ? chain.seenAttestationDatas.get(attSlot, seenAttDataKey) : null; let attIndex; if (ForkSeq[fork] >= ForkSeq.electra) { diff --git a/packages/beacon-node/src/util/sszBytes.ts b/packages/beacon-node/src/util/sszBytes.ts index 13b28212a04d..e82673a3167a 100644 --- a/packages/beacon-node/src/util/sszBytes.ts +++ b/packages/beacon-node/src/util/sszBytes.ts @@ -41,6 +41,7 @@ const ATTESTATION_BEACON_BLOCK_ROOT_OFFSET = VARIABLE_FIELD_OFFSET + 8 + 8; const ROOT_SIZE = 32; const SLOT_SIZE = 8; const ATTESTATION_DATA_SIZE = 128; +// MAX_COMMITTEES_PER_SLOT is in bit, need to convert to byte const COMMITTEE_BITS_SIZE = Math.max(Math.ceil(MAX_COMMITTEES_PER_SLOT / 8), 1); const SIGNATURE_SIZE = 96; @@ -94,7 +95,7 @@ export function getSeenAttDataKeyElectra(electraAttestationBytes: Uint8Array): A return null; } - return Buffer.from(electraAttestationBytes.subarray(startIndex, startIndex + seenKeyLength)).toString("base64"); + return toBase64(electraAttestationBytes.subarray(startIndex, startIndex + seenKeyLength)); } /** @@ -178,8 +179,9 @@ const SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET = AGGREGATE_OFFSET + VARIABLE_FIELD const SIGNED_AGGREGATE_AND_PROOF_BLOCK_ROOT_OFFSET = SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET + 8 + 8; /** - * Extract slot from signed aggregate and proof serialized bytes. - * Return null if data is not long enough to extract slot. + * Extract slot from signed aggregate and proof serialized bytes + * Return null if data is not long enough to extract slot + * This works for both phase + electra */ export function getSlotFromSignedAggregateAndProofSerialized(data: Uint8Array): Slot | null { if (data.length < SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET + SLOT_SIZE) { @@ -190,8 +192,9 @@ export function getSlotFromSignedAggregateAndProofSerialized(data: Uint8Array): } /** - * Extract block root from signed aggregate and proof serialized bytes. - * Return null if data is not long enough to extract block root. + * Extract block root from signed aggregate and proof serialized bytes + * Return null if data is not long enough to extract block root + * This works for both phase + electra */ export function getBlockRootFromSignedAggregateAndProofSerialized(data: Uint8Array): BlockRootHex | null { if (data.length < SIGNED_AGGREGATE_AND_PROOF_BLOCK_ROOT_OFFSET + ROOT_SIZE) { @@ -207,11 +210,39 @@ export function getBlockRootFromSignedAggregateAndProofSerialized(data: Uint8Arr return "0x" + blockRootBuf.toString("hex"); } +/** + * Extract attestation data key from SignedAggregateAndProof Uint8Array to use cached data from SeenAttestationDatas + */ +export function getSeenAttDataKeyFromSignedAggregateAndProof( + forkSeq: ForkSeq, + data: Uint8Array +): SeenAttDataKey | null { + return forkSeq >= ForkSeq.electra + ? getSeenAttDataKeyFromSignedAggregateAndProofElectra(data) + : getSeenAttDataKeyFromSignedAggregateAndProofPhase0(data); +} + +/** + * Extract AttestationData + CommitteeBits from SignedAggregateAndProof for electra + * Return null if data is not long enough + */ +export function getSeenAttDataKeyFromSignedAggregateAndProofElectra(data: Uint8Array): SeenAttDataKey | null { + const startIndex = SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET; + const endIndex = startIndex + ATTESTATION_DATA_SIZE + COMMITTEE_BITS_SIZE; + + if (data.length < endIndex) { + return null; + } + + // base64 is a bit efficient than hex + return toBase64(data.subarray(startIndex, endIndex)); +} + /** * Extract attestation data base64 from signed aggregate and proof serialized bytes. * Return null if data is not long enough to extract attestation data. */ -export function getAttDataBase64FromSignedAggregateAndProofSerialized(data: Uint8Array): AttDataBase64 | null { +export function getSeenAttDataKeyFromSignedAggregateAndProofPhase0(data: Uint8Array): AttDataBase64 | null { if (data.length < SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET + ATTESTATION_DATA_SIZE) { return null; } diff --git a/packages/beacon-node/test/unit/util/sszBytes.test.ts b/packages/beacon-node/test/unit/util/sszBytes.test.ts index 0c768bb3fbb3..d6ca3ec24621 100644 --- a/packages/beacon-node/test/unit/util/sszBytes.test.ts +++ b/packages/beacon-node/test/unit/util/sszBytes.test.ts @@ -1,12 +1,12 @@ import {describe, it, expect} from "vitest"; import {BitArray} from "@chainsafe/ssz"; -import {allForks, deneb, Epoch, isElectraAttestation, phase0, RootHex, Slot, ssz} from "@lodestar/types"; +import {allForks, deneb, electra, Epoch, isElectraAttestation, phase0, RootHex, Slot, ssz} from "@lodestar/types"; import {fromHex, toHex} from "@lodestar/utils"; import {ForkName, MAX_COMMITTEES_PER_SLOT} from "@lodestar/params"; import { getSeenAttDataKeyPhase0, - getAttDataBase64FromSignedAggregateAndProofSerialized, - getAggregationBitsFromAttestationSerialized, + getSeenAttDataKeyFromSignedAggregateAndProofPhase0, + getAggregationBitsFromAttestationSerialized as getAggregationBitsFromAttestationSerialized, getBlockRootFromAttestationSerialized, getBlockRootFromSignedAggregateAndProofSerialized, getSlotFromAttestationSerialized, @@ -15,6 +15,7 @@ import { getSlotFromSignedBeaconBlockSerialized, getSlotFromBlobSidecarSerialized, getCommitteeBitsFromAttestationSerialized, + getSeenAttDataKeyFromSignedAggregateAndProofElectra, } from "../../../src/util/sszBytes.js"; describe("attestation SSZ serialized picking", () => { @@ -104,16 +105,15 @@ describe("attestation SSZ serialized picking", () => { }); }); -describe("aggregateAndProof SSZ serialized picking", () => { +describe("phase0 SignedAggregateAndProof SSZ serialized picking", () => { const testCases: phase0.SignedAggregateAndProof[] = [ ssz.phase0.SignedAggregateAndProof.defaultValue(), - signedAggregateAndProofFromValues( + phase0SignedAggregateAndProofFromValues( 4_000_000, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 200_00, "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffffffffff" ), - ssz.electra.SignedAggregateAndProof.defaultValue(), ]; for (const [i, signedAggregateAndProof] of testCases.entries()) { @@ -128,7 +128,7 @@ describe("aggregateAndProof SSZ serialized picking", () => { ); const attDataBase64 = ssz.phase0.AttestationData.serialize(signedAggregateAndProof.message.aggregate.data); - expect(getAttDataBase64FromSignedAggregateAndProofSerialized(bytes)).toBe( + expect(getSeenAttDataKeyFromSignedAggregateAndProofPhase0(bytes)).toBe( Buffer.from(attDataBase64).toString("base64") ); }); @@ -151,7 +151,60 @@ describe("aggregateAndProof SSZ serialized picking", () => { it("getAttDataBase64FromSignedAggregateAndProofSerialized - invalid data", () => { const invalidAttDataBase64DataSizes = [0, 4, 100, 128, 339]; for (const size of invalidAttDataBase64DataSizes) { - expect(getAttDataBase64FromSignedAggregateAndProofSerialized(Buffer.alloc(size))).toBeNull(); + expect(getSeenAttDataKeyFromSignedAggregateAndProofPhase0(Buffer.alloc(size))).toBeNull(); + } + }); +}); + +describe("electra SignedAggregateAndProof SSZ serialized picking", () => { + const testCases: electra.SignedAggregateAndProof[] = [ + ssz.electra.SignedAggregateAndProof.defaultValue(), + electraSignedAggregateAndProofFromValues( + 4_000_000, + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + 200_00, + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffffffffff" + ), + ]; + + for (const [i, signedAggregateAndProof] of testCases.entries()) { + it(`signedAggregateAndProof ${i}`, () => { + const bytes = ssz.electra.SignedAggregateAndProof.serialize(signedAggregateAndProof); + + expect(getSlotFromSignedAggregateAndProofSerialized(bytes)).toBe( + signedAggregateAndProof.message.aggregate.data.slot + ); + expect(getBlockRootFromSignedAggregateAndProofSerialized(bytes)).toBe( + toHex(signedAggregateAndProof.message.aggregate.data.beaconBlockRoot) + ); + + const attDataBase64 = ssz.phase0.AttestationData.serialize(signedAggregateAndProof.message.aggregate.data); + const committeeBits = ssz.electra.CommitteeBits.serialize( + signedAggregateAndProof.message.aggregate.committeeBits + ); + const seenKey = Buffer.concat([attDataBase64, committeeBits]).toString("base64"); + expect(getSeenAttDataKeyFromSignedAggregateAndProofElectra(bytes)).toBe(seenKey); + }); + } + + it("getSlotFromSignedAggregateAndProofSerialized - invalid data", () => { + const invalidSlotDataSizes = [0, 4, 11]; + for (const size of invalidSlotDataSizes) { + expect(getSlotFromSignedAggregateAndProofSerialized(Buffer.alloc(size))).toBeNull(); + } + }); + + it("getBlockRootFromSignedAggregateAndProofSerialized - invalid data", () => { + const invalidBlockRootDataSizes = [0, 4, 20, 227]; + for (const size of invalidBlockRootDataSizes) { + expect(getBlockRootFromSignedAggregateAndProofSerialized(Buffer.alloc(size))).toBeNull(); + } + }); + + it("getAttDataBase64FromSignedAggregateAndProofSerialized - invalid data", () => { + const invalidAttDataBase64DataSizes = [0, 4, 100, 128, 339]; + for (const size of invalidAttDataBase64DataSizes) { + expect(getSeenAttDataKeyFromSignedAggregateAndProofPhase0(Buffer.alloc(size))).toBeNull(); } }); it("getSlotFromSignedAggregateAndProofSerialized - invalid data - large slots", () => { @@ -215,7 +268,7 @@ function attestationFromValues( return attestation; } -function signedAggregateAndProofFromValues( +function phase0SignedAggregateAndProofFromValues( slot: Slot, blockRoot: RootHex, targetEpoch: Epoch, @@ -229,6 +282,21 @@ function signedAggregateAndProofFromValues( return signedAggregateAndProof; } +function electraSignedAggregateAndProofFromValues( + slot: Slot, + blockRoot: RootHex, + targetEpoch: Epoch, + targetRoot: RootHex +): electra.SignedAggregateAndProof { + const signedAggregateAndProof = ssz.electra.SignedAggregateAndProof.defaultValue(); + signedAggregateAndProof.message.aggregate.data.slot = slot; + signedAggregateAndProof.message.aggregate.data.beaconBlockRoot = fromHex(blockRoot); + signedAggregateAndProof.message.aggregate.data.target.epoch = targetEpoch; + signedAggregateAndProof.message.aggregate.data.target.root = fromHex(targetRoot); + signedAggregateAndProof.message.aggregate.committeeBits = BitArray.fromSingleBit(MAX_COMMITTEES_PER_SLOT, 1); + return signedAggregateAndProof; +} + function signedBeaconBlockFromValues(slot: Slot): phase0.SignedBeaconBlock { const signedBeaconBlock = ssz.phase0.SignedBeaconBlock.defaultValue(); signedBeaconBlock.message.slot = slot; From bd5c8b7bf654e986c7ba3fdff2e54e96604b2fc2 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 23 May 2024 21:56:47 +0200 Subject: [PATCH 055/259] test: only skip ssz_static tests associated to missing type (#6798) * test: only skip ssz_static tests associated to missing type * More detailed error message if type is not defined --- .../test/spec/presets/ssz_static.test.ts | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index e4c5a1914827..bf7a3b5aad06 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -57,25 +57,28 @@ const sszStatic = (ssz.altair as Types)[typeName] || (ssz.phase0 as Types)[typeName]; + it(`${fork} - ${typeName} type exists`, function () { + expect(sszType).toEqualWithMessage(expect.any(Type), `SSZ type ${typeName} for fork ${fork} is not defined`); + }); + if (!sszType) { - expect.fail( - `Missing SSZ type definition for ${typeName}; this will prevent associated ssz_static tests to be executed` - ); - } else { - const sszTypeNoUint = replaceUintTypeWithUintBigintType(sszType); + // Return instead of throwing an error to only skip ssz_static tests associated to missing type + return; + } + + const sszTypeNoUint = replaceUintTypeWithUintBigintType(sszType); - for (const testCase of fs.readdirSync(testSuiteDirpath)) { - // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts - it(testCase, function () { - // Mainnet must deal with big full states and hash each one multiple times - if (ACTIVE_PRESET === "mainnet") { - vi.setConfig({testTimeout: 30 * 1000}); - } + for (const testCase of fs.readdirSync(testSuiteDirpath)) { + // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts + it(testCase, function () { + // Mainnet must deal with big full states and hash each one multiple times + if (ACTIVE_PRESET === "mainnet") { + vi.setConfig({testTimeout: 30 * 1000}); + } - const testData = parseSszStaticTestcase(path.join(testSuiteDirpath, testCase)); - runValidSszTest(sszTypeNoUint, testData); - }); - } + const testData = parseSszStaticTestcase(path.join(testSuiteDirpath, testCase)); + runValidSszTest(sszTypeNoUint, testData); + }); } }; From 3d19cb487717047caeaf3064790f45698eb4ca65 Mon Sep 17 00:00:00 2001 From: g11tech Date: Sat, 25 May 2024 13:45:36 +0530 Subject: [PATCH 056/259] chore: types and lint fixes (#6819) --- .../src/chain/validation/aggregateAndProof.ts | 4 +--- .../perf/chain/validation/attestation.test.ts | 2 +- .../attestation/validateAttestation.test.ts | 24 +++++++++---------- .../validator/src/services/attestation.ts | 2 +- .../validator/src/services/validatorStore.ts | 5 +--- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 176c90a665ac..3c8b102eb5ac 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -9,9 +9,7 @@ import {toRootHex} from "@lodestar/utils"; import {IBeaconChain} from ".."; import {AttestationError, AttestationErrorCode, GossipAction} from "../errors/index.js"; import {RegenCaller} from "../regen/index.js"; -import { - getSeenAttDataKeyFromSignedAggregateAndProof, -} from "../../util/sszBytes.js"; +import {getSeenAttDataKeyFromSignedAggregateAndProof} from "../../util/sszBytes.js"; import {getSelectionProofSignatureSet, getAggregateAndProofSignatureSet} from "./signatureSets/index.js"; import { getAttestationDataSigningRoot, diff --git a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts index 8f462609c063..e0e0a1e51169 100644 --- a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts +++ b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts @@ -42,7 +42,7 @@ describe("validate gossip attestation", () => { attestation: null, serializedData, attSlot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, subnet0 ); diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts index c7d9dc775c85..4a1c3badae50 100644 --- a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts @@ -52,7 +52,7 @@ describe("validateAttestation", () => { const {chain, subnet} = getValidData(); await expectGossipError( chain, - {attestation: null, serializedData: Buffer.alloc(0), attSlot: 0, seenAttestationDataKey: "invalid"}, + {attestation: null, serializedData: Buffer.alloc(0), attSlot: 0, seenAttestationKey: "invalid"}, subnet, GossipErrorCode.INVALID_SERIALIZED_BYTES_ERROR_CODE ); @@ -72,7 +72,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.BAD_TARGET_EPOCH @@ -91,7 +91,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.PAST_SLOT @@ -110,7 +110,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.FUTURE_SLOT @@ -135,7 +135,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET @@ -155,7 +155,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET @@ -179,7 +179,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT @@ -199,7 +199,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.INVALID_TARGET_ROOT @@ -226,7 +226,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS @@ -245,7 +245,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, invalidSubnet, AttestationErrorCode.INVALID_SUBNET_ID @@ -265,7 +265,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.ATTESTATION_ALREADY_KNOWN @@ -287,7 +287,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationDataKey: getSeenAttDataKeyPhase0(serializedData), + seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), }, subnet, AttestationErrorCode.INVALID_SIGNATURE diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index 51fff4096282..61bd169afeda 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -1,5 +1,5 @@ import {toHexString} from "@chainsafe/ssz"; -import {allForks, BLSSignature, electra, isElectraAttestation, phase0, Slot, ssz} from "@lodestar/types"; +import {allForks, BLSSignature, phase0, Slot, ssz} from "@lodestar/types"; import {computeEpochAtSlot, isAggregatorFromCommitteeLength} from "@lodestar/state-transition"; import {sleep} from "@lodestar/utils"; import {ApiClient, routes} from "@lodestar/api"; diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index ee40e80d811a..a85dd52a7c0d 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -29,7 +29,6 @@ import { BlindedBeaconBlock, BLSPubkey, BLSSignature, - electra, Epoch, phase0, Root, @@ -806,9 +805,7 @@ export class ValidatorStore { ); } if (isAfterElectra && data.index !== 0) { - throw Error( - `Non-zero committee index post-electra during signing: att.committeeIndex ${data.index}` - ); + throw Error(`Non-zero committee index post-electra during signing: att.committeeIndex ${data.index}`); } if (this.config.getForkSeq(duty.slot) >= ForkSeq.electra && data.index !== 0) { throw Error(`Attestataion data index must be 0 post electra: index ${data.index}`); From e75d90631fb3d33f3a65ddd8881de1757120d339 Mon Sep 17 00:00:00 2001 From: NC Date: Sat, 8 Jun 2024 12:46:01 +0300 Subject: [PATCH 057/259] feat: add engine_getPayloadBodiesByHash and ByRange V2 (#6852) * Add ByHash and ByRange V2 * Fix build issue * Fix CI error --- packages/beacon-node/src/chain/chain.ts | 2 +- .../beacon-node/src/eth1/eth1DepositDataTracker.ts | 4 ++-- packages/beacon-node/src/execution/engine/http.ts | 9 ++++++--- .../beacon-node/src/execution/engine/interface.ts | 6 ++++-- packages/beacon-node/src/execution/engine/mock.ts | 2 ++ packages/beacon-node/src/execution/engine/types.ts | 10 +++++++--- .../beacon-node/test/sim/electra-interop.test.ts | 10 +++++----- .../test/spec/presets/operations.test.ts | 2 +- .../test/unit/executionEngine/http.test.ts | 4 ++-- packages/beacon-node/test/utils/state.ts | 2 +- packages/light-client/src/spec/utils.ts | 6 +++--- .../src/block/processDepositRequest.ts | 4 ++-- .../src/block/processOperations.ts | 2 +- .../src/slot/upgradeStateToElectra.ts | 14 +++++++------- packages/state-transition/src/util/deposit.ts | 4 ++-- packages/state-transition/src/util/execution.ts | 4 ++-- packages/state-transition/src/util/genesis.ts | 2 +- .../test/unit/util/deposit.test.ts | 4 ++-- packages/types/src/electra/sszTypes.ts | 12 ++++++------ packages/types/src/electra/types.ts | 4 ++-- 20 files changed, 59 insertions(+), 48 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 9f67857fe530..9f30936305f0 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -1147,7 +1147,7 @@ export class BeaconChain implements IBeaconChain { // Will resolve this later // if (cpEpoch >= (this.config.ELECTRA_FORK_EPOCH ?? Infinity)) { // // finalizedState can be safely casted to Electra state since cp is already post-Electra - // if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateElectra).depositReceiptsStartIndex) { + // if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateElectra).depositRequestsStartIndex) { // // Signal eth1 to stop polling eth1Data // this.eth1.stopPollingEth1Data(); // } diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index c0b3ab35a73a..d0578718f29f 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -129,9 +129,9 @@ export class Eth1DepositDataTracker { async getEth1DataAndDeposits(state: CachedBeaconStateAllForks): Promise { if ( state.epochCtx.isAfterElectra() && - state.eth1DepositIndex >= (state as CachedBeaconStateElectra).depositReceiptsStartIndex + state.eth1DepositIndex >= (state as CachedBeaconStateElectra).depositRequestsStartIndex ) { - // No need to poll eth1Data since Electra deprecates the mechanism after depositReceiptsStartIndex is reached + // No need to poll eth1Data since Electra deprecates the mechanism after depositRequestsStartIndex is reached return {eth1Data: state.eth1Data, deposits: []}; } const eth1Data = this.forcedEth1DataVote ?? (await this.getEth1Data(state)); diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index 10a805e26d66..a69a5b94bd65 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -418,8 +418,9 @@ export class ExecutionEngineHttp implements IExecutionEngine { this.payloadIdCache.prune(); } - async getPayloadBodiesByHash(blockHashes: RootHex[]): Promise<(ExecutionPayloadBody | null)[]> { - const method = "engine_getPayloadBodiesByHashV1"; + async getPayloadBodiesByHash(fork: ForkName, blockHashes: RootHex[]): Promise<(ExecutionPayloadBody | null)[]> { + const method = + ForkSeq[fork] >= ForkSeq.electra ? "engine_getPayloadBodiesByHashV2" : "engine_getPayloadBodiesByHashV1"; assertReqSizeLimit(blockHashes.length, 32); const response = await this.rpc.fetchWithRetries< EngineApiRpcReturnTypes[typeof method], @@ -429,10 +430,12 @@ export class ExecutionEngineHttp implements IExecutionEngine { } async getPayloadBodiesByRange( + fork: ForkName, startBlockNumber: number, blockCount: number ): Promise<(ExecutionPayloadBody | null)[]> { - const method = "engine_getPayloadBodiesByRangeV1"; + const method = + ForkSeq[fork] >= ForkSeq.electra ? "engine_getPayloadBodiesByRangeV2" : "engine_getPayloadBodiesByRangeV1"; assertReqSizeLimit(blockCount, 32); const start = numToQuantity(startBlockNumber); const count = numToQuantity(blockCount); diff --git a/packages/beacon-node/src/execution/engine/interface.ts b/packages/beacon-node/src/execution/engine/interface.ts index c2e44901afbb..a835fa76f509 100644 --- a/packages/beacon-node/src/execution/engine/interface.ts +++ b/packages/beacon-node/src/execution/engine/interface.ts @@ -174,7 +174,9 @@ export interface IExecutionEngine { shouldOverrideBuilder?: boolean; }>; - getPayloadBodiesByHash(blockHash: DATA[]): Promise<(ExecutionPayloadBody | null)[]>; + getPayloadBodiesByHash(fork: ForkName, blockHash: DATA[]): Promise<(ExecutionPayloadBody | null)[]>; - getPayloadBodiesByRange(start: number, count: number): Promise<(ExecutionPayloadBody | null)[]>; + getPayloadBodiesByRange(fork: ForkName, start: number, count: number): Promise<(ExecutionPayloadBody | null)[]>; + + getState(): ExecutionEngineState; } diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index 4cff2a8d00f4..9fed781fa523 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -98,8 +98,10 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { engine_getPayloadV3: this.getPayload.bind(this), engine_getPayloadV4: this.getPayload.bind(this), engine_getPayloadBodiesByHashV1: this.getPayloadBodiesByHash.bind(this), + engine_getPayloadBodiesByHashV2: this.getPayloadBodiesByHash.bind(this), engine_getPayloadBodiesByRangeV1: this.getPayloadBodiesByRange.bind(this), engine_getClientVersionV1: this.getClientVersionV1.bind(this), + engine_getPayloadBodiesByRangeV2: this.getPayloadBodiesByRange.bind(this), }; } diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 8fcca29a026c..7d57b45d134d 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -58,6 +58,7 @@ export type EngineApiRpcParamTypes = { * 1. Array of DATA - Array of block_hash field values of the ExecutionPayload structure * */ engine_getPayloadBodiesByHashV1: DATA[][]; + engine_getPayloadBodiesByHashV2: DATA[][]; /** * 1. start: QUANTITY, 64 bits - Starting block number @@ -69,6 +70,7 @@ export type EngineApiRpcParamTypes = { * Object - Instance of ClientVersion */ engine_getClientVersionV1: [ClientVersionRpc]; + engine_getPayloadBodiesByRangeV2: [start: QUANTITY, count: QUANTITY]; }; export type PayloadStatus = { @@ -107,10 +109,12 @@ export type EngineApiRpcReturnTypes = { engine_getPayloadV4: ExecutionPayloadResponse; engine_getPayloadBodiesByHashV1: (ExecutionPayloadBodyRpc | null)[]; + engine_getPayloadBodiesByHashV2: (ExecutionPayloadBodyRpc | null)[]; engine_getPayloadBodiesByRangeV1: (ExecutionPayloadBodyRpc | null)[]; engine_getClientVersionV1: ClientVersionRpc[]; + engine_getPayloadBodiesByRangeV2: (ExecutionPayloadBodyRpc | null)[]; }; type ExecutionPayloadRpcWithValue = { @@ -235,8 +239,8 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload // ELECTRA adds depositRequests/depositRequests to the ExecutionPayload if (ForkSeq[fork] >= ForkSeq.electra) { - const {depositReceipts, withdrawalRequests} = data as electra.ExecutionPayload; - payload.depositRequests = depositReceipts.map(serializeDepositRequest); + const {depositRequests, withdrawalRequests} = data as electra.ExecutionPayload; + payload.depositRequests = depositRequests.map(serializeDepositRequest); payload.withdrawalRequests = withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest); } @@ -334,7 +338,7 @@ export function parseExecutionPayload( `depositRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` ); } - (executionPayload as electra.ExecutionPayload).depositReceipts = depositRequests.map(deserializeDepositRequest); + (executionPayload as electra.ExecutionPayload).depositRequests = depositRequests.map(deserializeDepositRequest); if (withdrawalRequests == null) { throw Error( diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index 962e0aa5dea9..2dfa5ee0f77c 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -219,11 +219,11 @@ describe("executionEngine / ExecutionEngineHttp", function () { } } - if (payload.depositReceipts.length !== 1) { - throw Error(`Number of depositRequests mismatched. Expected: 1, actual: ${payload.depositReceipts.length}`); + if (payload.depositRequests.length !== 1) { + throw Error(`Number of depositRequests mismatched. Expected: 1, actual: ${payload.depositRequests.length}`); } - const actualDepositRequest = payload.depositReceipts[0]; + const actualDepositRequest = payload.depositRequests[0]; assert.deepStrictEqual( actualDepositRequest, depositRequestB, @@ -431,8 +431,8 @@ describe("executionEngine / ExecutionEngineHttp", function () { throw Error("Historical validator length for epoch 1 or 2 is not dropped properly"); } - if (headState.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { - throw Error("state.depositReceiptsStartIndex is not set upon processing new deposit receipt"); + if (headState.depositRequestsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + throw Error("state.depositRequestsStartIndex is not set upon processing new deposit receipt"); } // wait for 1 slot to print current epoch stats diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index de8a32a6056a..552e0cfa44b6 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -143,7 +143,7 @@ const operations: TestRunnerFn = (fork, block: ssz[fork].BeaconBlock, body: ssz[fork].BeaconBlockBody, deposit: ssz.phase0.Deposit, - deposit_receipt: ssz.electra.DepositReceipt, + deposit_receipt: ssz.electra.DepositRequest, proposer_slashing: ssz.phase0.ProposerSlashing, voluntary_exit: ssz.phase0.SignedVoluntaryExit, // Altair diff --git a/packages/beacon-node/test/unit/executionEngine/http.test.ts b/packages/beacon-node/test/unit/executionEngine/http.test.ts index 2cc08c8c78d2..90ca6595d8a2 100644 --- a/packages/beacon-node/test/unit/executionEngine/http.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/http.test.ts @@ -223,7 +223,7 @@ describe("ExecutionEngine / http", () => { returnValue = response; - const res = await executionEngine.getPayloadBodiesByHash(reqBlockHashes); + const res = await executionEngine.getPayloadBodiesByHash(ForkName.bellatrix, reqBlockHashes); expect(reqJsonRpcPayload).toEqual(request); expect(res.map(serializeExecutionPayloadBody)).toEqual(response.result); @@ -276,7 +276,7 @@ describe("ExecutionEngine / http", () => { returnValue = response; - const res = await executionEngine.getPayloadBodiesByRange(startBlockNumber, blockCount); + const res = await executionEngine.getPayloadBodiesByRange(ForkName.bellatrix, startBlockNumber, blockCount); expect(reqJsonRpcPayload).toEqual(request); expect(res.map(serializeExecutionPayloadBody)).toEqual(response.result); diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index ad4dd4b88dac..bb55adca1eb0 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -97,7 +97,7 @@ export function generateState( if (forkSeq >= ForkSeq.electra) { const stateElectra = state as electra.BeaconState; - stateElectra.depositReceiptsStartIndex = 2023n; + stateElectra.depositRequestsStartIndex = 2023n; stateElectra.latestExecutionPayloadHeader = ssz.electra.ExecutionPayloadHeader.defaultValue(); } diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index b1145860833f..679371a54d6c 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -115,8 +115,8 @@ export function upgradeLightClientHeader( // eslint-disable-next-line no-fallthrough case ForkName.electra: - (upgradedHeader as LightClientHeader).execution.depositReceiptsRoot = - ssz.electra.LightClientHeader.fields.execution.fields.depositReceiptsRoot.defaultValue(); + (upgradedHeader as LightClientHeader).execution.depositRequestsRoot = + ssz.electra.LightClientHeader.fields.execution.fields.depositRequestsRoot.defaultValue(); (upgradedHeader as LightClientHeader).execution.withdrawalRequestsRoot = ssz.electra.LightClientHeader.fields.execution.fields.withdrawalRequestsRoot.defaultValue(); @@ -157,7 +157,7 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: LightC if (epoch < config.ELECTRA_FORK_EPOCH) { if ( - (header as LightClientHeader).execution.depositReceiptsRoot !== undefined || + (header as LightClientHeader).execution.depositRequestsRoot !== undefined || (header as LightClientHeader).execution.withdrawalRequestsRoot !== undefined ) { return false; diff --git a/packages/state-transition/src/block/processDepositRequest.ts b/packages/state-transition/src/block/processDepositRequest.ts index d5525f3cd544..ca6fe4206188 100644 --- a/packages/state-transition/src/block/processDepositRequest.ts +++ b/packages/state-transition/src/block/processDepositRequest.ts @@ -9,8 +9,8 @@ export function processDepositRequest( state: CachedBeaconStateElectra, depositRequest: electra.DepositRequest ): void { - if (state.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { - state.depositReceiptsStartIndex = BigInt(depositRequest.index); + if (state.depositRequestsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + state.depositRequestsStartIndex = BigInt(depositRequest.index); } applyDeposit(fork, state, depositRequest); diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index 86672a6572e9..a2bd691337ad 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -71,7 +71,7 @@ export function processOperations( processExecutionLayerWithdrawalRequest(fork, state as CachedBeaconStateElectra, elWithdrawalRequest); } - for (const depositRequest of bodyElectra.executionPayload.depositReceipts) { + for (const depositRequest of bodyElectra.executionPayload.depositRequests) { processDepositRequest(fork, stateElectra, depositRequest); } diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 72255ccddee3..3d77366cbe57 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -50,16 +50,16 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache stateElectraView.nextSyncCommittee = stateElectraCloned.nextSyncCommittee; stateElectraView.latestExecutionPayloadHeader = ssz.electra.BeaconState.fields.latestExecutionPayloadHeader.toViewDU({ ...stateElectraCloned.latestExecutionPayloadHeader.toValue(), - depositReceiptsRoot: ssz.Root.defaultValue(), + depositRequestsRoot: ssz.Root.defaultValue(), withdrawalRequestsRoot: ssz.Root.defaultValue(), }); stateElectraView.nextWithdrawalIndex = stateDeneb.nextWithdrawalIndex; stateElectraView.nextWithdrawalValidatorIndex = stateDeneb.nextWithdrawalValidatorIndex; stateElectraView.historicalSummaries = stateElectraCloned.historicalSummaries; - // latestExecutionPayloadHeader's depositReceiptsRoot and withdrawalRequestsRoot set to zeros by default - // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX - stateElectraView.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + // latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default + // default value of depositRequestsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX + stateElectraView.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; stateElectraView.depositBalanceToConsume = BigInt(0); stateElectraView.exitBalanceToConsume = BigInt(0); @@ -136,9 +136,9 @@ export function upgradeStateToElectraOriginal(stateDeneb: CachedBeaconStateDeneb epoch: stateDeneb.epochCtx.epoch, }); - // latestExecutionPayloadHeader's depositReceiptsRoot and withdrawalRequestsRoot set to zeros by default - // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX - stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + // latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default + // default value of depositRequestsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX + stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; const validatorsArr = stateElectra.validators.getAllReadonly(); diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index 493099fdd982..e8ef93c515d2 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -9,9 +9,9 @@ export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: // eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64 // since the result lies within upper and lower bound of UintNum64 const eth1DataIndexLimit: UintNum64 = - eth1DataToUse.depositCount < electraState.depositReceiptsStartIndex + eth1DataToUse.depositCount < electraState.depositRequestsStartIndex ? eth1DataToUse.depositCount - : Number(electraState.depositReceiptsStartIndex); + : Number(electraState.depositRequestsStartIndex); if (state.eth1DepositIndex < eth1DataIndexLimit) { return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index c7f0ec2f395c..2c55dc61a502 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -172,8 +172,8 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio } if (fork >= ForkSeq.electra) { - (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositReceiptsRoot = - ssz.electra.DepositReceipts.hashTreeRoot((payload as electra.ExecutionPayload).depositReceipts); + (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositRequestsRoot = + ssz.electra.DepositRequests.hashTreeRoot((payload as electra.ExecutionPayload).depositRequests); (bellatrixPayloadFields as electra.ExecutionPayloadHeader).withdrawalRequestsRoot = ssz.electra.ExecutionLayerWithdrawalRequests.hashTreeRoot( (payload as electra.ExecutionPayload).withdrawalRequests diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index e1003dca1946..ca894fd5b4e5 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -308,7 +308,7 @@ export function initializeBeaconStateFromEth1( stateElectra.latestExecutionPayloadHeader = (executionPayloadHeader as CompositeViewDU) ?? ssz.electra.ExecutionPayloadHeader.defaultViewDU(); - stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; } state.commit(); diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts index e8f7f7a86af8..677a15724ece 100644 --- a/packages/state-transition/test/unit/util/deposit.test.ts +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -43,7 +43,7 @@ describe("getEth1DepositCount", () => { throw Error("Not a post-Electra state"); } - postElectraState.depositReceiptsStartIndex = 1000n; + postElectraState.depositRequestsStartIndex = 1000n; postElectraState.eth1Data.depositCount = 995; // 1. Should get less than MAX_DEPOSIT @@ -77,7 +77,7 @@ describe("getEth1DepositCount", () => { throw Error("Not a post-Electra state"); } - postElectraState.depositReceiptsStartIndex = 1000n; + postElectraState.depositRequestsStartIndex = 1000n; postElectraState.eth1Data.depositCount = 1005; // Before eth1DepositIndex reaching the start index diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index a8249156c7b9..b03be1697fd1 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -112,7 +112,7 @@ export const SignedAggregateAndProof = new ContainerType( {typeName: "SignedAggregateAndProof", jsonCase: "eth2"} ); -export const DepositReceipt = new ContainerType( +export const DepositRequest = new ContainerType( { pubkey: BLSPubkey, withdrawalCredentials: Bytes32, @@ -120,10 +120,10 @@ export const DepositReceipt = new ContainerType( signature: BLSSignature, index: DepositIndex, }, - {typeName: "DepositReceipt", jsonCase: "eth2"} + {typeName: "DepositRequest", jsonCase: "eth2"} ); -export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); +export const DepositRequests = new ListCompositeType(DepositRequest, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); export const ExecutionLayerWithdrawalRequest = new ContainerType( { @@ -141,7 +141,7 @@ export const ExecutionLayerWithdrawalRequests = new ListCompositeType( export const ExecutionPayload = new ContainerType( { ...denebSsz.ExecutionPayload.fields, - depositReceipts: DepositReceipts, // New in ELECTRA + depositRequests: DepositRequests, // New in ELECTRA withdrawalRequests: ExecutionLayerWithdrawalRequests, // New in ELECTRA }, {typeName: "ExecutionPayload", jsonCase: "eth2"} @@ -150,7 +150,7 @@ export const ExecutionPayload = new ContainerType( export const ExecutionPayloadHeader = new ContainerType( { ...denebSsz.ExecutionPayloadHeader.fields, - depositReceiptsRoot: Root, // New in ELECTRA + depositRequestsRoot: Root, // New in ELECTRA withdrawalRequestsRoot: Root, // New in ELECTRA }, {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} @@ -340,7 +340,7 @@ export const BeaconState = new ContainerType( nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex, // Deep history valid from Capella onwards historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, - depositReceiptsStartIndex: UintBn64, // New in ELECTRA:EIP6110 + depositRequestsStartIndex: UintBn64, // New in ELECTRA:EIP6110 depositBalanceToConsume: Gwei, // New in Electra:EIP7251 exitBalanceToConsume: Gwei, // New in Electra:EIP7251 earliestExitEpoch: Epoch, // New in Electra:EIP7251 diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index fc95ecde562d..994e5a732243 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -9,8 +9,8 @@ export type AttesterSlashing = ValueOf; export type AggregateAndProof = ValueOf; export type SignedAggregateAndProof = ValueOf; -export type DepositRequest = ValueOf; -export type DepositRequests = ValueOf; +export type DepositRequest = ValueOf; +export type DepositRequests = ValueOf; export type ExecutionLayerWithdrawalRequest = ValueOf; export type ExecutionLayerWithdrawalRequests = ValueOf; From d87de02064a2d4ed2a10d142a6497f2ca183dc4f Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 12 Jun 2024 09:22:40 +0100 Subject: [PATCH 058/259] fix: align WithdrawalRequestV1 field names with latest spec (#6877) --- packages/beacon-node/src/execution/engine/payloadIdCache.ts | 2 +- packages/beacon-node/src/execution/engine/types.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index 35a50e97cfb3..f79c28582459 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -28,7 +28,7 @@ export type DepositRequestV1 = { export type ExecutionLayerWithdrawalRequestV1 = { sourceAddress: DATA; - validatorPublicKey: DATA; + validatorPubkey: DATA; amount: QUANTITY; }; diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 7d57b45d134d..447d14992526 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -441,7 +441,7 @@ export function serializeExecutionLayerWithdrawalRequest( ): ExecutionLayerWithdrawalRequestRpc { return { sourceAddress: bytesToData(withdrawalRequest.sourceAddress), - validatorPublicKey: bytesToData(withdrawalRequest.validatorPubkey), + validatorPubkey: bytesToData(withdrawalRequest.validatorPubkey), amount: numToQuantity(withdrawalRequest.amount), }; } @@ -451,7 +451,7 @@ export function deserializeExecutionLayerWithdrawalRequest( ): electra.ExecutionLayerWithdrawalRequest { return { sourceAddress: dataToBytes(withdrawalRequest.sourceAddress, 20), - validatorPubkey: dataToBytes(withdrawalRequest.validatorPublicKey, 48), + validatorPubkey: dataToBytes(withdrawalRequest.validatorPubkey, 48), amount: quantityToNum(withdrawalRequest.amount), }; } From 44e004156c9cd62733d2ead8ad8871645afe410d Mon Sep 17 00:00:00 2001 From: NC Date: Fri, 14 Jun 2024 14:11:23 +0300 Subject: [PATCH 059/259] feat: move attestation committee at the end of attestation (#6883) --- .../src/chain/validation/attestation.ts | 2 +- packages/beacon-node/src/util/sszBytes.ts | 26 ++++++++++--------- .../test/unit/util/sszBytes.test.ts | 8 +++--- packages/types/src/electra/sszTypes.ts | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index 1876d9a3d883..1d5568fbc868 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -457,7 +457,7 @@ async function validateGossipAttestationNoSignatureCheck( let attDataRootHex: RootHex; const signature = attestationOrCache.attestation ? attestationOrCache.attestation.signature - : getSignatureFromAttestationSerialized(fork, attestationOrCache.serializedData); + : getSignatureFromAttestationSerialized(attestationOrCache.serializedData); if (signature === null) { throw new AttestationError(GossipAction.REJECT, { code: AttestationErrorCode.INVALID_SERIALIZED_BYTES, diff --git a/packages/beacon-node/src/util/sszBytes.ts b/packages/beacon-node/src/util/sszBytes.ts index e82673a3167a..bac66ddf3a0d 100644 --- a/packages/beacon-node/src/util/sszBytes.ts +++ b/packages/beacon-node/src/util/sszBytes.ts @@ -25,8 +25,8 @@ export type AttDataCommitteeBitsBase64 = string; // class Attestation(Container): // aggregation_bits: BitList[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] - offset 4 // data: AttestationData - target data - 128 -// committee_bits: BitVector[MAX_COMMITTEES_PER_SLOT] // signature: BLSSignature - 96 +// committee_bits: BitVector[MAX_COMMITTEES_PER_SLOT] // // for all forks // class AttestationData(Container): 128 bytes fixed size @@ -88,14 +88,19 @@ export function getSeenAttDataKey(forkSeq: ForkSeq, data: Uint8Array): SeenAttDa * Return null if data is not long enough to extract attestation data. */ export function getSeenAttDataKeyElectra(electraAttestationBytes: Uint8Array): AttDataCommitteeBitsBase64 | null { - const startIndex = VARIABLE_FIELD_OFFSET; - const seenKeyLength = ATTESTATION_DATA_SIZE + COMMITTEE_BITS_SIZE; + const attestationData = getSeenAttDataKeyPhase0(electraAttestationBytes); - if (electraAttestationBytes.length < startIndex + seenKeyLength) { + if (attestationData === null) { return null; } - return toBase64(electraAttestationBytes.subarray(startIndex, startIndex + seenKeyLength)); + const committeeBits = getCommitteeBitsFromAttestationSerialized(electraAttestationBytes); + + if (committeeBits === null) { + return null; + } + + return attestationData + toBase64(committeeBits.uint8Array); } /** @@ -119,7 +124,7 @@ export function getSeenAttDataKeyPhase0(data: Uint8Array): AttDataBase64 | null export function getAggregationBitsFromAttestationSerialized(fork: ForkName, data: Uint8Array): BitArray | null { const aggregationBitsStartIndex = ForkSeq[fork] >= ForkSeq.electra - ? VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + COMMITTEE_BITS_SIZE + SIGNATURE_SIZE + ? VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + SIGNATURE_SIZE + COMMITTEE_BITS_SIZE : VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + SIGNATURE_SIZE; if (data.length < aggregationBitsStartIndex) { @@ -134,11 +139,8 @@ export function getAggregationBitsFromAttestationSerialized(fork: ForkName, data * Extract signature from attestation serialized bytes. * Return null if data is not long enough to extract signature. */ -export function getSignatureFromAttestationSerialized(fork: ForkName, data: Uint8Array): BLSSignature | null { - const signatureStartIndex = - ForkSeq[fork] >= ForkSeq.electra - ? VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + COMMITTEE_BITS_SIZE - : VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE; +export function getSignatureFromAttestationSerialized(data: Uint8Array): BLSSignature | null { + const signatureStartIndex = VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE; if (data.length < signatureStartIndex + SIGNATURE_SIZE) { return null; @@ -152,7 +154,7 @@ export function getSignatureFromAttestationSerialized(fork: ForkName, data: Uint * Return null if data is not long enough to extract committee bits. */ export function getCommitteeBitsFromAttestationSerialized(data: Uint8Array): BitArray | null { - const committeeBitsStartIndex = VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE; + const committeeBitsStartIndex = VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + SIGNATURE_SIZE; if (data.length < committeeBitsStartIndex + COMMITTEE_BITS_SIZE) { return null; diff --git a/packages/beacon-node/test/unit/util/sszBytes.test.ts b/packages/beacon-node/test/unit/util/sszBytes.test.ts index d6ca3ec24621..2d138111a05f 100644 --- a/packages/beacon-node/test/unit/util/sszBytes.test.ts +++ b/packages/beacon-node/test/unit/util/sszBytes.test.ts @@ -54,12 +54,12 @@ describe("attestation SSZ serialized picking", () => { attestation.aggregationBits.toBoolArray() ); expect(getCommitteeBitsFromAttestationSerialized(bytes)).toEqual(attestation.committeeBits); - expect(getSignatureFromAttestationSerialized(ForkName.electra, bytes)).toEqual(attestation.signature); + expect(getSignatureFromAttestationSerialized(bytes)).toEqual(attestation.signature); } else { expect(getAggregationBitsFromAttestationSerialized(ForkName.phase0, bytes)?.toBoolArray()).toEqual( attestation.aggregationBits.toBoolArray() ); - expect(getSignatureFromAttestationSerialized(ForkName.phase0, bytes)).toEqual(attestation.signature); + expect(getSignatureFromAttestationSerialized(bytes)).toEqual(attestation.signature); } const attDataBase64 = ssz.phase0.AttestationData.serialize(attestation.data); @@ -99,8 +99,8 @@ describe("attestation SSZ serialized picking", () => { it("getSignatureFromAttestationSerialized - invalid data", () => { const invalidSignatureDataSizes = [0, 4, 100, 128, 227]; for (const size of invalidSignatureDataSizes) { - expect(getSignatureFromAttestationSerialized(ForkName.phase0, Buffer.alloc(size))).toBeNull(); - expect(getSignatureFromAttestationSerialized(ForkName.electra, Buffer.alloc(size))).toBeNull(); + expect(getSignatureFromAttestationSerialized(Buffer.alloc(size))).toBeNull(); + expect(getSignatureFromAttestationSerialized(Buffer.alloc(size))).toBeNull(); } }); }); diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index b03be1697fd1..ab9cbbaacd80 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -62,8 +62,8 @@ export const Attestation = new ContainerType( { aggregationBits: AggregationBits, // Modified in ELECTRA data: phase0Ssz.AttestationData, - committeeBits: CommitteeBits, // New in ELECTRA signature: BLSSignature, + committeeBits: CommitteeBits, // New in ELECTRA }, {typeName: "Attestation", jsonCase: "eth2"} ); From 43fe8de1871882d671a3bdb8cbd8fe26dbd2aa81 Mon Sep 17 00:00:00 2001 From: harkamal Date: Wed, 19 Jun 2024 19:27:59 +0530 Subject: [PATCH 060/259] rebase fixes chore: fix bls and blst versioning fix: add ForkName.electra to ForkBlobsInfo some api header lookup fixes more api fixes make the api data safe Co-authored-by: matthewkeil --- packages/api/src/beacon/routes/beacon/pool.ts | 11 ++++++++-- packages/api/src/beacon/routes/validator.ts | 21 ++++++++++++++----- .../api/test/unit/beacon/testData/beacon.ts | 2 +- .../test/unit/beacon/testData/validator.ts | 2 +- .../test/unit/webEsmBundle.browser.test.ts | 4 ++-- packages/state-transition/package.json | 1 + .../test/unit/services/attestation.test.ts | 5 ++++- 7 files changed, 34 insertions(+), 12 deletions(-) diff --git a/packages/api/src/beacon/routes/beacon/pool.ts b/packages/api/src/beacon/routes/beacon/pool.ts index 3c390aa41481..499e8af432d7 100644 --- a/packages/api/src/beacon/routes/beacon/pool.ts +++ b/packages/api/src/beacon/routes/beacon/pool.ts @@ -17,6 +17,7 @@ import { } from "../../../utils/codecs.js"; import {MetaHeader, VersionCodec, VersionMeta} from "../../../utils/metadata.js"; import {toForkName} from "../../../utils/fork.js"; +import {fromHeaders} from "../../../utils/headers.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes @@ -247,7 +248,12 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { - const fork = toForkName(headers[MetaHeader.Version]); + const versionHeader = fromHeaders(headers, MetaHeader.Version, false); + const fork = + versionHeader !== undefined + ? toForkName(versionHeader) + : config.getForkName(Number((body as {data: {slot: string}}[])[0]?.data.slot ?? 0)); + return { signedAttestations: ForkSeq[fork] >= ForkSeq.electra @@ -266,7 +272,8 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { - const fork = toForkName(headers[MetaHeader.Version]); + const versionHeader = fromHeaders(headers, MetaHeader.Version, true); + const fork = toForkName(versionHeader); return { signedAttestations: ForkSeq[fork] >= ForkSeq.electra diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index 8c8355f63d07..ac8526947c3f 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -41,6 +41,7 @@ import { VersionMeta, VersionType, } from "../../utils/metadata.js"; +import {fromHeaders} from "../../utils/headers.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes @@ -811,7 +812,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ attestationDataRoot: fromHexString(query.attestation_data_root), slot: query.slot, - committeeIndex: query.slot, + committeeIndex: query.committeeIndex, }), schema: { query: { @@ -833,7 +834,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { - const fork = config.getForkName(signedAggregateAndProofs[0].message.aggregate.data.slot); + const fork = config.getForkName(signedAggregateAndProofs[0]?.message.aggregate.data.slot ?? 0); return { body: ForkSeq[fork] >= ForkSeq.electra @@ -847,7 +848,16 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { - const fork = toForkName(headers[MetaHeader.Version]); + const versionHeader = fromHeaders(headers, MetaHeader.Version, false); + const fork = + versionHeader !== undefined + ? toForkName(versionHeader) + : config.getForkName( + Number( + (body as {message: {aggregate: {data: {slot: string}}}}[])[0]?.message.aggregate.data.slot ?? 0 + ) + ); + return { signedAggregateAndProofs: ForkSeq[fork] >= ForkSeq.electra @@ -856,7 +866,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { - const fork = config.getForkName(signedAggregateAndProofs[0].message.aggregate.data.slot); + const fork = config.getForkName(signedAggregateAndProofs[0]?.message.aggregate.data.slot ?? 0); return { body: ForkSeq[fork] >= ForkSeq.electra @@ -870,7 +880,8 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { - const fork = toForkName(headers[MetaHeader.Version]); + const versionHeader = fromHeaders(headers, MetaHeader.Version, true); + const fork = toForkName(versionHeader); return { signedAggregateAndProofs: ForkSeq[fork] >= ForkSeq.electra diff --git a/packages/api/test/unit/beacon/testData/beacon.ts b/packages/api/test/unit/beacon/testData/beacon.ts index 9a89abd68a14..da13d4c7783c 100644 --- a/packages/api/test/unit/beacon/testData/beacon.ts +++ b/packages/api/test/unit/beacon/testData/beacon.ts @@ -92,7 +92,7 @@ export const testData: GenericServerTestCases = { getPoolAttestations: { args: {slot: 1, committeeIndex: 2}, - res: {data: [ssz.phase0.Attestation.defaultValue()]}, + res: {data: [ssz.phase0.Attestation.defaultValue()], meta: {version: ForkName.deneb}}, }, getPoolAttesterSlashings: { args: undefined, diff --git a/packages/api/test/unit/beacon/testData/validator.ts b/packages/api/test/unit/beacon/testData/validator.ts index 5f82d4a818b0..b27fc9c38733 100644 --- a/packages/api/test/unit/beacon/testData/validator.ts +++ b/packages/api/test/unit/beacon/testData/validator.ts @@ -99,7 +99,7 @@ export const testData: GenericServerTestCases = { res: {data: ssz.altair.SyncCommitteeContribution.defaultValue()}, }, getAggregatedAttestation: { - args: {attestationDataRoot: ZERO_HASH, slot: 32000, index: 2}, + args: {attestationDataRoot: ZERO_HASH, slot: 32000, committeeIndex: 2}, res: {data: ssz.phase0.Attestation.defaultValue(), meta: {version: ForkName.phase0}}, }, publishAggregateAndProofs: { diff --git a/packages/light-client/test/unit/webEsmBundle.browser.test.ts b/packages/light-client/test/unit/webEsmBundle.browser.test.ts index defc421d7071..49b0f877d46c 100644 --- a/packages/light-client/test/unit/webEsmBundle.browser.test.ts +++ b/packages/light-client/test/unit/webEsmBundle.browser.test.ts @@ -1,7 +1,7 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access */ import {expect, describe, it, vi, beforeAll} from "vitest"; import {sleep} from "@lodestar/utils"; -import {Lightclient, LightclientEvent, utils, transport} from "../../dist/lightclient.min.mjs"; +import {Lightclient, LightclientEvent, utils, transport} from "../../src/index.js"; describe("web bundle for lightclient", () => { vi.setConfig({testTimeout: 20_000}); diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 61b73ef7efc1..c9551195e87e 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -59,6 +59,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/as-sha256": "^0.5.0", + "@chainsafe/bls": "7.1.3", "@chainsafe/blst": "^2.0.3", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/persistent-ts": "^0.19.1", diff --git a/packages/validator/test/unit/services/attestation.test.ts b/packages/validator/test/unit/services/attestation.test.ts index f02b15f38853..fdfc34c857b9 100644 --- a/packages/validator/test/unit/services/attestation.test.ts +++ b/packages/validator/test/unit/services/attestation.test.ts @@ -5,6 +5,7 @@ import {ssz} from "@lodestar/types"; import {routes} from "@lodestar/api"; import {createChainForkConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; +import {ForkName} from "@lodestar/params"; import {AttestationService, AttestationServiceOpts} from "../../../src/services/attestation.js"; import {AttDutyAndProof} from "../../../src/services/attestationDuties.js"; import {ValidatorStore} from "../../../src/services/validatorStore.js"; @@ -105,7 +106,9 @@ describe("AttestationService", function () { // Mock beacon's attestation and aggregates endpoints api.validator.produceAttestationData.mockResolvedValue(mockApiResponse({data: attestation.data})); - api.validator.getAggregatedAttestation.mockResolvedValue(mockApiResponse({data: attestation})); + api.validator.getAggregatedAttestation.mockResolvedValue( + mockApiResponse({data: attestation, meta: {version: ForkName.phase0}}) + ); api.beacon.submitPoolAttestations.mockResolvedValue(mockApiResponse({})); api.validator.publishAggregateAndProofs.mockResolvedValue(mockApiResponse({})); From 4dfe326c6ba1807e285ab21f535543b611828b76 Mon Sep 17 00:00:00 2001 From: NC Date: Fri, 21 Jun 2024 19:32:37 +0300 Subject: [PATCH 061/259] feat: handle exited/exiting validators during top up (#6880) * Handle exiting validataor * lint * Add todo --- .../epoch/processPendingBalanceDeposits.ts | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts index 95928d66df2d..112832c920d7 100644 --- a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts @@ -1,6 +1,8 @@ +import {FAR_FUTURE_EPOCH} from "@lodestar/params"; import {CachedBeaconStateElectra} from "../types.js"; import {increaseBalance} from "../util/balance.js"; import {getActivationExitChurnLimit} from "../util/validator.js"; +import {getCurrentEpoch} from "../util/epoch.js"; /** * Starting from Electra: @@ -8,19 +10,40 @@ import {getActivationExitChurnLimit} from "../util/validator.js"; * For each eligible `deposit`, call `increaseBalance()`. * Remove the processed deposits from `state.pendingBalanceDeposits`. * Update `state.depositBalanceToConsume` for the next epoch + * + * TODO Electra: Update ssz library to support batch push to `pendingBalanceDeposits` */ export function processPendingBalanceDeposits(state: CachedBeaconStateElectra): void { const availableForProcessing = state.depositBalanceToConsume + BigInt(getActivationExitChurnLimit(state)); + const currentEpoch = getCurrentEpoch(state); let processedAmount = 0n; let nextDepositIndex = 0; + const depositsToPostpone = []; for (const deposit of state.pendingBalanceDeposits.getAllReadonly()) { - const {amount} = deposit; - if (processedAmount + amount > availableForProcessing) { - break; + const {amount, index: depositIndex} = deposit; + const validator = state.validators.get(depositIndex); + + // Validator is exiting, postpone the deposit until after withdrawable epoch + if (validator.exitEpoch < FAR_FUTURE_EPOCH) { + if (currentEpoch <= validator.withdrawableEpoch) { + depositsToPostpone.push(deposit); + } else { + // Deposited balance will never become active. Increase balance but do not consume churn + increaseBalance(state, deposit.index, Number(amount)); + } + } else { + // Validator is not exiting, attempt to process deposit + if (processedAmount + amount > availableForProcessing) { + // Deposit does not fit in the churn, no more deposit processing in this epoch. + break; + } else { + // Deposit fits in the churn, process it. Increase balance and consume churn. + increaseBalance(state, deposit.index, Number(amount)); + processedAmount = processedAmount + amount; + } } - increaseBalance(state, deposit.index, Number(amount)); - processedAmount = processedAmount + amount; + // Regardless of how the deposit was handled, we move on in the queue. nextDepositIndex++; } @@ -32,4 +55,9 @@ export function processPendingBalanceDeposits(state: CachedBeaconStateElectra): } else { state.depositBalanceToConsume = availableForProcessing - processedAmount; } + + // TODO Electra: add a function in ListCompositeTreeView to support batch push operation + for (const deposit of depositsToPostpone) { + state.pendingBalanceDeposits.push(deposit); + } } From 39edbfdfcd6170dc5ebfa1194b5973b8ce55102f Mon Sep 17 00:00:00 2001 From: NC Date: Fri, 21 Jun 2024 19:33:42 +0300 Subject: [PATCH 062/259] feat: add EL triggered consolidation and remove `ExecutionLayer` prefix (#6865) * init commit * Add consolidation request * fix lint * Remove ExecutionLayer prefix * Address comment * Fix verification logic * lint * Add todo --- .../chain/produceBlock/produceBlockBody.ts | 4 - .../src/execution/engine/payloadIdCache.ts | 2 +- .../beacon-node/src/execution/engine/types.ts | 33 ++---- .../test/spec/presets/operations.test.ts | 20 ++-- packages/params/src/index.ts | 2 +- packages/params/src/presets/mainnet.ts | 2 +- packages/params/src/presets/minimal.ts | 2 +- packages/params/src/types.ts | 4 +- .../src/block/processConsolidation.ts | 111 ------------------ .../src/block/processConsolidationRequest.ts | 74 ++++++++++++ .../src/block/processOperations.ts | 20 ++-- ...Request.ts => processWithdrawalRequest.ts} | 10 +- .../src/signatureSets/consolidation.ts | 51 -------- .../src/signatureSets/index.ts | 12 -- .../src/slot/upgradeStateToElectra.ts | 1 + .../state-transition/src/util/execution.ts | 4 +- packages/types/src/electra/sszTypes.ts | 44 +++---- packages/types/src/electra/types.ts | 10 +- packages/validator/src/util/params.ts | 2 +- .../test/unit/utils/interopConfigs.ts | 8 +- 20 files changed, 144 insertions(+), 272 deletions(-) delete mode 100644 packages/state-transition/src/block/processConsolidation.ts create mode 100644 packages/state-transition/src/block/processConsolidationRequest.ts rename packages/state-transition/src/block/{processExecutionLayerWithdrawalRequest.ts => processWithdrawalRequest.ts} (89%) delete mode 100644 packages/state-transition/src/signatureSets/consolidation.ts diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index 53f59850b647..638df42cba1b 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -343,10 +343,6 @@ export async function produceBlockBody( } } - if (ForkSeq[fork] >= ForkSeq.electra) { - (blockBody as electra.BeaconBlockBody).consolidations = []; - } - Object.assign(logMeta, {executionPayloadValue}); this.logger.verbose("Produced beacon block body", logMeta); diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index f79c28582459..8cb5b4e4f8e9 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -26,7 +26,7 @@ export type DepositRequestV1 = { index: QUANTITY; }; -export type ExecutionLayerWithdrawalRequestV1 = { +export type WithdrawalRequestV1 = { sourceAddress: DATA; validatorPubkey: DATA; amount: QUANTITY; diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 447d14992526..6b37f3854b8f 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -17,7 +17,7 @@ import { quantityToBigint, } from "../../eth1/provider/utils.js"; import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js"; -import {WithdrawalV1, DepositRequestV1, ExecutionLayerWithdrawalRequestV1} from "./payloadIdCache.js"; +import {WithdrawalV1, DepositRequestV1, WithdrawalRequestV1} from "./payloadIdCache.js"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -132,14 +132,14 @@ export type ExecutionPayloadBodyRpc = { // currently there is a discepancy between EL and CL field name references for deposit requests // its likely CL receipt will be renamed to requests depositRequests: DepositRequestV1[] | null | undefined; - withdrawalRequests: ExecutionLayerWithdrawalRequestV1[] | null | undefined; + withdrawalRequests: WithdrawalRequestV1[] | null | undefined; }; export type ExecutionPayloadBody = { transactions: bellatrix.Transaction[]; withdrawals: capella.Withdrawals | null; depositRequests: electra.DepositRequests | null; - withdrawalRequests: electra.ExecutionLayerWithdrawalRequests | null; + withdrawalRequests: electra.WithdrawalRequests | null; }; export type ExecutionPayloadRpc = { @@ -162,7 +162,7 @@ export type ExecutionPayloadRpc = { excessBlobGas?: QUANTITY; // DENEB parentBeaconBlockRoot?: QUANTITY; // DENEB depositRequests?: DepositRequestRpc[]; // ELECTRA - withdrawalRequests?: ExecutionLayerWithdrawalRequestRpc[]; // ELECTRA + withdrawalRequests?: WithdrawalRequestRpc[]; // ELECTRA }; export type WithdrawalRpc = { @@ -173,7 +173,7 @@ export type WithdrawalRpc = { }; export type DepositRequestRpc = DepositRequestV1; -export type ExecutionLayerWithdrawalRequestRpc = ExecutionLayerWithdrawalRequestV1; +export type WithdrawalRequestRpc = WithdrawalRequestV1; export type VersionedHashesRpc = DATA[]; @@ -241,7 +241,7 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload if (ForkSeq[fork] >= ForkSeq.electra) { const {depositRequests, withdrawalRequests} = data as electra.ExecutionPayload; payload.depositRequests = depositRequests.map(serializeDepositRequest); - payload.withdrawalRequests = withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest); + payload.withdrawalRequests = withdrawalRequests.map(serializeWithdrawalRequest); } return payload; @@ -345,9 +345,8 @@ export function parseExecutionPayload( `withdrawalRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` ); } - (executionPayload as electra.ExecutionPayload).withdrawalRequests = withdrawalRequests.map( - deserializeExecutionLayerWithdrawalRequest - ); + (executionPayload as electra.ExecutionPayload).withdrawalRequests = + withdrawalRequests.map(deserializeWithdrawalRequest); } return {executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder}; @@ -436,9 +435,7 @@ export function deserializeDepositRequest(serialized: DepositRequestRpc): electr } as electra.DepositRequest; } -export function serializeExecutionLayerWithdrawalRequest( - withdrawalRequest: electra.ExecutionLayerWithdrawalRequest -): ExecutionLayerWithdrawalRequestRpc { +export function serializeWithdrawalRequest(withdrawalRequest: electra.WithdrawalRequest): WithdrawalRequestRpc { return { sourceAddress: bytesToData(withdrawalRequest.sourceAddress), validatorPubkey: bytesToData(withdrawalRequest.validatorPubkey), @@ -446,9 +443,7 @@ export function serializeExecutionLayerWithdrawalRequest( }; } -export function deserializeExecutionLayerWithdrawalRequest( - withdrawalRequest: ExecutionLayerWithdrawalRequestRpc -): electra.ExecutionLayerWithdrawalRequest { +export function deserializeWithdrawalRequest(withdrawalRequest: WithdrawalRequestRpc): electra.WithdrawalRequest { return { sourceAddress: dataToBytes(withdrawalRequest.sourceAddress, 20), validatorPubkey: dataToBytes(withdrawalRequest.validatorPubkey, 48), @@ -462,9 +457,7 @@ export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | transactions: data.transactions.map((tran) => dataToBytes(tran, null)), withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null, depositRequests: data.depositRequests ? data.depositRequests.map(deserializeDepositRequest) : null, - withdrawalRequests: data.withdrawalRequests - ? data.withdrawalRequests.map(deserializeExecutionLayerWithdrawalRequest) - : null, + withdrawalRequests: data.withdrawalRequests ? data.withdrawalRequests.map(deserializeWithdrawalRequest) : null, } : null; } @@ -475,9 +468,7 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null) transactions: data.transactions.map((tran) => bytesToData(tran)), withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null, depositRequests: data.depositRequests ? data.depositRequests.map(serializeDepositRequest) : null, - withdrawalRequests: data.withdrawalRequests - ? data.withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest) - : null, + withdrawalRequests: data.withdrawalRequests ? data.withdrawalRequests.map(serializeWithdrawalRequest) : null, } : null; } diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index 552e0cfa44b6..47895540ac1a 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -92,20 +92,14 @@ const operationFns: Record> = blockFns.processWithdrawals(ForkSeq.capella, state as CachedBeaconStateCapella, testCase.execution_payload); }, - consolidation: (state, testCase: {consolidation: electra.SignedConsolidation}) => { - blockFns.processConsolidation(state as CachedBeaconStateElectra, testCase.consolidation); + withdrawal_request: (state, testCase: {withdrawal_request: electra.WithdrawalRequest}) => { + blockFns.processWithdrawalRequest(ForkSeq.electra, state as CachedBeaconStateElectra, testCase.withdrawal_request); }, - execution_layer_withdrawal_request: ( - state, - testCase: {execution_layer_withdrawal_request: electra.ExecutionLayerWithdrawalRequest} - ) => { - blockFns.processExecutionLayerWithdrawalRequest( - ForkSeq.electra, - state as CachedBeaconStateElectra, - testCase.execution_layer_withdrawal_request - ); + consolidation_request: (state, testCase: {consolidation_request: electra.ConsolidationRequest}) => { + blockFns.processConsolidationRequest(state as CachedBeaconStateElectra, testCase.consolidation_request); }, + }; export type BlockProcessFn = (state: T, testCase: any) => void; @@ -156,8 +150,8 @@ const operations: TestRunnerFn = (fork, // Capella address_change: ssz.capella.SignedBLSToExecutionChange, // Electra - consolidation: ssz.electra.SignedConsolidation, - execution_layer_withdrawal_request: ssz.electra.ExecutionLayerWithdrawalRequest, + withdrawal_request: ssz.electra.WithdrawalRequest, + consolidation_request: ssz.electra.ConsolidationRequest, }, shouldError: (testCase) => testCase.post === undefined, getExpected: (testCase) => testCase.post, diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 0c2e3b34794b..a3dfb65da350 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -100,7 +100,7 @@ export const { PENDING_PARTIAL_WITHDRAWALS_LIMIT, PENDING_CONSOLIDATIONS_LIMIT, MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA, - MAX_CONSOLIDATIONS, + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 2495f7ef97a1..072936492bd3 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -133,6 +133,6 @@ export const mainnetPreset: BeaconPreset = { PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, PENDING_PARTIAL_WITHDRAWALS_LIMIT: 134217728, PENDING_CONSOLIDATIONS_LIMIT: 262144, - MAX_CONSOLIDATIONS: 1, + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1, WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: 4096, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 8e71407965d7..4a1e4af50665 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -134,6 +134,6 @@ export const minimalPreset: BeaconPreset = { PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, PENDING_PARTIAL_WITHDRAWALS_LIMIT: 64, PENDING_CONSOLIDATIONS_LIMIT: 64, - MAX_CONSOLIDATIONS: 1, + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1, WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: 4096, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index dffd98518006..14e8f8c172d8 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -95,7 +95,7 @@ export type BeaconPreset = { PENDING_BALANCE_DEPOSITS_LIMIT: number; PENDING_PARTIAL_WITHDRAWALS_LIMIT: number; PENDING_CONSOLIDATIONS_LIMIT: number; - MAX_CONSOLIDATIONS: number; + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: number; WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: number; }; @@ -195,7 +195,7 @@ export const beaconPresetTypes: BeaconPresetTypes = { PENDING_BALANCE_DEPOSITS_LIMIT: "number", PENDING_PARTIAL_WITHDRAWALS_LIMIT: "number", PENDING_CONSOLIDATIONS_LIMIT: "number", - MAX_CONSOLIDATIONS: "number", + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: "number", WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: "number", }; diff --git a/packages/state-transition/src/block/processConsolidation.ts b/packages/state-transition/src/block/processConsolidation.ts deleted file mode 100644 index 846b0e2521b4..000000000000 --- a/packages/state-transition/src/block/processConsolidation.ts +++ /dev/null @@ -1,111 +0,0 @@ -import {toHexString} from "@chainsafe/ssz"; -import {electra, ssz} from "@lodestar/types"; -import {FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} from "@lodestar/params"; -import {verifyConsolidationSignature} from "../signatureSets/index.js"; - -import {CachedBeaconStateElectra} from "../types.js"; -import {getConsolidationChurnLimit, isActiveValidator} from "../util/validator.js"; -import {hasExecutionWithdrawalCredential} from "../util/electra.js"; -import {computeConsolidationEpochAndUpdateChurn} from "../util/epoch.js"; - -export function processConsolidation( - state: CachedBeaconStateElectra, - signedConsolidation: electra.SignedConsolidation -): void { - assertValidConsolidation(state, signedConsolidation); - - // Initiate source validator exit and append pending consolidation - const {sourceIndex, targetIndex} = signedConsolidation.message; - const sourceValidator = state.validators.get(sourceIndex); - - const exitEpoch = computeConsolidationEpochAndUpdateChurn(state, BigInt(sourceValidator.effectiveBalance)); - sourceValidator.exitEpoch = exitEpoch; - sourceValidator.withdrawableEpoch = exitEpoch + state.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY; - - const pendingConsolidation = ssz.electra.PendingConsolidation.toViewDU({ - sourceIndex, - targetIndex, - }); - state.pendingConsolidations.push(pendingConsolidation); -} - -function assertValidConsolidation( - state: CachedBeaconStateElectra, - signedConsolidation: electra.SignedConsolidation -): void { - // If the pending consolidations queue is full, no consolidations are allowed in the block - if (state.pendingConsolidations.length >= PENDING_CONSOLIDATIONS_LIMIT) { - throw new Error("Pending consolidation queue is full"); - } - - // If there is too little available consolidation churn limit, no consolidations are allowed in the block - // assert get_consolidation_churn_limit(state) > MIN_ACTIVATION_BALANCE - if (getConsolidationChurnLimit(state) <= MIN_ACTIVATION_BALANCE) { - throw new Error(`Consolidation churn limit too low. consolidationChurnLimit=${getConsolidationChurnLimit(state)}`); - } - - const consolidation = signedConsolidation.message; - const {sourceIndex, targetIndex} = consolidation; - - // Verify that source != target, so a consolidation cannot be used as an exit. - if (sourceIndex === targetIndex) { - throw new Error( - `Consolidation source and target index cannot be the same: sourceIndex=${sourceIndex} targetIndex=${targetIndex}` - ); - } - - const sourceValidator = state.validators.getReadonly(sourceIndex); - const targetValidator = state.validators.getReadonly(targetIndex); - const currentEpoch = state.epochCtx.epoch; - - // Verify the source and the target are active - if (!isActiveValidator(sourceValidator, currentEpoch)) { - throw new Error(`Consolidation source validator is not active: sourceIndex=${sourceIndex}`); - } - - if (!isActiveValidator(targetValidator, currentEpoch)) { - throw new Error(`Consolidation target validator is not active: targetIndex=${targetIndex}`); - } - - // Verify exits for source and target have not been initiated - if (sourceValidator.exitEpoch !== FAR_FUTURE_EPOCH) { - throw new Error(`Consolidation source validator has initialized exit: sourceIndex=${sourceIndex}`); - } - if (targetValidator.exitEpoch !== FAR_FUTURE_EPOCH) { - throw new Error(`Consolidation target validator has initialized exit: targetIndex=${targetIndex}`); - } - - // Consolidations must specify an epoch when they become valid; they are not valid before then - if (currentEpoch < consolidation.epoch) { - throw new Error( - `Consolidation epoch is after the current epoch: consolidationEpoch=${consolidation.epoch} currentEpoch=${currentEpoch}` - ); - } - - // Verify the source and the target have Execution layer withdrawal credentials - if (!hasExecutionWithdrawalCredential(sourceValidator.withdrawalCredentials)) { - throw new Error( - `Consolidation source validator does not have execution withdrawal credentials: sourceIndex=${sourceIndex}` - ); - } - if (!hasExecutionWithdrawalCredential(targetValidator.withdrawalCredentials)) { - throw new Error( - `Consolidation target validator does not have execution withdrawal credentials: targetIndex=${targetIndex}` - ); - } - - // Verify the same withdrawal address - const sourceWithdrawalAddress = toHexString(sourceValidator.withdrawalCredentials.subarray(12)); - const targetWithdrawalAddress = toHexString(targetValidator.withdrawalCredentials.subarray(12)); - - if (sourceWithdrawalAddress !== targetWithdrawalAddress) { - throw new Error( - `Consolidation source and target withdrawal address are different: source: ${sourceWithdrawalAddress} target: ${targetWithdrawalAddress}` - ); - } - - // Verify consolidation is signed by the source and the target - if (!verifyConsolidationSignature(state, signedConsolidation)) { - throw new Error("Consolidation not valid"); - } -} diff --git a/packages/state-transition/src/block/processConsolidationRequest.ts b/packages/state-transition/src/block/processConsolidationRequest.ts new file mode 100644 index 000000000000..4b6a65e036ad --- /dev/null +++ b/packages/state-transition/src/block/processConsolidationRequest.ts @@ -0,0 +1,74 @@ +import {electra, ssz} from "@lodestar/types"; +import {FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} from "@lodestar/params"; + +import {CachedBeaconStateElectra} from "../types.js"; +import {getConsolidationChurnLimit, isActiveValidator} from "../util/validator.js"; +import {hasExecutionWithdrawalCredential} from "../util/electra.js"; +import {computeConsolidationEpochAndUpdateChurn} from "../util/epoch.js"; + +export function processConsolidationRequest( + state: CachedBeaconStateElectra, + consolidationRequest: electra.ConsolidationRequest +): void { + + // If the pending consolidations queue is full, consolidation requests are ignored + if (state.pendingConsolidations.length >= PENDING_CONSOLIDATIONS_LIMIT) { + return; + } + + // If there is too little available consolidation churn limit, consolidation requests are ignored + if (getConsolidationChurnLimit(state) <= MIN_ACTIVATION_BALANCE) { + return; + } + + const {sourcePubkey, targetPubkey} = consolidationRequest; + const sourceIndex = state.epochCtx.getValidatorIndex(sourcePubkey); + const targetIndex = state.epochCtx.getValidatorIndex(targetPubkey); + + if (sourceIndex === undefined || targetIndex === undefined) { + return; + } + + // Verify that source != target, so a consolidation cannot be used as an exit. + if (sourceIndex === targetIndex){ + return; + } + + const sourceValidator = state.validators.getReadonly(sourceIndex); + const targetValidator = state.validators.getReadonly(targetIndex); + const sourceWithdrawalAddress = sourceValidator.withdrawalCredentials.subarray(12); + const currentEpoch = state.epochCtx.epoch; + + // Verify withdrawal credentials + if ( + !hasExecutionWithdrawalCredential(sourceValidator.withdrawalCredentials) || + !hasExecutionWithdrawalCredential(targetValidator.withdrawalCredentials) + ) { + return; + } + + if (Buffer.compare(sourceWithdrawalAddress, consolidationRequest.sourceAddress) !== 0) { + return; + } + + // Verify the source and the target are active + if (!isActiveValidator(sourceValidator, currentEpoch) || !isActiveValidator(targetValidator, currentEpoch)) { + return; + } + + // Verify exits for source and target have not been initiated + if (sourceValidator.exitEpoch !== FAR_FUTURE_EPOCH || targetValidator.exitEpoch !== FAR_FUTURE_EPOCH) { + return; + } + + // TODO Electra: See if we can get rid of big int + const exitEpoch = computeConsolidationEpochAndUpdateChurn(state, BigInt(sourceValidator.effectiveBalance)); + sourceValidator.exitEpoch = exitEpoch; + sourceValidator.withdrawableEpoch = exitEpoch + state.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY; + + const pendingConsolidation = ssz.electra.PendingConsolidation.toViewDU({ + sourceIndex, + targetIndex, + }); + state.pendingConsolidations.push(pendingConsolidation); +} \ No newline at end of file diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index a2bd691337ad..8290771d2d8e 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -9,10 +9,10 @@ import {processAttesterSlashing} from "./processAttesterSlashing.js"; import {processDeposit} from "./processDeposit.js"; import {processVoluntaryExit} from "./processVoluntaryExit.js"; import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js"; -import {processExecutionLayerWithdrawalRequest} from "./processExecutionLayerWithdrawalRequest.js"; +import {processWithdrawalRequest} from "./processWithdrawalRequest.js"; import {processDepositRequest} from "./processDepositRequest.js"; import {ProcessBlockOpts} from "./types.js"; -import {processConsolidation} from "./processConsolidation.js"; +import {processConsolidationRequest} from "./processConsolidationRequest.js"; export { processProposerSlashing, @@ -20,10 +20,10 @@ export { processAttestations, processDeposit, processVoluntaryExit, - processExecutionLayerWithdrawalRequest, + processWithdrawalRequest, processBlsToExecutionChange, processDepositRequest, - processConsolidation, + processConsolidationRequest, }; export function processOperations( @@ -67,16 +67,16 @@ export function processOperations( const stateElectra = state as CachedBeaconStateElectra; const bodyElectra = body as electra.BeaconBlockBody; - for (const elWithdrawalRequest of bodyElectra.executionPayload.withdrawalRequests) { - processExecutionLayerWithdrawalRequest(fork, state as CachedBeaconStateElectra, elWithdrawalRequest); + for (const depositRequest of bodyElectra.executionPayload.depositReceipts) { + processDepositRequest(fork, stateElectra, depositRequest); } - for (const depositRequest of bodyElectra.executionPayload.depositRequests) { - processDepositRequest(fork, stateElectra, depositRequest); + for (const elWithdrawalRequest of bodyElectra.executionPayload.withdrawalRequests) { + processWithdrawalRequest(fork, state as CachedBeaconStateElectra, elWithdrawalRequest); } - for (const consolidation of bodyElectra.consolidations) { - processConsolidation(stateElectra, consolidation); + for (const elConsolidationRequest of bodyElectra.executionPayload.consolidationRequests) { + processConsolidationRequest(stateElectra, elConsolidationRequest); } } } diff --git a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts b/packages/state-transition/src/block/processWithdrawalRequest.ts similarity index 89% rename from packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts rename to packages/state-transition/src/block/processWithdrawalRequest.ts index e02129a09d05..cff1ea03bd80 100644 --- a/packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts +++ b/packages/state-transition/src/block/processWithdrawalRequest.ts @@ -14,12 +14,12 @@ import {getPendingBalanceToWithdraw, isActiveValidator} from "../util/validator. import {computeExitEpochAndUpdateChurn} from "../util/epoch.js"; import {initiateValidatorExit} from "./initiateValidatorExit.js"; -export function processExecutionLayerWithdrawalRequest( +export function processWithdrawalRequest( fork: ForkSeq, state: CachedBeaconStateElectra, - executionLayerWithdrawalRequest: electra.ExecutionLayerWithdrawalRequest + withdrawalRequest: electra.WithdrawalRequest ): void { - const amount = Number(executionLayerWithdrawalRequest.amount); + const amount = Number(withdrawalRequest.amount); const {pendingPartialWithdrawals, validators, epochCtx} = state; // no need to use unfinalized pubkey cache from 6110 as validator won't be active anyway const {pubkey2index, config} = epochCtx; @@ -32,13 +32,13 @@ export function processExecutionLayerWithdrawalRequest( // bail out if validator is not in beacon state // note that we don't need to check for 6110 unfinalized vals as they won't be eligible for withdraw/exit anyway - const validatorIndex = pubkey2index.get(executionLayerWithdrawalRequest.validatorPubkey); + const validatorIndex = pubkey2index.get(withdrawalRequest.validatorPubkey); if (validatorIndex === undefined) { return; } const validator = validators.get(validatorIndex); - if (!isValidatorEligibleForWithdrawOrExit(validator, executionLayerWithdrawalRequest.sourceAddress, state)) { + if (!isValidatorEligibleForWithdrawOrExit(validator, withdrawalRequest.sourceAddress, state)) { return; } diff --git a/packages/state-transition/src/signatureSets/consolidation.ts b/packages/state-transition/src/signatureSets/consolidation.ts deleted file mode 100644 index 0aef47d417a5..000000000000 --- a/packages/state-transition/src/signatureSets/consolidation.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {DOMAIN_CONSOLIDATION, ForkName} from "@lodestar/params"; -import {electra, ssz} from "@lodestar/types"; - -import { - computeSigningRoot, - createAggregateSignatureSetFromComponents, - ISignatureSet, - verifySignatureSet, -} from "../util/index.js"; -import {CachedBeaconStateElectra} from "../types.js"; - -export function verifyConsolidationSignature( - state: CachedBeaconStateElectra, - signedConsolidation: electra.SignedConsolidation -): boolean { - return verifySignatureSet(getConsolidationSignatureSet(state, signedConsolidation)); -} - -/** - * Extract signatures to allow validating all block signatures at once - */ -export function getConsolidationSignatureSet( - state: CachedBeaconStateElectra, - signedConsolidation: electra.SignedConsolidation -): ISignatureSet { - const {config} = state; - const {index2pubkey} = state.epochCtx; // TODO Electra: Use 6110 pubkey cache - const {sourceIndex, targetIndex} = signedConsolidation.message; - const sourcePubkey = index2pubkey[sourceIndex]; - const targetPubkey = index2pubkey[targetIndex]; - - // signatureFork for signing domain is fixed - const signatureFork = ForkName.phase0; - const domain = config.getDomainAtFork(signatureFork, DOMAIN_CONSOLIDATION); - const signingRoot = computeSigningRoot(ssz.electra.Consolidation, signedConsolidation.message, domain); - - return createAggregateSignatureSetFromComponents( - [sourcePubkey, targetPubkey], - signingRoot, - signedConsolidation.signature - ); -} - -export function getConsolidationSignatureSets( - state: CachedBeaconStateElectra, - signedBlock: electra.SignedBeaconBlock -): ISignatureSet[] { - return signedBlock.message.body.consolidations.map((consolidation) => - getConsolidationSignatureSet(state, consolidation) - ); -} diff --git a/packages/state-transition/src/signatureSets/index.ts b/packages/state-transition/src/signatureSets/index.ts index 5f063235735c..eae1d434a121 100644 --- a/packages/state-transition/src/signatureSets/index.ts +++ b/packages/state-transition/src/signatureSets/index.ts @@ -10,7 +10,6 @@ import {getBlockProposerSignatureSet} from "./proposer.js"; import {getRandaoRevealSignatureSet} from "./randao.js"; import {getVoluntaryExitsSignatureSets} from "./voluntaryExits.js"; import {getBlsToExecutionChangeSignatureSets} from "./blsToExecutionChange.js"; -import {getConsolidationSignatureSets} from "./consolidation.js"; export * from "./attesterSlashings.js"; export * from "./indexedAttestation.js"; @@ -19,7 +18,6 @@ export * from "./proposerSlashings.js"; export * from "./randao.js"; export * from "./voluntaryExits.js"; export * from "./blsToExecutionChange.js"; -export * from "./consolidation.js"; /** * Includes all signatures on the block (except the deposit signatures) for verification. @@ -71,15 +69,5 @@ export function getBlockSignatureSets( } } - if (fork >= ForkSeq.electra) { - const consolidationSignatureSets = getConsolidationSignatureSets( - state as CachedBeaconStateElectra, - signedBlock as electra.SignedBeaconBlock - ); - if (consolidationSignatureSets.length > 0) { - signatureSets.push(...consolidationSignatureSets); - } - } - return signatureSets; } diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 3d77366cbe57..7031aaa76fce 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -52,6 +52,7 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache ...stateElectraCloned.latestExecutionPayloadHeader.toValue(), depositRequestsRoot: ssz.Root.defaultValue(), withdrawalRequestsRoot: ssz.Root.defaultValue(), + consolidationRequestsRoot: ssz.Root.defaultValue(), }); stateElectraView.nextWithdrawalIndex = stateDeneb.nextWithdrawalIndex; stateElectraView.nextWithdrawalValidatorIndex = stateDeneb.nextWithdrawalValidatorIndex; diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index 2c55dc61a502..2f9d5ae0f6d7 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -175,9 +175,7 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositRequestsRoot = ssz.electra.DepositRequests.hashTreeRoot((payload as electra.ExecutionPayload).depositRequests); (bellatrixPayloadFields as electra.ExecutionPayloadHeader).withdrawalRequestsRoot = - ssz.electra.ExecutionLayerWithdrawalRequests.hashTreeRoot( - (payload as electra.ExecutionPayload).withdrawalRequests - ); + ssz.electra.WithdrawalRequests.hashTreeRoot((payload as electra.ExecutionPayload).withdrawalRequests); } return bellatrixPayloadFields; diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index ab9cbbaacd80..f02a1a27aefe 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -17,7 +17,7 @@ import { MAX_ATTESTATIONS_ELECTRA, MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, - MAX_CONSOLIDATIONS, + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, PENDING_BALANCE_DEPOSITS_LIMIT, PENDING_PARTIAL_WITHDRAWALS_LIMIT, PENDING_CONSOLIDATIONS_LIMIT, @@ -125,24 +125,34 @@ export const DepositRequest = new ContainerType( export const DepositRequests = new ListCompositeType(DepositRequest, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); -export const ExecutionLayerWithdrawalRequest = new ContainerType( +export const WithdrawalRequest = new ContainerType( { sourceAddress: ExecutionAddress, validatorPubkey: BLSPubkey, amount: UintNum64, }, - {typeName: "ExecutionLayerWithdrawalRequest", jsonCase: "eth2"} + {typeName: "WithdrawalRequest", jsonCase: "eth2"} ); -export const ExecutionLayerWithdrawalRequests = new ListCompositeType( - ExecutionLayerWithdrawalRequest, - MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD +export const WithdrawalRequests = new ListCompositeType(WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD); +export const ConsolidationRequest = new ContainerType( + { + sourceAddress: ExecutionAddress, + sourcePubkey: BLSPubkey, + targetPubkey: BLSPubkey, + }, + {typeName: "ConsolidationRequest", jsonCase: "eth2"} +); +export const ConsolidationRequests = new ListCompositeType( + ConsolidationRequest, + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD ); export const ExecutionPayload = new ContainerType( { ...denebSsz.ExecutionPayload.fields, depositRequests: DepositRequests, // New in ELECTRA - withdrawalRequests: ExecutionLayerWithdrawalRequests, // New in ELECTRA + withdrawalRequests: WithdrawalRequests, // New in ELECTRA + consolidationRequests: ConsolidationRequests, // [New in Electra] }, {typeName: "ExecutionPayload", jsonCase: "eth2"} ); @@ -152,27 +162,11 @@ export const ExecutionPayloadHeader = new ContainerType( ...denebSsz.ExecutionPayloadHeader.fields, depositRequestsRoot: Root, // New in ELECTRA withdrawalRequestsRoot: Root, // New in ELECTRA + consolidationRequestsRoot: Root, // New in ELECTRA }, {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} ); -export const Consolidation = new ContainerType( - { - sourceIndex: ValidatorIndex, - targetIndex: ValidatorIndex, - epoch: Epoch, - }, - {typeName: "Consolidation", jsonCase: "eth2"} -); - -export const SignedConsolidation = new ContainerType( - { - message: Consolidation, - signature: BLSSignature, - }, - {typeName: "SignedConsolidation", jsonCase: "eth2"} -); - // We have to preserve Fields ordering while changing the type of ExecutionPayload export const BeaconBlockBody = new ContainerType( { @@ -188,7 +182,6 @@ export const BeaconBlockBody = new ContainerType( executionPayload: ExecutionPayload, // Modified in ELECTRA blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, - consolidations: new ListCompositeType(SignedConsolidation, MAX_CONSOLIDATIONS), // [New in Electra] }, {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); @@ -223,7 +216,6 @@ export const BlindedBeaconBlockBody = new ContainerType( executionPayloadHeader: ExecutionPayloadHeader, // Modified in ELECTRA blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, - consolidations: new ListCompositeType(SignedConsolidation, MAX_CONSOLIDATIONS), // [New in Electra] }, {typeName: "BlindedBeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index 994e5a732243..728ffc56ac83 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -12,8 +12,11 @@ export type SignedAggregateAndProof = ValueOf; export type DepositRequests = ValueOf; -export type ExecutionLayerWithdrawalRequest = ValueOf; -export type ExecutionLayerWithdrawalRequests = ValueOf; +export type WithdrawalRequest = ValueOf; +export type WithdrawalRequests = ValueOf; + +export type ConsolidationRequest = ValueOf; +export type ConsolidationRequests = ValueOf; export type ExecutionPayload = ValueOf; export type ExecutionPayloadHeader = ValueOf; @@ -43,9 +46,6 @@ export type LightClientFinalityUpdate = ValueOf; export type LightClientStore = ValueOf; -export type Consolidation = ValueOf; -export type SignedConsolidation = ValueOf; - export type PendingBalanceDeposit = ValueOf; export type PendingPartialWithdrawal = ValueOf; export type PendingConsolidation = ValueOf; diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 3a497555361a..d5369515d47b 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -234,7 +234,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Tue, 25 Jun 2024 12:48:06 +0300 Subject: [PATCH 063/259] feat: support electra devnet-1 (#6892) * Update spec test version * Use new max effective balance * Relax loop breaking condition for `computeProposerIndex` * fix remaining * check-types & lint * Skip invalid test * Fix rebase + lint * Remove early return statement in `computeProposers` * Address comment * Address comment --- .../chain/produceBlock/produceBlockBody.ts | 1 - .../spec/presets/epoch_processing.test.ts | 6 +++++- .../test/spec/presets/operations.test.ts | 6 +++++- .../test/spec/specTestVersioning.ts | 2 +- .../test/spec/utils/specTestIterator.ts | 3 ++- packages/config/src/forkConfig/index.ts | 8 +++++++- packages/config/src/forkConfig/types.ts | 5 ++++- .../src/block/processConsolidationRequest.ts | 7 +++---- .../src/block/processOperations.ts | 2 +- .../state-transition/src/cache/epochCache.ts | 15 +++++++++++++-- packages/state-transition/src/epoch/index.ts | 2 +- .../epoch/processPendingBalanceDeposits.ts | 2 +- .../src/epoch/processSyncCommitteeUpdates.ts | 5 +++-- .../src/signatureSets/index.ts | 4 ++-- .../src/slot/upgradeStateToAltair.ts | 1 + .../state-transition/src/util/execution.ts | 2 ++ packages/state-transition/src/util/genesis.ts | 8 ++++++-- packages/state-transition/src/util/seed.ts | 19 ++++++++++++++----- .../src/util/syncCommittee.ts | 4 +++- .../test/perf/epoch/epochAltair.test.ts | 2 +- .../epoch/processSyncCommitteeUpdates.test.ts | 4 ++-- packages/state-transition/test/perf/util.ts | 8 +++++++- .../test/perf/util/shufflings.test.ts | 5 ++++- 23 files changed, 88 insertions(+), 33 deletions(-) diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index 638df42cba1b..ba560d5a7ff0 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -17,7 +17,6 @@ import { BlindedBeaconBlockBody, BlindedBeaconBlock, sszTypesFor, - electra, } from "@lodestar/types"; import { CachedBeaconStateAllForks, diff --git a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts index f159612e416c..604243400aa0 100644 --- a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts +++ b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts @@ -5,6 +5,7 @@ import { EpochTransitionCache, BeaconStateAllForks, beforeProcessEpoch, + CachedBeaconStateAltair, } from "@lodestar/state-transition"; import * as epochFns from "@lodestar/state-transition/epoch"; import {ssz} from "@lodestar/types"; @@ -40,7 +41,10 @@ const epochTransitionFns: Record = { rewards_and_penalties: epochFns.processRewardsAndPenalties, slashings: epochFns.processSlashings, slashings_reset: epochFns.processSlashingsReset, - sync_committee_updates: epochFns.processSyncCommitteeUpdates as EpochTransitionFn, + sync_committee_updates: (state, _) => { + const fork = state.config.getForkSeq(state.slot); + epochFns.processSyncCommitteeUpdates(fork, state as CachedBeaconStateAltair); + }, historical_summaries_update: epochFns.processHistoricalSummariesUpdate as EpochTransitionFn, pending_balance_deposits: epochFns.processPendingBalanceDeposits as EpochTransitionFn, pending_consolidations: epochFns.processPendingConsolidations as EpochTransitionFn, diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index 47895540ac1a..1128cdd11ba9 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -96,10 +96,13 @@ const operationFns: Record> = blockFns.processWithdrawalRequest(ForkSeq.electra, state as CachedBeaconStateElectra, testCase.withdrawal_request); }, + deposit_request: (state, testCase: {deposit_request: electra.DepositRequest}) => { + blockFns.processDepositRequest(ForkSeq.electra, state as CachedBeaconStateElectra, testCase.deposit_request); + }, + consolidation_request: (state, testCase: {consolidation_request: electra.ConsolidationRequest}) => { blockFns.processConsolidationRequest(state as CachedBeaconStateElectra, testCase.consolidation_request); }, - }; export type BlockProcessFn = (state: T, testCase: any) => void; @@ -151,6 +154,7 @@ const operations: TestRunnerFn = (fork, address_change: ssz.capella.SignedBLSToExecutionChange, // Electra withdrawal_request: ssz.electra.WithdrawalRequest, + deposit_request: ssz.electra.DepositRequest, consolidation_request: ssz.electra.ConsolidationRequest, }, shouldError: (testCase) => testCase.post === undefined, diff --git a/packages/beacon-node/test/spec/specTestVersioning.ts b/packages/beacon-node/test/spec/specTestVersioning.ts index 9195532379a0..e97770e8146c 100644 --- a/packages/beacon-node/test/spec/specTestVersioning.ts +++ b/packages/beacon-node/test/spec/specTestVersioning.ts @@ -15,7 +15,7 @@ import {DownloadTestsOptions} from "@lodestar/spec-test-util/downloadTests"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const ethereumConsensusSpecsTests: DownloadTestsOptions = { - specVersion: "v1.5.0-alpha.2", + specVersion: "v1.5.0-alpha.3", // Target directory is the host package root: 'packages/*/spec-tests' outputDir: path.join(__dirname, "../../spec-tests"), specTestsRepoUrl: "https://github.com/ethereum/consensus-spec-tests", diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index 63fe0cc10442..ac0d70307d33 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -66,7 +66,8 @@ export const defaultSkipOpts: SkipOpts = { /^capella\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, /^deneb\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, ], - skippedTests: [], + // TODO Electra: Review this test in the next spec test release + skippedTests: [/incorrect_not_enough_consolidation_churn_available/], skippedRunners: ["merkle_proof", "networking"], }; diff --git a/packages/config/src/forkConfig/index.ts b/packages/config/src/forkConfig/index.ts index 54edc8b618e0..dd2a1773c390 100644 --- a/packages/config/src/forkConfig/index.ts +++ b/packages/config/src/forkConfig/index.ts @@ -11,7 +11,7 @@ import { ForkLightClient, ForkBlobs, } from "@lodestar/params"; -import {Slot, Version, SSZTypesFor, sszTypesFor} from "@lodestar/types"; +import {Slot, Version, SSZTypesFor, sszTypesFor, Epoch} from "@lodestar/types"; import {ChainConfig} from "../chainConfig/index.js"; import {ForkConfig, ForkInfo} from "./types.js"; @@ -84,6 +84,9 @@ export function createForkConfig(config: ChainConfig): ForkConfig { // Fork convenience methods getForkInfo(slot: Slot): ForkInfo { const epoch = Math.floor(Math.max(slot, 0) / SLOTS_PER_EPOCH); + return this.getForkInfoFromEpoch(epoch); + }, + getForkInfoFromEpoch(epoch: Epoch): ForkInfo { // NOTE: forks must be sorted by descending epoch, latest fork first for (const fork of forksDescendingEpochOrder) { if (epoch >= fork.epoch) return fork; @@ -96,6 +99,9 @@ export function createForkConfig(config: ChainConfig): ForkConfig { getForkSeq(slot: Slot): ForkSeq { return this.getForkInfo(slot).seq; }, + getForkSeqFromEpoch(epoch: Epoch): ForkSeq { + return this.getForkInfoFromEpoch(epoch).seq; + }, getForkVersion(slot: Slot): Version { return this.getForkInfo(slot).version; }, diff --git a/packages/config/src/forkConfig/types.ts b/packages/config/src/forkConfig/types.ts index 2905e6f03c34..dd0381f4e9bf 100644 --- a/packages/config/src/forkConfig/types.ts +++ b/packages/config/src/forkConfig/types.ts @@ -21,11 +21,14 @@ export type ForkConfig = { /** Get the hard-fork info for the active fork at `slot` */ getForkInfo(slot: Slot): ForkInfo; - + /** Get the hard-fork info for the active fork at `epoch` */ + getForkInfoFromEpoch(epoch: Epoch): ForkInfo; /** Get the hard-fork name at a given slot */ getForkName(slot: Slot): ForkName; /** Get the hard-fork sequence number at a given slot */ getForkSeq(slot: Slot): ForkSeq; + /** Get the hard-fork sequence number at a given epoch */ + getForkSeqFromEpoch(epoch: Epoch): ForkSeq; /** Get the hard-fork version at a given slot */ getForkVersion(slot: Slot): Version; /** Get SSZ types by hard-fork */ diff --git a/packages/state-transition/src/block/processConsolidationRequest.ts b/packages/state-transition/src/block/processConsolidationRequest.ts index 4b6a65e036ad..2f12065fde41 100644 --- a/packages/state-transition/src/block/processConsolidationRequest.ts +++ b/packages/state-transition/src/block/processConsolidationRequest.ts @@ -10,7 +10,6 @@ export function processConsolidationRequest( state: CachedBeaconStateElectra, consolidationRequest: electra.ConsolidationRequest ): void { - // If the pending consolidations queue is full, consolidation requests are ignored if (state.pendingConsolidations.length >= PENDING_CONSOLIDATIONS_LIMIT) { return; @@ -30,11 +29,11 @@ export function processConsolidationRequest( } // Verify that source != target, so a consolidation cannot be used as an exit. - if (sourceIndex === targetIndex){ + if (sourceIndex === targetIndex) { return; } - const sourceValidator = state.validators.getReadonly(sourceIndex); + const sourceValidator = state.validators.get(sourceIndex); const targetValidator = state.validators.getReadonly(targetIndex); const sourceWithdrawalAddress = sourceValidator.withdrawalCredentials.subarray(12); const currentEpoch = state.epochCtx.epoch; @@ -71,4 +70,4 @@ export function processConsolidationRequest( targetIndex, }); state.pendingConsolidations.push(pendingConsolidation); -} \ No newline at end of file +} diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index 8290771d2d8e..6d4fb25b9f5b 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -67,7 +67,7 @@ export function processOperations( const stateElectra = state as CachedBeaconStateElectra; const bodyElectra = body as electra.BeaconBlockBody; - for (const depositRequest of bodyElectra.executionPayload.depositReceipts) { + for (const depositRequest of bodyElectra.executionPayload.depositRequests) { processDepositRequest(fork, stateElectra, depositRequest); } diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index dbcacec0062d..1f95da1ad5fc 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -398,7 +398,12 @@ export class EpochCache { // Allow to create CachedBeaconState for empty states, or no active validators const proposers = currentShuffling.activeIndices.length > 0 - ? computeProposers(currentProposerSeed, currentShuffling, effectiveBalanceIncrements) + ? computeProposers( + config.getForkSeqFromEpoch(currentEpoch), + currentProposerSeed, + currentShuffling, + effectiveBalanceIncrements + ) : []; const proposersNextEpoch: ProposersDeferred = { @@ -577,7 +582,12 @@ export class EpochCache { this.proposersPrevEpoch = this.proposers; const currentProposerSeed = getSeed(state, this.currentShuffling.epoch, DOMAIN_BEACON_PROPOSER); - this.proposers = computeProposers(currentProposerSeed, this.currentShuffling, this.effectiveBalanceIncrements); + this.proposers = computeProposers( + this.config.getForkSeqFromEpoch(currEpoch), + currentProposerSeed, + this.currentShuffling, + this.effectiveBalanceIncrements + ); // Only pre-compute the seed since it's very cheap. Do the expensive computeProposers() call only on demand. this.proposersNextEpoch = {computed: false, seed: getSeed(state, this.nextShuffling.epoch, DOMAIN_BEACON_PROPOSER)}; @@ -774,6 +784,7 @@ export class EpochCache { getBeaconProposersNextEpoch(): ValidatorIndex[] { if (!this.proposersNextEpoch.computed) { const indexes = computeProposers( + this.config.getForkSeqFromEpoch(this.epoch + 1), this.proposersNextEpoch.seed, this.nextShuffling, this.effectiveBalanceIncrements diff --git a/packages/state-transition/src/epoch/index.ts b/packages/state-transition/src/epoch/index.ts index 6e736fdae2cc..21455521897b 100644 --- a/packages/state-transition/src/epoch/index.ts +++ b/packages/state-transition/src/epoch/index.ts @@ -178,7 +178,7 @@ export function processEpoch( const timer = metrics?.epochTransitionStepTime.startTimer({ step: EpochTransitionStep.processSyncCommitteeUpdates, }); - processSyncCommitteeUpdates(state as CachedBeaconStateAltair); + processSyncCommitteeUpdates(fork, state as CachedBeaconStateAltair); timer?.(); } } diff --git a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts index 112832c920d7..e6e43bbaa089 100644 --- a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts @@ -10,7 +10,7 @@ import {getCurrentEpoch} from "../util/epoch.js"; * For each eligible `deposit`, call `increaseBalance()`. * Remove the processed deposits from `state.pendingBalanceDeposits`. * Update `state.depositBalanceToConsume` for the next epoch - * + * * TODO Electra: Update ssz library to support batch push to `pendingBalanceDeposits` */ export function processPendingBalanceDeposits(state: CachedBeaconStateElectra): void { diff --git a/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts b/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts index b3fd9b45053c..aa22bb4f7bcf 100644 --- a/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts +++ b/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts @@ -1,5 +1,5 @@ import {aggregateSerializedPublicKeys} from "@chainsafe/blst"; -import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD} from "@lodestar/params"; +import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, ForkSeq} from "@lodestar/params"; import {ssz} from "@lodestar/types"; import {getNextSyncCommitteeIndices} from "../util/seed.js"; import {CachedBeaconStateAltair} from "../types.js"; @@ -10,7 +10,7 @@ import {CachedBeaconStateAltair} from "../types.js"; * PERF: Once every `EPOCHS_PER_SYNC_COMMITTEE_PERIOD`, do an expensive operation to compute the next committee. * Calculating the next sync committee has a proportional cost to $VALIDATOR_COUNT */ -export function processSyncCommitteeUpdates(state: CachedBeaconStateAltair): void { +export function processSyncCommitteeUpdates(fork: ForkSeq, state: CachedBeaconStateAltair): void { const nextEpoch = state.epochCtx.epoch + 1; if (nextEpoch % EPOCHS_PER_SYNC_COMMITTEE_PERIOD === 0) { @@ -18,6 +18,7 @@ export function processSyncCommitteeUpdates(state: CachedBeaconStateAltair): voi const {effectiveBalanceIncrements} = state.epochCtx; const nextSyncCommitteeIndices = getNextSyncCommitteeIndices( + fork, state, activeValidatorIndices, effectiveBalanceIncrements diff --git a/packages/state-transition/src/signatureSets/index.ts b/packages/state-transition/src/signatureSets/index.ts index eae1d434a121..c883bb0587f8 100644 --- a/packages/state-transition/src/signatureSets/index.ts +++ b/packages/state-transition/src/signatureSets/index.ts @@ -1,7 +1,7 @@ import {ForkSeq} from "@lodestar/params"; -import {SignedBeaconBlock, altair, capella, electra} from "@lodestar/types"; +import {SignedBeaconBlock, altair, capella} from "@lodestar/types"; import {ISignatureSet} from "../util/index.js"; -import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStateElectra} from "../types.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; import {getSyncCommitteeSignatureSet} from "../block/processSyncCommittee.js"; import {getProposerSlashingsSignatureSets} from "./proposerSlashings.js"; import {getAttesterSlashingsSignatureSets} from "./attesterSlashings.js"; diff --git a/packages/state-transition/src/slot/upgradeStateToAltair.ts b/packages/state-transition/src/slot/upgradeStateToAltair.ts index 0afa43930ef0..fa7e6fbeba8e 100644 --- a/packages/state-transition/src/slot/upgradeStateToAltair.ts +++ b/packages/state-transition/src/slot/upgradeStateToAltair.ts @@ -70,6 +70,7 @@ export function upgradeStateToAltair(statePhase0: CachedBeaconStatePhase0): Cach stateAltair.inactivityScores = ssz.altair.InactivityScores.toViewDU(newZeroedArray(validatorCount)); const {syncCommittee, indices} = getNextSyncCommittee( + ForkSeq.altair, stateAltair, stateAltair.epochCtx.nextShuffling.activeIndices, stateAltair.epochCtx.effectiveBalanceIncrements diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index 2f9d5ae0f6d7..06e654f9f1d2 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -176,6 +176,8 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio ssz.electra.DepositRequests.hashTreeRoot((payload as electra.ExecutionPayload).depositRequests); (bellatrixPayloadFields as electra.ExecutionPayloadHeader).withdrawalRequestsRoot = ssz.electra.WithdrawalRequests.hashTreeRoot((payload as electra.ExecutionPayload).withdrawalRequests); + (bellatrixPayloadFields as electra.ExecutionPayloadHeader).consolidationRequestsRoot = + ssz.electra.ConsolidationRequests.hashTreeRoot((payload as electra.ExecutionPayload).consolidationRequests); } return bellatrixPayloadFields; diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index ca894fd5b4e5..d1f09a9796e1 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -18,7 +18,7 @@ import {EpochCacheImmutableData} from "../cache/epochCache.js"; import {processDeposit} from "../block/processDeposit.js"; import {increaseBalance} from "../index.js"; import {computeEpochAtSlot} from "./epoch.js"; -import {getActiveValidatorIndices} from "./validator.js"; +import {getActiveValidatorIndices, getValidatorMaxEffectiveBalance} from "./validator.js"; import {getTemporaryBlockHeader} from "./blockRoot.js"; import {newFilledArray} from "./array.js"; import {getNextSyncCommittee} from "./syncCommittee.js"; @@ -193,7 +193,10 @@ export function applyDeposits( } const balance = balancesArr[i]; - const effectiveBalance = Math.min(balance - (balance % EFFECTIVE_BALANCE_INCREMENT), MAX_EFFECTIVE_BALANCE); + const effectiveBalance = Math.min( + balance - (balance % EFFECTIVE_BALANCE_INCREMENT), + getValidatorMaxEffectiveBalance(validator.withdrawalCredentials) + ); validator.effectiveBalance = effectiveBalance; epochCtx.effectiveBalanceIncrementsSet(i, effectiveBalance); @@ -263,6 +266,7 @@ export function initializeBeaconStateFromEth1( if (fork >= ForkSeq.altair) { const {syncCommittee} = getNextSyncCommittee( + fork, state, activeValidatorIndices, state.epochCtx.effectiveBalanceIncrements diff --git a/packages/state-transition/src/util/seed.ts b/packages/state-transition/src/util/seed.ts index cf48fda8bec4..a5a0028d6c17 100644 --- a/packages/state-transition/src/util/seed.ts +++ b/packages/state-transition/src/util/seed.ts @@ -5,7 +5,9 @@ import { DOMAIN_SYNC_COMMITTEE, EFFECTIVE_BALANCE_INCREMENT, EPOCHS_PER_HISTORICAL_VECTOR, + ForkSeq, MAX_EFFECTIVE_BALANCE, + MAX_EFFECTIVE_BALANCE_ELECTRA, MIN_SEED_LOOKAHEAD, SHUFFLE_ROUND_COUNT, SLOTS_PER_EPOCH, @@ -20,6 +22,7 @@ import {computeEpochAtSlot} from "./epoch.js"; * Compute proposer indices for an epoch */ export function computeProposers( + fork: ForkSeq, epochSeed: Uint8Array, shuffling: {epoch: Epoch; activeIndices: ArrayLike}, effectiveBalanceIncrements: EffectiveBalanceIncrements @@ -29,6 +32,7 @@ export function computeProposers( for (let slot = startSlot; slot < startSlot + SLOTS_PER_EPOCH; slot++) { proposers.push( computeProposerIndex( + fork, effectiveBalanceIncrements, shuffling.activeIndices, digest(Buffer.concat([epochSeed, intToBytes(slot, 8)])) @@ -44,6 +48,7 @@ export function computeProposers( * SLOW CODE - 🐢 */ export function computeProposerIndex( + fork: ForkSeq, effectiveBalanceIncrements: EffectiveBalanceIncrements, indices: ArrayLike, seed: Uint8Array @@ -54,7 +59,10 @@ export function computeProposerIndex( // TODO: Inline outside this function const MAX_RANDOM_BYTE = 2 ** 8 - 1; - const MAX_EFFECTIVE_BALANCE_INCREMENT = MAX_EFFECTIVE_BALANCE / EFFECTIVE_BALANCE_INCREMENT; + const MAX_EFFECTIVE_BALANCE_INCREMENT = + fork >= ForkSeq.electra + ? MAX_EFFECTIVE_BALANCE_ELECTRA / EFFECTIVE_BALANCE_INCREMENT + : MAX_EFFECTIVE_BALANCE / EFFECTIVE_BALANCE_INCREMENT; let i = 0; /* eslint-disable-next-line no-constant-condition */ @@ -73,9 +81,6 @@ export function computeProposerIndex( return candidateIndex; } i += 1; - if (i === indices.length) { - return -1; - } } } @@ -90,13 +95,17 @@ export function computeProposerIndex( * SLOW CODE - 🐢 */ export function getNextSyncCommitteeIndices( + fork: ForkSeq, state: BeaconStateAllForks, activeValidatorIndices: ArrayLike, effectiveBalanceIncrements: EffectiveBalanceIncrements ): ValidatorIndex[] { // TODO: Bechmark if it's necessary to inline outside of this function const MAX_RANDOM_BYTE = 2 ** 8 - 1; - const MAX_EFFECTIVE_BALANCE_INCREMENT = MAX_EFFECTIVE_BALANCE / EFFECTIVE_BALANCE_INCREMENT; + const MAX_EFFECTIVE_BALANCE_INCREMENT = + fork >= ForkSeq.electra + ? MAX_EFFECTIVE_BALANCE_ELECTRA / EFFECTIVE_BALANCE_INCREMENT + : MAX_EFFECTIVE_BALANCE / EFFECTIVE_BALANCE_INCREMENT; const epoch = computeEpochAtSlot(state.slot) + 1; diff --git a/packages/state-transition/src/util/syncCommittee.ts b/packages/state-transition/src/util/syncCommittee.ts index b6de821d5406..c1f53632e521 100644 --- a/packages/state-transition/src/util/syncCommittee.ts +++ b/packages/state-transition/src/util/syncCommittee.ts @@ -2,6 +2,7 @@ import {aggregateSerializedPublicKeys} from "@chainsafe/blst"; import { BASE_REWARD_FACTOR, EFFECTIVE_BALANCE_INCREMENT, + ForkSeq, SLOTS_PER_EPOCH, SYNC_COMMITTEE_SIZE, SYNC_REWARD_WEIGHT, @@ -19,11 +20,12 @@ import {getNextSyncCommitteeIndices} from "./seed.js"; * SLOW CODE - 🐢 */ export function getNextSyncCommittee( + fork: ForkSeq, state: BeaconStateAllForks, activeValidatorIndices: ArrayLike, effectiveBalanceIncrements: EffectiveBalanceIncrements ): {indices: ValidatorIndex[]; syncCommittee: altair.SyncCommittee} { - const indices = getNextSyncCommitteeIndices(state, activeValidatorIndices, effectiveBalanceIncrements); + const indices = getNextSyncCommitteeIndices(fork, state, activeValidatorIndices, effectiveBalanceIncrements); // Using the index2pubkey cache is slower because it needs the serialized pubkey. const pubkeys = indices.map((index) => state.validators.getReadonly(index).pubkey); diff --git a/packages/state-transition/test/perf/epoch/epochAltair.test.ts b/packages/state-transition/test/perf/epoch/epochAltair.test.ts index 6c43151cc137..39e0a1b4c5c3 100644 --- a/packages/state-transition/test/perf/epoch/epochAltair.test.ts +++ b/packages/state-transition/test/perf/epoch/epochAltair.test.ts @@ -172,7 +172,7 @@ function benchmarkAltairEpochSteps(stateOg: LazyValue id: `${stateId} - altair processSyncCommitteeUpdates`, convergeFactor: 1 / 100, // Very unstable make it converge faster beforeEach: () => stateOg.value.clone() as CachedBeaconStateAltair, - fn: (state) => processSyncCommitteeUpdates(state), + fn: (state) => processSyncCommitteeUpdates(ForkSeq.altair, state), }); itBench({ diff --git a/packages/state-transition/test/perf/epoch/processSyncCommitteeUpdates.test.ts b/packages/state-transition/test/perf/epoch/processSyncCommitteeUpdates.test.ts index ffde30e1302c..4497dc16be0c 100644 --- a/packages/state-transition/test/perf/epoch/processSyncCommitteeUpdates.test.ts +++ b/packages/state-transition/test/perf/epoch/processSyncCommitteeUpdates.test.ts @@ -1,5 +1,5 @@ import {itBench} from "@dapplion/benchmark"; -import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD} from "@lodestar/params"; +import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, ForkSeq} from "@lodestar/params"; import {processSyncCommitteeUpdates} from "../../../src/epoch/processSyncCommitteeUpdates.js"; import {StateAltair} from "../types.js"; import {generatePerfTestCachedStateAltair, numValidators} from "../util.js"; @@ -21,7 +21,7 @@ describe("altair processSyncCommitteeUpdates", () => { }, fn: (state) => { const nextSyncCommitteeBefore = state.nextSyncCommittee; - processSyncCommitteeUpdates(state); + processSyncCommitteeUpdates(ForkSeq.altair, state); if (state.nextSyncCommittee === nextSyncCommitteeBefore) { throw Error("nextSyncCommittee instance has not changed"); } diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index 4b2a7da4a50e..f3c2eaef91e5 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -7,6 +7,7 @@ import { EPOCHS_PER_ETH1_VOTING_PERIOD, EPOCHS_PER_HISTORICAL_VECTOR, ForkName, + ForkSeq, MAX_ATTESTATIONS, MAX_EFFECTIVE_BALANCE, SLOTS_PER_EPOCH, @@ -273,7 +274,12 @@ export function generatePerformanceStateAltair(pubkeysArg?: Uint8Array[]): Beaco const activeValidatorIndices = getActiveValidatorIndices(altairState, epoch); const effectiveBalanceIncrements = getEffectiveBalanceIncrements(altairState); - const {syncCommittee} = getNextSyncCommittee(altairState, activeValidatorIndices, effectiveBalanceIncrements); + const {syncCommittee} = getNextSyncCommittee( + ForkSeq.altair, + altairState, + activeValidatorIndices, + effectiveBalanceIncrements + ); state.currentSyncCommittee = syncCommittee; state.nextSyncCommittee = syncCommittee; diff --git a/packages/state-transition/test/perf/util/shufflings.test.ts b/packages/state-transition/test/perf/util/shufflings.test.ts index 96c7878a46ac..24be96c4676d 100644 --- a/packages/state-transition/test/perf/util/shufflings.test.ts +++ b/packages/state-transition/test/perf/util/shufflings.test.ts @@ -28,7 +28,8 @@ describe("epoch shufflings", () => { id: `computeProposers - vc ${numValidators}`, fn: () => { const epochSeed = getSeed(state, state.epochCtx.nextShuffling.epoch, DOMAIN_BEACON_PROPOSER); - computeProposers(epochSeed, state.epochCtx.nextShuffling, state.epochCtx.effectiveBalanceIncrements); + const fork = state.config.getForkSeq(state.slot); + computeProposers(fork, epochSeed, state.epochCtx.nextShuffling, state.epochCtx.effectiveBalanceIncrements); }, }); @@ -43,7 +44,9 @@ describe("epoch shufflings", () => { itBench({ id: `getNextSyncCommittee - vc ${numValidators}`, fn: () => { + const fork = state.config.getForkSeq(state.slot); getNextSyncCommittee( + fork, state, state.epochCtx.nextShuffling.activeIndices, state.epochCtx.effectiveBalanceIncrements From 1d9c3a3a7de3ff0720cee224fdb7e4c1858da446 Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 25 Jun 2024 18:37:55 +0530 Subject: [PATCH 064/259] fix: electra rebase fixes on the new generic typing model lint & type fix lint --- packages/api/src/beacon/routes/events.ts | 11 +++--- packages/api/src/beacon/routes/validator.ts | 3 +- .../opPools/aggregatedAttestationPool.ts | 22 +++++------- .../src/chain/opPools/attestationPool.ts | 18 +++++----- .../beacon-node/src/chain/opPools/opPool.ts | 6 ++-- .../src/chain/validation/aggregateAndProof.ts | 8 ++--- .../src/chain/validation/attestation.ts | 13 +++---- .../signatureSets/aggregateAndProof.ts | 6 ++-- .../src/metrics/validatorMonitor.ts | 2 +- .../src/network/gossip/interface.ts | 12 +++---- .../beacon-node/src/network/gossip/topic.ts | 4 +-- packages/beacon-node/src/network/interface.ts | 3 +- packages/beacon-node/src/network/network.ts | 3 +- .../test/unit/util/sszBytes.test.ts | 4 +-- .../fork-choice/src/forkChoice/interface.ts | 4 +-- packages/params/src/index.ts | 2 +- packages/params/src/presets/mainnet.ts | 2 +- packages/params/src/presets/minimal.ts | 2 +- packages/params/src/types.ts | 4 +-- .../src/block/processAttestationPhase0.ts | 8 ++--- .../src/block/processAttestations.ts | 4 +-- .../src/block/processAttestationsAltair.ts | 4 +-- .../state-transition/src/cache/epochCache.ts | 7 ++-- .../src/signatureSets/attesterSlashings.ts | 6 ++-- packages/state-transition/src/util/epoch.ts | 2 +- packages/types/src/electra/sszTypes.ts | 7 ++-- packages/types/src/types.ts | 35 +++++++++++++++++++ .../validator/src/services/attestation.ts | 6 ++-- .../validator/src/services/validatorStore.ts | 11 +++--- packages/validator/src/util/params.ts | 2 +- 30 files changed, 128 insertions(+), 93 deletions(-) diff --git a/packages/api/src/beacon/routes/events.ts b/packages/api/src/beacon/routes/events.ts index 04131750dbf2..e15790fd3bea 100644 --- a/packages/api/src/beacon/routes/events.ts +++ b/packages/api/src/beacon/routes/events.ts @@ -13,6 +13,9 @@ import { LightClientOptimisticUpdate, LightClientFinalityUpdate, SSEPayloadAttributes, + Attestation, + AttesterSlashing, + sszTypesFor, } from "@lodestar/types"; import {ForkName} from "@lodestar/params"; @@ -104,10 +107,10 @@ export type EventData = { block: RootHex; executionOptimistic: boolean; }; - [EventType.attestation]: {version: ForkName; data: allForks.Attestation}; + [EventType.attestation]: {version: ForkName; data: Attestation}; [EventType.voluntaryExit]: phase0.SignedVoluntaryExit; [EventType.proposerSlashing]: phase0.ProposerSlashing; - [EventType.attesterSlashing]: {version: ForkName; data: allForks.AttesterSlashing}; + [EventType.attesterSlashing]: {version: ForkName; data: AttesterSlashing}; [EventType.blsToExecutionChange]: capella.SignedBLSToExecutionChange; [EventType.finalizedCheckpoint]: { block: RootHex; @@ -225,10 +228,10 @@ export function getTypeByEvent(): {[K in EventType]: TypeJson} { {jsonCase: "eth2"} ), - [EventType.attestation]: WithVersion((fork) => (ssz.allForks[fork] as allForks.AllForksSSZTypes).Attestation), + [EventType.attestation]: WithVersion((fork) => sszTypesFor(fork).Attestation), [EventType.voluntaryExit]: ssz.phase0.SignedVoluntaryExit, [EventType.proposerSlashing]: ssz.phase0.ProposerSlashing, - [EventType.attesterSlashing]: WithVersion((fork) => ssz.allForks[fork].AttesterSlashing), + [EventType.attesterSlashing]: WithVersion((fork) => sszTypesFor(fork).AttesterSlashing), [EventType.blsToExecutionChange]: ssz.capella.SignedBLSToExecutionChange, [EventType.finalizedCheckpoint]: new ContainerType( diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index ac8526947c3f..154397107d47 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -17,6 +17,7 @@ import { stringType, BeaconBlockOrContents, BlindedBeaconBlock, + Attestation, } from "@lodestar/types"; import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import {fromGraffitiHex, toBoolean, toGraffitiHex} from "../../utils/serdes.js"; @@ -413,7 +414,7 @@ export type Endpoints = { committeeIndex: number; }, {query: {attestation_data_root: string; slot: number; committeeIndex: number}}, - allForks.Attestation, + Attestation, VersionMeta >; diff --git a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts index 31d461766947..491b5fd6f72a 100644 --- a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts @@ -17,9 +17,9 @@ import { ssz, ValidatorIndex, RootHex, - allForks, electra, isElectraAttestation, + Attestation, } from "@lodestar/types"; import { CachedBeaconStateAllForks, @@ -40,7 +40,7 @@ type DataRootHex = string; type CommitteeIndex = number; // for pre-electra -type AttestationWithScore = {attestation: allForks.Attestation; score: number}; +type AttestationWithScore = {attestation: Attestation; score: number}; /** * for electra, this is to consolidate aggregated attestations of the same attestation data into a single attestation to be included in block * note that this is local definition in this file and it's NOT validator consolidation @@ -118,7 +118,7 @@ export class AggregatedAttestationPool { } add( - attestation: allForks.Attestation, + attestation: Attestation, dataRootHex: RootHex, attestingIndicesCount: number, committee: Uint32Array @@ -162,11 +162,7 @@ export class AggregatedAttestationPool { this.lowestPermissibleSlot = Math.max(clockSlot - SLOTS_PER_EPOCH, 0); } - getAttestationsForBlock( - fork: ForkName, - forkChoice: IForkChoice, - state: CachedBeaconStateAllForks - ): allForks.Attestation[] { + getAttestationsForBlock(fork: ForkName, forkChoice: IForkChoice, state: CachedBeaconStateAllForks): Attestation[] { const forkSeq = ForkSeq[fork]; return forkSeq >= ForkSeq.electra ? this.getAttestationsForBlockElectra(fork, forkChoice, state) @@ -397,7 +393,7 @@ export class AggregatedAttestationPool { * Get all attestations optionally filtered by `attestation.data.slot` * @param bySlot slot to filter, `bySlot === attestation.data.slot` */ - getAll(bySlot?: Slot): allForks.Attestation[] { + getAll(bySlot?: Slot): Attestation[] { let attestationGroupsArr: Map[]; if (bySlot === undefined) { attestationGroupsArr = Array.from(this.attestationGroupByIndexByDataHexBySlot.values()).flatMap((byIndex) => @@ -409,7 +405,7 @@ export class AggregatedAttestationPool { attestationGroupsArr = Array.from(attestationGroupsByIndex.values()); } - const attestations: allForks.Attestation[] = []; + const attestations: Attestation[] = []; for (const attestationGroups of attestationGroupsArr) { for (const attestationGroup of attestationGroups.values()) { attestations.push(...attestationGroup.getAttestations()); @@ -420,12 +416,12 @@ export class AggregatedAttestationPool { } interface AttestationWithIndex { - attestation: allForks.Attestation; + attestation: Attestation; trueBitsCount: number; } type AttestationNonParticipant = { - attestation: allForks.Attestation; + attestation: Attestation; // this is <= attestingIndices.count since some attesters may be seen by the chain // this is only updated and used in removeBySeenValidators function notSeenAttesterCount: number; @@ -534,7 +530,7 @@ export class MatchingDataAttestationGroup { } /** Get attestations for API. */ - getAttestations(): allForks.Attestation[] { + getAttestations(): Attestation[] { return this.attestations.map((attestation) => attestation.attestation); } } diff --git a/packages/beacon-node/src/chain/opPools/attestationPool.ts b/packages/beacon-node/src/chain/opPools/attestationPool.ts index dfb3bc7348a2..8daae6b663c7 100644 --- a/packages/beacon-node/src/chain/opPools/attestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/attestationPool.ts @@ -1,6 +1,6 @@ import {BitArray} from "@chainsafe/ssz"; import {Signature, aggregateSignatures} from "@chainsafe/blst"; -import {Slot, RootHex, allForks, isElectraAttestation} from "@lodestar/types"; +import {Slot, RootHex, isElectraAttestation, Attestation} from "@lodestar/types"; import {MapDef, assert} from "@lodestar/utils"; import {IClock} from "../../util/clock.js"; import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js"; @@ -23,7 +23,7 @@ const SLOTS_RETAINED = 3; const MAX_ATTESTATIONS_PER_SLOT = 16_384; type AggregateFastPhase0 = { - data: allForks.Attestation["data"]; + data: Attestation["data"]; aggregationBits: BitArray; signature: Signature; }; @@ -101,7 +101,7 @@ export class AttestationPool { * - Valid committeeIndex * - Valid data */ - add(committeeIndex: CommitteeIndex, attestation: allForks.Attestation, attDataRootHex: RootHex): InsertOutcome { + add(committeeIndex: CommitteeIndex, attestation: Attestation, attDataRootHex: RootHex): InsertOutcome { const slot = attestation.data.slot; const lowestPermissibleSlot = this.lowestPermissibleSlot; @@ -144,7 +144,7 @@ export class AttestationPool { /** * For validator API to get an aggregate */ - getAggregate(slot: Slot, committeeIndex: CommitteeIndex, dataRootHex: RootHex): allForks.Attestation | null { + getAggregate(slot: Slot, committeeIndex: CommitteeIndex, dataRootHex: RootHex): Attestation | null { const aggregate = this.aggregateByIndexByRootBySlot.get(slot)?.get(dataRootHex)?.get(committeeIndex); if (!aggregate) { // TODO: Add metric for missing aggregates @@ -168,8 +168,8 @@ export class AttestationPool { * Get all attestations optionally filtered by `attestation.data.slot` * @param bySlot slot to filter, `bySlot === attestation.data.slot` */ - getAll(bySlot?: Slot): allForks.Attestation[] { - const attestations: allForks.Attestation[] = []; + getAll(bySlot?: Slot): Attestation[] { + const attestations: Attestation[] = []; const aggregateByRoots = bySlot === undefined @@ -196,7 +196,7 @@ export class AttestationPool { /** * Aggregate a new attestation into `aggregate` mutating it */ -function aggregateAttestationInto(aggregate: AggregateFast, attestation: allForks.Attestation): InsertOutcome { +function aggregateAttestationInto(aggregate: AggregateFast, attestation: Attestation): InsertOutcome { const bitIndex = attestation.aggregationBits.getSingleTrueBit(); // Should never happen, attestations are verified against this exact condition before @@ -214,7 +214,7 @@ function aggregateAttestationInto(aggregate: AggregateFast, attestation: allFork /** * Format `contribution` into an efficient `aggregate` to add more contributions in with aggregateContributionInto() */ -function attestationToAggregate(attestation: allForks.Attestation): AggregateFast { +function attestationToAggregate(attestation: Attestation): AggregateFast { if (isElectraAttestation(attestation)) { return { data: attestation.data, @@ -235,6 +235,6 @@ function attestationToAggregate(attestation: allForks.Attestation): AggregateFas /** * Unwrap AggregateFast to phase0.Attestation */ -function fastToAttestation(aggFast: AggregateFast): allForks.Attestation { +function fastToAttestation(aggFast: AggregateFast): Attestation { return {...aggFast, signature: aggFast.signature.toBytes()}; } diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index 8eb3cebcffdb..54fec380de86 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -16,8 +16,8 @@ import { ForkSeq, MAX_ATTESTER_SLASHINGS_ELECTRA, } from "@lodestar/params"; -import {Epoch, phase0, capella, ssz, ValidatorIndex, SignedBeaconBlock} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; +import {Epoch, phase0, capella, ssz, ValidatorIndex, SignedBeaconBlock, AttesterSlashing} from "@lodestar/types"; import {IBeaconDb} from "../../db/index.js"; import {SignedBLSToExecutionChangeVersioned} from "../../util/types.js"; import {BlockType} from "../interface.js"; @@ -175,7 +175,7 @@ export class OpPool { blockType: BlockType, metrics: Metrics | null ): [ - allForks.AttesterSlashing[], + AttesterSlashing[], phase0.ProposerSlashing[], phase0.SignedVoluntaryExit[], capella.SignedBLSToExecutionChange[], @@ -209,7 +209,7 @@ export class OpPool { }); const endAttesterSlashings = stepsMetrics?.startTimer(); - const attesterSlashings: allForks.AttesterSlashing[] = []; + const attesterSlashings: AttesterSlashing[] = []; const maxAttesterSlashing = stateFork >= ForkSeq.electra ? MAX_ATTESTER_SLASHINGS_ELECTRA : MAX_ATTESTER_SLASHINGS; attesterSlashing: for (const attesterSlashing of this.attesterSlashings.values()) { /** Indices slashable in this attester slashing */ diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 3c8b102eb5ac..839f7850f75d 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -1,5 +1,5 @@ import {ForkName, ForkSeq} from "@lodestar/params"; -import {allForks, electra, phase0, RootHex, ssz} from "@lodestar/types"; +import {electra, phase0, RootHex, ssz, IndexedAttestation, SignedAggregateAndProof} from "@lodestar/types"; import { computeEpochAtSlot, isAggregatorFromCommitteeLength, @@ -20,7 +20,7 @@ import { } from "./attestation.js"; export type AggregateAndProofValidationResult = { - indexedAttestation: allForks.IndexedAttestation; + indexedAttestation: IndexedAttestation; committeeIndices: Uint32Array; attDataRootHex: RootHex; }; @@ -41,7 +41,7 @@ export async function validateApiAggregateAndProof( export async function validateGossipAggregateAndProof( fork: ForkName, chain: IBeaconChain, - signedAggregateAndProof: allForks.SignedAggregateAndProof, + signedAggregateAndProof: SignedAggregateAndProof, serializedData: Uint8Array ): Promise { return validateAggregateAndProof(fork, chain, signedAggregateAndProof, serializedData); @@ -50,7 +50,7 @@ export async function validateGossipAggregateAndProof( async function validateAggregateAndProof( fork: ForkName, chain: IBeaconChain, - signedAggregateAndProof: allForks.SignedAggregateAndProof, + signedAggregateAndProof: SignedAggregateAndProof, serializedData: Uint8Array | null = null, opts: {skipValidationKnownAttesters: boolean; prioritizeBls: boolean} = { skipValidationKnownAttesters: false, diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index 1d5568fbc868..1dcf76cdc5ae 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -6,10 +6,11 @@ import { Slot, RootHex, ssz, - allForks, electra, isElectraAttestation, CommitteeIndex, + Attestation, + IndexedAttestation, } from "@lodestar/types"; import {ProtoBlock} from "@lodestar/fork-choice"; import {ATTESTATION_SUBNET_COUNT, SLOTS_PER_EPOCH, ForkName, ForkSeq, DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; @@ -46,8 +47,8 @@ export type BatchResult = { }; export type AttestationValidationResult = { - attestation: allForks.Attestation; - indexedAttestation: allForks.IndexedAttestation; + attestation: Attestation; + indexedAttestation: IndexedAttestation; subnet: number; attDataRootHex: RootHex; committeeIndex: CommitteeIndex; @@ -56,7 +57,7 @@ export type AttestationValidationResult = { export type AttestationOrBytes = ApiAttestation | GossipAttestation; /** attestation from api */ -export type ApiAttestation = {attestation: allForks.Attestation; serializedData: null}; +export type ApiAttestation = {attestation: Attestation; serializedData: null}; /** attestation from gossip */ export type GossipAttestation = { @@ -263,7 +264,7 @@ async function validateGossipAttestationNoSignatureCheck( // Run the checks that happen before an indexed attestation is constructed. let attestationOrCache: - | {attestation: allForks.Attestation; cache: null} + | {attestation: Attestation; cache: null} | {attestation: null; cache: AttestationDataCacheEntry; serializedData: Uint8Array}; let attDataKey: SeenAttDataKey | null = null; if (attestationOrBytes.serializedData) { @@ -513,7 +514,7 @@ async function validateGossipAttestationNoSignatureCheck( ? (indexedAttestationContent as electra.IndexedAttestation) : (indexedAttestationContent as phase0.IndexedAttestation); - const attestation: allForks.Attestation = attestationOrCache.attestation ?? { + const attestation: Attestation = attestationOrCache.attestation ?? { aggregationBits, data: attData, committeeBits, diff --git a/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts index 411f33f68e66..2945b4d445d0 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts @@ -1,6 +1,6 @@ import type {PublicKey} from "@chainsafe/bls/types"; import {DOMAIN_AGGREGATE_AND_PROOF, ForkSeq} from "@lodestar/params"; -import {allForks, ssz} from "@lodestar/types"; +import {ssz, SignedAggregateAndProof} from "@lodestar/types"; import {Epoch} from "@lodestar/types"; import { computeSigningRoot, @@ -13,7 +13,7 @@ import {BeaconConfig} from "@lodestar/config"; export function getAggregateAndProofSigningRoot( config: BeaconConfig, epoch: Epoch, - aggregateAndProof: allForks.SignedAggregateAndProof + aggregateAndProof: SignedAggregateAndProof ): Uint8Array { // previously, we call `const aggregatorDomain = state.config.getDomain(state.slot, DOMAIN_AGGREGATE_AND_PROOF, slot);` // at fork boundary, it's required to dial to target epoch https://github.com/ChainSafe/lodestar/blob/v1.11.3/packages/beacon-node/src/chain/validation/attestation.ts#L573 @@ -29,7 +29,7 @@ export function getAggregateAndProofSignatureSet( config: BeaconConfig, epoch: Epoch, aggregator: PublicKey, - aggregateAndProof: allForks.SignedAggregateAndProof + aggregateAndProof: SignedAggregateAndProof ): ISignatureSet { return createSingleSignatureSetFromComponents( aggregator, diff --git a/packages/beacon-node/src/metrics/validatorMonitor.ts b/packages/beacon-node/src/metrics/validatorMonitor.ts index 6331c5dca550..34dfa6b72e03 100644 --- a/packages/beacon-node/src/metrics/validatorMonitor.ts +++ b/packages/beacon-node/src/metrics/validatorMonitor.ts @@ -13,7 +13,7 @@ import {BeaconBlock, RootHex, altair, deneb} from "@lodestar/types"; import {ChainConfig, ChainForkConfig} from "@lodestar/config"; import {ForkSeq, INTERVALS_PER_SLOT, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params"; import {Epoch, Slot, ValidatorIndex} from "@lodestar/types"; -import {IndexedAttestation, SignedAggregateAndProof} from "@lodestar/types/allForks"; +import {IndexedAttestation, SignedAggregateAndProof} from "@lodestar/types"; import {GENESIS_SLOT} from "../constants/constants.js"; import {LodestarMetrics} from "./metrics/lodestar.js"; diff --git a/packages/beacon-node/src/network/gossip/interface.ts b/packages/beacon-node/src/network/gossip/interface.ts index 649bfd455387..ab9b8a65978d 100644 --- a/packages/beacon-node/src/network/gossip/interface.ts +++ b/packages/beacon-node/src/network/gossip/interface.ts @@ -11,6 +11,8 @@ import { phase0, SignedBeaconBlock, Slot, + Attestation, + SignedAggregateAndProof, } from "@lodestar/types"; import {BeaconConfig} from "@lodestar/config"; import {Logger} from "@lodestar/utils"; @@ -80,8 +82,8 @@ export type SSZTypeOfGossipTopic = T extends {type: infer export type GossipTypeMap = { [GossipType.beacon_block]: SignedBeaconBlock; [GossipType.blob_sidecar]: deneb.BlobSidecar; - [GossipType.beacon_aggregate_and_proof]: allForks.SignedAggregateAndProof; - [GossipType.beacon_attestation]: allForks.Attestation; + [GossipType.beacon_aggregate_and_proof]: SignedAggregateAndProof; + [GossipType.beacon_attestation]: Attestation; [GossipType.voluntary_exit]: phase0.SignedVoluntaryExit; [GossipType.proposer_slashing]: phase0.ProposerSlashing; [GossipType.attester_slashing]: phase0.AttesterSlashing; @@ -95,10 +97,8 @@ export type GossipTypeMap = { export type GossipFnByType = { [GossipType.beacon_block]: (signedBlock: SignedBeaconBlock) => Promise | void; [GossipType.blob_sidecar]: (blobSidecar: deneb.BlobSidecar) => Promise | void; - [GossipType.beacon_aggregate_and_proof]: ( - aggregateAndProof: allForks.SignedAggregateAndProof - ) => Promise | void; - [GossipType.beacon_attestation]: (attestation: allForks.Attestation) => Promise | void; + [GossipType.beacon_aggregate_and_proof]: (aggregateAndProof: SignedAggregateAndProof) => Promise | void; + [GossipType.beacon_attestation]: (attestation: Attestation) => Promise | void; [GossipType.voluntary_exit]: (voluntaryExit: phase0.SignedVoluntaryExit) => Promise | void; [GossipType.proposer_slashing]: (proposerSlashing: phase0.ProposerSlashing) => Promise | void; [GossipType.attester_slashing]: (attesterSlashing: phase0.AttesterSlashing) => Promise | void; diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index ffbad28cd936..2ccde0044037 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -1,4 +1,4 @@ -import {ssz, sszTypesFor} from "@lodestar/types"; +import {ssz, Attestation, sszTypesFor} from "@lodestar/types"; import {ForkDigestContext} from "@lodestar/config"; import { ATTESTATION_SUBNET_COUNT, @@ -128,7 +128,7 @@ export function sszDeserialize(topic: T, serializedData: /** * Deserialize a gossip serialized data into an Attestation object. */ -export function sszDeserializeAttestation(fork: ForkName, serializedData: Uint8Array): allForks.Attestation { +export function sszDeserializeAttestation(fork: ForkName, serializedData: Uint8Array): Attestation { const sszType = ssz.allForks[fork].Attestation; try { return sszType.deserialize(serializedData); diff --git a/packages/beacon-node/src/network/interface.ts b/packages/beacon-node/src/network/interface.ts index 4fd1235fe91a..8d73379af221 100644 --- a/packages/beacon-node/src/network/interface.ts +++ b/packages/beacon-node/src/network/interface.ts @@ -26,6 +26,7 @@ import { capella, deneb, phase0, + SignedAggregateAndProof, } from "@lodestar/types"; import {PeerIdStr} from "../util/peerId.js"; import {INetworkEventBus} from "./events.js"; @@ -71,7 +72,7 @@ export interface INetwork extends INetworkCorePublic { // Gossip publishBeaconBlock(signedBlock: SignedBeaconBlock): Promise; publishBlobSidecar(blobSidecar: deneb.BlobSidecar): Promise; - publishBeaconAggregateAndProof(aggregateAndProof: allForks.SignedAggregateAndProof): Promise; + publishBeaconAggregateAndProof(aggregateAndProof: SignedAggregateAndProof): Promise; publishBeaconAttestation(attestation: phase0.Attestation, subnet: number): Promise; publishVoluntaryExit(voluntaryExit: phase0.SignedVoluntaryExit): Promise; publishBlsToExecutionChange(blsToExecutionChange: capella.SignedBLSToExecutionChange): Promise; diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index f9550d4c0ec2..1b3ccaaaf75a 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -17,6 +17,7 @@ import { LightClientFinalityUpdate, LightClientOptimisticUpdate, LightClientUpdate, + SignedAggregateAndProof, } from "@lodestar/types"; import {routes} from "@lodestar/api"; import {ResponseIncoming} from "@lodestar/reqresp"; @@ -316,7 +317,7 @@ export class Network implements INetwork { }); } - async publishBeaconAggregateAndProof(aggregateAndProof: allForks.SignedAggregateAndProof): Promise { + async publishBeaconAggregateAndProof(aggregateAndProof: SignedAggregateAndProof): Promise { const fork = this.config.getForkName(aggregateAndProof.message.aggregate.data.slot); return this.publishGossip( {type: GossipType.beacon_aggregate_and_proof, fork}, diff --git a/packages/beacon-node/test/unit/util/sszBytes.test.ts b/packages/beacon-node/test/unit/util/sszBytes.test.ts index 2d138111a05f..643b6b1bac0f 100644 --- a/packages/beacon-node/test/unit/util/sszBytes.test.ts +++ b/packages/beacon-node/test/unit/util/sszBytes.test.ts @@ -1,6 +1,6 @@ import {describe, it, expect} from "vitest"; import {BitArray} from "@chainsafe/ssz"; -import {allForks, deneb, electra, Epoch, isElectraAttestation, phase0, RootHex, Slot, ssz} from "@lodestar/types"; +import {deneb, electra, Epoch, isElectraAttestation, phase0, RootHex, Slot, ssz} from "@lodestar/types"; import {fromHex, toHex} from "@lodestar/utils"; import {ForkName, MAX_COMMITTEES_PER_SLOT} from "@lodestar/params"; import { @@ -19,7 +19,7 @@ import { } from "../../../src/util/sszBytes.js"; describe("attestation SSZ serialized picking", () => { - const testCases: allForks.Attestation[] = [ + const testCases: (phase0.Attestation | electra.Attestation)[] = [ ssz.phase0.Attestation.defaultValue(), attestationFromValues( 4_000_000, diff --git a/packages/fork-choice/src/forkChoice/interface.ts b/packages/fork-choice/src/forkChoice/interface.ts index c9d1aa627b03..0b6d56a88bf2 100644 --- a/packages/fork-choice/src/forkChoice/interface.ts +++ b/packages/fork-choice/src/forkChoice/interface.ts @@ -1,6 +1,6 @@ import {EffectiveBalanceIncrements} from "@lodestar/state-transition"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; -import {Epoch, Slot, ValidatorIndex, phase0, Root, RootHex, BeaconBlock} from "@lodestar/types"; +import {Epoch, Slot, ValidatorIndex, phase0, Root, RootHex, BeaconBlock, IndexedAttestation} from "@lodestar/types"; import { ProtoBlock, MaybeValidExecutionStatus, @@ -156,7 +156,7 @@ export interface IForkChoice { * The supplied `attestation` **must** pass the `in_valid_indexed_attestation` function as it * will not be run here. */ - onAttestation(attestation: allForks.IndexedAttestation, attDataRoot: string, forceImport?: boolean): void; + onAttestation(attestation: IndexedAttestation, attDataRoot: string, forceImport?: boolean): void; /** * Register attester slashing in order not to consider their votes in `getHead` * diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index a3dfb65da350..0c2e3b34794b 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -100,7 +100,7 @@ export const { PENDING_PARTIAL_WITHDRAWALS_LIMIT, PENDING_CONSOLIDATIONS_LIMIT, MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA, - MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 072936492bd3..2495f7ef97a1 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -133,6 +133,6 @@ export const mainnetPreset: BeaconPreset = { PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, PENDING_PARTIAL_WITHDRAWALS_LIMIT: 134217728, PENDING_CONSOLIDATIONS_LIMIT: 262144, - MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1, + MAX_CONSOLIDATIONS: 1, WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: 4096, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 4a1e4af50665..8e71407965d7 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -134,6 +134,6 @@ export const minimalPreset: BeaconPreset = { PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, PENDING_PARTIAL_WITHDRAWALS_LIMIT: 64, PENDING_CONSOLIDATIONS_LIMIT: 64, - MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1, + MAX_CONSOLIDATIONS: 1, WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: 4096, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index 14e8f8c172d8..dffd98518006 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -95,7 +95,7 @@ export type BeaconPreset = { PENDING_BALANCE_DEPOSITS_LIMIT: number; PENDING_PARTIAL_WITHDRAWALS_LIMIT: number; PENDING_CONSOLIDATIONS_LIMIT: number; - MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: number; + MAX_CONSOLIDATIONS: number; WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: number; }; @@ -195,7 +195,7 @@ export const beaconPresetTypes: BeaconPresetTypes = { PENDING_BALANCE_DEPOSITS_LIMIT: "number", PENDING_PARTIAL_WITHDRAWALS_LIMIT: "number", PENDING_CONSOLIDATIONS_LIMIT: "number", - MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: "number", + MAX_CONSOLIDATIONS: "number", WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: "number", }; diff --git a/packages/state-transition/src/block/processAttestationPhase0.ts b/packages/state-transition/src/block/processAttestationPhase0.ts index 3bb5b71fa267..ab21841069ec 100644 --- a/packages/state-transition/src/block/processAttestationPhase0.ts +++ b/packages/state-transition/src/block/processAttestationPhase0.ts @@ -1,5 +1,5 @@ import {toRootHex} from "@lodestar/utils"; -import {Slot, allForks, electra, phase0, ssz} from "@lodestar/types"; +import {Slot, Attestation, electra, phase0, ssz} from "@lodestar/types"; import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH, ForkSeq} from "@lodestar/params"; import {assert} from "@lodestar/utils"; import {computeEpochAtSlot} from "../util/index.js"; @@ -56,11 +56,7 @@ export function processAttestationPhase0( } } -export function validateAttestation( - fork: ForkSeq, - state: CachedBeaconStateAllForks, - attestation: allForks.Attestation -): void { +export function validateAttestation(fork: ForkSeq, state: CachedBeaconStateAllForks, attestation: Attestation): void { const {epochCtx} = state; const slot = state.slot; const data = attestation.data; diff --git a/packages/state-transition/src/block/processAttestations.ts b/packages/state-transition/src/block/processAttestations.ts index 991ba5621905..844bda768570 100644 --- a/packages/state-transition/src/block/processAttestations.ts +++ b/packages/state-transition/src/block/processAttestations.ts @@ -1,4 +1,4 @@ -import {allForks} from "@lodestar/types"; +import {Attestation} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../types.js"; import {processAttestationPhase0} from "./processAttestationPhase0.js"; @@ -10,7 +10,7 @@ import {processAttestationsAltair} from "./processAttestationsAltair.js"; export function processAttestations( fork: ForkSeq, state: CachedBeaconStateAllForks, - attestations: allForks.Attestation[], + attestations: Attestation[], verifySignatures = true ): void { if (fork === ForkSeq.phase0) { diff --git a/packages/state-transition/src/block/processAttestationsAltair.ts b/packages/state-transition/src/block/processAttestationsAltair.ts index 48d304c08133..f3d4a3e16c21 100644 --- a/packages/state-transition/src/block/processAttestationsAltair.ts +++ b/packages/state-transition/src/block/processAttestationsAltair.ts @@ -1,5 +1,5 @@ import {byteArrayEquals} from "@chainsafe/ssz"; -import {Epoch, allForks, phase0} from "@lodestar/types"; +import {Epoch, Attestation, phase0} from "@lodestar/types"; import {intSqrt} from "@lodestar/utils"; import { @@ -32,7 +32,7 @@ const SLOTS_PER_EPOCH_SQRT = intSqrt(SLOTS_PER_EPOCH); export function processAttestationsAltair( fork: ForkSeq, state: CachedBeaconStateAltair, - attestations: allForks.Attestation[], + attestations: Attestation[], verifySignature = true ): void { const {epochCtx} = state; diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 1f95da1ad5fc..cf463a93a92b 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -9,7 +9,8 @@ import { ValidatorIndex, phase0, SyncPeriod, - allForks, + Attestation, + IndexedAttestation, electra, } from "@lodestar/types"; import {createBeaconConfig, BeaconConfig, ChainConfig} from "@lodestar/config"; @@ -798,7 +799,7 @@ export class EpochCache { /** * Return the indexed attestation corresponding to ``attestation``. */ - getIndexedAttestation(fork: ForkSeq, attestation: allForks.Attestation): allForks.IndexedAttestation { + getIndexedAttestation(fork: ForkSeq, attestation: Attestation): IndexedAttestation { const {data} = attestation; const attestingIndices = this.getAttestingIndices(fork, attestation); @@ -814,7 +815,7 @@ export class EpochCache { /** * Return indices of validators who attestested in `attestation` */ - getAttestingIndices(fork: ForkSeq, attestation: allForks.Attestation): number[] { + getAttestingIndices(fork: ForkSeq, attestation: Attestation): number[] { if (fork < ForkSeq.electra) { const {aggregationBits, data} = attestation; const validatorIndices = this.getBeaconCommittee(data.slot, data.index); diff --git a/packages/state-transition/src/signatureSets/attesterSlashings.ts b/packages/state-transition/src/signatureSets/attesterSlashings.ts index 10e7a1991e4f..8088c2522282 100644 --- a/packages/state-transition/src/signatureSets/attesterSlashings.ts +++ b/packages/state-transition/src/signatureSets/attesterSlashings.ts @@ -1,4 +1,4 @@ -import {SignedBeaconBlock, ssz} from "@lodestar/types"; +import {SignedBeaconBlock, ssz, AttesterSlashing, IndexedAttestationBigint} from "@lodestar/types"; import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; import {computeSigningRoot, computeStartSlotAtEpoch, ISignatureSet, SignatureSetType} from "../util/index.js"; import {CachedBeaconStateAllForks} from "../types.js"; @@ -16,7 +16,7 @@ export function getAttesterSlashingsSignatureSets( /** Get signature sets from a single AttesterSlashing object */ export function getAttesterSlashingSignatureSets( state: CachedBeaconStateAllForks, - attesterSlashing: allForks.AttesterSlashing + attesterSlashing: AttesterSlashing ): ISignatureSet[] { return [attesterSlashing.attestation1, attesterSlashing.attestation2].map((attestation) => getIndexedAttestationBigintSignatureSet(state, attestation) @@ -25,7 +25,7 @@ export function getAttesterSlashingSignatureSets( export function getIndexedAttestationBigintSignatureSet( state: CachedBeaconStateAllForks, - indexedAttestation: allForks.IndexedAttestationBigint + indexedAttestation: IndexedAttestationBigint ): ISignatureSet { const slot = computeStartSlotAtEpoch(Number(indexedAttestation.data.target.epoch as bigint)); const domain = state.config.getDomain(state.slot, DOMAIN_BEACON_ATTESTER, slot); diff --git a/packages/state-transition/src/util/epoch.ts b/packages/state-transition/src/util/epoch.ts index b9b911137fd9..66bd2ad76b34 100644 --- a/packages/state-transition/src/util/epoch.ts +++ b/packages/state-transition/src/util/epoch.ts @@ -1,5 +1,5 @@ import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, GENESIS_EPOCH, MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {BeaconState, Epoch, Slot, SyncPeriod} from "@lodestar/types"; +import {BeaconState, Epoch, Slot, SyncPeriod, Gwei} from "@lodestar/types"; import {CachedBeaconStateElectra} from "../types.js"; import {getActivationExitChurnLimit, getConsolidationChurnLimit} from "./validator.js"; diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index f02a1a27aefe..0df4f4893350 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -17,7 +17,7 @@ import { MAX_ATTESTATIONS_ELECTRA, MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, - MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, PENDING_BALANCE_DEPOSITS_LIMIT, PENDING_PARTIAL_WITHDRAWALS_LIMIT, PENDING_CONSOLIDATIONS_LIMIT, @@ -142,10 +142,7 @@ export const ConsolidationRequest = new ContainerType( }, {typeName: "ConsolidationRequest", jsonCase: "eth2"} ); -export const ConsolidationRequests = new ListCompositeType( - ConsolidationRequest, - MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD -); +export const ConsolidationRequests = new ListCompositeType(ConsolidationRequest, MAX_CONSOLIDATIONS); export const ExecutionPayload = new ContainerType( { diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 73cb84f5eab6..5f2cc7b72b15 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -37,6 +37,11 @@ type TypesByFork = { SignedBeaconBlock: phase0.SignedBeaconBlock; Metadata: phase0.Metadata; Attestation: phase0.Attestation; + IndexedAttestation: phase0.IndexedAttestation; + IndexedAttestationBigint: phase0.IndexedAttestationBigint; + AttesterSlashing: phase0.AttesterSlashing; + AggregateAndProof: phase0.AggregateAndProof; + SignedAggregateAndProof: phase0.SignedAggregateAndProof; }; [ForkName.altair]: { BeaconBlockHeader: phase0.BeaconBlockHeader; @@ -55,6 +60,11 @@ type TypesByFork = { SyncCommittee: altair.SyncCommittee; SyncAggregate: altair.SyncAggregate; Attestation: phase0.Attestation; + IndexedAttestation: phase0.IndexedAttestation; + IndexedAttestationBigint: phase0.IndexedAttestationBigint; + AttesterSlashing: phase0.AttesterSlashing; + AggregateAndProof: phase0.AggregateAndProof; + SignedAggregateAndProof: phase0.SignedAggregateAndProof; }; [ForkName.bellatrix]: { BeaconBlockHeader: phase0.BeaconBlockHeader; @@ -81,6 +91,11 @@ type TypesByFork = { SyncCommittee: altair.SyncCommittee; SyncAggregate: altair.SyncAggregate; Attestation: phase0.Attestation; + IndexedAttestation: phase0.IndexedAttestation; + IndexedAttestationBigint: phase0.IndexedAttestationBigint; + AttesterSlashing: phase0.AttesterSlashing; + AggregateAndProof: phase0.AggregateAndProof; + SignedAggregateAndProof: phase0.SignedAggregateAndProof; }; [ForkName.capella]: { BeaconBlockHeader: phase0.BeaconBlockHeader; @@ -107,6 +122,11 @@ type TypesByFork = { SyncCommittee: altair.SyncCommittee; SyncAggregate: altair.SyncAggregate; Attestation: phase0.Attestation; + IndexedAttestation: phase0.IndexedAttestation; + IndexedAttestationBigint: phase0.IndexedAttestationBigint; + AttesterSlashing: phase0.AttesterSlashing; + AggregateAndProof: phase0.AggregateAndProof; + SignedAggregateAndProof: phase0.SignedAggregateAndProof; }; [ForkName.deneb]: { BeaconBlockHeader: phase0.BeaconBlockHeader; @@ -138,6 +158,11 @@ type TypesByFork = { SyncCommittee: altair.SyncCommittee; SyncAggregate: altair.SyncAggregate; Attestation: phase0.Attestation; + IndexedAttestation: phase0.IndexedAttestation; + IndexedAttestationBigint: phase0.IndexedAttestationBigint; + AttesterSlashing: phase0.AttesterSlashing; + AggregateAndProof: phase0.AggregateAndProof; + SignedAggregateAndProof: phase0.SignedAggregateAndProof; }; [ForkName.electra]: { BeaconBlockHeader: phase0.BeaconBlockHeader; @@ -173,6 +198,11 @@ type TypesByFork = { SyncCommittee: altair.SyncCommittee; SyncAggregate: altair.SyncAggregate; Attestation: electra.Attestation; + IndexedAttestation: electra.IndexedAttestation; + IndexedAttestationBigint: electra.IndexedAttestationBigint; + AttesterSlashing: electra.AttesterSlashing; + AggregateAndProof: electra.AggregateAndProof; + SignedAggregateAndProof: electra.SignedAggregateAndProof; }; }; @@ -233,3 +263,8 @@ export type SignedBuilderBid = TypesByF export type SSEPayloadAttributes = TypesByFork[F]["SSEPayloadAttributes"]; export type Attestation = TypesByFork[F]["Attestation"]; +export type IndexedAttestation = TypesByFork[F]["IndexedAttestation"]; +export type IndexedAttestationBigint = TypesByFork[F]["IndexedAttestationBigint"]; +export type AttesterSlashing = TypesByFork[F]["AttesterSlashing"]; +export type AggregateAndProof = TypesByFork[F]["AggregateAndProof"]; +export type SignedAggregateAndProof = TypesByFork[F]["SignedAggregateAndProof"]; diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index 61bd169afeda..4f33368e6581 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -1,5 +1,5 @@ import {toHexString} from "@chainsafe/ssz"; -import {allForks, BLSSignature, phase0, Slot, ssz} from "@lodestar/types"; +import {BLSSignature, phase0, Slot, ssz, Attestation, SignedAggregateAndProof} from "@lodestar/types"; import {computeEpochAtSlot, isAggregatorFromCommitteeLength} from "@lodestar/state-transition"; import {sleep} from "@lodestar/utils"; import {ApiClient, routes} from "@lodestar/api"; @@ -193,7 +193,7 @@ export class AttestationService { attestationNoCommittee: phase0.AttestationData, duties: AttDutyAndProof[] ): Promise { - const signedAttestations: allForks.Attestation[] = []; + const signedAttestations: Attestation[] = []; const headRootHex = toHexString(attestationNoCommittee.beaconBlockRoot); const currentEpoch = computeEpochAtSlot(slot); const isAfterElectra = currentEpoch >= this.config.ELECTRA_FORK_EPOCH; @@ -277,7 +277,7 @@ export class AttestationService { const aggregate = res.value(); this.metrics?.numParticipantsInAggregate.observe(aggregate.aggregationBits.getTrueBitIndexes().length); - const signedAggregateAndProofs: allForks.SignedAggregateAndProof[] = []; + const signedAggregateAndProofs: SignedAggregateAndProof[] = []; await Promise.all( duties.map(async ({duty, selectionProof}) => { diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index a85dd52a7c0d..cea281f0d144 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -37,6 +37,9 @@ import { Slot, ssz, ValidatorIndex, + Attestation, + AggregateAndProof, + SignedAggregateAndProof, } from "@lodestar/types"; import {routes} from "@lodestar/api"; import {ISlashingProtection} from "../slashingProtection/index.js"; @@ -495,7 +498,7 @@ export class ValidatorStore { duty: routes.validator.AttesterDuty, attestationData: phase0.AttestationData, currentEpoch: Epoch - ): Promise { + ): Promise { // Make sure the target epoch is not higher than the current epoch to avoid potential attacks. if (attestationData.target.epoch > currentEpoch) { throw Error( @@ -546,11 +549,11 @@ export class ValidatorStore { async signAggregateAndProof( duty: routes.validator.AttesterDuty, selectionProof: BLSSignature, - aggregate: allForks.Attestation - ): Promise { + aggregate: Attestation + ): Promise { this.validateAttestationDuty(duty, aggregate.data); - const aggregateAndProof: allForks.AggregateAndProof = { + const aggregateAndProof: AggregateAndProof = { aggregate, aggregatorIndex: duty.validatorIndex, selectionProof, diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index d5369515d47b..3a497555361a 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -234,7 +234,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Mon, 1 Jul 2024 15:05:37 +0530 Subject: [PATCH 065/259] feat: add and parse consolidation requests from engine api get the signing log --- .../src/execution/engine/payloadIdCache.ts | 6 +++ .../beacon-node/src/execution/engine/types.ts | 46 +++++++++++++++++-- packages/validator/src/services/block.ts | 2 +- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index 8cb5b4e4f8e9..005a1ef14322 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -32,6 +32,12 @@ export type WithdrawalRequestV1 = { amount: QUANTITY; }; +export type ConsolidationRequestV1 = { + sourceAddress: DATA; + sourcePubkey: DATA; + targetPubkey: DATA; +}; + type FcuAttributes = {headBlockHash: DATA; finalizedBlockHash: DATA} & Omit; export class PayloadIdCache { diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 6b37f3854b8f..63cb4da88b6c 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -17,7 +17,7 @@ import { quantityToBigint, } from "../../eth1/provider/utils.js"; import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js"; -import {WithdrawalV1, DepositRequestV1, WithdrawalRequestV1} from "./payloadIdCache.js"; +import {WithdrawalV1, DepositRequestV1, WithdrawalRequestV1, ConsolidationRequestV1} from "./payloadIdCache.js"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -133,6 +133,7 @@ export type ExecutionPayloadBodyRpc = { // its likely CL receipt will be renamed to requests depositRequests: DepositRequestV1[] | null | undefined; withdrawalRequests: WithdrawalRequestV1[] | null | undefined; + consolidationRequests: ConsolidationRequestV1[] | null | undefined; }; export type ExecutionPayloadBody = { @@ -140,6 +141,7 @@ export type ExecutionPayloadBody = { withdrawals: capella.Withdrawals | null; depositRequests: electra.DepositRequests | null; withdrawalRequests: electra.WithdrawalRequests | null; + consolidationRequests: electra.ConsolidationRequests | null; }; export type ExecutionPayloadRpc = { @@ -163,6 +165,7 @@ export type ExecutionPayloadRpc = { parentBeaconBlockRoot?: QUANTITY; // DENEB depositRequests?: DepositRequestRpc[]; // ELECTRA withdrawalRequests?: WithdrawalRequestRpc[]; // ELECTRA + consolidationRequests?: ConsolidationRequestRpc[]; // ELECTRA }; export type WithdrawalRpc = { @@ -174,6 +177,7 @@ export type WithdrawalRpc = { export type DepositRequestRpc = DepositRequestV1; export type WithdrawalRequestRpc = WithdrawalRequestV1; +export type ConsolidationRequestRpc = ConsolidationRequestV1; export type VersionedHashesRpc = DATA[]; @@ -239,9 +243,10 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload // ELECTRA adds depositRequests/depositRequests to the ExecutionPayload if (ForkSeq[fork] >= ForkSeq.electra) { - const {depositRequests, withdrawalRequests} = data as electra.ExecutionPayload; + const {depositRequests, withdrawalRequests, consolidationRequests} = data as electra.ExecutionPayload; payload.depositRequests = depositRequests.map(serializeDepositRequest); payload.withdrawalRequests = withdrawalRequests.map(serializeWithdrawalRequest); + payload.consolidationRequests = consolidationRequests.map(serializeConsolidationRequest); } return payload; @@ -331,7 +336,7 @@ export function parseExecutionPayload( if (ForkSeq[fork] >= ForkSeq.electra) { // electra adds depositRequests/depositRequests - const {depositRequests, withdrawalRequests} = data; + const {depositRequests, withdrawalRequests, consolidationRequests} = data; // Geth can also reply with null if (depositRequests == null) { throw Error( @@ -347,6 +352,15 @@ export function parseExecutionPayload( } (executionPayload as electra.ExecutionPayload).withdrawalRequests = withdrawalRequests.map(deserializeWithdrawalRequest); + + if (consolidationRequests == null) { + throw Error( + `consolidationRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` + ); + } + (executionPayload as electra.ExecutionPayload).consolidationRequests = consolidationRequests.map( + deserializeConsolidationRequest + ); } return {executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder}; @@ -451,6 +465,26 @@ export function deserializeWithdrawalRequest(withdrawalRequest: WithdrawalReques }; } +export function serializeConsolidationRequest( + consolidationRequest: electra.ConsolidationRequest +): ConsolidationRequestRpc { + return { + sourceAddress: bytesToData(consolidationRequest.sourceAddress), + sourcePubkey: bytesToData(consolidationRequest.sourcePubkey), + targetPubkey: bytesToData(consolidationRequest.targetPubkey), + }; +} + +export function deserializeConsolidationRequest( + consolidationRequest: ConsolidationRequestRpc +): electra.ConsolidationRequest { + return { + sourceAddress: dataToBytes(consolidationRequest.sourceAddress, 20), + sourcePubkey: dataToBytes(consolidationRequest.sourcePubkey, 48), + targetPubkey: dataToBytes(consolidationRequest.targetPubkey, 48), + }; +} + export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | null): ExecutionPayloadBody | null { return data ? { @@ -458,6 +492,9 @@ export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null, depositRequests: data.depositRequests ? data.depositRequests.map(deserializeDepositRequest) : null, withdrawalRequests: data.withdrawalRequests ? data.withdrawalRequests.map(deserializeWithdrawalRequest) : null, + consolidationRequests: data.consolidationRequests + ? data.consolidationRequests.map(deserializeConsolidationRequest) + : null, } : null; } @@ -469,6 +506,9 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null) withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null, depositRequests: data.depositRequests ? data.depositRequests.map(serializeDepositRequest) : null, withdrawalRequests: data.withdrawalRequests ? data.withdrawalRequests.map(serializeWithdrawalRequest) : null, + consolidationRequests: data.consolidationRequests + ? data.consolidationRequests.map(serializeConsolidationRequest) + : null, } : null; } diff --git a/packages/validator/src/services/block.ts b/packages/validator/src/services/block.ts index a9dd7654a8fc..7792ef85be95 100644 --- a/packages/validator/src/services/block.ts +++ b/packages/validator/src/services/block.ts @@ -160,7 +160,7 @@ export class BlockProposingService { this.logger.debug("Produced block", {...debugLogCtx, ...blockContents.debugLogCtx}); this.metrics?.blocksProduced.inc(); - const signedBlock = await this.validatorStore.signBlock(pubkey, blockContents.block, slot); + const signedBlock = await this.validatorStore.signBlock(pubkey, blockContents.block, slot, this.logger); const {broadcastValidation} = this.opts; const publishOpts = {broadcastValidation}; From 08445fd9406b52374f37b76cf6b580be747dfa64 Mon Sep 17 00:00:00 2001 From: gajinder Date: Mon, 1 Jul 2024 20:01:27 +0530 Subject: [PATCH 066/259] feat: make produce block/signed block contents api multifork --- packages/api/src/beacon/routes/validator.ts | 16 +++++----------- packages/types/src/electra/sszTypes.ts | 18 ++++++++++++++++++ packages/types/src/electra/types.ts | 3 +++ packages/types/src/types.ts | 8 ++------ 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index 154397107d47..86d4c6930951 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -83,15 +83,6 @@ export type ProduceBlockV3Meta = ValueOf & { executionPayloadSource: ProducedBlockSource; }; -export const BlockContentsType = new ContainerType( - { - block: ssz.deneb.BeaconBlock, - kzgProofs: ssz.deneb.KZGProofs, - blobs: ssz.deneb.Blobs, - }, - {jsonCase: "eth2"} -); - export const AttesterDutyType = new ContainerType( { /** The validator's public key, uniquely identifying them */ @@ -630,7 +621,10 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions (isForkBlobs(fork) ? BlockContentsType : ssz[fork].BeaconBlock) as Type + (fork) => + (isForkBlobs(fork) + ? ssz.allForksBlobs[fork].BlockContents + : ssz[fork].BeaconBlock) as Type ), meta: VersionCodec, }, @@ -693,7 +687,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ), meta: { diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 0df4f4893350..7ccbd16d8e9e 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -417,3 +417,21 @@ export const SSEPayloadAttributes = new ContainerType( }, {typeName: "SSEPayloadAttributes", jsonCase: "eth2"} ); + +export const BlockContents = new ContainerType( + { + block: BeaconBlock, + kzgProofs: denebSsz.KZGProofs, + blobs: denebSsz.Blobs, + }, + {typeName: "BlockContents", jsonCase: "eth2"} +); + +export const SignedBlockContents = new ContainerType( + { + signedBlock: SignedBeaconBlock, + kzgProofs: denebSsz.KZGProofs, + blobs: denebSsz.Blobs, + }, + {typeName: "BlockContents", jsonCase: "eth2"} +); diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index 728ffc56ac83..9a81aec43b53 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -49,3 +49,6 @@ export type LightClientStore = ValueOf; export type PendingBalanceDeposit = ValueOf; export type PendingPartialWithdrawal = ValueOf; export type PendingConsolidation = ValueOf; + +export type BlockContents = ValueOf; +export type SignedBlockContents = ValueOf; diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 5f2cc7b72b15..1071eed79a10 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -186,12 +186,8 @@ type TypesByFork = { BuilderBid: electra.BuilderBid; SignedBuilderBid: electra.SignedBuilderBid; SSEPayloadAttributes: electra.SSEPayloadAttributes; - BlockContents: {block: BeaconBlock; kzgProofs: deneb.KZGProofs; blobs: deneb.Blobs}; - SignedBlockContents: { - signedBlock: SignedBeaconBlock; - kzgProofs: deneb.KZGProofs; - blobs: deneb.Blobs; - }; + BlockContents: electra.BlockContents; + SignedBlockContents: electra.SignedBlockContents; ExecutionPayloadAndBlobsBundle: deneb.ExecutionPayloadAndBlobsBundle; BlobsBundle: deneb.BlobsBundle; Contents: deneb.Contents; From 3a98b2f026f6a3fa657cae39ec5edbe719b757b2 Mon Sep 17 00:00:00 2001 From: harkamal Date: Mon, 1 Jul 2024 22:40:56 +0530 Subject: [PATCH 067/259] fix: electra rebase fixes on the allforks type refactor tests fixes --- packages/api/src/beacon/routes/validator.ts | 7 +++---- packages/beacon-node/src/network/gossip/topic.ts | 6 +++--- .../src/network/processor/gossipHandlers.ts | 4 ++-- packages/beacon-node/src/util/sszBytes.ts | 10 +++++++--- .../beacon-node/test/spec/presets/fork_choice.test.ts | 4 ++-- .../beacon-node/test/spec/presets/operations.test.ts | 4 ++-- .../beacon-node/test/spec/presets/ssz_static.test.ts | 5 ----- .../test/unit/executionEngine/http.test.ts | 4 ++++ .../network/beaconBlocksMaybeBlobsByRange.test.ts | 2 +- packages/light-client/src/spec/utils.ts | 2 ++ packages/params/src/index.ts | 4 ++-- packages/params/src/presets/mainnet.ts | 4 ++-- packages/params/src/presets/minimal.ts | 4 ++-- packages/params/src/types.ts | 8 ++++---- .../params/test/e2e/ensure-config-is-synced.test.ts | 2 +- packages/types/src/electra/sszTypes.ts | 11 +++++++---- packages/types/test/unit/blinded.test.ts | 2 +- packages/validator/src/util/params.ts | 4 ++-- 18 files changed, 47 insertions(+), 40 deletions(-) diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index 86d4c6930951..c0078c97d5f8 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -18,6 +18,7 @@ import { BeaconBlockOrContents, BlindedBeaconBlock, Attestation, + sszTypesFor, } from "@lodestar/types"; import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import {fromGraffitiHex, toBoolean, toGraffitiHex} from "../../utils/serdes.js"; @@ -622,9 +623,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions - (isForkBlobs(fork) - ? ssz.allForksBlobs[fork].BlockContents - : ssz[fork].BeaconBlock) as Type + (isForkBlobs(fork) ? sszTypesFor(fork).BlockContents : ssz[fork].BeaconBlock) as Type ), meta: VersionCodec, }, @@ -687,7 +686,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ), meta: { diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index 2ccde0044037..dfca0eaf3dcd 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -87,9 +87,9 @@ export function getGossipSSZType(topic: GossipTopic) { case GossipType.blob_sidecar: return ssz.deneb.BlobSidecar; case GossipType.beacon_aggregate_and_proof: - return ssz.allForks[topic.fork].SignedAggregateAndProof; + return sszTypesFor(topic.fork).SignedAggregateAndProof; case GossipType.beacon_attestation: - return ssz.allForks[topic.fork].Attestation; + return sszTypesFor(topic.fork).Attestation; case GossipType.proposer_slashing: return ssz.phase0.ProposerSlashing; case GossipType.attester_slashing: @@ -129,7 +129,7 @@ export function sszDeserialize(topic: T, serializedData: * Deserialize a gossip serialized data into an Attestation object. */ export function sszDeserializeAttestation(fork: ForkName, serializedData: Uint8Array): Attestation { - const sszType = ssz.allForks[fork].Attestation; + const sszType = sszTypesFor(fork).Attestation; try { return sszType.deserialize(serializedData); } catch (e) { diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index 3f2d6368928d..51fa7bd376c8 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -1,6 +1,6 @@ import {BeaconConfig, ChainForkConfig} from "@lodestar/config"; import {LogLevel, Logger, prettyBytes, toRootHex} from "@lodestar/utils"; -import {Root, Slot, ssz, deneb, UintNum64, SignedBeaconBlock} from "@lodestar/types"; +import {Root, Slot, ssz, deneb, UintNum64, SignedBeaconBlock, sszTypesFor} from "@lodestar/types"; import {ForkName, ForkSeq} from "@lodestar/params"; import {routes} from "@lodestar/api"; import {computeTimeAtSlot} from "@lodestar/state-transition"; @@ -422,7 +422,7 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler } catch (e) { if (e instanceof AttestationError && e.action === GossipAction.REJECT) { chain.persistInvalidSszValue( - ssz.allForks[fork].SignedAggregateAndProof, + sszTypesFor(fork).SignedAggregateAndProof, signedAggregateAndProof, "gossip_reject" ); diff --git a/packages/beacon-node/src/util/sszBytes.ts b/packages/beacon-node/src/util/sszBytes.ts index bac66ddf3a0d..89f1dd20a473 100644 --- a/packages/beacon-node/src/util/sszBytes.ts +++ b/packages/beacon-node/src/util/sszBytes.ts @@ -230,14 +230,18 @@ export function getSeenAttDataKeyFromSignedAggregateAndProof( */ export function getSeenAttDataKeyFromSignedAggregateAndProofElectra(data: Uint8Array): SeenAttDataKey | null { const startIndex = SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET; - const endIndex = startIndex + ATTESTATION_DATA_SIZE + COMMITTEE_BITS_SIZE; + const endIndex = startIndex + ATTESTATION_DATA_SIZE; - if (data.length < endIndex) { + if (data.length < endIndex + SIGNATURE_SIZE + COMMITTEE_BITS_SIZE) { return null; } // base64 is a bit efficient than hex - return toBase64(data.subarray(startIndex, endIndex)); + + return Buffer.concat([ + data.subarray(startIndex, endIndex), + data.subarray(endIndex + SIGNATURE_SIZE, endIndex + SIGNATURE_SIZE + COMMITTEE_BITS_SIZE), + ]).toString("base64"); } /** 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 9f8d5c727879..01adcc77500b 100644 --- a/packages/beacon-node/test/spec/presets/fork_choice.test.ts +++ b/packages/beacon-node/test/spec/presets/fork_choice.test.ts @@ -343,8 +343,8 @@ const forkChoiceTest = [BLOCK_FILE_NAME]: ssz[fork].SignedBeaconBlock, [BLOBS_FILE_NAME]: ssz.deneb.Blobs, [POW_BLOCK_FILE_NAME]: ssz.bellatrix.PowBlock, - [ATTESTATION_FILE_NAME]: ssz.allForks[fork].Attestation, - [ATTESTER_SLASHING_FILE_NAME]: ssz.allForks[fork].AttesterSlashing, + [ATTESTATION_FILE_NAME]: ssz.phase0.Attestation, + [ATTESTER_SLASHING_FILE_NAME]: ssz.phase0.AttesterSlashing, }, mapToTestCase: (t: Record) => { // t has input file name as key diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index 1128cdd11ba9..24f51b05c4f6 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -135,8 +135,8 @@ const operations: TestRunnerFn = (fork, sszTypes: { pre: ssz[fork].BeaconState, post: ssz[fork].BeaconState, - attestation: ssz.allForks[fork].Attestation, - attester_slashing: ssz.allForks[fork].AttesterSlashing, + attestation: ssz.phase0.Attestation, + attester_slashing: ssz.phase0.AttesterSlashing, block: ssz[fork].BeaconBlock, body: ssz[fork].BeaconBlockBody, deposit: ssz.phase0.Deposit, diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index bf7a3b5aad06..6e43d851ef66 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -2,13 +2,8 @@ import fs from "node:fs"; import path from "node:path"; import {expect, it, vi} from "vitest"; import {Type} from "@chainsafe/ssz"; -<<<<<<< HEAD import {ssz, sszTypesFor} from "@lodestar/types"; import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; -======= -import {ssz} from "@lodestar/types"; -import {ACTIVE_PRESET, ForkName, ForkLightClient, ForkExecution} from "@lodestar/params"; ->>>>>>> 82d0692d63d (test: fix ssz_static spec tests for all forks (#6771)) import {replaceUintTypeWithUintBigintType} from "../utils/replaceUintTypeWithUintBigintType.js"; import {parseSszStaticTestcase} from "../utils/sszTestCaseParser.js"; import {runValidSszTest} from "../utils/runValidSszTest.js"; diff --git a/packages/beacon-node/test/unit/executionEngine/http.test.ts b/packages/beacon-node/test/unit/executionEngine/http.test.ts index 90ca6595d8a2..5ac4fd4ca670 100644 --- a/packages/beacon-node/test/unit/executionEngine/http.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/http.test.ts @@ -195,6 +195,7 @@ describe("ExecutionEngine / http", () => { ], depositRequests: null, // depositRequests is null pre-electra withdrawalRequests: null, + consolidationRequests: null, }, null, // null returned for missing blocks { @@ -205,6 +206,7 @@ describe("ExecutionEngine / http", () => { withdrawals: null, // withdrawals is null pre-capella depositRequests: null, // depositRequests is null pre-electra withdrawalRequests: null, + consolidationRequests: null, }, ], }; @@ -254,6 +256,7 @@ describe("ExecutionEngine / http", () => { ], depositRequests: null, // depositRequests is null pre-electra withdrawalRequests: null, + consolidationRequests: null, }, null, // null returned for missing blocks { @@ -264,6 +267,7 @@ describe("ExecutionEngine / http", () => { withdrawals: null, // withdrawals is null pre-capella depositRequests: null, // depositRequests is null pre-electra withdrawalRequests: null, + consolidationRequests: null, }, ], }; diff --git a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts index c7de35d468df..d1dc7ba57fa9 100644 --- a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts +++ b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts @@ -102,7 +102,7 @@ describe("beaconBlocksMaybeBlobsByRange", () => { const expectedResponse = blocksWithBlobs.map(([block, blobSidecars]) => { const blobs = blobSidecars !== undefined ? blobSidecars : []; return getBlockInput.availableData(config, block, BlockSource.byRange, null, { - fork: ForkName.deneb, + fork: ForkName.electra, blobs, blobsSource: BlobsSource.byRange, blobsBytes: blobs.map(() => null), diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 679371a54d6c..3e59cb14cfa0 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -119,6 +119,8 @@ export function upgradeLightClientHeader( ssz.electra.LightClientHeader.fields.execution.fields.depositRequestsRoot.defaultValue(); (upgradedHeader as LightClientHeader).execution.withdrawalRequestsRoot = ssz.electra.LightClientHeader.fields.execution.fields.withdrawalRequestsRoot.defaultValue(); + (upgradedHeader as LightClientHeader).execution.consolidationRequestsRoot = + ssz.electra.LightClientHeader.fields.execution.fields.consolidationRequestsRoot.defaultValue(); // Break if no further upgrades is required else fall through if (ForkSeq[targetFork] <= ForkSeq.electra) break; diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 0c2e3b34794b..00e9d48346c1 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -100,9 +100,9 @@ export const { PENDING_PARTIAL_WITHDRAWALS_LIMIT, PENDING_CONSOLIDATIONS_LIMIT, MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA, - MAX_CONSOLIDATIONS, + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, - MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_DEPOSIT_REQUESTS_PER_PAYLOAD, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_ATTESTATIONS_ELECTRA, diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 2495f7ef97a1..a4a88aac1f58 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -120,7 +120,7 @@ export const mainnetPreset: BeaconPreset = { KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 17, // ELECTRA - MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192, + MAX_DEPOSIT_REQUESTS_PER_PAYLOAD: 8192, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 16, MAX_ATTESTER_SLASHINGS_ELECTRA: 1, MAX_ATTESTATIONS_ELECTRA: 8, @@ -133,6 +133,6 @@ export const mainnetPreset: BeaconPreset = { PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, PENDING_PARTIAL_WITHDRAWALS_LIMIT: 134217728, PENDING_CONSOLIDATIONS_LIMIT: 262144, - MAX_CONSOLIDATIONS: 1, + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1, WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: 4096, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 8e71407965d7..97eff53cf013 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -121,7 +121,7 @@ export const minimalPreset: BeaconPreset = { KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 9, // ELECTRA - MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 4, + MAX_DEPOSIT_REQUESTS_PER_PAYLOAD: 4, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 2, MAX_ATTESTER_SLASHINGS_ELECTRA: 1, MAX_ATTESTATIONS_ELECTRA: 8, @@ -134,6 +134,6 @@ export const minimalPreset: BeaconPreset = { PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, PENDING_PARTIAL_WITHDRAWALS_LIMIT: 64, PENDING_CONSOLIDATIONS_LIMIT: 64, - MAX_CONSOLIDATIONS: 1, + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1, WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: 4096, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index dffd98518006..e867b4a3cf71 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -84,7 +84,7 @@ export type BeaconPreset = { KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: number; // ELECTRA - MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: number; + MAX_DEPOSIT_REQUESTS_PER_PAYLOAD: number; MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: number; MAX_ATTESTER_SLASHINGS_ELECTRA: number; MAX_ATTESTATIONS_ELECTRA: number; @@ -95,7 +95,7 @@ export type BeaconPreset = { PENDING_BALANCE_DEPOSITS_LIMIT: number; PENDING_PARTIAL_WITHDRAWALS_LIMIT: number; PENDING_CONSOLIDATIONS_LIMIT: number; - MAX_CONSOLIDATIONS: number; + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: number; WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: number; }; @@ -184,7 +184,7 @@ export const beaconPresetTypes: BeaconPresetTypes = { KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: "number", // ELECTRA - MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: "number", + MAX_DEPOSIT_REQUESTS_PER_PAYLOAD: "number", MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: "number", MAX_ATTESTER_SLASHINGS_ELECTRA: "number", MAX_ATTESTATIONS_ELECTRA: "number", @@ -195,7 +195,7 @@ export const beaconPresetTypes: BeaconPresetTypes = { PENDING_BALANCE_DEPOSITS_LIMIT: "number", PENDING_PARTIAL_WITHDRAWALS_LIMIT: "number", PENDING_CONSOLIDATIONS_LIMIT: "number", - MAX_CONSOLIDATIONS: "number", + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: "number", WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: "number", }; diff --git a/packages/params/test/e2e/ensure-config-is-synced.test.ts b/packages/params/test/e2e/ensure-config-is-synced.test.ts index 515d8f44a710..38168fa02bae 100644 --- a/packages/params/test/e2e/ensure-config-is-synced.test.ts +++ b/packages/params/test/e2e/ensure-config-is-synced.test.ts @@ -8,7 +8,7 @@ import {loadConfigYaml} from "../yaml.js"; // Not e2e, but slow. Run with e2e tests /** https://github.com/ethereum/consensus-specs/releases */ -const specConfigCommit = "v1.5.0-alpha.2"; +const specConfigCommit = "v1.5.0-alpha.3"; describe("Ensure config is synced", function () { vi.setConfig({testTimeout: 60 * 1000}); diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 7ccbd16d8e9e..a6874c7894e3 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -11,13 +11,13 @@ import { BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, - MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_DEPOSIT_REQUESTS_PER_PAYLOAD, MAX_VALIDATORS_PER_COMMITTEE, MAX_COMMITTEES_PER_SLOT, MAX_ATTESTATIONS_ELECTRA, MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, - MAX_CONSOLIDATIONS, + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, PENDING_BALANCE_DEPOSITS_LIMIT, PENDING_PARTIAL_WITHDRAWALS_LIMIT, PENDING_CONSOLIDATIONS_LIMIT, @@ -123,7 +123,7 @@ export const DepositRequest = new ContainerType( {typeName: "DepositRequest", jsonCase: "eth2"} ); -export const DepositRequests = new ListCompositeType(DepositRequest, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); +export const DepositRequests = new ListCompositeType(DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD); export const WithdrawalRequest = new ContainerType( { @@ -142,7 +142,10 @@ export const ConsolidationRequest = new ContainerType( }, {typeName: "ConsolidationRequest", jsonCase: "eth2"} ); -export const ConsolidationRequests = new ListCompositeType(ConsolidationRequest, MAX_CONSOLIDATIONS); +export const ConsolidationRequests = new ListCompositeType( + ConsolidationRequest, + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD +); export const ExecutionPayload = new ContainerType( { diff --git a/packages/types/test/unit/blinded.test.ts b/packages/types/test/unit/blinded.test.ts index 77005f1defc2..3a4b346d29bf 100644 --- a/packages/types/test/unit/blinded.test.ts +++ b/packages/types/test/unit/blinded.test.ts @@ -10,7 +10,7 @@ describe("blinded data structures", function () { ]; for (const {a, b} of blindedTypes) { - for (const fork of Object.keys(ssz.allForks) as ForkName[]) { + for (const fork of Object.keys(ssz.sszTypesFor) as ForkName[]) { if (!isForkExecution(fork)) { continue; } diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 3a497555361a..6d6705f512df 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -223,7 +223,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Tue, 30 Jul 2024 17:04:58 +0530 Subject: [PATCH 068/259] chore: rebase fixes lint lint and type fix update spec version fix tests fix spec test Update packages/beacon-node/src/chain/stateCache/types.ts Co-authored-by: Cayman Update packages/beacon-node/src/chain/stateCache/types.ts Co-authored-by: Cayman Update packages/beacon-node/src/chain/blocks/types.ts Co-authored-by: Cayman Update packages/types/src/utils/typeguards.ts Co-authored-by: Cayman Variable naming fix the ForkElectra fix build fix spec test Co-authored-by: Cayman --- .../api/test/unit/beacon/oapiSpec.test.ts | 5 ++++ .../src/api/impl/config/constants.ts | 4 +-- .../beacon-node/src/chain/blocks/types.ts | 4 +-- .../opPools/aggregatedAttestationPool.ts | 3 +-- .../beacon-node/src/chain/opPools/opPool.ts | 4 +-- .../beacon-node/src/chain/stateCache/types.ts | 6 +++-- .../signatureSets/aggregateAndProof.ts | 2 +- .../src/execution/engine/interface.ts | 2 -- .../updateUnfinalizedPubkeys.test.ts | 6 ++--- .../test/sim/electra-interop.test.ts | 4 +-- .../test/spec/presets/fork_choice.test.ts | 26 +++++++++++++------ .../test/spec/presets/operations.test.ts | 4 +-- .../opPools/aggregatedAttestationPool.test.ts | 10 +++---- packages/params/src/forkName.ts | 13 ++++++++++ packages/params/src/index.ts | 2 +- .../unit/__snapshots__/forkName.test.ts.snap | 5 ++++ .../src/block/processDeposit.ts | 2 +- .../src/block/processDepositRequest.ts | 4 +-- .../src/slot/upgradeStateToElectra.ts | 10 +++---- packages/state-transition/src/util/electra.ts | 14 +++++----- packages/state-transition/src/util/genesis.ts | 4 +-- packages/types/src/utils/typeguards.ts | 6 ++--- yarn.lock | 14 ++++++++++ 23 files changed, 99 insertions(+), 55 deletions(-) diff --git a/packages/api/test/unit/beacon/oapiSpec.test.ts b/packages/api/test/unit/beacon/oapiSpec.test.ts index e5d473ab6a55..00f1a3d8731d 100644 --- a/packages/api/test/unit/beacon/oapiSpec.test.ts +++ b/packages/api/test/unit/beacon/oapiSpec.test.ts @@ -86,6 +86,11 @@ const ignoredTopics = [ topic block_gossip not implemented */ "block_gossip", + + // Modified in electra to include version + // should be removed from the ignore list after spec update + "attestation", + "attester_slashing", ]; // eventstream types are defined as comments in the description of "examples". diff --git a/packages/beacon-node/src/api/impl/config/constants.ts b/packages/beacon-node/src/api/impl/config/constants.ts index b5f810157581..78262ce15237 100644 --- a/packages/beacon-node/src/api/impl/config/constants.ts +++ b/packages/beacon-node/src/api/impl/config/constants.ts @@ -38,7 +38,7 @@ import { VERSIONED_HASH_VERSION_KZG, COMPOUNDING_WITHDRAWAL_PREFIX, DOMAIN_CONSOLIDATION, - UNSET_DEPOSIT_RECEIPTS_START_INDEX, + UNSET_DEPOSIT_REQUESTS_START_INDEX, FULL_EXIT_REQUEST_AMOUNT, } from "@lodestar/params"; @@ -108,6 +108,6 @@ export const specConstants = { VERSIONED_HASH_VERSION_KZG, // electra - UNSET_DEPOSIT_RECEIPTS_START_INDEX, + UNSET_DEPOSIT_REQUESTS_START_INDEX, FULL_EXIT_REQUEST_AMOUNT, }; diff --git a/packages/beacon-node/src/chain/blocks/types.ts b/packages/beacon-node/src/chain/blocks/types.ts index 5eb5eebc7840..80c94e2d6fde 100644 --- a/packages/beacon-node/src/chain/blocks/types.ts +++ b/packages/beacon-node/src/chain/blocks/types.ts @@ -1,7 +1,7 @@ import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition"; import {MaybeValidExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; import {deneb, Slot, RootHex, SignedBeaconBlock} from "@lodestar/types"; -import {ForkSeq, ForkName} from "@lodestar/params"; +import {ForkSeq, ForkName, ForkBlobs} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; export enum BlockInputType { @@ -36,7 +36,7 @@ export enum GossipedInputType { type BlobsCacheMap = Map; -type ForkBlobsInfo = {fork: ForkName.deneb | ForkName.electra}; +type ForkBlobsInfo = {fork: ForkBlobs}; type BlobsData = {blobs: deneb.BlobSidecars; blobsBytes: (Uint8Array | null)[]; blobsSource: BlobsSource}; export type BlockInputDataBlobs = ForkBlobsInfo & BlobsData; export type BlockInputData = BlockInputDataBlobs; diff --git a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts index 491b5fd6f72a..b3e82c0c6366 100644 --- a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts @@ -1,5 +1,4 @@ -import {aggregateSignatures} from "@chainsafe/blst"; -import {Signature} from "@chainsafe/bls/types"; +import {aggregateSignatures, Signature} from "@chainsafe/blst"; import {BitArray, toHexString} from "@chainsafe/ssz"; import { ForkName, diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index 54fec380de86..fc4558d9d995 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -210,7 +210,7 @@ export class OpPool { const endAttesterSlashings = stepsMetrics?.startTimer(); const attesterSlashings: AttesterSlashing[] = []; - const maxAttesterSlashing = stateFork >= ForkSeq.electra ? MAX_ATTESTER_SLASHINGS_ELECTRA : MAX_ATTESTER_SLASHINGS; + const maxAttesterSlashings = stateFork >= ForkSeq.electra ? MAX_ATTESTER_SLASHINGS_ELECTRA : MAX_ATTESTER_SLASHINGS; attesterSlashing: for (const attesterSlashing of this.attesterSlashings.values()) { /** Indices slashable in this attester slashing */ const slashableIndices = new Set(); @@ -225,7 +225,7 @@ export class OpPool { if (isSlashableAtEpoch(validator, stateEpoch)) { slashableIndices.add(index); } - if (attesterSlashings.length >= maxAttesterSlashing) { + if (attesterSlashings.length >= maxAttesterSlashings) { break attesterSlashing; } } diff --git a/packages/beacon-node/src/chain/stateCache/types.ts b/packages/beacon-node/src/chain/stateCache/types.ts index ad93def481e7..1e8d6bd1bd62 100644 --- a/packages/beacon-node/src/chain/stateCache/types.ts +++ b/packages/beacon-node/src/chain/stateCache/types.ts @@ -33,7 +33,8 @@ export interface BlockStateCache { prune(headStateRootHex: RootHex): void; deleteAllBeforeEpoch(finalizedEpoch: Epoch): void; dumpSummary(): routes.lodestar.StateCacheItem[]; - getStates(): IterableIterator; // Expose beacon states stored in cache. Use with caution + /** Expose beacon states stored in cache. Use with caution */ + getStates(): IterableIterator; } /** @@ -75,7 +76,8 @@ export interface CheckpointStateCache { processState(blockRootHex: RootHex, state: CachedBeaconStateAllForks): Promise; clear(): void; dumpSummary(): routes.lodestar.StateCacheItem[]; - getStates(): IterableIterator; // Expose beacon states stored in cache. Use with caution + /** Expose beacon states stored in cache. Use with caution */ + getStates(): IterableIterator; } export enum CacheItemType { diff --git a/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts index 2945b4d445d0..31d931818595 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts @@ -1,4 +1,4 @@ -import type {PublicKey} from "@chainsafe/bls/types"; +import {PublicKey} from "@chainsafe/blst"; import {DOMAIN_AGGREGATE_AND_PROOF, ForkSeq} from "@lodestar/params"; import {ssz, SignedAggregateAndProof} from "@lodestar/types"; import {Epoch} from "@lodestar/types"; diff --git a/packages/beacon-node/src/execution/engine/interface.ts b/packages/beacon-node/src/execution/engine/interface.ts index a835fa76f509..5226a46ac720 100644 --- a/packages/beacon-node/src/execution/engine/interface.ts +++ b/packages/beacon-node/src/execution/engine/interface.ts @@ -177,6 +177,4 @@ export interface IExecutionEngine { getPayloadBodiesByHash(fork: ForkName, blockHash: DATA[]): Promise<(ExecutionPayloadBody | null)[]>; getPayloadBodiesByRange(fork: ForkName, start: number, count: number): Promise<(ExecutionPayloadBody | null)[]>; - - getState(): ExecutionEngineState; } diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index b8f5c30a70ea..46659ab3d287 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -2,8 +2,7 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {Map} from "immutable"; import {toBufferBE} from "bigint-buffer"; import {digest} from "@chainsafe/as-sha256"; -import type {SecretKey} from "@chainsafe/bls/types"; -import bls from "@chainsafe/bls"; +import {SecretKey} from "@chainsafe/blst"; import {ssz} from "@lodestar/types"; import {type CachedBeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; import {bytesToBigInt, intToBytes} from "@lodestar/utils"; @@ -106,6 +105,7 @@ describe("updateUnfinalizedPubkeys perf tests", function () { function generatePrivateKey(index: number): SecretKey { const secretKeyBytes = toBufferBE(bytesToBigInt(digest(intToBytes(index, 32))) % BigInt("38581184513"), 32); - return bls.SecretKey.fromBytes(secretKeyBytes); + const secret: SecretKey = SecretKey.fromBytes(secretKeyBytes); + return secret; } }); diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index 2dfa5ee0f77c..02fc99f9cfae 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -3,7 +3,7 @@ import assert from "node:assert"; import {describe, it, vi, afterAll, afterEach} from "vitest"; import {LogLevel, sleep} from "@lodestar/utils"; -import {ForkName, SLOTS_PER_EPOCH, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; +import {ForkName, SLOTS_PER_EPOCH, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; import {electra, Epoch, Slot} from "@lodestar/types"; import {ValidatorProposerConfig} from "@lodestar/validator"; @@ -431,7 +431,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { throw Error("Historical validator length for epoch 1 or 2 is not dropped properly"); } - if (headState.depositRequestsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + if (headState.depositRequestsStartIndex === UNSET_DEPOSIT_REQUESTS_START_INDEX) { throw Error("state.depositRequestsStartIndex is not set upon processing new deposit receipt"); } 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 01adcc77500b..7cb6e3c3d692 100644 --- a/packages/beacon-node/test/spec/presets/fork_choice.test.ts +++ b/packages/beacon-node/test/spec/presets/fork_choice.test.ts @@ -4,7 +4,17 @@ import {toHexString} from "@chainsafe/ssz"; import {BeaconStateAllForks, isExecutionStateType, signedBlockToSignedHeader} from "@lodestar/state-transition"; import {InputType} from "@lodestar/spec-test-util"; import {CheckpointWithHex, ForkChoice} from "@lodestar/fork-choice"; -import {phase0, bellatrix, ssz, RootHex, deneb, BeaconBlock, SignedBeaconBlock} from "@lodestar/types"; +import { + bellatrix, + ssz, + RootHex, + deneb, + BeaconBlock, + SignedBeaconBlock, + sszTypesFor, + Attestation, + AttesterSlashing, +} from "@lodestar/types"; import {bnToNum, fromHex} from "@lodestar/utils"; import {createBeaconConfig} from "@lodestar/config"; import {ACTIVE_PRESET, ForkSeq, isForkBlobs, ForkName} from "@lodestar/params"; @@ -136,7 +146,7 @@ const forkChoiceTest = const attestation = testcase.attestations.get(step.attestation); if (!attestation) throw Error(`No attestation ${step.attestation}`); const headState = chain.getHeadState(); - const attDataRootHex = toHexString(ssz.phase0.AttestationData.hashTreeRoot(attestation.data)); + const attDataRootHex = toHexString(sszTypesFor(fork).AttestationData.hashTreeRoot(attestation.data)); chain.forkChoice.onAttestation( headState.epochCtx.getIndexedAttestation(ForkSeq[fork], attestation), attDataRootHex @@ -343,16 +353,16 @@ const forkChoiceTest = [BLOCK_FILE_NAME]: ssz[fork].SignedBeaconBlock, [BLOBS_FILE_NAME]: ssz.deneb.Blobs, [POW_BLOCK_FILE_NAME]: ssz.bellatrix.PowBlock, - [ATTESTATION_FILE_NAME]: ssz.phase0.Attestation, - [ATTESTER_SLASHING_FILE_NAME]: ssz.phase0.AttesterSlashing, + [ATTESTATION_FILE_NAME]: sszTypesFor(fork).Attestation, + [ATTESTER_SLASHING_FILE_NAME]: sszTypesFor(fork).AttesterSlashing, }, mapToTestCase: (t: Record) => { // t has input file name as key const blocks = new Map(); const blobs = new Map(); const powBlocks = new Map(); - const attestations = new Map(); - const attesterSlashings = new Map(); + const attestations = new Map(); + const attesterSlashings = new Map(); for (const key in t) { const blockMatch = key.match(BLOCK_FILE_NAME); if (blockMatch) { @@ -495,8 +505,8 @@ type ForkChoiceTestCase = { blocks: Map; blobs: Map; powBlocks: Map; - attestations: Map; - attesterSlashings: Map; + attestations: Map; + attesterSlashings: Map; }; function isTick(step: Step): step is OnTick { diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index 24f51b05c4f6..c978cac3c8a2 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -135,8 +135,8 @@ const operations: TestRunnerFn = (fork, sszTypes: { pre: ssz[fork].BeaconState, post: ssz[fork].BeaconState, - attestation: ssz.phase0.Attestation, - attester_slashing: ssz.phase0.AttesterSlashing, + attestation: sszTypesFor(fork).Attestation, + attester_slashing: sszTypesFor(fork).AttesterSlashing, block: ssz[fork].BeaconBlock, body: ssz[fork].BeaconBlockBody, deposit: ssz.phase0.Deposit, diff --git a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts index 57b5d6fad00f..c9c128e5485e 100644 --- a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts @@ -1,6 +1,6 @@ import {BitArray, fromHexString, toHexString} from "@chainsafe/ssz"; import {describe, it, expect, beforeEach, beforeAll, afterEach, vi} from "vitest"; -import {SecretKey, Signature, fastAggregateVerify} from "@chainsafe/blst"; +import {SecretKey, Signature, fastAggregateVerify, aggregateSignatures} from "@chainsafe/blst"; import {CachedBeaconStateAllForks, newFilledArray} from "@lodestar/state-transition"; import { FAR_FUTURE_EPOCH, @@ -331,9 +331,9 @@ describe("MatchingDataAttestationGroup aggregateInto", function () { }); describe("aggregateConsolidation", function () { - const sk0 = bls.SecretKey.fromBytes(Buffer.alloc(32, 1)); - const sk1 = bls.SecretKey.fromBytes(Buffer.alloc(32, 2)); - const sk2 = bls.SecretKey.fromBytes(Buffer.alloc(32, 3)); + const sk0 = SecretKey.fromBytes(Buffer.alloc(32, 1)); + const sk1 = SecretKey.fromBytes(Buffer.alloc(32, 2)); + const sk2 = SecretKey.fromBytes(Buffer.alloc(32, 3)); const skArr = [sk0, sk1, sk2]; const testCases: { name: string; @@ -397,7 +397,7 @@ describe("aggregateConsolidation", function () { expect(finalAttestation.aggregationBits.uint8Array).toEqual(new Uint8Array(expectedAggregationBits)); expect(finalAttestation.committeeBits.toBoolArray()).toEqual(expectedCommitteeBits); expect(finalAttestation.data).toEqual(attData); - expect(finalAttestation.signature).toEqual(bls.Signature.aggregate(sigArr).toBytes()); + expect(finalAttestation.signature).toEqual(aggregateSignatures(sigArr).toBytes()); }); } }); diff --git a/packages/params/src/forkName.ts b/packages/params/src/forkName.ts index e1f1b2eda73a..4a41f0637340 100644 --- a/packages/params/src/forkName.ts +++ b/packages/params/src/forkName.ts @@ -80,3 +80,16 @@ export const forkBlobs = exclude(forkAll, [ForkName.phase0, ForkName.altair, For export function isForkBlobs(fork: ForkName): fork is ForkBlobs { return isForkWithdrawals(fork) && fork !== ForkName.capella; } + +export type ForkPreElectra = ForkPreBlobs | ForkName.deneb; +export type ForkElectra = Exclude; +export const forkElectra = exclude(forkAll, [ + ForkName.phase0, + ForkName.altair, + ForkName.bellatrix, + ForkName.capella, + ForkName.deneb, +]); +export function isForkElectra(fork: ForkName): fork is ForkElectra { + return isForkBlobs(fork) && fork !== ForkName.deneb; +} diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 00e9d48346c1..e7fd5b976336 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -262,7 +262,7 @@ export const KZG_COMMITMENT_SUBTREE_INDEX0 = KZG_COMMITMENT_GINDEX0 - 2 ** KZG_C export const BLOBSIDECAR_FIXED_SIZE = ACTIVE_PRESET === PresetName.minimal ? 131672 : 131928; // Electra Misc -export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = 2n ** 64n - 1n; +export const UNSET_DEPOSIT_REQUESTS_START_INDEX = 2n ** 64n - 1n; export const FULL_EXIT_REQUEST_AMOUNT = 0; export const NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA = 87; export const NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA = 6; diff --git a/packages/params/test/unit/__snapshots__/forkName.test.ts.snap b/packages/params/test/unit/__snapshots__/forkName.test.ts.snap index 3d7009a7c2ec..a54f9dd6913b 100644 --- a/packages/params/test/unit/__snapshots__/forkName.test.ts.snap +++ b/packages/params/test/unit/__snapshots__/forkName.test.ts.snap @@ -7,12 +7,14 @@ exports[`forkName > should have valid allForks 1`] = ` "bellatrix", "capella", "deneb", + "electra", ] `; exports[`forkName > should have valid blobs forks 1`] = ` [ "deneb", + "electra", ] `; @@ -21,6 +23,7 @@ exports[`forkName > should have valid execution forks 1`] = ` "bellatrix", "capella", "deneb", + "electra", ] `; @@ -30,6 +33,7 @@ exports[`forkName > should have valid lightclient forks 1`] = ` "bellatrix", "capella", "deneb", + "electra", ] `; @@ -37,5 +41,6 @@ exports[`forkName > should have valid withdrawal forks 1`] = ` [ "capella", "deneb", + "electra", ] `; diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index bc140b864ad9..7e343d7fc33d 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -172,7 +172,7 @@ function isValidDepositSignature( const publicKey = PublicKey.fromBytes(pubkey, true); const signature = Signature.fromBytes(depositSignature, true); - return verify(signingRoot, publicKey, signature) + return verify(signingRoot, publicKey, signature); } catch (e) { return false; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature } diff --git a/packages/state-transition/src/block/processDepositRequest.ts b/packages/state-transition/src/block/processDepositRequest.ts index ca6fe4206188..e5dd99a40c4e 100644 --- a/packages/state-transition/src/block/processDepositRequest.ts +++ b/packages/state-transition/src/block/processDepositRequest.ts @@ -1,5 +1,5 @@ import {electra} from "@lodestar/types"; -import {ForkSeq, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; +import {ForkSeq, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateElectra} from "../types.js"; import {applyDeposit} from "./processDeposit.js"; @@ -9,7 +9,7 @@ export function processDepositRequest( state: CachedBeaconStateElectra, depositRequest: electra.DepositRequest ): void { - if (state.depositRequestsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + if (state.depositRequestsStartIndex === UNSET_DEPOSIT_REQUESTS_START_INDEX) { state.depositRequestsStartIndex = BigInt(depositRequest.index); } diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 7031aaa76fce..974f0d6a608b 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -1,5 +1,5 @@ import {Epoch, ValidatorIndex, ssz} from "@lodestar/types"; -import {FAR_FUTURE_EPOCH, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; +import {FAR_FUTURE_EPOCH, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateDeneb} from "../types.js"; import {CachedBeaconStateElectra, getCachedBeaconState} from "../cache/stateCache.js"; import { @@ -59,8 +59,8 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache stateElectraView.historicalSummaries = stateElectraCloned.historicalSummaries; // latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default - // default value of depositRequestsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX - stateElectraView.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + // default value of depositRequestsStartIndex is UNSET_DEPOSIT_REQUESTS_START_INDEX + stateElectraView.depositRequestsStartIndex = UNSET_DEPOSIT_REQUESTS_START_INDEX; stateElectraView.depositBalanceToConsume = BigInt(0); stateElectraView.exitBalanceToConsume = BigInt(0); @@ -138,8 +138,8 @@ export function upgradeStateToElectraOriginal(stateDeneb: CachedBeaconStateDeneb }); // latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default - // default value of depositRequestsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX - stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + // default value of depositRequestsStartIndex is UNSET_DEPOSIT_REQUESTS_START_INDEX + stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_REQUESTS_START_INDEX; const validatorsArr = stateElectra.validators.getAllReadonly(); diff --git a/packages/state-transition/src/util/electra.ts b/packages/state-transition/src/util/electra.ts index 53f53aaf8d61..666f45435eb1 100644 --- a/packages/state-transition/src/util/electra.ts +++ b/packages/state-transition/src/util/electra.ts @@ -28,15 +28,15 @@ export function isFullyWithdrawableValidator( balance: number, epoch: number ): boolean { - const {withdrawableEpoch, withdrawalCredentials: withdrawalCredential} = validatorCredential; + const {withdrawableEpoch, withdrawalCredentials} = validatorCredential; if (fork < ForkSeq.capella) { throw new Error(`isFullyWithdrawableValidator not supported at forkSeq=${fork} < ForkSeq.capella`); } const hasWithdrawableCredentials = fork >= ForkSeq.electra - ? hasExecutionWithdrawalCredential(withdrawalCredential) - : hasEth1WithdrawalCredential(withdrawalCredential); + ? hasExecutionWithdrawalCredential(withdrawalCredentials) + : hasEth1WithdrawalCredential(withdrawalCredentials); return hasWithdrawableCredentials && withdrawableEpoch <= epoch && balance > 0; } @@ -46,18 +46,18 @@ export function isPartiallyWithdrawableValidator( validatorCredential: ValidatorInfo, balance: number ): boolean { - const {effectiveBalance, withdrawalCredentials: withdrawalCredential} = validatorCredential; + const {effectiveBalance, withdrawalCredentials} = validatorCredential; if (fork < ForkSeq.capella) { throw new Error(`isPartiallyWithdrawableValidator not supported at forkSeq=${fork} < ForkSeq.capella`); } const hasWithdrawableCredentials = fork >= ForkSeq.electra - ? hasExecutionWithdrawalCredential(withdrawalCredential) - : hasEth1WithdrawalCredential(withdrawalCredential); + ? hasExecutionWithdrawalCredential(withdrawalCredentials) + : hasEth1WithdrawalCredential(withdrawalCredentials); const validatorMaxEffectiveBalance = - fork >= ForkSeq.electra ? getValidatorMaxEffectiveBalance(withdrawalCredential) : MAX_EFFECTIVE_BALANCE; + fork >= ForkSeq.electra ? getValidatorMaxEffectiveBalance(withdrawalCredentials) : MAX_EFFECTIVE_BALANCE; const hasMaxEffectiveBalance = effectiveBalance === validatorMaxEffectiveBalance; const hasExcessBalance = balance > validatorMaxEffectiveBalance; diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index d1f09a9796e1..7bdc420d6458 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -8,7 +8,7 @@ import { GENESIS_EPOCH, GENESIS_SLOT, MAX_EFFECTIVE_BALANCE, - UNSET_DEPOSIT_RECEIPTS_START_INDEX, + UNSET_DEPOSIT_REQUESTS_START_INDEX, } from "@lodestar/params"; import {Bytes32, phase0, Root, ssz, TimeSeconds} from "@lodestar/types"; @@ -312,7 +312,7 @@ export function initializeBeaconStateFromEth1( stateElectra.latestExecutionPayloadHeader = (executionPayloadHeader as CompositeViewDU) ?? ssz.electra.ExecutionPayloadHeader.defaultViewDU(); - stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_REQUESTS_START_INDEX; } state.commit(); diff --git a/packages/types/src/utils/typeguards.ts b/packages/types/src/utils/typeguards.ts index a41b45eec546..2af11159878c 100644 --- a/packages/types/src/utils/typeguards.ts +++ b/packages/types/src/utils/typeguards.ts @@ -1,4 +1,4 @@ -import {ForkBlobs, ForkExecution, ForkName} from "@lodestar/params"; +import {ForkBlobs, ForkExecution, ForkElectra} from "@lodestar/params"; import { BlockContents, SignedBeaconBlock, @@ -68,8 +68,6 @@ export function isSignedBlockContents( return (data as SignedBlockContents).kzgProofs !== undefined; } -export function isElectraAttestation( - attestation: Attestation -): attestation is Attestation { +export function isElectraAttestation(attestation: Attestation): attestation is Attestation { return (attestation as Attestation).committeeBits !== undefined; } diff --git a/yarn.lock b/yarn.lock index 50e79fc267f3..ecfcb2c5ee6f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3050,6 +3050,13 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw== +"@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/cacheable-request@^6.0.1": version "6.0.3" resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" @@ -4626,6 +4633,13 @@ 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.yarnpkg.com/buffer-xor/-/buffer-xor-2.0.2.tgz#34f7c64f04c777a1f8aac5e661273bb9dd320289" + 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" From 5f9f223fb2716fd35beca18c4ec511e2c5c65986 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Tue, 6 Aug 2024 03:53:04 +0800 Subject: [PATCH 069/259] feat: add Electra attestation V2 endpoints (#6951) * Initial commit * getAggregatedAttestationV2 * Lint * Fix minor flaw * Add publishAggregateAndProofsV2 * Fix spelling * Fix CI * Fix spec test * Clean up events api * Run against latest beacon api spec * Revert changes to emitted events * Update packages/api/src/beacon/routes/beacon/pool.ts Co-authored-by: Nico Flaig * Update packages/api/src/beacon/routes/beacon/pool.ts Co-authored-by: Nico Flaig * Update packages/api/src/beacon/routes/beacon/pool.ts Co-authored-by: Nico Flaig * Update packages/api/src/beacon/routes/beacon/pool.ts Co-authored-by: Nico Flaig * Address comment * Add api stub back * Add todos * Review PR * Fix rebase * Lint --------- Co-authored-by: Nico Flaig --- .../api/src/beacon/routes/beacon/block.ts | 27 ++- packages/api/src/beacon/routes/beacon/pool.ts | 201 +++++++++++++++--- packages/api/src/beacon/routes/events.ts | 11 +- packages/api/src/beacon/routes/validator.ts | 148 +++++++++---- .../api/test/unit/beacon/oapiSpec.test.ts | 4 +- .../api/test/unit/beacon/testData/beacon.ts | 25 ++- .../api/test/unit/beacon/testData/events.ts | 98 ++++----- .../test/unit/beacon/testData/validator.ts | 10 +- .../src/api/impl/beacon/blocks/index.ts | 8 + .../src/api/impl/beacon/pool/index.ts | 29 ++- .../src/api/impl/validator/index.ts | 13 +- .../beacon-node/src/chain/blocks/types.ts | 2 +- .../src/chain/opPools/attestationPool.ts | 3 +- .../beacon-node/src/chain/opPools/opPool.ts | 1 + .../src/chain/validation/aggregateAndProof.ts | 2 +- .../src/network/processor/gossipHandlers.ts | 11 +- .../test/unit/api/impl/events/events.test.ts | 6 +- packages/flare/src/cmds/selfSlashAttester.ts | 2 +- .../validator/src/services/attestation.ts | 7 +- .../test/unit/services/attestation.test.ts | 16 +- packages/validator/test/utils/apiStub.ts | 3 + 21 files changed, 448 insertions(+), 179 deletions(-) diff --git a/packages/api/src/beacon/routes/beacon/block.ts b/packages/api/src/beacon/routes/beacon/block.ts index 99fbf7d45645..2c141e3bdefd 100644 --- a/packages/api/src/beacon/routes/beacon/block.ts +++ b/packages/api/src/beacon/routes/beacon/block.ts @@ -8,13 +8,13 @@ import { deneb, isSignedBlockContents, SignedBeaconBlock, - BeaconBlockBody, SignedBeaconBlockOrContents, SignedBlindedBeaconBlock, SignedBlockContents, sszTypesFor, + BeaconBlockBody, } from "@lodestar/types"; -import {ForkName, ForkPreExecution, isForkBlobs, isForkExecution} from "@lodestar/params"; +import {ForkName, ForkPreElectra, ForkPreExecution, isForkBlobs, isForkExecution} from "@lodestar/params"; import {Endpoint, RequestCodec, RouteDefinitions, Schema} from "../../../utils/index.js"; import {EmptyMeta, EmptyResponseCodec, EmptyResponseData, WithVersion} from "../../../utils/codecs.js"; import { @@ -101,10 +101,22 @@ export type Endpoints = { "GET", BlockArgs, {params: {block_id: string}}, - BeaconBlockBody["attestations"], + BeaconBlockBody["attestations"], ExecutionOptimisticAndFinalizedMeta >; + /** + * Get block attestations + * Retrieves attestation included in requested block. + */ + getBlockAttestationsV2: Endpoint< + "GET", + BlockArgs, + {params: {block_id: string}}, + BeaconBlockBody["attestations"], + ExecutionOptimisticFinalizedAndVersionMeta + >; + /** * Get block header * Retrieves block header for given block id. @@ -251,6 +263,15 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ssz[fork].BeaconBlockBody.fields.attestations), + meta: ExecutionOptimisticFinalizedAndVersionCodec, + }, + }, getBlockHeader: { url: "/eth/v1/beacon/headers/{block_id}", method: "GET", diff --git a/packages/api/src/beacon/routes/beacon/pool.ts b/packages/api/src/beacon/routes/beacon/pool.ts index 499e8af432d7..aa2c36d3bc92 100644 --- a/packages/api/src/beacon/routes/beacon/pool.ts +++ b/packages/api/src/beacon/routes/beacon/pool.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; -import {ForkSeq} from "@lodestar/params"; -import {phase0, capella, CommitteeIndex, Slot, ssz} from "@lodestar/types"; +import {isForkElectra} from "@lodestar/params"; +import {phase0, capella, CommitteeIndex, Slot, ssz, electra, AttesterSlashing} from "@lodestar/types"; import {Schema, Endpoint, RouteDefinitions} from "../../../utils/index.js"; import { ArrayOf, @@ -23,7 +23,8 @@ import {fromHeaders} from "../../../utils/headers.js"; const AttestationListTypePhase0 = ArrayOf(ssz.phase0.Attestation); const AttestationListTypeElectra = ArrayOf(ssz.electra.Attestation); -const AttesterSlashingListType = ArrayOf(ssz.phase0.AttesterSlashing); +const AttesterSlashingListTypePhase0 = ArrayOf(ssz.phase0.AttesterSlashing); +const AttesterSlashingListTypeElectra = ArrayOf(ssz.electra.AttesterSlashing); const ProposerSlashingListType = ArrayOf(ssz.phase0.ProposerSlashing); const SignedVoluntaryExitListType = ArrayOf(ssz.phase0.SignedVoluntaryExit); const SignedBLSToExecutionChangeListType = ArrayOf(ssz.capella.SignedBLSToExecutionChange); @@ -32,7 +33,11 @@ const SyncCommitteeMessageListType = ArrayOf(ssz.altair.SyncCommitteeMessage); type AttestationListPhase0 = ValueOf; type AttestationListElectra = ValueOf; type AttestationList = AttestationListPhase0 | AttestationListElectra; -type AttesterSlashingList = ValueOf; + +type AttesterSlashingListPhase0 = ValueOf; +type AttesterSlashingListElectra = ValueOf; +type AttesterSlashingList = AttesterSlashingListPhase0 | AttesterSlashingListElectra; + type ProposerSlashingList = ValueOf; type SignedVoluntaryExitList = ValueOf; type SignedBLSToExecutionChangeList = ValueOf; @@ -44,6 +49,18 @@ export type Endpoints = { * Retrieves attestations known by the node but not necessarily incorporated into any block */ getPoolAttestations: Endpoint< + "GET", + {slot?: Slot; committeeIndex?: CommitteeIndex}, + {query: {slot?: number; committee_index?: number}}, + AttestationListPhase0, + EmptyMeta + >; + + /** + * Get Attestations from operations pool + * Retrieves attestations known by the node but not necessarily incorporated into any block + */ + getPoolAttestationsV2: Endpoint< "GET", {slot?: Slot; committeeIndex?: CommitteeIndex}, {query: {slot?: number; committee_index?: number}}, @@ -60,10 +77,23 @@ export type Endpoints = { "GET", EmptyArgs, EmptyRequest, - AttesterSlashingList, + AttesterSlashingListPhase0, EmptyMeta >; + /** + * Get AttesterSlashings from operations pool + * Retrieves attester slashings known by the node but not necessarily incorporated into any block + */ + getPoolAttesterSlashingsV2: Endpoint< + // ⏎ + "GET", + EmptyArgs, + EmptyRequest, + AttesterSlashingList, + VersionMeta + >; + /** * Get ProposerSlashings from operations pool * Retrieves proposer slashings known by the node but not necessarily incorporated into any block @@ -112,6 +142,22 @@ export type Endpoints = { * If one or more attestations fail validation the node MUST return a 400 error with details of which attestations have failed, and why. */ submitPoolAttestations: Endpoint< + "POST", + {signedAttestations: AttestationListPhase0}, + {body: unknown}, + EmptyResponseData, + EmptyMeta + >; + + /** + * Submit Attestation objects to node + * Submits Attestation objects to the node. Each attestation in the request body is processed individually. + * + * If an attestation is validated successfully the node MUST publish that attestation on the appropriate subnet. + * + * If one or more attestations fail validation the node MUST return a 400 error with details of which attestations have failed, and why. + */ + submitPoolAttestationsV2: Endpoint< "POST", {signedAttestations: AttestationList}, {body: unknown; headers: {[MetaHeader.Version]: string}}, @@ -131,6 +177,18 @@ export type Endpoints = { EmptyMeta >; + /** + * Submit AttesterSlashing object to node's pool + * Submits AttesterSlashing object to node's pool and if passes validation node MUST broadcast it to network. + */ + submitPoolAttesterSlashingsV2: Endpoint< + "POST", + {attesterSlashing: AttesterSlashing}, + {body: unknown; headers: {[MetaHeader.Version]: string}}, + EmptyResponseData, + EmptyMeta + >; + /** * Submit ProposerSlashing object to node's pool * Submits ProposerSlashing object to node's pool and if passes validation node MUST broadcast it to network. @@ -191,9 +249,20 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions - ForkSeq[fork] >= ForkSeq.electra ? AttestationListTypeElectra : AttestationListTypePhase0 - ), + data: AttestationListTypePhase0, + meta: EmptyMetaCodec, + }, + }, + getPoolAttestationsV2: { + url: "/eth/v2/beacon/pool/attestations", + method: "GET", + req: { + writeReq: ({slot, committeeIndex}) => ({query: {slot, committee_index: committeeIndex}}), + parseReq: ({query}) => ({slot: query.slot, committeeIndex: query.committee_index}), + schema: {query: {slot: Schema.Uint, committee_index: Schema.Uint}}, + }, + resp: { + data: WithVersion((fork) => (isForkElectra(fork) ? AttestationListTypeElectra : AttestationListTypePhase0)), meta: VersionCodec, }, }, @@ -202,10 +271,21 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions + isForkElectra(fork) ? AttesterSlashingListTypeElectra : AttesterSlashingListTypePhase0 + ), + meta: VersionCodec, + }, + }, getPoolProposerSlashings: { url: "/eth/v1/beacon/pool/proposer_slashings", method: "GET", @@ -236,49 +316,55 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ + body: AttestationListTypePhase0.toJson(signedAttestations), + }), + parseReqJson: ({body}) => ({signedAttestations: AttestationListTypePhase0.fromJson(body)}), + writeReqSsz: ({signedAttestations}) => ({body: AttestationListTypePhase0.serialize(signedAttestations)}), + parseReqSsz: ({body}) => ({signedAttestations: AttestationListTypePhase0.deserialize(body)}), + schema: { + body: Schema.ObjectArray, + }, + }, + resp: EmptyResponseCodec, + }, + submitPoolAttestationsV2: { + url: "/eth/v2/beacon/pool/attestations", + method: "POST", req: { writeReqJson: ({signedAttestations}) => { - const fork = config.getForkName(signedAttestations[0].data.slot); + const fork = config.getForkName(signedAttestations[0]?.data.slot ?? 0); return { - body: - ForkSeq[fork] >= ForkSeq.electra - ? AttestationListTypeElectra.toJson(signedAttestations as AttestationListElectra) - : AttestationListTypePhase0.toJson(signedAttestations as AttestationListPhase0), + body: isForkElectra(fork) + ? AttestationListTypeElectra.toJson(signedAttestations as AttestationListElectra) + : AttestationListTypePhase0.toJson(signedAttestations as AttestationListPhase0), headers: {[MetaHeader.Version]: fork}, }; }, parseReqJson: ({body, headers}) => { - const versionHeader = fromHeaders(headers, MetaHeader.Version, false); - const fork = - versionHeader !== undefined - ? toForkName(versionHeader) - : config.getForkName(Number((body as {data: {slot: string}}[])[0]?.data.slot ?? 0)); - + const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedAttestations: - ForkSeq[fork] >= ForkSeq.electra - ? AttestationListTypeElectra.fromJson(body) - : AttestationListTypePhase0.fromJson(body), + signedAttestations: isForkElectra(fork) + ? AttestationListTypeElectra.fromJson(body) + : AttestationListTypePhase0.fromJson(body), }; }, writeReqSsz: ({signedAttestations}) => { - const fork = config.getForkName(signedAttestations[0].data.slot); + const fork = config.getForkName(signedAttestations[0]?.data.slot ?? 0); return { - body: - ForkSeq[fork] >= ForkSeq.electra - ? AttestationListTypeElectra.serialize(signedAttestations as AttestationListElectra) - : AttestationListTypePhase0.serialize(signedAttestations as AttestationListPhase0), + body: isForkElectra(fork) + ? AttestationListTypeElectra.serialize(signedAttestations as AttestationListElectra) + : AttestationListTypePhase0.serialize(signedAttestations as AttestationListPhase0), headers: {[MetaHeader.Version]: fork}, }; }, parseReqSsz: ({body, headers}) => { - const versionHeader = fromHeaders(headers, MetaHeader.Version, true); - const fork = toForkName(versionHeader); + const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedAttestations: - ForkSeq[fork] >= ForkSeq.electra - ? AttestationListTypeElectra.deserialize(body) - : AttestationListTypePhase0.deserialize(body), + signedAttestations: isForkElectra(fork) + ? AttestationListTypeElectra.deserialize(body) + : AttestationListTypePhase0.deserialize(body), }; }, schema: { @@ -302,6 +388,51 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { + const fork = config.getForkName(Number(attesterSlashing.attestation1.data.slot)); + return { + body: isForkElectra(fork) + ? ssz.electra.AttesterSlashing.toJson(attesterSlashing) + : ssz.phase0.AttesterSlashing.toJson(attesterSlashing), + headers: {[MetaHeader.Version]: fork}, + }; + }, + parseReqJson: ({body, headers}) => { + const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); + return { + attesterSlashing: isForkElectra(fork) + ? ssz.electra.AttesterSlashing.fromJson(body) + : ssz.phase0.AttesterSlashing.fromJson(body), + }; + }, + writeReqSsz: ({attesterSlashing}) => { + const fork = config.getForkName(Number(attesterSlashing.attestation1.data.slot)); + return { + body: isForkElectra(fork) + ? ssz.electra.AttesterSlashing.serialize(attesterSlashing as electra.AttesterSlashing) + : ssz.electra.AttesterSlashing.serialize(attesterSlashing as phase0.AttesterSlashing), + headers: {[MetaHeader.Version]: fork}, + }; + }, + parseReqSsz: ({body, headers}) => { + const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); + return { + attesterSlashing: isForkElectra(fork) + ? ssz.electra.AttesterSlashing.deserialize(body) + : ssz.phase0.AttesterSlashing.deserialize(body), + }; + }, + schema: { + body: Schema.Object, + headers: {[MetaHeader.Version]: Schema.String}, + }, + }, + resp: EmptyResponseCodec, + }, submitPoolProposerSlashings: { url: "/eth/v1/beacon/pool/proposer_slashings", method: "POST", diff --git a/packages/api/src/beacon/routes/events.ts b/packages/api/src/beacon/routes/events.ts index e15790fd3bea..23be5e7c2288 100644 --- a/packages/api/src/beacon/routes/events.ts +++ b/packages/api/src/beacon/routes/events.ts @@ -13,9 +13,6 @@ import { LightClientOptimisticUpdate, LightClientFinalityUpdate, SSEPayloadAttributes, - Attestation, - AttesterSlashing, - sszTypesFor, } from "@lodestar/types"; import {ForkName} from "@lodestar/params"; @@ -107,10 +104,10 @@ export type EventData = { block: RootHex; executionOptimistic: boolean; }; - [EventType.attestation]: {version: ForkName; data: Attestation}; + [EventType.attestation]: phase0.Attestation; [EventType.voluntaryExit]: phase0.SignedVoluntaryExit; [EventType.proposerSlashing]: phase0.ProposerSlashing; - [EventType.attesterSlashing]: {version: ForkName; data: AttesterSlashing}; + [EventType.attesterSlashing]: phase0.AttesterSlashing; [EventType.blsToExecutionChange]: capella.SignedBLSToExecutionChange; [EventType.finalizedCheckpoint]: { block: RootHex; @@ -228,10 +225,10 @@ export function getTypeByEvent(): {[K in EventType]: TypeJson} { {jsonCase: "eth2"} ), - [EventType.attestation]: WithVersion((fork) => sszTypesFor(fork).Attestation), + [EventType.attestation]: ssz.phase0.Attestation, [EventType.voluntaryExit]: ssz.phase0.SignedVoluntaryExit, [EventType.proposerSlashing]: ssz.phase0.ProposerSlashing, - [EventType.attesterSlashing]: WithVersion((fork) => sszTypesFor(fork).AttesterSlashing), + [EventType.attesterSlashing]: ssz.phase0.AttesterSlashing, [EventType.blsToExecutionChange]: ssz.capella.SignedBLSToExecutionChange, [EventType.finalizedCheckpoint]: new ContainerType( diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index c0078c97d5f8..ed7c0fd9ba0a 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, fromHexString, toHexString, Type, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; -import {isForkBlobs, ForkSeq} from "@lodestar/params"; +import {isForkBlobs, isForkElectra} from "@lodestar/params"; import { altair, BLSSignature, @@ -203,7 +203,7 @@ export const AttesterDutyListType = ArrayOf(AttesterDutyType); export const ProposerDutyListType = ArrayOf(ProposerDutyType); export const SyncDutyListType = ArrayOf(SyncDutyType); export const SignedAggregateAndProofListPhase0Type = ArrayOf(ssz.phase0.SignedAggregateAndProof); -export const SignedAggregateAndProofListElectaType = ArrayOf(ssz.electra.SignedAggregateAndProof); +export const SignedAggregateAndProofListElectraType = ArrayOf(ssz.electra.SignedAggregateAndProof); export const SignedContributionAndProofListType = ArrayOf(ssz.altair.SignedContributionAndProof); export const BeaconCommitteeSubscriptionListType = ArrayOf(BeaconCommitteeSubscriptionType); export const SyncCommitteeSubscriptionListType = ArrayOf(SyncCommitteeSubscriptionType); @@ -221,8 +221,8 @@ export type ProposerDutyList = ValueOf; export type SyncDuty = ValueOf; export type SyncDutyList = ValueOf; export type SignedAggregateAndProofListPhase0 = ValueOf; -export type SignedAggregateAndProofListElecta = ValueOf; -export type SignedAggregateAndProofList = SignedAggregateAndProofListPhase0 | SignedAggregateAndProofListElecta; +export type SignedAggregateAndProofListElectra = ValueOf; +export type SignedAggregateAndProofList = SignedAggregateAndProofListPhase0 | SignedAggregateAndProofListElectra; export type SignedContributionAndProofList = ValueOf; export type BeaconCommitteeSubscription = ValueOf; export type BeaconCommitteeSubscriptionList = ValueOf; @@ -398,6 +398,23 @@ export type Endpoints = { * Returns an aggregated `Attestation` object with same `AttestationData` root. */ getAggregatedAttestation: Endpoint< + "GET", + { + /** HashTreeRoot of AttestationData that validator want's aggregated */ + attestationDataRoot: Root; + slot: Slot; + }, + {query: {attestation_data_root: string; slot: number}}, + phase0.Attestation, + EmptyMeta + >; + + /** + * Get aggregated attestation + * Aggregates all attestations matching given attestation data root, slot and committee index + * Returns an aggregated `Attestation` object with same `AttestationData` root. + */ + getAggregatedAttestationV2: Endpoint< "GET", { /** HashTreeRoot of AttestationData that validator want's aggregated */ @@ -405,7 +422,7 @@ export type Endpoints = { slot: Slot; committeeIndex: number; }, - {query: {attestation_data_root: string; slot: number; committeeIndex: number}}, + {query: {attestation_data_root: string; slot: number; committee_index: number}}, Attestation, VersionMeta >; @@ -415,6 +432,18 @@ export type Endpoints = { * Verifies given aggregate and proofs and publishes them on appropriate gossipsub topic. */ publishAggregateAndProofs: Endpoint< + "POST", + {signedAggregateAndProofs: SignedAggregateAndProofListPhase0}, + {body: unknown}, + EmptyResponseData, + EmptyMeta + >; + + /** + * Publish multiple aggregate and proofs + * Verifies given aggregate and proofs and publishes them on appropriate gossipsub topic. + */ + publishAggregateAndProofsV2: Endpoint< "POST", {signedAggregateAndProofs: SignedAggregateAndProofList}, {body: unknown; headers: {[MetaHeader.Version]: string}}, @@ -799,88 +828,113 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ + query: {attestation_data_root: toHexString(attestationDataRoot), slot}, + }), + parseReq: ({query}) => ({ + attestationDataRoot: fromHexString(query.attestation_data_root), + slot: query.slot, + }), + schema: { + query: { + attestation_data_root: Schema.StringRequired, + slot: Schema.UintRequired, + }, + }, + }, + resp: { + data: ssz.phase0.Attestation, + meta: EmptyMetaCodec, + }, + }, + getAggregatedAttestationV2: { + url: "/eth/v2/validator/aggregate_attestation", + method: "GET", req: { writeReq: ({attestationDataRoot, slot, committeeIndex}) => ({ - query: {attestation_data_root: toHexString(attestationDataRoot), slot, committeeIndex}, + query: {attestation_data_root: toHexString(attestationDataRoot), slot, committee_index: committeeIndex}, }), parseReq: ({query}) => ({ attestationDataRoot: fromHexString(query.attestation_data_root), slot: query.slot, - committeeIndex: query.committeeIndex, + committeeIndex: query.committee_index, }), schema: { query: { attestation_data_root: Schema.StringRequired, slot: Schema.UintRequired, - committeeIndex: Schema.UintRequired, + committee_index: Schema.UintRequired, }, }, }, resp: { - data: WithVersion((fork) => - ForkSeq[fork] >= ForkSeq.electra ? ssz.electra.Attestation : ssz.phase0.Attestation - ), + data: WithVersion((fork) => (isForkElectra(fork) ? ssz.electra.Attestation : ssz.phase0.Attestation)), meta: VersionCodec, }, }, publishAggregateAndProofs: { url: "/eth/v1/validator/aggregate_and_proofs", method: "POST", + req: { + writeReqJson: ({signedAggregateAndProofs}) => ({ + body: SignedAggregateAndProofListPhase0Type.toJson(signedAggregateAndProofs), + }), + parseReqJson: ({body}) => ({signedAggregateAndProofs: SignedAggregateAndProofListPhase0Type.fromJson(body)}), + writeReqSsz: ({signedAggregateAndProofs}) => ({ + body: SignedAggregateAndProofListPhase0Type.serialize(signedAggregateAndProofs), + }), + parseReqSsz: ({body}) => ({signedAggregateAndProofs: SignedAggregateAndProofListPhase0Type.deserialize(body)}), + schema: { + body: Schema.ObjectArray, + }, + }, + resp: EmptyResponseCodec, + }, + publishAggregateAndProofsV2: { + url: "/eth/v2/validator/aggregate_and_proofs", + method: "POST", req: { writeReqJson: ({signedAggregateAndProofs}) => { const fork = config.getForkName(signedAggregateAndProofs[0]?.message.aggregate.data.slot ?? 0); return { - body: - ForkSeq[fork] >= ForkSeq.electra - ? SignedAggregateAndProofListElectaType.toJson( - signedAggregateAndProofs as SignedAggregateAndProofListElecta - ) - : SignedAggregateAndProofListPhase0Type.toJson( - signedAggregateAndProofs as SignedAggregateAndProofListPhase0 - ), + body: isForkElectra(fork) + ? SignedAggregateAndProofListElectraType.toJson( + signedAggregateAndProofs as SignedAggregateAndProofListElectra + ) + : SignedAggregateAndProofListPhase0Type.toJson( + signedAggregateAndProofs as SignedAggregateAndProofListPhase0 + ), headers: {[MetaHeader.Version]: fork}, }; }, parseReqJson: ({body, headers}) => { - const versionHeader = fromHeaders(headers, MetaHeader.Version, false); - const fork = - versionHeader !== undefined - ? toForkName(versionHeader) - : config.getForkName( - Number( - (body as {message: {aggregate: {data: {slot: string}}}}[])[0]?.message.aggregate.data.slot ?? 0 - ) - ); - + const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedAggregateAndProofs: - ForkSeq[fork] >= ForkSeq.electra - ? SignedAggregateAndProofListElectaType.fromJson(body) - : SignedAggregateAndProofListPhase0Type.fromJson(body), + signedAggregateAndProofs: isForkElectra(fork) + ? SignedAggregateAndProofListElectraType.fromJson(body) + : SignedAggregateAndProofListPhase0Type.fromJson(body), }; }, writeReqSsz: ({signedAggregateAndProofs}) => { const fork = config.getForkName(signedAggregateAndProofs[0]?.message.aggregate.data.slot ?? 0); return { - body: - ForkSeq[fork] >= ForkSeq.electra - ? SignedAggregateAndProofListElectaType.serialize( - signedAggregateAndProofs as SignedAggregateAndProofListElecta - ) - : SignedAggregateAndProofListPhase0Type.serialize( - signedAggregateAndProofs as SignedAggregateAndProofListPhase0 - ), + body: isForkElectra(fork) + ? SignedAggregateAndProofListElectraType.serialize( + signedAggregateAndProofs as SignedAggregateAndProofListElectra + ) + : SignedAggregateAndProofListPhase0Type.serialize( + signedAggregateAndProofs as SignedAggregateAndProofListPhase0 + ), headers: {[MetaHeader.Version]: fork}, }; }, parseReqSsz: ({body, headers}) => { - const versionHeader = fromHeaders(headers, MetaHeader.Version, true); - const fork = toForkName(versionHeader); + const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedAggregateAndProofs: - ForkSeq[fork] >= ForkSeq.electra - ? SignedAggregateAndProofListElectaType.deserialize(body) - : SignedAggregateAndProofListPhase0Type.deserialize(body), + signedAggregateAndProofs: isForkElectra(fork) + ? SignedAggregateAndProofListElectraType.deserialize(body) + : SignedAggregateAndProofListPhase0Type.deserialize(body), }; }, schema: { diff --git a/packages/api/test/unit/beacon/oapiSpec.test.ts b/packages/api/test/unit/beacon/oapiSpec.test.ts index 00f1a3d8731d..2ccf4720db27 100644 --- a/packages/api/test/unit/beacon/oapiSpec.test.ts +++ b/packages/api/test/unit/beacon/oapiSpec.test.ts @@ -21,9 +21,9 @@ import {testData as validatorTestData} from "./testData/validator.js"; // eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const version = "v2.5.0"; +const version = "v2.6.0-alpha.1"; const openApiFile: OpenApiFile = { - url: `https://github.com/ethereum/beacon-APIs/releases/download/${version}/beacon-node-oapi.json`, + url: `https://raw.githubusercontent.com/nflaig/beacon-api-spec/main/${version}/beacon-node-oapi.json`, filepath: path.join(__dirname, "../../../oapi-schemas/beacon-node-oapi.json"), version: RegExp(version), }; diff --git a/packages/api/test/unit/beacon/testData/beacon.ts b/packages/api/test/unit/beacon/testData/beacon.ts index da13d4c7783c..ac47a58777eb 100644 --- a/packages/api/test/unit/beacon/testData/beacon.ts +++ b/packages/api/test/unit/beacon/testData/beacon.ts @@ -49,6 +49,13 @@ export const testData: GenericServerTestCases = { args: {blockId: "head"}, res: {data: [ssz.phase0.Attestation.defaultValue()], meta: {executionOptimistic: true, finalized: false}}, }, + getBlockAttestationsV2: { + args: {blockId: "head"}, + res: { + data: [ssz.electra.Attestation.defaultValue()], + meta: {executionOptimistic: true, finalized: false, version: ForkName.electra}, + }, + }, getBlockHeader: { args: {blockId: "head"}, res: {data: blockHeaderResponse, meta: {executionOptimistic: true, finalized: false}}, @@ -92,12 +99,20 @@ export const testData: GenericServerTestCases = { getPoolAttestations: { args: {slot: 1, committeeIndex: 2}, - res: {data: [ssz.phase0.Attestation.defaultValue()], meta: {version: ForkName.deneb}}, + res: {data: [ssz.phase0.Attestation.defaultValue()]}, + }, + getPoolAttestationsV2: { + args: {slot: 1, committeeIndex: 2}, + res: {data: [ssz.electra.Attestation.defaultValue()], meta: {version: ForkName.electra}}, }, getPoolAttesterSlashings: { args: undefined, res: {data: [ssz.phase0.AttesterSlashing.defaultValue()]}, }, + getPoolAttesterSlashingsV2: { + args: undefined, + res: {data: [ssz.electra.AttesterSlashing.defaultValue()], meta: {version: ForkName.electra}}, + }, getPoolProposerSlashings: { args: undefined, res: {data: [ssz.phase0.ProposerSlashing.defaultValue()]}, @@ -114,10 +129,18 @@ export const testData: GenericServerTestCases = { args: {signedAttestations: [ssz.phase0.Attestation.defaultValue()]}, res: undefined, }, + submitPoolAttestationsV2: { + args: {signedAttestations: [ssz.phase0.Attestation.defaultValue()]}, + res: undefined, + }, submitPoolAttesterSlashings: { args: {attesterSlashing: ssz.phase0.AttesterSlashing.defaultValue()}, res: undefined, }, + submitPoolAttesterSlashingsV2: { + args: {attesterSlashing: ssz.electra.AttesterSlashing.defaultValue()}, + res: undefined, + }, submitPoolProposerSlashings: { args: {proposerSlashing: ssz.phase0.ProposerSlashing.defaultValue()}, res: undefined, diff --git a/packages/api/test/unit/beacon/testData/events.ts b/packages/api/test/unit/beacon/testData/events.ts index 7966d0ea3b8a..8a7610a26836 100644 --- a/packages/api/test/unit/beacon/testData/events.ts +++ b/packages/api/test/unit/beacon/testData/events.ts @@ -31,21 +31,18 @@ export const eventTestData: EventData = { block: "0x9a2fefd2fdb57f74993c7780ea5b9030d2897b615b89f808011ca5aebed54eaf", executionOptimistic: false, }, - [EventType.attestation]: { - version: ForkName.altair, - data: ssz.phase0.Attestation.fromJson({ - aggregation_bits: "0x01", - signature: - "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", - data: { - slot: "1", - index: "1", - beacon_block_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", - source: {epoch: "1", root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}, - target: {epoch: "1", root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}, - }, - }), - }, + [EventType.attestation]: ssz.phase0.Attestation.fromJson({ + aggregation_bits: "0x01", + signature: + "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + data: { + slot: "1", + index: "1", + beacon_block_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + source: {epoch: "1", root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}, + target: {epoch: "1", root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}, + }, + }), [EventType.voluntaryExit]: ssz.phase0.SignedVoluntaryExit.fromJson({ message: {epoch: "1", validator_index: "1"}, signature: @@ -75,47 +72,44 @@ export const eventTestData: EventData = { "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, }), - [EventType.attesterSlashing]: { - version: ForkName.altair, - data: ssz.phase0.AttesterSlashing.fromJson({ - attestation_1: { - attesting_indices: ["0", "1"], - data: { - slot: "0", - index: "0", - beacon_block_root: "0x0000000000000000000000000000000000000000000000000000000000000000", - source: { - epoch: "0", - root: "0x0000000000000000000000000000000000000000000000000000000000000000", - }, - target: { - epoch: "0", - root: "0x0000000000000000000000000000000000000000000000000000000000000000", - }, + [EventType.attesterSlashing]: ssz.phase0.AttesterSlashing.fromJson({ + attestation_1: { + attesting_indices: ["0", "1"], + data: { + slot: "0", + index: "0", + beacon_block_root: "0x0000000000000000000000000000000000000000000000000000000000000000", + source: { + epoch: "0", + root: "0x0000000000000000000000000000000000000000000000000000000000000000", + }, + target: { + epoch: "0", + root: "0x0000000000000000000000000000000000000000000000000000000000000000", }, - signature: - "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, - attestation_2: { - attesting_indices: ["0", "1"], - data: { - slot: "0", - index: "0", - beacon_block_root: "0x0000000000000000000000000000000000000000000000000000000000000000", - source: { - epoch: "0", - root: "0x0000000000000000000000000000000000000000000000000000000000000000", - }, - target: { - epoch: "0", - root: "0x0000000000000000000000000000000000000000000000000000000000000000", - }, + signature: + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + attestation_2: { + attesting_indices: ["0", "1"], + data: { + slot: "0", + index: "0", + beacon_block_root: "0x0000000000000000000000000000000000000000000000000000000000000000", + source: { + epoch: "0", + root: "0x0000000000000000000000000000000000000000000000000000000000000000", + }, + target: { + epoch: "0", + root: "0x0000000000000000000000000000000000000000000000000000000000000000", }, - signature: - "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, - }), - }, + signature: + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + }), [EventType.blsToExecutionChange]: ssz.capella.SignedBLSToExecutionChange.fromJson({ message: { validator_index: "1", diff --git a/packages/api/test/unit/beacon/testData/validator.ts b/packages/api/test/unit/beacon/testData/validator.ts index b27fc9c38733..d4fae4bfe290 100644 --- a/packages/api/test/unit/beacon/testData/validator.ts +++ b/packages/api/test/unit/beacon/testData/validator.ts @@ -99,13 +99,21 @@ export const testData: GenericServerTestCases = { res: {data: ssz.altair.SyncCommitteeContribution.defaultValue()}, }, getAggregatedAttestation: { + args: {attestationDataRoot: ZERO_HASH, slot: 32000}, + res: {data: ssz.phase0.Attestation.defaultValue()}, + }, + getAggregatedAttestationV2: { args: {attestationDataRoot: ZERO_HASH, slot: 32000, committeeIndex: 2}, - res: {data: ssz.phase0.Attestation.defaultValue(), meta: {version: ForkName.phase0}}, + res: {data: ssz.electra.Attestation.defaultValue(), meta: {version: ForkName.electra}}, }, publishAggregateAndProofs: { args: {signedAggregateAndProofs: [ssz.phase0.SignedAggregateAndProof.defaultValue()]}, res: undefined, }, + publishAggregateAndProofsV2: { + args: {signedAggregateAndProofs: [ssz.phase0.SignedAggregateAndProof.defaultValue()]}, + res: undefined, + }, publishContributionAndProofs: { args: {contributionAndProofs: [ssz.altair.SignedContributionAndProof.defaultValue()]}, res: undefined, 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 4d0f96d1ea08..251218f510ec 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -413,6 +413,14 @@ export function getBeaconBlockApi({ }; }, + async getBlockAttestationsV2({blockId}) { + const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId); + return { + data: Array.from(block.message.body.attestations), + meta: {executionOptimistic, finalized, version: config.getForkName(block.message.slot)}, + }; + }, + async getBlockRoot({blockId}) { // Fast path: From head state already available in memory get historical blockRoot const slot = typeof blockId === "string" ? parseInt(blockId) : blockId; diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index 19c11362c910..bc8c838a5401 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -27,7 +27,18 @@ export function getBeaconPoolApi({ async getPoolAttestations({slot, committeeIndex}) { // Already filtered by slot let attestations = chain.aggregatedAttestationPool.getAll(slot); - const fork = chain.config.getForkName(slot ?? attestations[0].data.slot) ?? ForkName.phase0; + + if (committeeIndex !== undefined) { + attestations = attestations.filter((attestation) => committeeIndex === attestation.data.index); + } + + return {data: attestations}; + }, + + async getPoolAttestationsV2({slot, committeeIndex}) { + // Already filtered by slot + let attestations = chain.aggregatedAttestationPool.getAll(slot); + const fork = chain.config.getForkName(slot ?? attestations[0]?.data.slot ?? chain.clock.currentSlot); if (committeeIndex !== undefined) { attestations = attestations.filter((attestation) => committeeIndex === attestation.data.index); @@ -40,6 +51,11 @@ export function getBeaconPoolApi({ return {data: chain.opPool.getAllAttesterSlashings()}; }, + async getPoolAttesterSlashingsV2() { + // TODO Electra: Determine fork based on data returned by api + return {data: chain.opPool.getAllAttesterSlashings(), meta: {version: ForkName.phase0}}; + }, + async getPoolProposerSlashings() { return {data: chain.opPool.getAllProposerSlashings()}; }, @@ -53,6 +69,10 @@ export function getBeaconPoolApi({ }, async submitPoolAttestations({signedAttestations}) { + await this.submitPoolAttestationsV2({signedAttestations}); + }, + + async submitPoolAttestationsV2({signedAttestations}) { const seenTimestampSec = Date.now() / 1000; const errors: Error[] = []; @@ -79,7 +99,7 @@ export function getBeaconPoolApi({ metrics?.opPool.attestationPoolInsertOutcome.inc({insertOutcome}); } - chain.emitter.emit(routes.events.EventType.attestation, {data: attestation, version: ForkName.phase0}); + chain.emitter.emit(routes.events.EventType.attestation, attestation); const sentPeers = await network.publishBeaconAttestation(attestation, subnet); metrics?.onPoolSubmitUnaggregatedAttestation(seenTimestampSec, indexedAttestation, subnet, sentPeers); @@ -115,6 +135,11 @@ export function getBeaconPoolApi({ await network.publishAttesterSlashing(attesterSlashing); }, + async submitPoolAttesterSlashingsV2({attesterSlashing}) { + // TODO Electra: Refactor submitPoolAttesterSlashings and submitPoolAttesterSlashingsV2 + await this.submitPoolAttesterSlashings({attesterSlashing}); + }, + async submitPoolProposerSlashings({proposerSlashing}) { await validateApiProposerSlashing(chain, proposerSlashing); chain.opPool.insertProposerSlashing(proposerSlashing); diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 856b301d7a21..06502146ce2f 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -1072,7 +1072,12 @@ export function getValidatorApi( }; }, - async getAggregatedAttestation({attestationDataRoot, slot, committeeIndex}) { + // TODO Electra: Implement getAggregatedAttestation to properly handle pre-electra + async getAggregatedAttestation() { + throw new Error("Not implemented. Use getAggregatedAttestationV2 for now."); + }, + + async getAggregatedAttestationV2({attestationDataRoot, slot, committeeIndex}) { notWhileSyncing(); await waitForSlot(slot); // Must never request for a future slot > currentSlot @@ -1083,7 +1088,7 @@ export function getValidatorApi( if (!aggregate) { throw new ApiError( 404, - `No aggregated attestation for slot=${slot} committeeIndex=${committeeIndex}, dataRoot=${dataRootHex}` + `No aggregated attestation for slot=${slot}, committeeIndex=${committeeIndex}, dataRoot=${dataRootHex}` ); } @@ -1096,6 +1101,10 @@ export function getValidatorApi( }, async publishAggregateAndProofs({signedAggregateAndProofs}) { + await this.publishAggregateAndProofsV2({signedAggregateAndProofs}); + }, + + async publishAggregateAndProofsV2({signedAggregateAndProofs}) { notWhileSyncing(); const seenTimestampSec = Date.now() / 1000; diff --git a/packages/beacon-node/src/chain/blocks/types.ts b/packages/beacon-node/src/chain/blocks/types.ts index 80c94e2d6fde..8b793932e951 100644 --- a/packages/beacon-node/src/chain/blocks/types.ts +++ b/packages/beacon-node/src/chain/blocks/types.ts @@ -1,7 +1,7 @@ import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition"; import {MaybeValidExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; import {deneb, Slot, RootHex, SignedBeaconBlock} from "@lodestar/types"; -import {ForkSeq, ForkName, ForkBlobs} from "@lodestar/params"; +import {ForkSeq, ForkBlobs} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; export enum BlockInputType { diff --git a/packages/beacon-node/src/chain/opPools/attestationPool.ts b/packages/beacon-node/src/chain/opPools/attestationPool.ts index 8daae6b663c7..f125b8c941db 100644 --- a/packages/beacon-node/src/chain/opPools/attestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/attestationPool.ts @@ -144,6 +144,7 @@ export class AttestationPool { /** * For validator API to get an aggregate */ + // TODO Electra: Change attestation pool to accomodate pre-electra request getAggregate(slot: Slot, committeeIndex: CommitteeIndex, dataRootHex: RootHex): Attestation | null { const aggregate = this.aggregateByIndexByRootBySlot.get(slot)?.get(dataRootHex)?.get(committeeIndex); if (!aggregate) { @@ -233,7 +234,7 @@ function attestationToAggregate(attestation: Attestation): AggregateFast { } /** - * Unwrap AggregateFast to phase0.Attestation + * Unwrap AggregateFast to Attestation */ function fastToAttestation(aggFast: AggregateFast): Attestation { return {...aggFast, signature: aggFast.signature.toBytes()}; diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index fc4558d9d995..a2180a718fee 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -285,6 +285,7 @@ export class OpPool { } /** For beacon pool API */ + // TODO Electra: Update to adapt electra.AttesterSlashing getAllAttesterSlashings(): phase0.AttesterSlashing[] { return Array.from(this.attesterSlashings.values()).map((attesterSlashings) => attesterSlashings.attesterSlashing); } diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 839f7850f75d..8034b998fdce 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -28,7 +28,7 @@ export type AggregateAndProofValidationResult = { export async function validateApiAggregateAndProof( fork: ForkName, chain: IBeaconChain, - signedAggregateAndProof: phase0.SignedAggregateAndProof + signedAggregateAndProof: SignedAggregateAndProof ): Promise { const skipValidationKnownAttesters = true; const prioritizeBls = true; diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index 51fa7bd376c8..9e6f08a803c1 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -454,10 +454,7 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler } } - chain.emitter.emit(routes.events.EventType.attestation, { - version: fork, - data: signedAggregateAndProof.message.aggregate, - }); + chain.emitter.emit(routes.events.EventType.attestation, signedAggregateAndProof.message.aggregate); }, [GossipType.beacon_attestation]: async ({ gossipData, @@ -509,7 +506,7 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler } } - chain.emitter.emit(routes.events.EventType.attestation, {version: fork, data: attestation}); + chain.emitter.emit(routes.events.EventType.attestation, attestation); }, [GossipType.attester_slashing]: async ({ @@ -529,7 +526,7 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler logger.error("Error adding attesterSlashing to pool", {}, e as Error); } - chain.emitter.emit(routes.events.EventType.attesterSlashing, {version: topic.fork, data: attesterSlashing}); + chain.emitter.emit(routes.events.EventType.attesterSlashing, attesterSlashing); }, [GossipType.proposer_slashing]: async ({ @@ -717,7 +714,7 @@ function getBatchHandlers(modules: ValidatorFnsModules, options: GossipHandlerOp } } - chain.emitter.emit(routes.events.EventType.attestation, {version: fork, data: attestation}); + chain.emitter.emit(routes.events.EventType.attestation, attestation); } if (batchableBls) { diff --git a/packages/beacon-node/test/unit/api/impl/events/events.test.ts b/packages/beacon-node/test/unit/api/impl/events/events.test.ts index b1f85b5e6e44..e031c3ac9958 100644 --- a/packages/beacon-node/test/unit/api/impl/events/events.test.ts +++ b/packages/beacon-node/test/unit/api/impl/events/events.test.ts @@ -2,7 +2,6 @@ import {describe, it, expect, beforeEach, afterEach, vi, MockedObject} from "vit import {routes} from "@lodestar/api"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; -import {ForkName} from "@lodestar/params"; import {BeaconChain, ChainEventEmitter, HeadEventData} from "../../../../../src/chain/index.js"; import {getEventsApi} from "../../../../../src/api/impl/events/index.js"; import {ZERO_HASH_HEX} from "../../../../../src/constants/constants.js"; @@ -67,10 +66,7 @@ describe("Events api impl", function () { it("should ignore not sent topics", async function () { const events = getEvents([routes.events.EventType.head]); - chainEventEmmitter.emit(routes.events.EventType.attestation, { - version: ForkName.phase0, - data: ssz.phase0.Attestation.defaultValue(), - }); + chainEventEmmitter.emit(routes.events.EventType.attestation, ssz.phase0.Attestation.defaultValue()); chainEventEmmitter.emit(routes.events.EventType.head, headEventData); expect(events).toHaveLength(1); diff --git a/packages/flare/src/cmds/selfSlashAttester.ts b/packages/flare/src/cmds/selfSlashAttester.ts index 8b43e6a92cb0..cb29ed94bb74 100644 --- a/packages/flare/src/cmds/selfSlashAttester.ts +++ b/packages/flare/src/cmds/selfSlashAttester.ts @@ -130,7 +130,7 @@ export async function selfSlashAttesterHandler(args: SelfSlashArgs): Promise 0) { try { - (await this.api.validator.publishAggregateAndProofs({signedAggregateAndProofs})).assertOk(); + (await this.api.validator.publishAggregateAndProofsV2({signedAggregateAndProofs})).assertOk(); this.logger.info("Published aggregateAndProofs", {...logCtx, count: signedAggregateAndProofs.length}); this.metrics?.publishedAggregates.inc(signedAggregateAndProofs.length); } catch (e) { diff --git a/packages/validator/test/unit/services/attestation.test.ts b/packages/validator/test/unit/services/attestation.test.ts index fdfc34c857b9..591ac51fa05e 100644 --- a/packages/validator/test/unit/services/attestation.test.ts +++ b/packages/validator/test/unit/services/attestation.test.ts @@ -106,12 +106,12 @@ describe("AttestationService", function () { // Mock beacon's attestation and aggregates endpoints api.validator.produceAttestationData.mockResolvedValue(mockApiResponse({data: attestation.data})); - api.validator.getAggregatedAttestation.mockResolvedValue( + api.validator.getAggregatedAttestationV2.mockResolvedValue( mockApiResponse({data: attestation, meta: {version: ForkName.phase0}}) ); - api.beacon.submitPoolAttestations.mockResolvedValue(mockApiResponse({})); - api.validator.publishAggregateAndProofs.mockResolvedValue(mockApiResponse({})); + api.beacon.submitPoolAttestationsV2.mockResolvedValue(mockApiResponse({})); + api.validator.publishAggregateAndProofsV2.mockResolvedValue(mockApiResponse({})); if (opts.distributedAggregationSelection) { // Mock distributed validator middleware client selections endpoint @@ -153,12 +153,12 @@ describe("AttestationService", function () { } // Must submit the attestation received through produceAttestationData() - expect(api.beacon.submitPoolAttestations).toHaveBeenCalledOnce(); - expect(api.beacon.submitPoolAttestations).toHaveBeenCalledWith({signedAttestations: [attestation]}); + expect(api.beacon.submitPoolAttestationsV2).toHaveBeenCalledOnce(); + expect(api.beacon.submitPoolAttestationsV2).toHaveBeenCalledWith({signedAttestations: [attestation]}); - // Must submit the aggregate received through getAggregatedAttestation() then createAndSignAggregateAndProof() - expect(api.validator.publishAggregateAndProofs).toHaveBeenCalledOnce(); - expect(api.validator.publishAggregateAndProofs).toHaveBeenCalledWith({signedAggregateAndProofs: [aggregate]}); + // Must submit the aggregate received through getAggregatedAttestationV2() then createAndSignAggregateAndProof() + expect(api.validator.publishAggregateAndProofsV2).toHaveBeenCalledOnce(); + expect(api.validator.publishAggregateAndProofsV2).toHaveBeenCalledWith({signedAggregateAndProofs: [aggregate]}); }); }); } diff --git a/packages/validator/test/utils/apiStub.ts b/packages/validator/test/utils/apiStub.ts index 3c1d80fff75d..ef615af03369 100644 --- a/packages/validator/test/utils/apiStub.ts +++ b/packages/validator/test/utils/apiStub.ts @@ -20,6 +20,7 @@ export function getApiClientStub(): ApiClientStub { publishBlockV2: vi.fn(), submitPoolSyncCommitteeSignatures: vi.fn(), submitPoolAttestations: vi.fn(), + submitPoolAttestationsV2: vi.fn(), }, node: { getSyncingStatus: vi.fn(), @@ -36,7 +37,9 @@ export function getApiClientStub(): ApiClientStub { submitSyncCommitteeSelections: vi.fn(), produceAttestationData: vi.fn(), getAggregatedAttestation: vi.fn(), + getAggregatedAttestationV2: vi.fn(), publishAggregateAndProofs: vi.fn(), + publishAggregateAndProofsV2: vi.fn(), submitBeaconCommitteeSelections: vi.fn(), }, httpClient: httpClientStub, From e5cda9caf12168f9364be36afbdec653f1018082 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Tue, 6 Aug 2024 16:13:21 +0800 Subject: [PATCH 070/259] Update packages/beacon-node/src/chain/validation/aggregateAndProof.ts Co-authored-by: Cayman Update packages/types/src/utils/typeguards.ts Co-authored-by: Cayman Partial address comment Partial address comment Co-authored-by: Cayman --- packages/api/src/beacon/routes/beacon/pool.ts | 22 +++++++++---------- packages/api/src/beacon/routes/validator.ts | 12 +++++----- packages/beacon-node/src/chain/chain.ts | 3 +-- .../beacon-node/src/chain/genesis/genesis.ts | 8 +------ .../chain/stateCache/fifoBlockStateCache.ts | 2 +- .../stateCache/persistentCheckpointsCache.ts | 6 ++++- .../src/chain/validation/aggregateAndProof.ts | 2 +- .../src/eth1/eth1DepositDataTracker.ts | 2 +- .../src/metrics/metrics/lodestar.ts | 2 +- .../beacon-node/src/network/gossip/topic.ts | 3 +-- .../src/options/beaconNodeOptions/network.ts | 8 +++---- packages/cli/src/util/gitData/index.ts | 4 ++-- packages/config/src/forkConfig/index.ts | 8 +++---- packages/config/src/forkConfig/types.ts | 4 ++-- packages/params/src/forkName.ts | 6 ++--- packages/prover/src/utils/gitData/index.ts | 4 ++-- packages/state-transition/package.json | 4 ---- .../src/block/processConsolidationRequest.ts | 2 +- .../state-transition/src/cache/epochCache.ts | 16 +++++++------- .../epoch/processPendingBalanceDeposits.ts | 2 +- .../src/slot/upgradeStateToElectra.ts | 4 ++-- packages/state-transition/src/util/epoch.ts | 4 ++-- packages/state-transition/src/util/genesis.ts | 4 ++-- .../state-transition/src/util/validator.ts | 16 +++++++------- .../test/unit/util/deposit.test.ts | 6 ++--- packages/types/src/utils/typeguards.ts | 6 ++--- packages/utils/src/promise.ts | 2 +- .../validator/src/services/attestation.ts | 8 +++---- .../validator/src/services/validatorStore.ts | 6 ++--- 29 files changed, 84 insertions(+), 92 deletions(-) diff --git a/packages/api/src/beacon/routes/beacon/pool.ts b/packages/api/src/beacon/routes/beacon/pool.ts index aa2c36d3bc92..42880b276732 100644 --- a/packages/api/src/beacon/routes/beacon/pool.ts +++ b/packages/api/src/beacon/routes/beacon/pool.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; -import {isForkElectra} from "@lodestar/params"; +import {isForkPostElectra} from "@lodestar/params"; import {phase0, capella, CommitteeIndex, Slot, ssz, electra, AttesterSlashing} from "@lodestar/types"; import {Schema, Endpoint, RouteDefinitions} from "../../../utils/index.js"; import { @@ -262,7 +262,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions (isForkElectra(fork) ? AttestationListTypeElectra : AttestationListTypePhase0)), + data: WithVersion((fork) => (isForkPostElectra(fork) ? AttestationListTypeElectra : AttestationListTypePhase0)), meta: VersionCodec, }, }, @@ -281,7 +281,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions - isForkElectra(fork) ? AttesterSlashingListTypeElectra : AttesterSlashingListTypePhase0 + isForkPostElectra(fork) ? AttesterSlashingListTypeElectra : AttesterSlashingListTypePhase0 ), meta: VersionCodec, }, @@ -336,7 +336,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = config.getForkName(signedAttestations[0]?.data.slot ?? 0); return { - body: isForkElectra(fork) + body: isForkPostElectra(fork) ? AttestationListTypeElectra.toJson(signedAttestations as AttestationListElectra) : AttestationListTypePhase0.toJson(signedAttestations as AttestationListPhase0), headers: {[MetaHeader.Version]: fork}, @@ -345,7 +345,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedAttestations: isForkElectra(fork) + signedAttestations: isForkPostElectra(fork) ? AttestationListTypeElectra.fromJson(body) : AttestationListTypePhase0.fromJson(body), }; @@ -353,7 +353,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = config.getForkName(signedAttestations[0]?.data.slot ?? 0); return { - body: isForkElectra(fork) + body: isForkPostElectra(fork) ? AttestationListTypeElectra.serialize(signedAttestations as AttestationListElectra) : AttestationListTypePhase0.serialize(signedAttestations as AttestationListPhase0), headers: {[MetaHeader.Version]: fork}, @@ -362,7 +362,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedAttestations: isForkElectra(fork) + signedAttestations: isForkPostElectra(fork) ? AttestationListTypeElectra.deserialize(body) : AttestationListTypePhase0.deserialize(body), }; @@ -395,7 +395,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = config.getForkName(Number(attesterSlashing.attestation1.data.slot)); return { - body: isForkElectra(fork) + body: isForkPostElectra(fork) ? ssz.electra.AttesterSlashing.toJson(attesterSlashing) : ssz.phase0.AttesterSlashing.toJson(attesterSlashing), headers: {[MetaHeader.Version]: fork}, @@ -404,7 +404,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - attesterSlashing: isForkElectra(fork) + attesterSlashing: isForkPostElectra(fork) ? ssz.electra.AttesterSlashing.fromJson(body) : ssz.phase0.AttesterSlashing.fromJson(body), }; @@ -412,7 +412,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = config.getForkName(Number(attesterSlashing.attestation1.data.slot)); return { - body: isForkElectra(fork) + body: isForkPostElectra(fork) ? ssz.electra.AttesterSlashing.serialize(attesterSlashing as electra.AttesterSlashing) : ssz.electra.AttesterSlashing.serialize(attesterSlashing as phase0.AttesterSlashing), headers: {[MetaHeader.Version]: fork}, @@ -421,7 +421,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - attesterSlashing: isForkElectra(fork) + attesterSlashing: isForkPostElectra(fork) ? ssz.electra.AttesterSlashing.deserialize(body) : ssz.phase0.AttesterSlashing.deserialize(body), }; diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index ed7c0fd9ba0a..5bc5c17c09b3 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, fromHexString, toHexString, Type, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; -import {isForkBlobs, isForkElectra} from "@lodestar/params"; +import {isForkBlobs, isForkPostElectra} from "@lodestar/params"; import { altair, BLSSignature, @@ -869,7 +869,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions (isForkElectra(fork) ? ssz.electra.Attestation : ssz.phase0.Attestation)), + data: WithVersion((fork) => (isForkPostElectra(fork) ? ssz.electra.Attestation : ssz.phase0.Attestation)), meta: VersionCodec, }, }, @@ -898,7 +898,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = config.getForkName(signedAggregateAndProofs[0]?.message.aggregate.data.slot ?? 0); return { - body: isForkElectra(fork) + body: isForkPostElectra(fork) ? SignedAggregateAndProofListElectraType.toJson( signedAggregateAndProofs as SignedAggregateAndProofListElectra ) @@ -911,7 +911,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedAggregateAndProofs: isForkElectra(fork) + signedAggregateAndProofs: isForkPostElectra(fork) ? SignedAggregateAndProofListElectraType.fromJson(body) : SignedAggregateAndProofListPhase0Type.fromJson(body), }; @@ -919,7 +919,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = config.getForkName(signedAggregateAndProofs[0]?.message.aggregate.data.slot ?? 0); return { - body: isForkElectra(fork) + body: isForkPostElectra(fork) ? SignedAggregateAndProofListElectraType.serialize( signedAggregateAndProofs as SignedAggregateAndProofListElectra ) @@ -932,7 +932,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedAggregateAndProofs: isForkElectra(fork) + signedAggregateAndProofs: isForkPostElectra(fork) ? SignedAggregateAndProofListElectraType.deserialize(body) : SignedAggregateAndProofListPhase0Type.deserialize(body), }; diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 9f30936305f0..598b26d7061f 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -1120,11 +1120,10 @@ export class BeaconChain implements IBeaconChain { } const cpEpoch = cp.epoch; - const electraEpoch = headState?.config.ELECTRA_FORK_EPOCH ?? Infinity; if (headState === null) { this.logger.verbose("Head state is null"); - } else if (cpEpoch >= electraEpoch) { + } else if (cpEpoch >= this.config.ELECTRA_FORK_EPOCH) { // Get the validator.length from the state at cpEpoch // We are confident the last element in the list is from headEpoch // Thus we query from the end of the list. (cpEpoch - headEpoch - 1) is negative number diff --git a/packages/beacon-node/src/chain/genesis/genesis.ts b/packages/beacon-node/src/chain/genesis/genesis.ts index 5efd352357eb..979476c69530 100644 --- a/packages/beacon-node/src/chain/genesis/genesis.ts +++ b/packages/beacon-node/src/chain/genesis/genesis.ts @@ -174,13 +174,7 @@ export class GenesisBuilder implements IGenesisBuilder { }; }); - const {activatedValidatorCount} = applyDeposits( - this.config.getForkSeq(this.state.slot), - this.config, - this.state, - newDeposits, - this.depositTree - ); + const {activatedValidatorCount} = applyDeposits(this.config, this.state, newDeposits, this.depositTree); this.activatedValidatorCount += activatedValidatorCount; // TODO: If necessary persist deposits here to this.db.depositData, this.db.depositDataRoot diff --git a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts index f115806874f8..d38fc323174c 100644 --- a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts +++ b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts @@ -191,7 +191,7 @@ export class FIFOBlockStateCache implements BlockStateCache { } getStates(): IterableIterator { - throw new Error("Method not implemented."); + return this.cache.values(); } /** diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index c59c15de616d..b315beba46d9 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -595,7 +595,11 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { } getStates(): IterableIterator { - throw new Error("Method not implemented."); + const items = Array.from(this.cache.values()) + .filter(isInMemoryCacheItem) + .map((item) => item.state); + + return items.values(); } /** ONLY FOR DEBUGGING PURPOSES. For spec tests on error */ diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 8034b998fdce..02c6613b170f 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -180,7 +180,7 @@ async function validateAggregateAndProof( } const attestingIndices = aggregate.aggregationBits.intersectValues(committeeIndices); - const indexedAttestationContent = { + const indexedAttestationContent: IndexedAttestation = { attestingIndices, data: attData, signature: aggregate.signature, diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index d0578718f29f..a38b3f9987d9 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -128,7 +128,7 @@ export class Eth1DepositDataTracker { */ async getEth1DataAndDeposits(state: CachedBeaconStateAllForks): Promise { if ( - state.epochCtx.isAfterElectra() && + state.epochCtx.isPostElectra() && state.eth1DepositIndex >= (state as CachedBeaconStateElectra).depositRequestsStartIndex ) { // No need to poll eth1Data since Electra deprecates the mechanism after depositRequestsStartIndex is reached diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index 595e4a7a45fc..6b4bdb111f41 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -1397,7 +1397,7 @@ export function createLodestarMetrics( regenFnDeletePubkeyTime: register.histogram({ name: "lodestar_regen_fn_delete_pubkey_time_seconds", help: "Histrogram of time spent on deleting pubkeys from all state cache items in seconds", - buckets: [0.01, 0.1, 0.5, 1, 2, 5], + buckets: [0.01, 0.1, 0.5, 1], }), regenFnNumStatesUpdated: register.histogram({ name: "lodestar_regen_state_cache_state_updated_count", diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index dfca0eaf3dcd..f3968b8e65b6 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -129,9 +129,8 @@ export function sszDeserialize(topic: T, serializedData: * Deserialize a gossip serialized data into an Attestation object. */ export function sszDeserializeAttestation(fork: ForkName, serializedData: Uint8Array): Attestation { - const sszType = sszTypesFor(fork).Attestation; try { - return sszType.deserialize(serializedData); + return sszTypesFor(fork).Attestation.deserialize(serializedData); } catch (e) { throw new GossipActionError(GossipAction.REJECT, {code: GossipErrorCode.INVALID_SERIALIZED_BYTES_ERROR_CODE}); } diff --git a/packages/cli/src/options/beaconNodeOptions/network.ts b/packages/cli/src/options/beaconNodeOptions/network.ts index 25ba036a5dbf..6c6f1ed70cc6 100644 --- a/packages/cli/src/options/beaconNodeOptions/network.ts +++ b/packages/cli/src/options/beaconNodeOptions/network.ts @@ -63,13 +63,13 @@ export function parseListenArgs(args: NetworkArgs) { // If listenAddress is explicitly set, use it // If listenAddress6 is not set, use defaultListenAddress const listenAddress = args.listenAddress ?? (args.listenAddress6 ? undefined : defaultListenAddress); - const port = listenAddress ? args.port ?? defaultP2pPort : undefined; - const discoveryPort = listenAddress ? args.discoveryPort ?? args.port ?? defaultP2pPort : undefined; + const port = listenAddress ? (args.port ?? defaultP2pPort) : undefined; + const discoveryPort = listenAddress ? (args.discoveryPort ?? args.port ?? defaultP2pPort) : undefined; // Only use listenAddress6 if it is explicitly set const listenAddress6 = args.listenAddress6; - const port6 = listenAddress6 ? args.port6 ?? defaultP2pPort6 : undefined; - const discoveryPort6 = listenAddress6 ? args.discoveryPort6 ?? args.port6 ?? defaultP2pPort6 : undefined; + const port6 = listenAddress6 ? (args.port6 ?? defaultP2pPort6) : undefined; + const discoveryPort6 = listenAddress6 ? (args.discoveryPort6 ?? args.port6 ?? defaultP2pPort6) : undefined; return {listenAddress, port, discoveryPort, listenAddress6, port6, discoveryPort6}; } diff --git a/packages/cli/src/util/gitData/index.ts b/packages/cli/src/util/gitData/index.ts index 96c5e4bbaef2..93b748d42071 100644 --- a/packages/cli/src/util/gitData/index.ts +++ b/packages/cli/src/util/gitData/index.ts @@ -23,11 +23,11 @@ export function readAndGetGitData(): GitData { branch: currentGitData.branch && currentGitData.branch.length > 0 ? currentGitData.branch - : persistedGitData.branch ?? "", + : (persistedGitData.branch ?? ""), commit: currentGitData.commit && currentGitData.commit.length > 0 ? currentGitData.commit - : persistedGitData.commit ?? "", + : (persistedGitData.commit ?? ""), }; } catch (e) { return { diff --git a/packages/config/src/forkConfig/index.ts b/packages/config/src/forkConfig/index.ts index dd2a1773c390..513cd7559ee3 100644 --- a/packages/config/src/forkConfig/index.ts +++ b/packages/config/src/forkConfig/index.ts @@ -84,9 +84,9 @@ export function createForkConfig(config: ChainConfig): ForkConfig { // Fork convenience methods getForkInfo(slot: Slot): ForkInfo { const epoch = Math.floor(Math.max(slot, 0) / SLOTS_PER_EPOCH); - return this.getForkInfoFromEpoch(epoch); + return this.getForkInfoAtEpoch(epoch); }, - getForkInfoFromEpoch(epoch: Epoch): ForkInfo { + getForkInfoAtEpoch(epoch: Epoch): ForkInfo { // NOTE: forks must be sorted by descending epoch, latest fork first for (const fork of forksDescendingEpochOrder) { if (epoch >= fork.epoch) return fork; @@ -99,8 +99,8 @@ export function createForkConfig(config: ChainConfig): ForkConfig { getForkSeq(slot: Slot): ForkSeq { return this.getForkInfo(slot).seq; }, - getForkSeqFromEpoch(epoch: Epoch): ForkSeq { - return this.getForkInfoFromEpoch(epoch).seq; + getForkSeqAtEpoch(epoch: Epoch): ForkSeq { + return this.getForkInfoAtEpoch(epoch).seq; }, getForkVersion(slot: Slot): Version { return this.getForkInfo(slot).version; diff --git a/packages/config/src/forkConfig/types.ts b/packages/config/src/forkConfig/types.ts index dd0381f4e9bf..ebb2899a2a21 100644 --- a/packages/config/src/forkConfig/types.ts +++ b/packages/config/src/forkConfig/types.ts @@ -22,13 +22,13 @@ export type ForkConfig = { /** Get the hard-fork info for the active fork at `slot` */ getForkInfo(slot: Slot): ForkInfo; /** Get the hard-fork info for the active fork at `epoch` */ - getForkInfoFromEpoch(epoch: Epoch): ForkInfo; + getForkInfoAtEpoch(epoch: Epoch): ForkInfo; /** Get the hard-fork name at a given slot */ getForkName(slot: Slot): ForkName; /** Get the hard-fork sequence number at a given slot */ getForkSeq(slot: Slot): ForkSeq; /** Get the hard-fork sequence number at a given epoch */ - getForkSeqFromEpoch(epoch: Epoch): ForkSeq; + getForkSeqAtEpoch(epoch: Epoch): ForkSeq; /** Get the hard-fork version at a given slot */ getForkVersion(slot: Slot): Version; /** Get SSZ types by hard-fork */ diff --git a/packages/params/src/forkName.ts b/packages/params/src/forkName.ts index 4a41f0637340..42e8917942d2 100644 --- a/packages/params/src/forkName.ts +++ b/packages/params/src/forkName.ts @@ -82,14 +82,14 @@ export function isForkBlobs(fork: ForkName): fork is ForkBlobs { } export type ForkPreElectra = ForkPreBlobs | ForkName.deneb; -export type ForkElectra = Exclude; -export const forkElectra = exclude(forkAll, [ +export type ForkPostElectra = Exclude; +export const forkPostElectra = exclude(forkAll, [ ForkName.phase0, ForkName.altair, ForkName.bellatrix, ForkName.capella, ForkName.deneb, ]); -export function isForkElectra(fork: ForkName): fork is ForkElectra { +export function isForkPostElectra(fork: ForkName): fork is ForkPostElectra { return isForkBlobs(fork) && fork !== ForkName.deneb; } diff --git a/packages/prover/src/utils/gitData/index.ts b/packages/prover/src/utils/gitData/index.ts index 96c5e4bbaef2..93b748d42071 100644 --- a/packages/prover/src/utils/gitData/index.ts +++ b/packages/prover/src/utils/gitData/index.ts @@ -23,11 +23,11 @@ export function readAndGetGitData(): GitData { branch: currentGitData.branch && currentGitData.branch.length > 0 ? currentGitData.branch - : persistedGitData.branch ?? "", + : (persistedGitData.branch ?? ""), commit: currentGitData.commit && currentGitData.commit.length > 0 ? currentGitData.commit - : persistedGitData.commit ?? "", + : (persistedGitData.commit ?? ""), }; } catch (e) { return { diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index c9551195e87e..480f804785e8 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -69,12 +69,8 @@ "@lodestar/types": "^1.21.0", "@lodestar/utils": "^1.21.0", "bigint-buffer": "^1.1.5", - "buffer-xor": "^2.0.2", "immutable": "^4.3.2" }, - "devDependencies": { - "@types/buffer-xor": "^2.0.0" - }, "keywords": [ "ethereum", "eth-consensus", diff --git a/packages/state-transition/src/block/processConsolidationRequest.ts b/packages/state-transition/src/block/processConsolidationRequest.ts index 2f12065fde41..71b85e927336 100644 --- a/packages/state-transition/src/block/processConsolidationRequest.ts +++ b/packages/state-transition/src/block/processConsolidationRequest.ts @@ -16,7 +16,7 @@ export function processConsolidationRequest( } // If there is too little available consolidation churn limit, consolidation requests are ignored - if (getConsolidationChurnLimit(state) <= MIN_ACTIVATION_BALANCE) { + if (getConsolidationChurnLimit(state.epochCtx) <= MIN_ACTIVATION_BALANCE) { return; } diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index cf463a93a92b..af6e976e9089 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -400,7 +400,7 @@ export class EpochCache { const proposers = currentShuffling.activeIndices.length > 0 ? computeProposers( - config.getForkSeqFromEpoch(currentEpoch), + config.getForkSeqAtEpoch(currentEpoch), currentProposerSeed, currentShuffling, effectiveBalanceIncrements @@ -584,7 +584,7 @@ export class EpochCache { const currentProposerSeed = getSeed(state, this.currentShuffling.epoch, DOMAIN_BEACON_PROPOSER); this.proposers = computeProposers( - this.config.getForkSeqFromEpoch(currEpoch), + this.config.getForkSeqAtEpoch(currEpoch), currentProposerSeed, this.currentShuffling, this.effectiveBalanceIncrements @@ -785,7 +785,7 @@ export class EpochCache { getBeaconProposersNextEpoch(): ValidatorIndex[] { if (!this.proposersNextEpoch.computed) { const indexes = computeProposers( - this.config.getForkSeqFromEpoch(this.epoch + 1), + this.config.getForkSeqAtEpoch(this.epoch + 1), this.proposersNextEpoch.seed, this.nextShuffling, this.effectiveBalanceIncrements @@ -914,7 +914,7 @@ export class EpochCache { } getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { - if (this.isAfterElectra()) { + if (this.isPostElectra()) { return this.pubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); } else { return this.pubkey2index.get(pubkey); @@ -927,7 +927,7 @@ export class EpochCache { * */ addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { - if (this.isAfterElectra()) { + if (this.isPostElectra()) { this.addUnFinalizedPubkey(index, pubkey); } else { // deposit mechanism pre ELECTRA follows a safe distance with assumption @@ -1049,7 +1049,7 @@ export class EpochCache { } effectiveBalanceIncrementsSet(index: number, effectiveBalance: number): void { - if (this.isAfterElectra()) { + if (this.isPostElectra()) { // TODO: electra // getting length and setting getEffectiveBalanceIncrementsByteLen is not fork safe // so each time we add an index, we should new the Uint8Array to keep it forksafe @@ -1074,8 +1074,8 @@ export class EpochCache { this.effectiveBalanceIncrements[index] = Math.floor(effectiveBalance / EFFECTIVE_BALANCE_INCREMENT); } - isAfterElectra(): boolean { - return this.epoch >= (this.config.ELECTRA_FORK_EPOCH ?? Infinity); + isPostElectra(): boolean { + return this.epoch >= this.config.ELECTRA_FORK_EPOCH; } getValidatorCountAtEpoch(targetEpoch: Epoch): number | undefined { diff --git a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts index e6e43bbaa089..f89e938cc790 100644 --- a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts @@ -14,7 +14,7 @@ import {getCurrentEpoch} from "../util/epoch.js"; * TODO Electra: Update ssz library to support batch push to `pendingBalanceDeposits` */ export function processPendingBalanceDeposits(state: CachedBeaconStateElectra): void { - const availableForProcessing = state.depositBalanceToConsume + BigInt(getActivationExitChurnLimit(state)); + const availableForProcessing = state.depositBalanceToConsume + BigInt(getActivationExitChurnLimit(state.epochCtx)); const currentEpoch = getCurrentEpoch(state); let processedAmount = 0n; let nextDepositIndex = 0; diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 974f0d6a608b..ef7b0bd661b4 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -92,8 +92,8 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache // TODO-electra: can we improve this? stateElectraView.commit(); const tmpElectraState = getCachedBeaconState(stateElectraView, stateDeneb); - stateElectraView.exitBalanceToConsume = BigInt(getActivationExitChurnLimit(tmpElectraState)); - stateElectraView.consolidationBalanceToConsume = BigInt(getConsolidationChurnLimit(tmpElectraState)); + stateElectraView.exitBalanceToConsume = BigInt(getActivationExitChurnLimit(tmpElectraState.epochCtx)); + stateElectraView.consolidationBalanceToConsume = BigInt(getConsolidationChurnLimit(tmpElectraState.epochCtx)); preActivation.sort((i0, i1) => { const res = validatorsArr[i0].activationEligibilityEpoch - validatorsArr[i1].activationEligibilityEpoch; diff --git a/packages/state-transition/src/util/epoch.ts b/packages/state-transition/src/util/epoch.ts index 66bd2ad76b34..7fed5e53f1f3 100644 --- a/packages/state-transition/src/util/epoch.ts +++ b/packages/state-transition/src/util/epoch.ts @@ -43,7 +43,7 @@ export function computeActivationExitEpoch(epoch: Epoch): Epoch { export function computeExitEpochAndUpdateChurn(state: CachedBeaconStateElectra, exitBalance: Gwei): number { let earliestExitEpoch = Math.max(state.earliestExitEpoch, computeActivationExitEpoch(state.epochCtx.epoch)); - const perEpochChurn = getActivationExitChurnLimit(state); + const perEpochChurn = getActivationExitChurnLimit(state.epochCtx); // New epoch for exits. let exitBalanceToConsume = @@ -72,7 +72,7 @@ export function computeConsolidationEpochAndUpdateChurn( state.earliestConsolidationEpoch, computeActivationExitEpoch(state.epochCtx.epoch) ); - const perEpochConsolidationChurn = getConsolidationChurnLimit(state); + const perEpochConsolidationChurn = getConsolidationChurnLimit(state.epochCtx); // New epoch for consolidations let consolidationBalanceToConsume = diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 7bdc420d6458..02bcef00bb55 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -129,12 +129,12 @@ export function applyTimestamp(config: ChainForkConfig, state: CachedBeaconState * @returns active validator indices */ export function applyDeposits( - fork: ForkSeq, config: ChainForkConfig, state: CachedBeaconStateAllForks, newDeposits: phase0.Deposit[], fullDepositDataRootList?: DepositDataRootViewDU ): {activatedValidatorCount: number} { + const fork = config.getForkSeq(state.slot); const depositDataRootList: Root[] = []; const fullDepositDataRootArr = fullDepositDataRootList ? fullDepositDataRootList.getAllReadonlyValues() : null; @@ -258,7 +258,7 @@ export function initializeBeaconStateFromEth1( applyEth1BlockHash(state, eth1BlockHash); // Process deposits - applyDeposits(fork, config, state, deposits, fullDepositDataRootList); + applyDeposits(config, state, deposits, fullDepositDataRootList); // Commit before reading all validators in `getActiveValidatorIndices()` state.commit(); diff --git a/packages/state-transition/src/util/validator.ts b/packages/state-transition/src/util/validator.ts index 0c8c74b2cb03..728f14587fde 100644 --- a/packages/state-transition/src/util/validator.ts +++ b/packages/state-transition/src/util/validator.ts @@ -7,7 +7,7 @@ import { MAX_EFFECTIVE_BALANCE_ELECTRA, MIN_ACTIVATION_BALANCE, } from "@lodestar/params"; -import {BeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; +import {BeaconStateAllForks, CachedBeaconStateElectra, EpochCache} from "../types.js"; import {hasCompoundingWithdrawalCredential} from "./electra.js"; /** @@ -57,22 +57,22 @@ export function getChurnLimit(config: ChainForkConfig, activeValidatorCount: num /** * Get combined churn limit of activation-exit and consolidation */ -export function getBalanceChurnLimit(state: CachedBeaconStateElectra): number { +export function getBalanceChurnLimit(epochCtx: EpochCache): number { const churnLimitByTotalActiveBalance = Math.floor( - (state.epochCtx.totalActiveBalanceIncrements / state.config.CHURN_LIMIT_QUOTIENT) * EFFECTIVE_BALANCE_INCREMENT + (epochCtx.totalActiveBalanceIncrements / epochCtx.config.CHURN_LIMIT_QUOTIENT) * EFFECTIVE_BALANCE_INCREMENT ); // TODO Electra: verify calculation - const churn = Math.max(churnLimitByTotalActiveBalance, state.config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA); + const churn = Math.max(churnLimitByTotalActiveBalance, epochCtx.config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA); return churn - (churn % EFFECTIVE_BALANCE_INCREMENT); } -export function getActivationExitChurnLimit(state: CachedBeaconStateElectra): number { - return Math.min(state.config.MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT, getBalanceChurnLimit(state)); +export function getActivationExitChurnLimit(epochCtx: EpochCache): number { + return Math.min(epochCtx.config.MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT, getBalanceChurnLimit(epochCtx)); } -export function getConsolidationChurnLimit(state: CachedBeaconStateElectra): number { - return getBalanceChurnLimit(state) - getActivationExitChurnLimit(state); +export function getConsolidationChurnLimit(epochCtx: EpochCache): number { + return getBalanceChurnLimit(epochCtx) - getActivationExitChurnLimit(epochCtx); } export function getValidatorMaxEffectiveBalance(withdrawalCredentials: Uint8Array): number { diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts index 677a15724ece..b108de502a1f 100644 --- a/packages/state-transition/test/unit/util/deposit.test.ts +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -10,7 +10,7 @@ describe("getEth1DepositCount", () => { const stateView = ssz.altair.BeaconState.defaultViewDU(); const preElectraState = createCachedBeaconStateTest(stateView); - if (preElectraState.epochCtx.isAfterElectra()) { + if (preElectraState.epochCtx.isPostElectra()) { throw Error("Not a pre-Electra state"); } @@ -39,7 +39,7 @@ describe("getEth1DepositCount", () => { {skipSyncCommitteeCache: true, skipSyncPubkeys: true} ) as CachedBeaconStateElectra; - if (!postElectraState.epochCtx.isAfterElectra()) { + if (!postElectraState.epochCtx.isPostElectra()) { throw Error("Not a post-Electra state"); } @@ -73,7 +73,7 @@ describe("getEth1DepositCount", () => { {skipSyncCommitteeCache: true, skipSyncPubkeys: true} ) as CachedBeaconStateElectra; - if (!postElectraState.epochCtx.isAfterElectra()) { + if (!postElectraState.epochCtx.isPostElectra()) { throw Error("Not a post-Electra state"); } diff --git a/packages/types/src/utils/typeguards.ts b/packages/types/src/utils/typeguards.ts index 2af11159878c..72910645f6e1 100644 --- a/packages/types/src/utils/typeguards.ts +++ b/packages/types/src/utils/typeguards.ts @@ -1,4 +1,4 @@ -import {ForkBlobs, ForkExecution, ForkElectra} from "@lodestar/params"; +import {ForkBlobs, ForkExecution, ForkPostElectra} from "@lodestar/params"; import { BlockContents, SignedBeaconBlock, @@ -68,6 +68,6 @@ export function isSignedBlockContents( return (data as SignedBlockContents).kzgProofs !== undefined; } -export function isElectraAttestation(attestation: Attestation): attestation is Attestation { - return (attestation as Attestation).committeeBits !== undefined; +export function isElectraAttestation(attestation: Attestation): attestation is Attestation { + return (attestation as Attestation).committeeBits !== undefined; } diff --git a/packages/utils/src/promise.ts b/packages/utils/src/promise.ts index 2be7467bfff4..81fa72e7d587 100644 --- a/packages/utils/src/promise.ts +++ b/packages/utils/src/promise.ts @@ -109,7 +109,7 @@ export async function resolveOrRacePromises wrapPromise(p)) as ReturnPromiseWithTuple; // We intentionally want an array of promises here - // eslint-disable-next-line @typescript-eslint/no-floating-promises + promises = (promiseResults as PromiseResult[]).map((p) => p.promise) as unknown as T; try { diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index 4226bd572bd0..d6f48aeb3d1f 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -159,13 +159,13 @@ export class AttestationService { this.metrics?.attesterStepCallProduceAggregate.observe(this.clock.secFromSlot(slot + 2 / 3)); const dutiesByCommitteeIndex = groupAttDutiesByCommitteeIndex(dutiesAll); - const isAfterElectra = computeEpochAtSlot(slot) >= this.config.ELECTRA_FORK_EPOCH; + const isPostElectra = computeEpochAtSlot(slot) >= this.config.ELECTRA_FORK_EPOCH; // Then download, sign and publish a `SignedAggregateAndProof` for each // validator that is elected to aggregate for this `slot` and `committeeIndex`. await Promise.all( Array.from(dutiesByCommitteeIndex.entries()).map(([index, dutiesSameCommittee]) => { - const attestationData: phase0.AttestationData = {...attestationNoCommittee, index: isAfterElectra ? 0 : index}; + const attestationData: phase0.AttestationData = {...attestationNoCommittee, index: isPostElectra ? 0 : index}; return this.produceAndPublishAggregates(attestationData, index, dutiesSameCommittee); }) ); @@ -196,11 +196,11 @@ export class AttestationService { const signedAttestations: Attestation[] = []; const headRootHex = toHexString(attestationNoCommittee.beaconBlockRoot); const currentEpoch = computeEpochAtSlot(slot); - const isAfterElectra = currentEpoch >= this.config.ELECTRA_FORK_EPOCH; + const isPostElectra = currentEpoch >= this.config.ELECTRA_FORK_EPOCH; await Promise.all( duties.map(async ({duty}) => { - const index = isAfterElectra ? 0 : duty.committeeIndex; + const index = isPostElectra ? 0 : duty.committeeIndex; const attestationData: phase0.AttestationData = {...attestationNoCommittee, index}; const logCtxValidator = {slot, index, head: headRootHex, validatorIndex: duty.validatorIndex}; diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index cea281f0d144..252d0886cc6e 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -801,13 +801,13 @@ export class ValidatorStore { throw Error(`Inconsistent duties during signing: duty.slot ${duty.slot} != att.slot ${data.slot}`); } - const isAfterElectra = computeEpochAtSlot(duty.slot) >= this.config.ELECTRA_FORK_EPOCH; - if (!isAfterElectra && duty.committeeIndex != data.index) { + const isPostElectra = computeEpochAtSlot(duty.slot) >= this.config.ELECTRA_FORK_EPOCH; + if (!isPostElectra && duty.committeeIndex != data.index) { throw Error( `Inconsistent duties during signing: duty.committeeIndex ${duty.committeeIndex} != att.committeeIndex ${data.index}` ); } - if (isAfterElectra && data.index !== 0) { + if (isPostElectra && data.index !== 0) { throw Error(`Non-zero committee index post-electra during signing: att.committeeIndex ${data.index}`); } if (this.config.getForkSeq(duty.slot) >= ForkSeq.electra && data.index !== 0) { From da0f40c43c8068892c2a5eae4d562ce330765428 Mon Sep 17 00:00:00 2001 From: harkamal Date: Wed, 7 Aug 2024 16:25:24 +0530 Subject: [PATCH 071/259] fix: fix the devnet2 bug of invalid stateroot calc post consolidation --- packages/state-transition/src/util/electra.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/state-transition/src/util/electra.ts b/packages/state-transition/src/util/electra.ts index 666f45435eb1..63f74bc96cc9 100644 --- a/packages/state-transition/src/util/electra.ts +++ b/packages/state-transition/src/util/electra.ts @@ -68,7 +68,12 @@ export function switchToCompoundingValidator(state: CachedBeaconStateElectra, in const validator = state.validators.get(index); if (hasEth1WithdrawalCredential(validator.withdrawalCredentials)) { - validator.withdrawalCredentials[0] = COMPOUNDING_WITHDRAWAL_PREFIX; + // directly modifying the byte leads to ssz missing the modification resulting into + // wrong root compute, although slicing can be avoided but anyway this is not going + // to be a hot path so its better to clean slice and avoid side effects + const newWithdrawalCredentials = validator.withdrawalCredentials.slice(); + newWithdrawalCredentials[0] = COMPOUNDING_WITHDRAWAL_PREFIX; + validator.withdrawalCredentials = newWithdrawalCredentials; queueExcessActiveBalance(state, index); } } From dc4fa9ec04c14e87c96e70871ae3d422f61203ed Mon Sep 17 00:00:00 2001 From: gajinder Date: Fri, 9 Aug 2024 14:19:39 +0530 Subject: [PATCH 072/259] chore: further rebase fixes to unstable lint fixes lint Fix browser test Fix unit test --------- Co-authored-by: NC <17676176+ensi321@users.noreply.github.com> --- .../src/chain/blocks/importBlock.ts | 10 ++---- .../src/options/beaconNodeOptions/network.ts | 8 ++--- packages/cli/src/util/gitData/index.ts | 4 +-- .../test/unit/webEsmBundle.browser.test.ts | 4 +-- packages/prover/src/utils/gitData/index.ts | 4 +-- .../state-transition/src/cache/pubkeyCache.ts | 1 - .../test/unit/cachedBeaconState.test.ts | 2 +- packages/utils/src/promise.ts | 2 +- yarn.lock | 36 ++----------------- 9 files changed, 16 insertions(+), 55 deletions(-) diff --git a/packages/beacon-node/src/chain/blocks/importBlock.ts b/packages/beacon-node/src/chain/blocks/importBlock.ts index fa862a2fb31e..de5ecf607d95 100644 --- a/packages/beacon-node/src/chain/blocks/importBlock.ts +++ b/packages/beacon-node/src/chain/blocks/importBlock.ts @@ -409,18 +409,12 @@ export async function importBlock( } if (this.emitter.listenerCount(routes.events.EventType.attestation)) { for (const attestation of block.message.body.attestations) { - this.emitter.emit(routes.events.EventType.attestation, { - version: this.config.getForkName(blockSlot), - data: attestation, - }); + this.emitter.emit(routes.events.EventType.attestation, attestation); } } if (this.emitter.listenerCount(routes.events.EventType.attesterSlashing)) { for (const attesterSlashing of block.message.body.attesterSlashings) { - this.emitter.emit(routes.events.EventType.attesterSlashing, { - version: this.config.getForkName(blockSlot), - data: attesterSlashing, - }); + this.emitter.emit(routes.events.EventType.attesterSlashing, attesterSlashing); } } if (this.emitter.listenerCount(routes.events.EventType.proposerSlashing)) { diff --git a/packages/cli/src/options/beaconNodeOptions/network.ts b/packages/cli/src/options/beaconNodeOptions/network.ts index 6c6f1ed70cc6..25ba036a5dbf 100644 --- a/packages/cli/src/options/beaconNodeOptions/network.ts +++ b/packages/cli/src/options/beaconNodeOptions/network.ts @@ -63,13 +63,13 @@ export function parseListenArgs(args: NetworkArgs) { // If listenAddress is explicitly set, use it // If listenAddress6 is not set, use defaultListenAddress const listenAddress = args.listenAddress ?? (args.listenAddress6 ? undefined : defaultListenAddress); - const port = listenAddress ? (args.port ?? defaultP2pPort) : undefined; - const discoveryPort = listenAddress ? (args.discoveryPort ?? args.port ?? defaultP2pPort) : undefined; + const port = listenAddress ? args.port ?? defaultP2pPort : undefined; + const discoveryPort = listenAddress ? args.discoveryPort ?? args.port ?? defaultP2pPort : undefined; // Only use listenAddress6 if it is explicitly set const listenAddress6 = args.listenAddress6; - const port6 = listenAddress6 ? (args.port6 ?? defaultP2pPort6) : undefined; - const discoveryPort6 = listenAddress6 ? (args.discoveryPort6 ?? args.port6 ?? defaultP2pPort6) : undefined; + const port6 = listenAddress6 ? args.port6 ?? defaultP2pPort6 : undefined; + const discoveryPort6 = listenAddress6 ? args.discoveryPort6 ?? args.port6 ?? defaultP2pPort6 : undefined; return {listenAddress, port, discoveryPort, listenAddress6, port6, discoveryPort6}; } diff --git a/packages/cli/src/util/gitData/index.ts b/packages/cli/src/util/gitData/index.ts index 93b748d42071..96c5e4bbaef2 100644 --- a/packages/cli/src/util/gitData/index.ts +++ b/packages/cli/src/util/gitData/index.ts @@ -23,11 +23,11 @@ export function readAndGetGitData(): GitData { branch: currentGitData.branch && currentGitData.branch.length > 0 ? currentGitData.branch - : (persistedGitData.branch ?? ""), + : persistedGitData.branch ?? "", commit: currentGitData.commit && currentGitData.commit.length > 0 ? currentGitData.commit - : (persistedGitData.commit ?? ""), + : persistedGitData.commit ?? "", }; } catch (e) { return { diff --git a/packages/light-client/test/unit/webEsmBundle.browser.test.ts b/packages/light-client/test/unit/webEsmBundle.browser.test.ts index 49b0f877d46c..08ca86e52d75 100644 --- a/packages/light-client/test/unit/webEsmBundle.browser.test.ts +++ b/packages/light-client/test/unit/webEsmBundle.browser.test.ts @@ -1,7 +1,7 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ import {expect, describe, it, vi, beforeAll} from "vitest"; import {sleep} from "@lodestar/utils"; -import {Lightclient, LightclientEvent, utils, transport} from "../../src/index.js"; +import {Lightclient, LightclientEvent, utils, transport} from "../../dist/lightclient.min.mjs"; describe("web bundle for lightclient", () => { vi.setConfig({testTimeout: 20_000}); diff --git a/packages/prover/src/utils/gitData/index.ts b/packages/prover/src/utils/gitData/index.ts index 93b748d42071..96c5e4bbaef2 100644 --- a/packages/prover/src/utils/gitData/index.ts +++ b/packages/prover/src/utils/gitData/index.ts @@ -23,11 +23,11 @@ export function readAndGetGitData(): GitData { branch: currentGitData.branch && currentGitData.branch.length > 0 ? currentGitData.branch - : (persistedGitData.branch ?? ""), + : persistedGitData.branch ?? "", commit: currentGitData.commit && currentGitData.commit.length > 0 ? currentGitData.commit - : (persistedGitData.commit ?? ""), + : persistedGitData.commit ?? "", }; } catch (e) { return { diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index a7eacb7961fd..44fe6df45592 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -1,7 +1,6 @@ import {PublicKey} from "@chainsafe/blst"; import * as immutable from "immutable"; import {ValidatorIndex, phase0} from "@lodestar/types"; -import {BeaconStateAllForks} from "./types.js"; export type Index2PubkeyCache = PublicKey[]; /** diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index 9b05b8947f73..77c5da7a5f4a 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -131,7 +131,7 @@ describe("CachedBeaconState", () => { const capellaStateType = ssz.capella.BeaconState; - for (let validatorCountDelta = -numValidator; validatorCountDelta <= numValidator; validatorCountDelta++) { + for (let validatorCountDelta = -numValidator + 1; validatorCountDelta <= numValidator; validatorCountDelta++) { const testName = `loadCachedBeaconState - ${validatorCountDelta > 0 ? "more" : "less"} ${Math.abs( validatorCountDelta )} validators`; diff --git a/packages/utils/src/promise.ts b/packages/utils/src/promise.ts index 81fa72e7d587..2be7467bfff4 100644 --- a/packages/utils/src/promise.ts +++ b/packages/utils/src/promise.ts @@ -109,7 +109,7 @@ export async function resolveOrRacePromises wrapPromise(p)) as ReturnPromiseWithTuple; // We intentionally want an array of promises here - + // eslint-disable-next-line @typescript-eslint/no-floating-promises promises = (promiseResults as PromiseResult[]).map((p) => p.promise) as unknown as T; try { diff --git a/yarn.lock b/yarn.lock index ecfcb2c5ee6f..7e2e3d8e6447 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3050,13 +3050,6 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw== -"@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/cacheable-request@^6.0.1": version "6.0.3" resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" @@ -4633,13 +4626,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.yarnpkg.com/buffer-xor/-/buffer-xor-2.0.2.tgz#34f7c64f04c777a1f8aac5e661273bb9dd320289" - 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" @@ -12094,16 +12080,7 @@ string-argv@~0.3.1: 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" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -13678,7 +13655,7 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -13696,15 +13673,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From ce6a0c719f3e6d80f932b0bd8321985ac69251a9 Mon Sep 17 00:00:00 2001 From: twoeths Date: Tue, 13 Aug 2024 19:35:51 +0700 Subject: [PATCH 073/259] fix: cached balances in epoch transition (#7018) * fix: update cached balances in epoch transition * fix: more comments in processEffectiveBalanceUpdates() --- .../src/block/processAttestationsAltair.ts | 3 ++- packages/state-transition/src/epoch/index.ts | 4 ++-- .../epoch/processEffectiveBalanceUpdates.ts | 10 ++++------ .../src/epoch/processPendingBalanceDeposits.ts | 18 +++++++++++++----- .../src/epoch/processPendingConsolidations.ts | 12 +++++++++--- .../src/epoch/processSyncCommitteeUpdates.ts | 5 ++--- 6 files changed, 32 insertions(+), 20 deletions(-) diff --git a/packages/state-transition/src/block/processAttestationsAltair.ts b/packages/state-transition/src/block/processAttestationsAltair.ts index f3d4a3e16c21..046a23d7dc27 100644 --- a/packages/state-transition/src/block/processAttestationsAltair.ts +++ b/packages/state-transition/src/block/processAttestationsAltair.ts @@ -75,6 +75,7 @@ export function processAttestationsAltair( // For each participant, update their participation // In epoch processing, this participation info is used to calculate balance updates let totalBalanceIncrementsWithWeight = 0; + const validators = state.validators; for (const index of attestingIndices) { const flags = epochParticipation.get(index); @@ -104,7 +105,7 @@ export function processAttestationsAltair( // TODO: describe issue. Compute progressive target balances // When processing each attestation, increase the cummulative target balance. Only applies post-altair if ((flagsNewSet & TIMELY_TARGET) === TIMELY_TARGET) { - const validator = state.validators.getReadonly(index); + const validator = validators.getReadonly(index); if (!validator.slashed) { if (inCurrentEpoch) { epochCtx.currentTargetUnslashedBalanceIncrements += effectiveBalanceIncrements[index]; diff --git a/packages/state-transition/src/epoch/index.ts b/packages/state-transition/src/epoch/index.ts index 21455521897b..85e7c348dad3 100644 --- a/packages/state-transition/src/epoch/index.ts +++ b/packages/state-transition/src/epoch/index.ts @@ -133,7 +133,7 @@ export function processEpoch( const timer = metrics?.epochTransitionStepTime.startTimer({ step: EpochTransitionStep.processPendingBalanceDeposits, }); - processPendingBalanceDeposits(stateElectra); + processPendingBalanceDeposits(stateElectra, cache); timer?.(); } @@ -141,7 +141,7 @@ export function processEpoch( const timer = metrics?.epochTransitionStepTime.startTimer({ step: EpochTransitionStep.processPendingConsolidations, }); - processPendingConsolidations(stateElectra); + processPendingConsolidations(stateElectra, cache); timer?.(); } } diff --git a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts index f4fae6e41d4f..fdbc99b9265e 100644 --- a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts +++ b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts @@ -39,12 +39,10 @@ export function processEffectiveBalanceUpdates( // update effective balances with hysteresis - // epochTransitionCache.balances is set in processRewardsAndPenalties(), so it's recycled here for performance. - // It defaults to `state.balances.getAll()` to make Typescript happy and for spec tests - const balances = state.balances.getAll(); - - // TODO: (@matthewkeil) This was causing additional failures but should not. Check the EpochTransitionCache for why - // const balances = cache.balances ?? state.balances.getAll(); + // epochTransitionCache.balances is initialized in processRewardsAndPenalties() + // and updated in processPendingBalanceDeposits() and processPendingConsolidations() + // so it's recycled here for performance. + const balances = cache.balances ?? state.balances.getAll(); for (let i = 0, len = balances.length; i < len; i++) { const balance = balances[i]; diff --git a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts index f89e938cc790..81da34349e53 100644 --- a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts @@ -1,5 +1,5 @@ import {FAR_FUTURE_EPOCH} from "@lodestar/params"; -import {CachedBeaconStateElectra} from "../types.js"; +import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; import {increaseBalance} from "../util/balance.js"; import {getActivationExitChurnLimit} from "../util/validator.js"; import {getCurrentEpoch} from "../util/epoch.js"; @@ -13,16 +13,18 @@ import {getCurrentEpoch} from "../util/epoch.js"; * * TODO Electra: Update ssz library to support batch push to `pendingBalanceDeposits` */ -export function processPendingBalanceDeposits(state: CachedBeaconStateElectra): void { +export function processPendingBalanceDeposits(state: CachedBeaconStateElectra, cache: EpochTransitionCache): void { const availableForProcessing = state.depositBalanceToConsume + BigInt(getActivationExitChurnLimit(state.epochCtx)); const currentEpoch = getCurrentEpoch(state); let processedAmount = 0n; let nextDepositIndex = 0; const depositsToPostpone = []; + const validators = state.validators; + const cachedBalances = cache.balances; for (const deposit of state.pendingBalanceDeposits.getAllReadonly()) { const {amount, index: depositIndex} = deposit; - const validator = state.validators.get(depositIndex); + const validator = validators.getReadonly(depositIndex); // Validator is exiting, postpone the deposit until after withdrawable epoch if (validator.exitEpoch < FAR_FUTURE_EPOCH) { @@ -30,7 +32,10 @@ export function processPendingBalanceDeposits(state: CachedBeaconStateElectra): depositsToPostpone.push(deposit); } else { // Deposited balance will never become active. Increase balance but do not consume churn - increaseBalance(state, deposit.index, Number(amount)); + increaseBalance(state, depositIndex, Number(amount)); + if (cachedBalances) { + cachedBalances[depositIndex] += Number(amount); + } } } else { // Validator is not exiting, attempt to process deposit @@ -39,7 +44,10 @@ export function processPendingBalanceDeposits(state: CachedBeaconStateElectra): break; } else { // Deposit fits in the churn, process it. Increase balance and consume churn. - increaseBalance(state, deposit.index, Number(amount)); + increaseBalance(state, depositIndex, Number(amount)); + if (cachedBalances) { + cachedBalances[depositIndex] += Number(amount); + } processedAmount = processedAmount + amount; } } diff --git a/packages/state-transition/src/epoch/processPendingConsolidations.ts b/packages/state-transition/src/epoch/processPendingConsolidations.ts index e025a454f64e..d6f760a6b27a 100644 --- a/packages/state-transition/src/epoch/processPendingConsolidations.ts +++ b/packages/state-transition/src/epoch/processPendingConsolidations.ts @@ -1,4 +1,4 @@ -import {CachedBeaconStateElectra} from "../types.js"; +import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; import {decreaseBalance, increaseBalance} from "../util/balance.js"; import {getActiveBalance} from "../util/validator.js"; import {switchToCompoundingValidator} from "../util/electra.js"; @@ -16,12 +16,14 @@ import {switchToCompoundingValidator} from "../util/electra.js"; * Dequeue all processed consolidations from `state.pendingConsolidation` * */ -export function processPendingConsolidations(state: CachedBeaconStateElectra): void { +export function processPendingConsolidations(state: CachedBeaconStateElectra, cache: EpochTransitionCache): void { let nextPendingConsolidation = 0; + const validators = state.validators; + const cachedBalances = cache.balances; for (const pendingConsolidation of state.pendingConsolidations.getAllReadonly()) { const {sourceIndex, targetIndex} = pendingConsolidation; - const sourceValidator = state.validators.getReadonly(sourceIndex); + const sourceValidator = validators.getReadonly(sourceIndex); if (sourceValidator.slashed) { nextPendingConsolidation++; @@ -37,6 +39,10 @@ export function processPendingConsolidations(state: CachedBeaconStateElectra): v const activeBalance = getActiveBalance(state, sourceIndex); decreaseBalance(state, sourceIndex, activeBalance); increaseBalance(state, targetIndex, activeBalance); + if (cachedBalances) { + cachedBalances[sourceIndex] -= activeBalance; + cachedBalances[targetIndex] += activeBalance; + } nextPendingConsolidation++; } diff --git a/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts b/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts index aa22bb4f7bcf..df4e0364be17 100644 --- a/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts +++ b/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts @@ -23,11 +23,10 @@ export function processSyncCommitteeUpdates(fork: ForkSeq, state: CachedBeaconSt activeValidatorIndices, effectiveBalanceIncrements ); + const validators = state.validators; // Using the index2pubkey cache is slower because it needs the serialized pubkey. - const nextSyncCommitteePubkeys = nextSyncCommitteeIndices.map( - (index) => state.validators.getReadonly(index).pubkey - ); + const nextSyncCommitteePubkeys = nextSyncCommitteeIndices.map((index) => validators.getReadonly(index).pubkey); // Rotate syncCommittee in state state.currentSyncCommittee = state.nextSyncCommittee; From 4b2f34b1945f4c3e0f4df83dc5fb5138194d63db Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 13 Aug 2024 21:16:28 +0100 Subject: [PATCH 074/259] chore: review electra branch - part 1 (#7015) --- packages/api/src/beacon/routes/beacon/block.ts | 2 +- packages/api/src/beacon/routes/beacon/pool.ts | 6 ++---- packages/api/src/beacon/routes/validator.ts | 8 ++++++-- packages/api/test/unit/beacon/oapiSpec.test.ts | 5 ----- .../api/test/unit/beacon/testData/beacon.ts | 2 +- .../src/api/impl/beacon/blocks/index.ts | 14 ++++++++++---- .../src/api/impl/config/constants.ts | 2 +- .../beacon-node/src/api/impl/validator/index.ts | 5 +++-- .../src/chain/errors/attestationError.ts | 2 +- packages/beacon-node/src/eth1/interface.ts | 2 +- .../beacon-node/src/network/gossip/topic.ts | 2 +- .../opPools/aggregatedAttestationPool.test.ts | 2 +- .../test/perf/chain/opPools/opPool.test.ts | 2 +- .../chain/produceBlock/produceBlockBody.test.ts | 2 +- .../scripts/el-interop/besu/common-setup.sh | 2 +- .../test/scripts/el-interop/besu/post-merge.sh | 2 +- .../scripts/el-interop/besudocker/post-merge.sh | 2 +- .../el-interop/ethereumjsdocker/electra.tmpl | 2 +- .../test/sim/electra-interop.test.ts | 2 +- .../test/spec/presets/genesis.test.ts | 4 +--- .../test/spec/presets/operations.test.ts | 17 +++++++---------- .../test/unit/chain/shufflingCache.test.ts | 8 ++++---- .../test/unit/eth1/utils/deposits.test.ts | 6 +++--- .../beacon-node/test/unit/util/sszBytes.test.ts | 2 +- .../test/utils/validationData/attestation.ts | 7 +++---- packages/flare/src/cmds/selfSlashAttester.ts | 4 ++-- .../test/unit/webEsmBundle.browser.test.ts | 2 +- packages/state-transition/package.json | 1 - 28 files changed, 57 insertions(+), 60 deletions(-) diff --git a/packages/api/src/beacon/routes/beacon/block.ts b/packages/api/src/beacon/routes/beacon/block.ts index 2c141e3bdefd..be6789753e0f 100644 --- a/packages/api/src/beacon/routes/beacon/block.ts +++ b/packages/api/src/beacon/routes/beacon/block.ts @@ -8,11 +8,11 @@ import { deneb, isSignedBlockContents, SignedBeaconBlock, + BeaconBlockBody, SignedBeaconBlockOrContents, SignedBlindedBeaconBlock, SignedBlockContents, sszTypesFor, - BeaconBlockBody, } from "@lodestar/types"; import {ForkName, ForkPreElectra, ForkPreExecution, isForkBlobs, isForkExecution} from "@lodestar/params"; import {Endpoint, RequestCodec, RouteDefinitions, Schema} from "../../../utils/index.js"; diff --git a/packages/api/src/beacon/routes/beacon/pool.ts b/packages/api/src/beacon/routes/beacon/pool.ts index 42880b276732..4fe3efd4daf2 100644 --- a/packages/api/src/beacon/routes/beacon/pool.ts +++ b/packages/api/src/beacon/routes/beacon/pool.ts @@ -317,9 +317,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ - body: AttestationListTypePhase0.toJson(signedAttestations), - }), + writeReqJson: ({signedAttestations}) => ({body: AttestationListTypePhase0.toJson(signedAttestations)}), parseReqJson: ({body}) => ({signedAttestations: AttestationListTypePhase0.fromJson(body)}), writeReqSsz: ({signedAttestations}) => ({body: AttestationListTypePhase0.serialize(signedAttestations)}), parseReqSsz: ({body}) => ({signedAttestations: AttestationListTypePhase0.deserialize(body)}), @@ -414,7 +412,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ body: SignedAggregateAndProofListPhase0Type.toJson(signedAggregateAndProofs), }), - parseReqJson: ({body}) => ({signedAggregateAndProofs: SignedAggregateAndProofListPhase0Type.fromJson(body)}), + parseReqJson: ({body}) => ({ + signedAggregateAndProofs: SignedAggregateAndProofListPhase0Type.fromJson(body), + }), writeReqSsz: ({signedAggregateAndProofs}) => ({ body: SignedAggregateAndProofListPhase0Type.serialize(signedAggregateAndProofs), }), - parseReqSsz: ({body}) => ({signedAggregateAndProofs: SignedAggregateAndProofListPhase0Type.deserialize(body)}), + parseReqSsz: ({body}) => ({ + signedAggregateAndProofs: SignedAggregateAndProofListPhase0Type.deserialize(body), + }), schema: { body: Schema.ObjectArray, }, diff --git a/packages/api/test/unit/beacon/oapiSpec.test.ts b/packages/api/test/unit/beacon/oapiSpec.test.ts index 2ccf4720db27..efce60a5338f 100644 --- a/packages/api/test/unit/beacon/oapiSpec.test.ts +++ b/packages/api/test/unit/beacon/oapiSpec.test.ts @@ -86,11 +86,6 @@ const ignoredTopics = [ topic block_gossip not implemented */ "block_gossip", - - // Modified in electra to include version - // should be removed from the ignore list after spec update - "attestation", - "attester_slashing", ]; // eventstream types are defined as comments in the description of "examples". diff --git a/packages/api/test/unit/beacon/testData/beacon.ts b/packages/api/test/unit/beacon/testData/beacon.ts index ac47a58777eb..b0e958f4bc58 100644 --- a/packages/api/test/unit/beacon/testData/beacon.ts +++ b/packages/api/test/unit/beacon/testData/beacon.ts @@ -138,7 +138,7 @@ export const testData: GenericServerTestCases = { res: undefined, }, submitPoolAttesterSlashingsV2: { - args: {attesterSlashing: ssz.electra.AttesterSlashing.defaultValue()}, + args: {attesterSlashing: ssz.phase0.AttesterSlashing.defaultValue()}, res: undefined, }, submitPoolProposerSlashings: { 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 251218f510ec..89e8a20d4f86 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -1,12 +1,12 @@ import {routes} from "@lodestar/api"; -import {ApplicationMethods} from "@lodestar/api/server"; +import {ApiError, ApplicationMethods} from "@lodestar/api/server"; import { computeEpochAtSlot, computeTimeAtSlot, reconstructFullBlockOrContents, signedBeaconBlockToBlinded, } from "@lodestar/state-transition"; -import {ForkExecution, SLOTS_PER_HISTORICAL_ROOT, isForkExecution} from "@lodestar/params"; +import {ForkExecution, SLOTS_PER_HISTORICAL_ROOT, isForkExecution, isForkPostElectra} from "@lodestar/params"; import {sleep, fromHex, toRootHex} from "@lodestar/utils"; import { deneb, @@ -407,8 +407,14 @@ export function getBeaconBlockApi({ async getBlockAttestations({blockId}) { const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId); + const fork = config.getForkName(block.message.slot); + + if (isForkPostElectra(fork)) { + throw new ApiError(400, `Use getBlockAttestationsV2 to retrieve electra+ block attestations fork=${fork}`); + } + return { - data: Array.from(block.message.body.attestations), + data: block.message.body.attestations, meta: {executionOptimistic, finalized}, }; }, @@ -416,7 +422,7 @@ export function getBeaconBlockApi({ async getBlockAttestationsV2({blockId}) { const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId); return { - data: Array.from(block.message.body.attestations), + data: block.message.body.attestations, meta: {executionOptimistic, finalized, version: config.getForkName(block.message.slot)}, }; }, diff --git a/packages/beacon-node/src/api/impl/config/constants.ts b/packages/beacon-node/src/api/impl/config/constants.ts index 78262ce15237..4b239ee4cac6 100644 --- a/packages/beacon-node/src/api/impl/config/constants.ts +++ b/packages/beacon-node/src/api/impl/config/constants.ts @@ -46,7 +46,7 @@ import { /** * Hand-picked list of constants declared in consensus-spec .md files. - * This list is asserted to be up-to-date with the test `test/e2e/api/specConstants.test.ts` + * This list is asserted to be up-to-date with the test `test/e2e/api/impl/config.test.ts` */ export const specConstants = { // phase0/beacon-chain.md diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 06502146ce2f..2d453f0d24c7 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -21,6 +21,7 @@ import { ForkPreBlobs, ForkBlobs, ForkExecution, + isForkPostElectra, } from "@lodestar/params"; import {MAX_BUILDER_BOOST_FACTOR} from "@lodestar/validator"; import { @@ -814,7 +815,7 @@ export function getValidatorApi( const attEpoch = computeEpochAtSlot(slot); const headBlockRootHex = chain.forkChoice.getHead().blockRoot; const headBlockRoot = fromHex(headBlockRootHex); - const fork = config.getForkSeq(slot); + const fork = config.getForkName(slot); const beaconBlockRoot = slot >= headSlot @@ -846,7 +847,7 @@ export function getValidatorApi( return { data: { slot, - index: fork >= ForkSeq.electra ? 0 : committeeIndex, + index: isForkPostElectra(fork) ? 0 : committeeIndex, beaconBlockRoot, source: attEpochState.currentJustifiedCheckpoint, target: {epoch: attEpoch, root: targetRoot}, diff --git a/packages/beacon-node/src/chain/errors/attestationError.ts b/packages/beacon-node/src/chain/errors/attestationError.ts index d53a6f99682d..9f8e86cea1ab 100644 --- a/packages/beacon-node/src/chain/errors/attestationError.ts +++ b/packages/beacon-node/src/chain/errors/attestationError.ts @@ -128,7 +128,7 @@ export enum AttestationErrorCode { /** Too many skipped slots. */ TOO_MANY_SKIPPED_SLOTS = "ATTESTATION_ERROR_TOO_MANY_SKIPPED_SLOTS", /** - * Electra: The aggregated attestation doesn't have only one committee bit set. + * Electra: The aggregated attestation does not have exactly one committee bit set. */ NOT_EXACTLY_ONE_COMMITTEE_BIT_SET = "ATTESTATION_ERROR_NOT_EXACTLY_ONE_COMMITTEE_BIT_SET", /** diff --git a/packages/beacon-node/src/eth1/interface.ts b/packages/beacon-node/src/eth1/interface.ts index 898041ac8947..54fcdd12492f 100644 --- a/packages/beacon-node/src/eth1/interface.ts +++ b/packages/beacon-node/src/eth1/interface.ts @@ -64,7 +64,7 @@ export interface IEth1ForBlockProduction { startPollingMergeBlock(): void; /** - * Should stop polling eth1Data after a Electra block is finalized AND deposit_receipts_start_index is reached + * Should stop polling eth1Data after a Electra block is finalized AND deposit_requests_start_index is reached */ stopPollingEth1Data(): void; } diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index f3968b8e65b6..b7c7425584c5 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -93,7 +93,7 @@ export function getGossipSSZType(topic: GossipTopic) { case GossipType.proposer_slashing: return ssz.phase0.ProposerSlashing; case GossipType.attester_slashing: - return ssz.phase0.AttesterSlashing; + return sszTypesFor(topic.fork).AttesterSlashing; case GossipType.voluntary_exit: return ssz.phase0.SignedVoluntaryExit; case GossipType.sync_committee_contribution_and_proof: diff --git a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts index ee14eb27b51d..60ff6ce48302 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -32,7 +32,7 @@ describe(`getAttestationsForBlock vc=${vc}`, () => { before(function () { this.timeout(5 * 60 * 1000); // Generating the states for the first time is very slow - originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true, vc}) as CachedBeaconStateAltair; + originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true, vc}); const {blockHeader, checkpoint} = computeAnchorCheckpoint(originalState.config, originalState); // TODO figure out why getBlockRootAtSlot(originalState, justifiedSlot) is not the same to justifiedCheckpoint.root diff --git a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts index 2632c593e78c..6e420f0e1011 100644 --- a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts @@ -24,7 +24,7 @@ describe("opPool", () => { before(function () { this.timeout(2 * 60 * 1000); // Generating the states for the first time is very slow - originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true}) as CachedBeaconStateAltair; + originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true}); }); itBench({ diff --git a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts index f90f148f3e01..7bf8c2f7252f 100644 --- a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts +++ b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts @@ -25,7 +25,7 @@ describe("produceBlockBody", () => { before(async () => { db = new BeaconDb(config, await LevelDbController.create({name: ".tmpdb"}, {logger})); - state = stateOg.clone() as CachedBeaconStateAltair; + state = stateOg.clone(); chain = new BeaconChain( { proposerBoost: true, diff --git a/packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh b/packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh index 1444f6d3a479..f211f5d0714b 100755 --- a/packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh +++ b/packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh @@ -16,4 +16,4 @@ echo "12345678" > $DATA_DIR/password.txt pubKey="0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" # echo a hex encoded 256 bit secret into a file -echo $JWT_SECRET_HEX> $DATA_DIR/jwtsecret \ No newline at end of file +echo $JWT_SECRET_HEX> $DATA_DIR/jwtsecret diff --git a/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh b/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh index 47bec71cf8bb..d864814ece7a 100755 --- a/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh +++ b/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh @@ -5,4 +5,4 @@ currentDir=$(pwd) . $scriptDir/common-setup.sh -$EL_BINARY_DIR/besu --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ADMIN,ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-rpc-port $ENGINE_PORT --engine-jwt-secret $currentDir/$DATA_DIR/jwtsecret --data-path $DATA_DIR --data-storage-format BONSAI --genesis-file $DATA_DIR/genesis.json \ No newline at end of file +$EL_BINARY_DIR/besu --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ADMIN,ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-rpc-port $ENGINE_PORT --engine-jwt-secret $currentDir/$DATA_DIR/jwtsecret --data-path $DATA_DIR --data-storage-format BONSAI --genesis-file $DATA_DIR/genesis.json diff --git a/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh b/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh index fb091a7d838b..d26307ee3d24 100755 --- a/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh +++ b/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh @@ -5,4 +5,4 @@ currentDir=$(pwd) . $scriptDir/common-setup.sh -docker run --rm -u $(id -u ${USER}):$(id -g ${USER}) --name custom-execution -p $ETH_PORT:$ETH_PORT -p $ENGINE_PORT:$ENGINE_PORT -v $currentDir/$DATA_DIR:/data $EL_BINARY_DIR --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ADMIN,ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-rpc-port $ENGINE_PORT --engine-jwt-secret /data/jwtsecret --data-path /data/besu --data-storage-format BONSAI --genesis-file /data/genesis.json \ No newline at end of file +docker run --rm -u $(id -u ${USER}):$(id -g ${USER}) --name custom-execution -p $ETH_PORT:$ETH_PORT -p $ENGINE_PORT:$ENGINE_PORT -v $currentDir/$DATA_DIR:/data $EL_BINARY_DIR --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ADMIN,ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-rpc-port $ENGINE_PORT --engine-jwt-secret /data/jwtsecret --data-path /data/besu --data-storage-format BONSAI --genesis-file /data/genesis.json diff --git a/packages/beacon-node/test/scripts/el-interop/ethereumjsdocker/electra.tmpl b/packages/beacon-node/test/scripts/el-interop/ethereumjsdocker/electra.tmpl index d557d505c649..3a06b75cd000 100644 --- a/packages/beacon-node/test/scripts/el-interop/ethereumjsdocker/electra.tmpl +++ b/packages/beacon-node/test/scripts/el-interop/ethereumjsdocker/electra.tmpl @@ -91,4 +91,4 @@ "gasUsed":"0x0", "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", "baseFeePerGas":"0x7" -} \ No newline at end of file +} diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index 02fc99f9cfae..d0c00e75fd59 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -252,7 +252,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { /** * Want to test two things: - * 1) Send two raw deposit transactions, and see if two new validators with corrent balances show up in the state.validators and unfinalized cache + * 1) Send two raw deposit transactions, and see if two new validators with correct balances show up in the state.validators and unfinalized cache * 2) Upon state-transition, see if the two new validators move from unfinalized cache to finalized cache */ async function runNodeWithEL({ diff --git a/packages/beacon-node/test/spec/presets/genesis.test.ts b/packages/beacon-node/test/spec/presets/genesis.test.ts index d8f85dd9b5b8..773debe3bb19 100644 --- a/packages/beacon-node/test/spec/presets/genesis.test.ts +++ b/packages/beacon-node/test/spec/presets/genesis.test.ts @@ -60,9 +60,7 @@ const genesisInitialization: TestRunnerFn - ) + executionPayloadHeaderType.toViewDU(testcase["execution_payload_header"]) ); }, // eth1.yaml diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index c978cac3c8a2..7e2e9c1e9c5d 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -11,7 +11,7 @@ import { import * as blockFns from "@lodestar/state-transition/block"; import {ssz, phase0, altair, bellatrix, capella, electra, sszTypesFor} from "@lodestar/types"; import {InputType} from "@lodestar/spec-test-util"; -import {ACTIVE_PRESET, ForkName, ForkSeq} from "@lodestar/params"; +import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; @@ -57,11 +57,6 @@ const operationFns: Record> = blockFns.processDeposit(fork, state, testCase.deposit); }, - deposit_receipt: (state, testCase: {deposit_receipt: electra.DepositRequest}) => { - const fork = state.config.getForkSeq(state.slot); - blockFns.processDepositRequest(fork, state as CachedBeaconStateElectra, testCase.deposit_receipt); - }, - proposer_slashing: (state, testCase: {proposer_slashing: phase0.ProposerSlashing}) => { const fork = state.config.getForkSeq(state.slot); blockFns.processProposerSlashing(fork, state, testCase.proposer_slashing); @@ -89,15 +84,18 @@ const operationFns: Record> = }, withdrawals: (state, testCase: {execution_payload: capella.ExecutionPayload}) => { - blockFns.processWithdrawals(ForkSeq.capella, state as CachedBeaconStateCapella, testCase.execution_payload); + const fork = state.config.getForkSeq(state.slot); + blockFns.processWithdrawals(fork, state as CachedBeaconStateCapella, testCase.execution_payload); }, withdrawal_request: (state, testCase: {withdrawal_request: electra.WithdrawalRequest}) => { - blockFns.processWithdrawalRequest(ForkSeq.electra, state as CachedBeaconStateElectra, testCase.withdrawal_request); + const fork = state.config.getForkSeq(state.slot); + blockFns.processWithdrawalRequest(fork, state as CachedBeaconStateElectra, testCase.withdrawal_request); }, deposit_request: (state, testCase: {deposit_request: electra.DepositRequest}) => { - blockFns.processDepositRequest(ForkSeq.electra, state as CachedBeaconStateElectra, testCase.deposit_request); + const fork = state.config.getForkSeq(state.slot); + blockFns.processDepositRequest(fork, state as CachedBeaconStateElectra, testCase.deposit_request); }, consolidation_request: (state, testCase: {consolidation_request: electra.ConsolidationRequest}) => { @@ -140,7 +138,6 @@ const operations: TestRunnerFn = (fork, block: ssz[fork].BeaconBlock, body: ssz[fork].BeaconBlockBody, deposit: ssz.phase0.Deposit, - deposit_receipt: ssz.electra.DepositRequest, proposer_slashing: ssz.phase0.ProposerSlashing, voluntary_exit: ssz.phase0.SignedVoluntaryExit, // Altair diff --git a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts index 035746438563..6295a993c072 100644 --- a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts +++ b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts @@ -1,6 +1,6 @@ import {describe, it, expect, beforeEach} from "vitest"; -import {getShufflingDecisionBlock, CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import {getShufflingDecisionBlock} from "@lodestar/state-transition"; // eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../state-transition/test/perf/util.js"; import {ShufflingCache} from "../../../src/chain/shufflingCache.js"; @@ -14,7 +14,7 @@ describe("ShufflingCache", function () { beforeEach(() => { shufflingCache = new ShufflingCache(null, {maxShufflingCacheEpochs: 1}); - shufflingCache.processState(state as CachedBeaconStateAllForks, currentEpoch); + shufflingCache.processState(state, currentEpoch); }); it("should get shuffling from cache", async function () { @@ -29,7 +29,7 @@ describe("ShufflingCache", function () { shufflingCache.insertPromise(currentEpoch, "0x00"); expect(await shufflingCache.get(currentEpoch, decisionRoot)).toEqual(state.epochCtx.currentShuffling); // insert shufflings at other epochs does prune the cache - shufflingCache.processState(state as CachedBeaconStateAllForks, currentEpoch + 1); + shufflingCache.processState(state, currentEpoch + 1); // the current shuffling is not available anymore expect(await shufflingCache.get(currentEpoch, decisionRoot)).toBeNull(); }); @@ -39,7 +39,7 @@ describe("ShufflingCache", function () { shufflingCache.insertPromise(currentEpoch + 1, nextDecisionRoot); const shufflingRequest0 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); const shufflingRequest1 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); - shufflingCache.processState(state as CachedBeaconStateAllForks, currentEpoch + 1); + shufflingCache.processState(state, currentEpoch + 1); expect(await shufflingRequest0).toEqual(state.epochCtx.nextShuffling); expect(await shufflingRequest1).toEqual(state.epochCtx.nextShuffling); }); diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index 6cc3ae8f1ce0..316f75efc5ce 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -74,7 +74,7 @@ describe("eth1 / util / deposits", function () { expectedReturnedIndexes: [], }, { - id: "No deposits to be included post Electra after deposit_receipts_start_index", + id: "No deposits to be included post Electra after deposit_requests_start_index", depositCount: 2030, eth1DepositIndex: 2025, depositIndexes: Array.from({length: 2030}, (_, i) => i), @@ -82,7 +82,7 @@ describe("eth1 / util / deposits", function () { postElectra: true, }, { - id: "Should return deposits post Electra before deposit_receipts_start_index", + id: "Should return deposits post Electra before deposit_requests_start_index", depositCount: 2022, eth1DepositIndex: 2018, depositIndexes: Array.from({length: 2022}, (_, i) => i), @@ -90,7 +90,7 @@ describe("eth1 / util / deposits", function () { postElectra: true, }, { - id: "Should return deposits less than MAX_DEPOSITS post Electra before deposit_receipts_start_index", + id: "Should return deposits less than MAX_DEPOSITS post Electra before deposit_requests_start_index", depositCount: 10 * MAX_DEPOSITS, eth1DepositIndex: 0, depositIndexes: Array.from({length: 10 * MAX_DEPOSITS}, (_, i) => i), diff --git a/packages/beacon-node/test/unit/util/sszBytes.test.ts b/packages/beacon-node/test/unit/util/sszBytes.test.ts index 643b6b1bac0f..6fe6ae15c448 100644 --- a/packages/beacon-node/test/unit/util/sszBytes.test.ts +++ b/packages/beacon-node/test/unit/util/sszBytes.test.ts @@ -88,7 +88,7 @@ describe("attestation SSZ serialized picking", () => { } }); - it("getAggregateionBitsFromAttestationSerialized - invalid data", () => { + it("getAggregationBitsFromAttestationSerialized - invalid data", () => { const invalidAggregationBitsDataSizes = [0, 4, 100, 128, 227]; for (const size of invalidAggregationBitsDataSizes) { expect(getAggregationBitsFromAttestationSerialized(ForkName.phase0, Buffer.alloc(size))).toBeNull(); diff --git a/packages/beacon-node/test/utils/validationData/attestation.ts b/packages/beacon-node/test/utils/validationData/attestation.ts index 82bdca901889..c33d942dabc5 100644 --- a/packages/beacon-node/test/utils/validationData/attestation.ts +++ b/packages/beacon-node/test/utils/validationData/attestation.ts @@ -4,7 +4,6 @@ import { computeSigningRoot, computeStartSlotAtEpoch, getShufflingDecisionBlock, - CachedBeaconStateAllForks, } from "@lodestar/state-transition"; import {ProtoBlock, IForkChoice, ExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; @@ -83,8 +82,8 @@ export function getAttestationValidData(opts: AttestationValidDataOpts): { }; const shufflingCache = new ShufflingCache(); - shufflingCache.processState(state as CachedBeaconStateAllForks, state.epochCtx.currentShuffling.epoch); - shufflingCache.processState(state as CachedBeaconStateAllForks, state.epochCtx.nextShuffling.epoch); + shufflingCache.processState(state, state.epochCtx.currentShuffling.epoch); + shufflingCache.processState(state, state.epochCtx.nextShuffling.epoch); const dependentRoot = getShufflingDecisionBlock(state, state.epochCtx.currentShuffling.epoch); const forkChoice = { @@ -134,7 +133,7 @@ export function getAttestationValidData(opts: AttestationValidDataOpts): { getState: async () => state, // TODO: remove this once we have a better way to get state getStateSync: () => state, - } as unknown as Partial as IStateRegenerator; + } as Partial as IStateRegenerator; const chain = { clock, diff --git a/packages/flare/src/cmds/selfSlashAttester.ts b/packages/flare/src/cmds/selfSlashAttester.ts index cb29ed94bb74..e29a956a9306 100644 --- a/packages/flare/src/cmds/selfSlashAttester.ts +++ b/packages/flare/src/cmds/selfSlashAttester.ts @@ -1,6 +1,6 @@ import {SecretKey, aggregateSignatures} from "@chainsafe/blst"; import {getClient} from "@lodestar/api"; -import {phase0, ssz} from "@lodestar/types"; +import {AttesterSlashing, phase0, ssz} from "@lodestar/types"; import {config as chainConfig} from "@lodestar/config/default"; import {createBeaconConfig, BeaconConfig} from "@lodestar/config"; import {DOMAIN_BEACON_ATTESTER, MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; @@ -117,7 +117,7 @@ export async function selfSlashAttesterHandler(args: SelfSlashArgs): Promise Date: Tue, 13 Aug 2024 21:18:16 +0100 Subject: [PATCH 075/259] chore: review electra branch - part 2 (#7019) --- .../src/block/processOperations.ts | 2 +- .../src/signatureSets/indexedAttestation.ts | 2 +- .../src/slot/upgradeStateToElectra.ts | 2 +- .../state-transition/src/stateTransition.ts | 12 ++++++------ .../test/unit/util/deposit.test.ts | 6 +++--- packages/types/src/electra/sszTypes.ts | 18 +++++++++--------- packages/validator/src/services/attestation.ts | 3 ++- .../validator/src/services/validatorStore.ts | 7 ++----- 8 files changed, 25 insertions(+), 27 deletions(-) diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index 6d4fb25b9f5b..6f61e7c242fb 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -72,7 +72,7 @@ export function processOperations( } for (const elWithdrawalRequest of bodyElectra.executionPayload.withdrawalRequests) { - processWithdrawalRequest(fork, state as CachedBeaconStateElectra, elWithdrawalRequest); + processWithdrawalRequest(fork, stateElectra, elWithdrawalRequest); } for (const elConsolidationRequest of bodyElectra.executionPayload.consolidationRequests) { diff --git a/packages/state-transition/src/signatureSets/indexedAttestation.ts b/packages/state-transition/src/signatureSets/indexedAttestation.ts index d3decaf6406f..86535fece8b8 100644 --- a/packages/state-transition/src/signatureSets/indexedAttestation.ts +++ b/packages/state-transition/src/signatureSets/indexedAttestation.ts @@ -45,7 +45,7 @@ export function getAttestationsSignatureSets( return signedBlock.message.body.attestations.map((attestation) => getIndexedAttestationSignatureSet( state, - state.epochCtx.getIndexedAttestation(state.epochCtx.config.getForkSeq(signedBlock.message.slot), attestation) + state.epochCtx.getIndexedAttestation(state.config.getForkSeq(signedBlock.message.slot), attestation) ) ); } diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index ef7b0bd661b4..6600ad98e80a 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -11,7 +11,7 @@ import {computeActivationExitEpoch} from "../util/epoch.js"; import {getActivationExitChurnLimit, getConsolidationChurnLimit} from "../util/validator.js"; /** - * Upgrade a state from Capella to Deneb. + * Upgrade a state from Deneb to Electra. */ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): CachedBeaconStateElectra { const {config} = stateDeneb; diff --git a/packages/state-transition/src/stateTransition.ts b/packages/state-transition/src/stateTransition.ts index 5f433918415a..40e87c8d07d2 100644 --- a/packages/state-transition/src/stateTransition.ts +++ b/packages/state-transition/src/stateTransition.ts @@ -228,20 +228,20 @@ function processSlotsWithTransientCache( epochTransitionTimer?.(); // Upgrade state if exactly at epoch boundary - const stateSlot = computeEpochAtSlot(postState.slot); - if (stateSlot === config.ALTAIR_FORK_EPOCH) { + const stateEpoch = computeEpochAtSlot(postState.slot); + if (stateEpoch === config.ALTAIR_FORK_EPOCH) { postState = upgradeStateToAltair(postState as CachedBeaconStatePhase0) as CachedBeaconStateAllForks; } - if (stateSlot === config.BELLATRIX_FORK_EPOCH) { + if (stateEpoch === config.BELLATRIX_FORK_EPOCH) { postState = upgradeStateToBellatrix(postState as CachedBeaconStateAltair) as CachedBeaconStateAllForks; } - if (stateSlot === config.CAPELLA_FORK_EPOCH) { + if (stateEpoch === config.CAPELLA_FORK_EPOCH) { postState = upgradeStateToCapella(postState as CachedBeaconStateBellatrix) as CachedBeaconStateAllForks; } - if (stateSlot === config.DENEB_FORK_EPOCH) { + if (stateEpoch === config.DENEB_FORK_EPOCH) { postState = upgradeStateToDeneb(postState as CachedBeaconStateCapella) as CachedBeaconStateAllForks; } - if (stateSlot === config.ELECTRA_FORK_EPOCH) { + if (stateEpoch === config.ELECTRA_FORK_EPOCH) { postState = upgradeStateToElectra(postState as CachedBeaconStateDeneb) as CachedBeaconStateAllForks; } } else { diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts index b108de502a1f..3cfa4abb3409 100644 --- a/packages/state-transition/test/unit/util/deposit.test.ts +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -2,7 +2,7 @@ import {describe, it, expect} from "vitest"; import {ssz} from "@lodestar/types"; import {createChainForkConfig} from "@lodestar/config"; import {MAX_DEPOSITS} from "@lodestar/params"; -import {CachedBeaconStateElectra, getEth1DepositCount} from "../../../src/index.js"; +import {getEth1DepositCount} from "../../../src/index.js"; import {createCachedBeaconStateTest} from "../../utils/state.js"; describe("getEth1DepositCount", () => { @@ -37,7 +37,7 @@ describe("getEth1DepositCount", () => { ELECTRA_FORK_EPOCH: 0, }), {skipSyncCommitteeCache: true, skipSyncPubkeys: true} - ) as CachedBeaconStateElectra; + ); if (!postElectraState.epochCtx.isPostElectra()) { throw Error("Not a post-Electra state"); @@ -71,7 +71,7 @@ describe("getEth1DepositCount", () => { ELECTRA_FORK_EPOCH: 0, }), {skipSyncCommitteeCache: true, skipSyncPubkeys: true} - ) as CachedBeaconStateElectra; + ); if (!postElectraState.epochCtx.isPostElectra()) { throw Error("Not a post-Electra state"); diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index a6874c7894e3..31844aac86cc 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -152,7 +152,7 @@ export const ExecutionPayload = new ContainerType( ...denebSsz.ExecutionPayload.fields, depositRequests: DepositRequests, // New in ELECTRA withdrawalRequests: WithdrawalRequests, // New in ELECTRA - consolidationRequests: ConsolidationRequests, // [New in Electra] + consolidationRequests: ConsolidationRequests, // New in ELECTRA }, {typeName: "ExecutionPayload", jsonCase: "eth2"} ); @@ -333,14 +333,14 @@ export const BeaconState = new ContainerType( // Deep history valid from Capella onwards historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, depositRequestsStartIndex: UintBn64, // New in ELECTRA:EIP6110 - depositBalanceToConsume: Gwei, // New in Electra:EIP7251 - exitBalanceToConsume: Gwei, // New in Electra:EIP7251 - earliestExitEpoch: Epoch, // New in Electra:EIP7251 - consolidationBalanceToConsume: Gwei, // New in Electra:EIP7251 - earliestConsolidationEpoch: Epoch, // New in Electra:EIP7251 - pendingBalanceDeposits: PendingBalanceDeposits, // New in Electra:EIP7251 - pendingPartialWithdrawals: new ListCompositeType(PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT), // New in Electra:EIP7251 - pendingConsolidations: new ListCompositeType(PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT), // New in Electra:EIP7251 + depositBalanceToConsume: Gwei, // New in ELECTRA:EIP7251 + exitBalanceToConsume: Gwei, // New in ELECTRA:EIP7251 + earliestExitEpoch: Epoch, // New in ELECTRA:EIP7251 + consolidationBalanceToConsume: Gwei, // New in ELECTRA:EIP7251 + earliestConsolidationEpoch: Epoch, // New in ELECTRA:EIP7251 + pendingBalanceDeposits: PendingBalanceDeposits, // New in ELECTRA:EIP7251 + pendingPartialWithdrawals: new ListCompositeType(PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT), // New in ELECTRA:EIP7251 + pendingConsolidations: new ListCompositeType(PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT), // New in ELECTRA:EIP7251 }, {typeName: "BeaconState", jsonCase: "eth2"} ); diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index d6f48aeb3d1f..604f4adeb47e 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -1,5 +1,6 @@ import {toHexString} from "@chainsafe/ssz"; import {BLSSignature, phase0, Slot, ssz, Attestation, SignedAggregateAndProof} from "@lodestar/types"; +import {ForkSeq} from "@lodestar/params"; import {computeEpochAtSlot, isAggregatorFromCommitteeLength} from "@lodestar/state-transition"; import {sleep} from "@lodestar/utils"; import {ApiClient, routes} from "@lodestar/api"; @@ -159,7 +160,7 @@ export class AttestationService { this.metrics?.attesterStepCallProduceAggregate.observe(this.clock.secFromSlot(slot + 2 / 3)); const dutiesByCommitteeIndex = groupAttDutiesByCommitteeIndex(dutiesAll); - const isPostElectra = computeEpochAtSlot(slot) >= this.config.ELECTRA_FORK_EPOCH; + const isPostElectra = this.config.getForkSeq(slot) >= ForkSeq.electra; // Then download, sign and publish a `SignedAggregateAndProof` for each // validator that is elected to aggregate for this `slot` and `committeeIndex`. diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index 252d0886cc6e..fa9d855aa24a 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -534,8 +534,8 @@ export class ValidatorStore { return { aggregationBits: BitArray.fromSingleBit(duty.committeeLength, duty.validatorCommitteeIndex), data: attestationData, - committeeBits: BitArray.fromSingleBit(MAX_COMMITTEES_PER_SLOT, duty.committeeIndex), signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage), + committeeBits: BitArray.fromSingleBit(MAX_COMMITTEES_PER_SLOT, duty.committeeIndex), }; } else { return { @@ -801,7 +801,7 @@ export class ValidatorStore { throw Error(`Inconsistent duties during signing: duty.slot ${duty.slot} != att.slot ${data.slot}`); } - const isPostElectra = computeEpochAtSlot(duty.slot) >= this.config.ELECTRA_FORK_EPOCH; + const isPostElectra = this.config.getForkSeq(duty.slot) >= ForkSeq.electra; if (!isPostElectra && duty.committeeIndex != data.index) { throw Error( `Inconsistent duties during signing: duty.committeeIndex ${duty.committeeIndex} != att.committeeIndex ${data.index}` @@ -810,9 +810,6 @@ export class ValidatorStore { if (isPostElectra && data.index !== 0) { throw Error(`Non-zero committee index post-electra during signing: att.committeeIndex ${data.index}`); } - if (this.config.getForkSeq(duty.slot) >= ForkSeq.electra && data.index !== 0) { - throw Error(`Attestataion data index must be 0 post electra: index ${data.index}`); - } } private assertDoppelgangerSafe(pubKey: PubkeyHex | BLSPubkey): void { From a157b55577546819d51fff4c7cdcfdfbe5e63c37 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 15 Aug 2024 11:36:13 +0100 Subject: [PATCH 076/259] feat: support post-electra attestation and attester slashing events (#7026) --- packages/api/src/beacon/client/events.ts | 2 +- packages/api/src/beacon/routes/events.ts | 35 +++++++++++++++---- packages/api/src/beacon/server/events.ts | 2 +- .../api/test/unit/beacon/oapiSpec.test.ts | 2 +- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/packages/api/src/beacon/client/events.ts b/packages/api/src/beacon/client/events.ts index 2d63925a738a..34f14f2e8397 100644 --- a/packages/api/src/beacon/client/events.ts +++ b/packages/api/src/beacon/client/events.ts @@ -13,7 +13,7 @@ export type ApiClient = ApiClientMethods; */ export function getClient(config: ChainForkConfig, baseUrl: string): ApiClient { const definitions = getDefinitions(config); - const eventSerdes = getEventSerdes(); + const eventSerdes = getEventSerdes(config); return { eventstream: async ({topics, signal, onEvent, onError, onClose}) => { diff --git a/packages/api/src/beacon/routes/events.ts b/packages/api/src/beacon/routes/events.ts index 23be5e7c2288..1f041aa30194 100644 --- a/packages/api/src/beacon/routes/events.ts +++ b/packages/api/src/beacon/routes/events.ts @@ -13,6 +13,9 @@ import { LightClientOptimisticUpdate, LightClientFinalityUpdate, SSEPayloadAttributes, + Attestation, + AttesterSlashing, + sszTypesFor, } from "@lodestar/types"; import {ForkName} from "@lodestar/params"; @@ -104,10 +107,10 @@ export type EventData = { block: RootHex; executionOptimistic: boolean; }; - [EventType.attestation]: phase0.Attestation; + [EventType.attestation]: Attestation; [EventType.voluntaryExit]: phase0.SignedVoluntaryExit; [EventType.proposerSlashing]: phase0.ProposerSlashing; - [EventType.attesterSlashing]: phase0.AttesterSlashing; + [EventType.attesterSlashing]: AttesterSlashing; [EventType.blsToExecutionChange]: capella.SignedBLSToExecutionChange; [EventType.finalizedCheckpoint]: { block: RootHex; @@ -184,7 +187,7 @@ export type TypeJson = { fromJson: (data: unknown) => T; // client }; -export function getTypeByEvent(): {[K in EventType]: TypeJson} { +export function getTypeByEvent(config: ChainForkConfig): {[K in EventType]: TypeJson} { // eslint-disable-next-line @typescript-eslint/naming-convention const WithVersion = (getType: (fork: ForkName) => TypeJson): TypeJson<{data: T; version: ForkName}> => { return { @@ -225,10 +228,28 @@ export function getTypeByEvent(): {[K in EventType]: TypeJson} { {jsonCase: "eth2"} ), - [EventType.attestation]: ssz.phase0.Attestation, + [EventType.attestation]: { + toJson: (attestation) => { + const fork = config.getForkName(attestation.data.slot); + return sszTypesFor(fork).Attestation.toJson(attestation); + }, + fromJson: (attestation) => { + const fork = config.getForkName((attestation as Attestation).data.slot); + return sszTypesFor(fork).Attestation.fromJson(attestation); + }, + }, [EventType.voluntaryExit]: ssz.phase0.SignedVoluntaryExit, [EventType.proposerSlashing]: ssz.phase0.ProposerSlashing, - [EventType.attesterSlashing]: ssz.phase0.AttesterSlashing, + [EventType.attesterSlashing]: { + toJson: (attesterSlashing) => { + const fork = config.getForkName(Number(attesterSlashing.attestation1.data.slot)); + return sszTypesFor(fork).AttesterSlashing.toJson(attesterSlashing); + }, + fromJson: (attesterSlashing) => { + const fork = config.getForkName(Number((attesterSlashing as AttesterSlashing).attestation1.data.slot)); + return sszTypesFor(fork).AttesterSlashing.fromJson(attesterSlashing); + }, + }, [EventType.blsToExecutionChange]: ssz.capella.SignedBLSToExecutionChange, [EventType.finalizedCheckpoint]: new ContainerType( @@ -269,8 +290,8 @@ export function getTypeByEvent(): {[K in EventType]: TypeJson} { } // eslint-disable-next-line @typescript-eslint/explicit-function-return-type -export function getEventSerdes() { - const typeByEvent = getTypeByEvent(); +export function getEventSerdes(config: ChainForkConfig) { + const typeByEvent = getTypeByEvent(config); return { toJson: (event: BeaconEvent): unknown => { diff --git a/packages/api/src/beacon/server/events.ts b/packages/api/src/beacon/server/events.ts index cbeae24f6908..96212f006d8f 100644 --- a/packages/api/src/beacon/server/events.ts +++ b/packages/api/src/beacon/server/events.ts @@ -3,7 +3,7 @@ import {ApiError, ApplicationMethods, FastifyRoutes, createFastifyRoutes} from " import {Endpoints, getDefinitions, eventTypes, getEventSerdes} from "../routes/events.js"; export function getRoutes(config: ChainForkConfig, methods: ApplicationMethods): FastifyRoutes { - const eventSerdes = getEventSerdes(); + const eventSerdes = getEventSerdes(config); const serverRoutes = createFastifyRoutes(getDefinitions(config), methods); return { diff --git a/packages/api/test/unit/beacon/oapiSpec.test.ts b/packages/api/test/unit/beacon/oapiSpec.test.ts index efce60a5338f..a84b2cc36767 100644 --- a/packages/api/test/unit/beacon/oapiSpec.test.ts +++ b/packages/api/test/unit/beacon/oapiSpec.test.ts @@ -108,7 +108,7 @@ describe("eventstream event data", () => { } }); - const eventSerdes = routes.events.getEventSerdes(); + const eventSerdes = routes.events.getEventSerdes(config); const knownTopics = new Set(Object.values(routes.events.eventTypes)); for (const [topic, {value}] of Object.entries(eventstreamExamples ?? {}).filter( From 7d900c5b37577ac875a953d0250da945ddb286ab Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Fri, 16 Aug 2024 22:40:14 +0800 Subject: [PATCH 077/259] feat: pre-electra support from attestation pool (#6998) * Initial commit * Update packages/beacon-node/src/chain/chain.ts Co-authored-by: Nico Flaig * Update packages/beacon-node/src/api/impl/validator/index.ts Co-authored-by: Nico Flaig * Update packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts Co-authored-by: Nico Flaig * address comment * Add unit test for attestation pool * fix: getSeenAttDataKey apis (#7009) * fix: getSeenAttDataKey apis * chore: use ForkName instead of ForkSeq * Update packages/beacon-node/src/util/sszBytes.ts Co-authored-by: Nico Flaig * Update packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts Co-authored-by: Nico Flaig * address comment * Update error message * Update packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts Co-authored-by: Nico Flaig * address comment * Move determining post-electra fork out of loops --------- Co-authored-by: Nico Flaig Co-authored-by: twoeths --- .../src/api/impl/beacon/pool/index.ts | 20 ++- .../src/api/impl/validator/index.ts | 28 +++- packages/beacon-node/src/chain/chain.ts | 10 +- .../opPools/aggregatedAttestationPool.ts | 40 ++++-- .../src/chain/opPools/attestationPool.ts | 34 ++++- .../beacon-node/src/chain/opPools/utils.ts | 5 + .../chain/seenCache/seenAttestationData.ts | 7 +- .../src/chain/validation/aggregateAndProof.ts | 6 +- .../src/chain/validation/attestation.ts | 68 ++++++++-- .../network/processor/gossipQueues/index.ts | 7 +- packages/beacon-node/src/util/sszBytes.ts | 88 +++++-------- packages/beacon-node/test/mocks/clock.ts | 1 + .../test/mocks/mockedBeaconChain.ts | 2 +- .../opPools/aggregatedAttestationPool.test.ts | 9 +- .../perf/chain/validation/attestation.test.ts | 6 +- .../opPools/aggregatedAttestationPool.test.ts | 6 +- .../chain/opPools/attestationPool.test.ts | 120 ++++++++++++++++++ .../attestation/validateAttestation.test.ts | 83 +++++++++--- .../test/unit/util/sszBytes.test.ts | 32 +++-- .../src/block/processAttestationPhase0.ts | 1 - 20 files changed, 437 insertions(+), 136 deletions(-) create mode 100644 packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index bc8c838a5401..398238aa2508 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -1,7 +1,7 @@ import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; -import {Epoch, ssz} from "@lodestar/types"; -import {ForkName, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; +import {Attestation, Epoch, isElectraAttestation, ssz} from "@lodestar/types"; +import {ForkName, SYNC_COMMITTEE_SUBNET_SIZE, isForkPostElectra} from "@lodestar/params"; import {validateApiAttestation} from "../../../../chain/validation/index.js"; import {validateApiAttesterSlashing} from "../../../../chain/validation/attesterSlashing.js"; import {validateApiProposerSlashing} from "../../../../chain/validation/proposerSlashing.js"; @@ -16,6 +16,7 @@ import { SyncCommitteeError, } from "../../../../chain/errors/index.js"; import {validateGossipFnRetryUnknownRoot} from "../../../../network/processor/gossipHandlers.js"; +import {ApiError} from "../../errors.js"; export function getBeaconPoolApi({ chain, @@ -26,7 +27,15 @@ export function getBeaconPoolApi({ return { async getPoolAttestations({slot, committeeIndex}) { // Already filtered by slot - let attestations = chain.aggregatedAttestationPool.getAll(slot); + let attestations: Attestation[] = chain.aggregatedAttestationPool.getAll(slot); + const fork = chain.config.getForkName(slot ?? chain.clock.currentSlot); + + if (isForkPostElectra(fork)) { + throw new ApiError( + 400, + `Use getPoolAttestationsV2 to retrieve pool attestations for post-electra fork=${fork}` + ); + } if (committeeIndex !== undefined) { attestations = attestations.filter((attestation) => committeeIndex === attestation.data.index); @@ -39,6 +48,11 @@ export function getBeaconPoolApi({ // Already filtered by slot let attestations = chain.aggregatedAttestationPool.getAll(slot); const fork = chain.config.getForkName(slot ?? attestations[0]?.data.slot ?? chain.clock.currentSlot); + const isPostElectra = isForkPostElectra(fork); + + attestations = attestations.filter((attestation) => + isPostElectra ? isElectraAttestation(attestation) : !isElectraAttestation(attestation) + ); if (committeeIndex !== undefined) { attestations = attestations.filter((attestation) => committeeIndex === attestation.data.index); diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 2d453f0d24c7..a17c1418809e 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -1073,9 +1073,31 @@ export function getValidatorApi( }; }, - // TODO Electra: Implement getAggregatedAttestation to properly handle pre-electra - async getAggregatedAttestation() { - throw new Error("Not implemented. Use getAggregatedAttestationV2 for now."); + async getAggregatedAttestation({attestationDataRoot, slot}) { + notWhileSyncing(); + + await waitForSlot(slot); // Must never request for a future slot > currentSlot + + const dataRootHex = toHex(attestationDataRoot); + const aggregate = chain.attestationPool.getAggregate(slot, null, dataRootHex); + const fork = chain.config.getForkName(slot); + + if (isForkPostElectra(fork)) { + throw new ApiError( + 400, + `Use getAggregatedAttestationV2 to retrieve aggregated attestations for post-electra fork=${fork}` + ); + } + + if (!aggregate) { + throw new ApiError(404, `No aggregated attestation for slot=${slot}, dataRoot=${dataRootHex}`); + } + + metrics?.production.producedAggregateParticipants.observe(aggregate.aggregationBits.getTrueBitIndexes().length); + + return { + data: aggregate, + }; }, async getAggregatedAttestationV2({attestationDataRoot, slot, committeeIndex}) { diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 598b26d7061f..b410a1e84655 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -133,7 +133,7 @@ export class BeaconChain implements IBeaconChain { // Ops pool readonly attestationPool: AttestationPool; - readonly aggregatedAttestationPool = new AggregatedAttestationPool(); + readonly aggregatedAttestationPool: AggregatedAttestationPool; readonly syncCommitteeMessagePool: SyncCommitteeMessagePool; readonly syncContributionAndProofPool = new SyncContributionAndProofPool(); readonly opPool = new OpPool(); @@ -226,7 +226,13 @@ export class BeaconChain implements IBeaconChain { if (!clock) clock = new Clock({config, genesisTime: this.genesisTime, signal}); const preAggregateCutOffTime = (2 / 3) * this.config.SECONDS_PER_SLOT; - this.attestationPool = new AttestationPool(clock, preAggregateCutOffTime, this.opts?.preaggregateSlotDistance); + this.attestationPool = new AttestationPool( + config, + clock, + preAggregateCutOffTime, + this.opts?.preaggregateSlotDistance + ); + this.aggregatedAttestationPool = new AggregatedAttestationPool(this.config); this.syncCommitteeMessagePool = new SyncCommitteeMessagePool( clock, preAggregateCutOffTime, diff --git a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts index b3e82c0c6366..e656915552b4 100644 --- a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts @@ -3,6 +3,7 @@ import {BitArray, toHexString} from "@chainsafe/ssz"; import { ForkName, ForkSeq, + isForkPostElectra, MAX_ATTESTATIONS, MAX_ATTESTATIONS_ELECTRA, MAX_COMMITTEES_PER_SLOT, @@ -30,6 +31,7 @@ import { } from "@lodestar/state-transition"; import {IForkChoice, EpochDifference} from "@lodestar/fork-choice"; import {MapDef, toRootHex, assert} from "@lodestar/utils"; +import {ChainForkConfig} from "@lodestar/config"; import {intersectUint8Arrays, IntersectResult} from "../../util/bitArray.js"; import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; import {InsertOutcome} from "./types.js"; @@ -101,6 +103,8 @@ export class AggregatedAttestationPool { >(() => new Map>()); private lowestPermissibleSlot = 0; + constructor(private readonly config: ChainForkConfig) {} + /** For metrics to track size of the pool */ getAttestationCount(): {attestationCount: number; attestationDataCount: number} { let attestationCount = 0; @@ -136,10 +140,20 @@ export class AggregatedAttestationPool { attestationGroupByIndex = new Map(); attestationGroupByIndexByDataHash.set(dataRootHex, attestationGroupByIndex); } - const committeeIndex = isElectraAttestation(attestation) - ? // this attestation is added to pool after validation - attestation.committeeBits.getSingleTrueBit() - : attestation.data.index; + + let committeeIndex; + + if (isForkPostElectra(this.config.getForkName(slot))) { + if (!isElectraAttestation(attestation)) { + throw Error(`Attestation should be type electra.Attestation for slot ${slot}`); + } + committeeIndex = attestation.committeeBits.getSingleTrueBit(); + } else { + if (isElectraAttestation(attestation)) { + throw Error(`Attestation should be type phase0.Attestation for slot ${slot}`); + } + committeeIndex = attestation.data.index; + } // this should not happen because attestation should be validated before reaching this assert.notNull(committeeIndex, "Committee index should not be null in aggregated attestation pool"); let attestationGroup = attestationGroupByIndex.get(committeeIndex); @@ -390,6 +404,10 @@ export class AggregatedAttestationPool { /** * Get all attestations optionally filtered by `attestation.data.slot` + * Note this function is not fork aware and can potentially return a mix + * of phase0.Attestations and electra.Attestations. + * Caller of this function is expected to filtered result if they desire + * a homogenous array. * @param bySlot slot to filter, `bySlot === attestation.data.slot` */ getAll(bySlot?: Slot): Attestation[] { @@ -504,8 +522,15 @@ export class MatchingDataAttestationGroup { */ getAttestationsForBlock(fork: ForkName, notSeenAttestingIndices: Set): AttestationNonParticipant[] { const attestations: AttestationNonParticipant[] = []; - const forkSeq = ForkSeq[fork]; + const isPostElectra = isForkPostElectra(fork); for (const {attestation} of this.attestations) { + if ( + (isPostElectra && !isElectraAttestation(attestation)) || + (!isPostElectra && isElectraAttestation(attestation)) + ) { + continue; + } + let notSeenAttesterCount = 0; const {aggregationBits} = attestation; for (const notSeenIndex of notSeenAttestingIndices) { @@ -514,13 +539,12 @@ export class MatchingDataAttestationGroup { } } - // if fork >= electra, should return electra-only attestations - if (notSeenAttesterCount > 0 && (forkSeq < ForkSeq.electra || isElectraAttestation(attestation))) { + if (notSeenAttesterCount > 0) { attestations.push({attestation, notSeenAttesterCount}); } } - const maxAttestation = forkSeq >= ForkSeq.electra ? MAX_ATTESTATIONS_PER_GROUP_ELECTRA : MAX_ATTESTATIONS_PER_GROUP; + const maxAttestation = isPostElectra ? MAX_ATTESTATIONS_PER_GROUP_ELECTRA : MAX_ATTESTATIONS_PER_GROUP; if (attestations.length <= maxAttestation) { return attestations; } else { diff --git a/packages/beacon-node/src/chain/opPools/attestationPool.ts b/packages/beacon-node/src/chain/opPools/attestationPool.ts index f125b8c941db..887448b1e553 100644 --- a/packages/beacon-node/src/chain/opPools/attestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/attestationPool.ts @@ -2,9 +2,11 @@ import {BitArray} from "@chainsafe/ssz"; import {Signature, aggregateSignatures} from "@chainsafe/blst"; import {Slot, RootHex, isElectraAttestation, Attestation} from "@lodestar/types"; import {MapDef, assert} from "@lodestar/utils"; +import {isForkPostElectra} from "@lodestar/params"; +import {ChainForkConfig} from "@lodestar/config"; import {IClock} from "../../util/clock.js"; import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js"; -import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; +import {isElectraAggregate, pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; /** * The number of slots that will be stored in the pool. @@ -28,14 +30,15 @@ type AggregateFastPhase0 = { signature: Signature; }; -type AggregateFastElectra = AggregateFastPhase0 & {committeeBits: BitArray}; +export type AggregateFastElectra = AggregateFastPhase0 & {committeeBits: BitArray}; -type AggregateFast = AggregateFastPhase0 | AggregateFastElectra; +export type AggregateFast = AggregateFastPhase0 | AggregateFastElectra; /** Hex string of DataRoot `TODO` */ type DataRootHex = string; -type CommitteeIndex = number; +/** CommitteeIndex must be null for pre-electra. Must not be null post-electra */ +type CommitteeIndex = number | null; /** * A pool of `Attestation` that is specially designed to store "unaggregated" attestations from @@ -68,6 +71,7 @@ export class AttestationPool { private lowestPermissibleSlot = 0; constructor( + private readonly config: ChainForkConfig, private readonly clock: IClock, private readonly cutOffSecFromSlot: number, private readonly preaggregateSlotDistance = 0 @@ -103,6 +107,7 @@ export class AttestationPool { */ add(committeeIndex: CommitteeIndex, attestation: Attestation, attDataRootHex: RootHex): InsertOutcome { const slot = attestation.data.slot; + const fork = this.config.getForkName(slot); const lowestPermissibleSlot = this.lowestPermissibleSlot; // Reject any attestations that are too old. @@ -121,8 +126,14 @@ export class AttestationPool { throw new OpPoolError({code: OpPoolErrorCode.REACHED_MAX_PER_SLOT}); } - // this should not happen because attestation should be validated before reaching this - assert.notNull(committeeIndex, "Committee index should not be null in attestation pool"); + if (isForkPostElectra(fork)) { + // Electra only: this should not happen because attestation should be validated before reaching this + assert.notNull(committeeIndex, "Committee index should not be null in attestation pool post-electra"); + assert.true(isElectraAttestation(attestation), "Attestation should be type electra.Attestation"); + } else { + assert.true(!isElectraAttestation(attestation), "Attestation should be type phase0.Attestation"); + committeeIndex = null; // For pre-electra, committee index info is encoded in attDataRootIndex + } // Pre-aggregate the contribution with existing items let aggregateByIndex = aggregateByRoot.get(attDataRootHex); @@ -144,14 +155,23 @@ export class AttestationPool { /** * For validator API to get an aggregate */ - // TODO Electra: Change attestation pool to accomodate pre-electra request getAggregate(slot: Slot, committeeIndex: CommitteeIndex, dataRootHex: RootHex): Attestation | null { + const fork = this.config.getForkName(slot); + const isPostElectra = isForkPostElectra(fork); + committeeIndex = isPostElectra ? committeeIndex : null; + const aggregate = this.aggregateByIndexByRootBySlot.get(slot)?.get(dataRootHex)?.get(committeeIndex); if (!aggregate) { // TODO: Add metric for missing aggregates return null; } + if (isPostElectra) { + assert.true(isElectraAggregate(aggregate), "Aggregate should be type AggregateFastElectra"); + } else { + assert.true(!isElectraAggregate(aggregate), "Aggregate should be type AggregateFastPhase0"); + } + return fastToAttestation(aggregate); } diff --git a/packages/beacon-node/src/chain/opPools/utils.ts b/packages/beacon-node/src/chain/opPools/utils.ts index 039e95af6c9f..e136bf1d4094 100644 --- a/packages/beacon-node/src/chain/opPools/utils.ts +++ b/packages/beacon-node/src/chain/opPools/utils.ts @@ -2,6 +2,7 @@ import {Signature} from "@chainsafe/blst"; import {BLS_WITHDRAWAL_PREFIX} from "@lodestar/params"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {Slot, capella} from "@lodestar/types"; +import {AggregateFast, AggregateFastElectra} from "./attestationPool.js"; /** * Prune a Map indexed by slot to keep the most recent slots, up to `slotsRetained` @@ -58,3 +59,7 @@ export function isValidBlsToExecutionChangeForBlockInclusion( return true; } + +export function isElectraAggregate(aggregate: AggregateFast): aggregate is AggregateFastElectra { + return (aggregate as AggregateFastElectra).committeeBits !== undefined; +} diff --git a/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts b/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts index 17343e386fd7..a0aa6db35893 100644 --- a/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts +++ b/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts @@ -2,9 +2,14 @@ import {BitArray} from "@chainsafe/ssz"; import {CommitteeIndex, phase0, RootHex, Slot} from "@lodestar/types"; import {MapDef} from "@lodestar/utils"; import {Metrics} from "../../metrics/metrics.js"; -import {SeenAttDataKey} from "../../util/sszBytes.js"; import {InsertOutcome} from "../opPools/types.js"; +export type SeenAttDataKey = AttDataBase64 | AttDataCommitteeBitsBase64; +// pre-electra, AttestationData is used to cache attestations +type AttDataBase64 = string; +// electra, AttestationData + CommitteeBits are used to cache attestations +type AttDataCommitteeBitsBase64 = string; + export type AttestationDataCacheEntry = { // part of shuffling data, so this does not take memory committeeValidatorIndices: Uint32Array; diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 02c6613b170f..39a3700aacf9 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -9,11 +9,11 @@ import {toRootHex} from "@lodestar/utils"; import {IBeaconChain} from ".."; import {AttestationError, AttestationErrorCode, GossipAction} from "../errors/index.js"; import {RegenCaller} from "../regen/index.js"; -import {getSeenAttDataKeyFromSignedAggregateAndProof} from "../../util/sszBytes.js"; import {getSelectionProofSignatureSet, getAggregateAndProofSignatureSet} from "./signatureSets/index.js"; import { getAttestationDataSigningRoot, getCommitteeIndices, + getSeenAttDataKeyFromSignedAggregateAndProof, getShufflingForAttestationVerification, verifyHeadBlockAndTargetRoot, verifyPropagationSlotRange, @@ -71,9 +71,7 @@ async function validateAggregateAndProof( const attData = aggregate.data; const attSlot = attData.slot; - const seenAttDataKey = serializedData - ? getSeenAttDataKeyFromSignedAggregateAndProof(ForkSeq[fork], serializedData) - : null; + const seenAttDataKey = serializedData ? getSeenAttDataKeyFromSignedAggregateAndProof(fork, serializedData) : null; const cachedAttData = seenAttDataKey ? chain.seenAttestationDatas.get(attSlot, seenAttDataKey) : null; let attIndex; diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index 1dcf76cdc5ae..4ceaf64d658d 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -13,7 +13,14 @@ import { IndexedAttestation, } from "@lodestar/types"; import {ProtoBlock} from "@lodestar/fork-choice"; -import {ATTESTATION_SUBNET_COUNT, SLOTS_PER_EPOCH, ForkName, ForkSeq, DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; +import { + ATTESTATION_SUBNET_COUNT, + SLOTS_PER_EPOCH, + ForkName, + ForkSeq, + DOMAIN_BEACON_ATTESTER, + isForkPostElectra, +} from "@lodestar/params"; import { computeEpochAtSlot, createSingleSignatureSetFromComponents, @@ -30,12 +37,15 @@ import {AttestationError, AttestationErrorCode, GossipAction} from "../errors/in import {MAXIMUM_GOSSIP_CLOCK_DISPARITY_SEC} from "../../constants/index.js"; import {RegenCaller} from "../regen/index.js"; import { - SeenAttDataKey, getAggregationBitsFromAttestationSerialized, - getSeenAttDataKey, + getAttDataFromAttestationSerialized, + getAttDataFromSignedAggregateAndProofElectra, + getCommitteeBitsFromAttestationSerialized, + getCommitteeBitsFromSignedAggregateAndProofElectra, + getAttDataFromSignedAggregateAndProofPhase0, getSignatureFromAttestationSerialized, } from "../../util/sszBytes.js"; -import {AttestationDataCacheEntry} from "../seenCache/seenAttestationData.js"; +import {AttestationDataCacheEntry, SeenAttDataKey} from "../seenCache/seenAttestationData.js"; import {sszDeserializeAttestation} from "../../network/gossip/topic.js"; import {Result, wrapError} from "../../util/wrapError.js"; import {IBeaconChain} from "../interface.js"; @@ -67,7 +77,7 @@ export type GossipAttestation = { attSlot: Slot; // for old LIFO linear gossip queue we don't have attDataBase64 // for indexed gossip queue we have attDataBase64 - seenAttestationKey?: SeenAttDataKey | null; + attDataBase64?: SeenAttDataKey | null; }; export type Step0Result = AttestationValidationResult & { @@ -270,11 +280,7 @@ async function validateGossipAttestationNoSignatureCheck( if (attestationOrBytes.serializedData) { // gossip const attSlot = attestationOrBytes.attSlot; - attDataKey = - // we always have seenAttestationKey from the IndexedGossipQueue, getSeenAttDataKey() just for backward - // compatible in case beaconAttestationBatchValidation is false - // TODO: remove beaconAttestationBatchValidation flag since the batch attestation is stable - attestationOrBytes.seenAttestationKey ?? getSeenAttDataKey(ForkSeq[fork], attestationOrBytes.serializedData); + attDataKey = getSeenAttDataKeyFromGossipAttestation(fork, attestationOrBytes); const cachedAttData = attDataKey !== null ? chain.seenAttestationDatas.get(attSlot, attDataKey) : null; if (cachedAttData === null) { const attestation = sszDeserializeAttestation(fork, attestationOrBytes.serializedData); @@ -790,3 +796,45 @@ export function computeSubnetForSlot(shuffling: EpochShuffling, slot: number, co const committeesSinceEpochStart = shuffling.committeesPerSlot * slotsSinceEpochStart; return (committeesSinceEpochStart + committeeIndex) % ATTESTATION_SUBNET_COUNT; } + +/** + * Return fork-dependent seen attestation key + * - for pre-electra, it's the AttestationData base64 + * - for electra and later, it's the AttestationData base64 + committeeBits base64 + * + * we always have attDataBase64 from the IndexedGossipQueue, getAttDataFromAttestationSerialized() just for backward compatible when beaconAttestationBatchValidation is false + * TODO: remove beaconAttestationBatchValidation flag since the batch attestation is stable + */ +export function getSeenAttDataKeyFromGossipAttestation( + fork: ForkName, + attestation: GossipAttestation +): SeenAttDataKey | null { + const {attDataBase64, serializedData} = attestation; + if (isForkPostElectra(fork)) { + const attData = attDataBase64 ?? getAttDataFromAttestationSerialized(serializedData); + const committeeBits = getCommitteeBitsFromAttestationSerialized(serializedData); + return attData && committeeBits ? attDataBase64 + committeeBits : null; + } + + // pre-electra + return attDataBase64 ?? getAttDataFromAttestationSerialized(serializedData); +} + +/** + * Extract attestation data key from SignedAggregateAndProof Uint8Array to use cached data from SeenAttestationDatas + * - for pre-electra, it's the AttestationData base64 + * - for electra and later, it's the AttestationData base64 + committeeBits base64 + */ +export function getSeenAttDataKeyFromSignedAggregateAndProof( + fork: ForkName, + aggregateAndProof: Uint8Array +): SeenAttDataKey | null { + if (isForkPostElectra(fork)) { + const attData = getAttDataFromSignedAggregateAndProofElectra(aggregateAndProof); + const committeeBits = getCommitteeBitsFromSignedAggregateAndProofElectra(aggregateAndProof); + return attData && committeeBits ? attData + committeeBits : null; + } + + // pre-electra + return getAttDataFromSignedAggregateAndProofPhase0(aggregateAndProof); +} diff --git a/packages/beacon-node/src/network/processor/gossipQueues/index.ts b/packages/beacon-node/src/network/processor/gossipQueues/index.ts index b38ee74279ca..347458c91445 100644 --- a/packages/beacon-node/src/network/processor/gossipQueues/index.ts +++ b/packages/beacon-node/src/network/processor/gossipQueues/index.ts @@ -1,8 +1,7 @@ import {mapValues} from "@lodestar/utils"; -import {ForkSeq} from "@lodestar/params"; import {GossipType} from "../../gossip/interface.js"; import {PendingGossipsubMessage} from "../types.js"; -import {getSeenAttDataKey} from "../../../util/sszBytes.js"; +import {getGossipAttestationIndex} from "../../../util/sszBytes.js"; import {LinearGossipQueue} from "./linear.js"; import { DropType, @@ -88,8 +87,8 @@ const indexedGossipQueueOpts: { [GossipType.beacon_attestation]: { maxLength: 24576, indexFn: (item: PendingGossipsubMessage) => { - const {topic, msg} = item; - return getSeenAttDataKey(ForkSeq[topic.fork], msg.data); + // Note indexFn is fork agnostic despite changes introduced in Electra + return getGossipAttestationIndex(item.msg.data); }, minChunkSize: MIN_SIGNATURE_SETS_TO_BATCH_VERIFY, maxChunkSize: MAX_GOSSIP_ATTESTATION_BATCH_SIZE, diff --git a/packages/beacon-node/src/util/sszBytes.ts b/packages/beacon-node/src/util/sszBytes.ts index 89f1dd20a473..81821b5eb710 100644 --- a/packages/beacon-node/src/util/sszBytes.ts +++ b/packages/beacon-node/src/util/sszBytes.ts @@ -9,11 +9,10 @@ import { } from "@lodestar/params"; export type BlockRootHex = RootHex; -export type SeenAttDataKey = AttDataBase64 | AttDataCommitteeBitsBase64; // pre-electra, AttestationData is used to cache attestations export type AttDataBase64 = string; -// electra, AttestationData + CommitteeBits are used to cache attestations -export type AttDataCommitteeBitsBase64 = string; +// electra, CommitteeBits +export type CommitteeBitsBase64 = string; // pre-electra // class Attestation(Container): @@ -48,6 +47,7 @@ const SIGNATURE_SIZE = 96; // shared Buffers to convert bytes to hex/base64 const blockRootBuf = Buffer.alloc(ROOT_SIZE); const attDataBuf = Buffer.alloc(ATTESTATION_DATA_SIZE); +const committeeBitsDataBuf = Buffer.alloc(COMMITTEE_BITS_SIZE); /** * Extract slot from attestation serialized bytes. @@ -77,37 +77,10 @@ export function getBlockRootFromAttestationSerialized(data: Uint8Array): BlockRo } /** - * Extract attestation data key from an attestation Uint8Array in order to index gossip queue and cache later in SeenAttestationDatas - */ -export function getSeenAttDataKey(forkSeq: ForkSeq, data: Uint8Array): SeenAttDataKey | null { - return forkSeq >= ForkSeq.electra ? getSeenAttDataKeyElectra(data) : getSeenAttDataKeyPhase0(data); -} - -/** - * Extract attestation data + committeeBits base64 from electra attestation serialized bytes. - * Return null if data is not long enough to extract attestation data. - */ -export function getSeenAttDataKeyElectra(electraAttestationBytes: Uint8Array): AttDataCommitteeBitsBase64 | null { - const attestationData = getSeenAttDataKeyPhase0(electraAttestationBytes); - - if (attestationData === null) { - return null; - } - - const committeeBits = getCommitteeBitsFromAttestationSerialized(electraAttestationBytes); - - if (committeeBits === null) { - return null; - } - - return attestationData + toBase64(committeeBits.uint8Array); -} - -/** - * Extract attestation data base64 from phase0 attestation serialized bytes. + * Extract attestation data base64 from all forks' attestation serialized bytes. * Return null if data is not long enough to extract attestation data. */ -export function getSeenAttDataKeyPhase0(data: Uint8Array): AttDataBase64 | null { +export function getAttDataFromAttestationSerialized(data: Uint8Array): AttDataBase64 | null { if (data.length < VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE) { return null; } @@ -117,6 +90,13 @@ export function getSeenAttDataKeyPhase0(data: Uint8Array): AttDataBase64 | null return attDataBuf.toString("base64"); } +/** + * Alias of `getAttDataFromAttestationSerialized` specifically for batch handling indexing in gossip queue + */ +export function getGossipAttestationIndex(data: Uint8Array): AttDataBase64 | null { + return getAttDataFromAttestationSerialized(data); +} + /** * Extract aggregation bits from attestation serialized bytes. * Return null if data is not long enough to extract aggregation bits. @@ -153,16 +133,15 @@ export function getSignatureFromAttestationSerialized(data: Uint8Array): BLSSign * Extract committee bits from Electra attestation serialized bytes. * Return null if data is not long enough to extract committee bits. */ -export function getCommitteeBitsFromAttestationSerialized(data: Uint8Array): BitArray | null { +export function getCommitteeBitsFromAttestationSerialized(data: Uint8Array): CommitteeBitsBase64 | null { const committeeBitsStartIndex = VARIABLE_FIELD_OFFSET + ATTESTATION_DATA_SIZE + SIGNATURE_SIZE; if (data.length < committeeBitsStartIndex + COMMITTEE_BITS_SIZE) { return null; } - const uint8Array = data.subarray(committeeBitsStartIndex, committeeBitsStartIndex + COMMITTEE_BITS_SIZE); - - return new BitArray(uint8Array, MAX_COMMITTEES_PER_SLOT); + committeeBitsDataBuf.set(data.subarray(committeeBitsStartIndex, committeeBitsStartIndex + COMMITTEE_BITS_SIZE)); + return committeeBitsDataBuf.toString("base64"); } // @@ -213,42 +192,39 @@ export function getBlockRootFromSignedAggregateAndProofSerialized(data: Uint8Arr } /** - * Extract attestation data key from SignedAggregateAndProof Uint8Array to use cached data from SeenAttestationDatas - */ -export function getSeenAttDataKeyFromSignedAggregateAndProof( - forkSeq: ForkSeq, - data: Uint8Array -): SeenAttDataKey | null { - return forkSeq >= ForkSeq.electra - ? getSeenAttDataKeyFromSignedAggregateAndProofElectra(data) - : getSeenAttDataKeyFromSignedAggregateAndProofPhase0(data); -} - -/** - * Extract AttestationData + CommitteeBits from SignedAggregateAndProof for electra + * Extract AttestationData base64 from SignedAggregateAndProof for electra * Return null if data is not long enough */ -export function getSeenAttDataKeyFromSignedAggregateAndProofElectra(data: Uint8Array): SeenAttDataKey | null { +export function getAttDataFromSignedAggregateAndProofElectra(data: Uint8Array): AttDataBase64 | null { const startIndex = SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET; const endIndex = startIndex + ATTESTATION_DATA_SIZE; if (data.length < endIndex + SIGNATURE_SIZE + COMMITTEE_BITS_SIZE) { return null; } + return toBase64(data.subarray(startIndex, endIndex)); +} - // base64 is a bit efficient than hex +/** + * Extract CommitteeBits base64 from SignedAggregateAndProof for electra + * Return null if data is not long enough + */ +export function getCommitteeBitsFromSignedAggregateAndProofElectra(data: Uint8Array): CommitteeBitsBase64 | null { + const startIndex = SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET + ATTESTATION_DATA_SIZE + SIGNATURE_SIZE; + const endIndex = startIndex + COMMITTEE_BITS_SIZE; + + if (data.length < endIndex) { + return null; + } - return Buffer.concat([ - data.subarray(startIndex, endIndex), - data.subarray(endIndex + SIGNATURE_SIZE, endIndex + SIGNATURE_SIZE + COMMITTEE_BITS_SIZE), - ]).toString("base64"); + return toBase64(data.subarray(startIndex, endIndex)); } /** * Extract attestation data base64 from signed aggregate and proof serialized bytes. * Return null if data is not long enough to extract attestation data. */ -export function getSeenAttDataKeyFromSignedAggregateAndProofPhase0(data: Uint8Array): AttDataBase64 | null { +export function getAttDataFromSignedAggregateAndProofPhase0(data: Uint8Array): AttDataBase64 | null { if (data.length < SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET + ATTESTATION_DATA_SIZE) { return null; } diff --git a/packages/beacon-node/test/mocks/clock.ts b/packages/beacon-node/test/mocks/clock.ts index c38794bf16d4..6f09bd292491 100644 --- a/packages/beacon-node/test/mocks/clock.ts +++ b/packages/beacon-node/test/mocks/clock.ts @@ -74,5 +74,6 @@ export function getMockedClock(): Mocked { }, currentSlotWithGossipDisparity: undefined, isCurrentSlotGivenGossipDisparity: vi.fn(), + secFromSlot: vi.fn(), } as unknown as Mocked; } diff --git a/packages/beacon-node/test/mocks/mockedBeaconChain.ts b/packages/beacon-node/test/mocks/mockedBeaconChain.ts index cc85cfd7d553..addeacf26a89 100644 --- a/packages/beacon-node/test/mocks/mockedBeaconChain.ts +++ b/packages/beacon-node/test/mocks/mockedBeaconChain.ts @@ -124,7 +124,7 @@ vi.mock("../../src/chain/chain.js", async (importActual) => { // @ts-expect-error eth1: new Eth1ForBlockProduction(), opPool: new OpPool(), - aggregatedAttestationPool: new AggregatedAttestationPool(), + aggregatedAttestationPool: new AggregatedAttestationPool(config), // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error beaconProposerCache: new BeaconProposerCache(), diff --git a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts index 60ff6ce48302..ec66f6dd8905 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -10,8 +10,9 @@ import { import {HISTORICAL_ROOTS_LIMIT, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ExecutionStatus, ForkChoice, IForkChoiceStore, ProtoArray, DataAvailabilityStatus} from "@lodestar/fork-choice"; import {ssz} from "@lodestar/types"; -// eslint-disable-next-line import/no-relative-packages -import {generatePerfTestCachedStateAltair} from "../../../../../state-transition/test/perf/util.js"; + +import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; +import {generatePerfTestCachedStateAltair} from "@lodestar/state-transition/test/perf/util.js"; import {AggregatedAttestationPool} from "../../../../src/chain/opPools/aggregatedAttestationPool.js"; import {computeAnchorCheckpoint} from "../../../../src/chain/initState.js"; @@ -230,7 +231,9 @@ function getAggregatedAttestationPool( numMissedVotes: number, numBadVotes: number ): AggregatedAttestationPool { - const pool = new AggregatedAttestationPool(); + const config = createChainForkConfig(defaultChainConfig); + + const pool = new AggregatedAttestationPool(config); for (let epochSlot = 0; epochSlot < SLOTS_PER_EPOCH; epochSlot++) { const slot = state.slot - 1 - epochSlot; const epoch = computeEpochAtSlot(slot); diff --git a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts index e0e0a1e51169..f285317474d6 100644 --- a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts +++ b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts @@ -5,7 +5,7 @@ import {ssz} from "@lodestar/types"; import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../state-transition/test/perf/util.js"; import {validateAttestation, validateGossipAttestationsSameAttData} from "../../../../src/chain/validation/index.js"; import {getAttestationValidData} from "../../../utils/validationData/attestation.js"; -import {getSeenAttDataKeyPhase0} from "../../../../src/util/sszBytes.js"; +import {getAttDataFromAttestationSerialized} from "../../../../src/util/sszBytes.js"; describe("validate gossip attestation", () => { setBenchOpts({ @@ -42,7 +42,7 @@ describe("validate gossip attestation", () => { attestation: null, serializedData, attSlot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, subnet0 ); @@ -67,7 +67,7 @@ describe("validate gossip attestation", () => { attestation: null, serializedData, attSlot, - attDataBase64: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }; }); diff --git a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts index c9c128e5485e..f00a300bbe4d 100644 --- a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts @@ -11,6 +11,7 @@ import { } from "@lodestar/params"; import {ssz, phase0} from "@lodestar/types"; import {CachedBeaconStateAltair} from "@lodestar/state-transition/src/types.js"; +import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {MockedForkChoice, getMockedForkChoice} from "../../../mocks/mockedBeaconChain.js"; import { aggregateConsolidation, @@ -36,6 +37,9 @@ const validSignature = fromHexString( describe("AggregatedAttestationPool", function () { let pool: AggregatedAttestationPool; const fork = ForkName.altair; + const config = createChainForkConfig({ + ...defaultChainConfig, + }); const altairForkEpoch = 2020; const currentEpoch = altairForkEpoch + 10; const currentSlot = SLOTS_PER_EPOCH * currentEpoch; @@ -79,7 +83,7 @@ describe("AggregatedAttestationPool", function () { let forkchoiceStub: MockedForkChoice; beforeEach(() => { - pool = new AggregatedAttestationPool(); + pool = new AggregatedAttestationPool(config); altairState = originalState.clone(); forkchoiceStub = getMockedForkChoice(); }); diff --git a/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts new file mode 100644 index 000000000000..68efd0751585 --- /dev/null +++ b/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts @@ -0,0 +1,120 @@ +import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {describe, it, expect, beforeEach, vi} from "vitest"; +import {GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; +import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; +import {InsertOutcome} from "../../../../src/chain/opPools/types.js"; +import {AttestationPool} from "../../../../src/chain/opPools/attestationPool.js"; +import {getMockedClock} from "../../../mocks/clock.js"; + +/** Valid signature of random data to prevent BLS errors */ +export const validSignature = fromHexString( + "0xb2afb700f6c561ce5e1b4fedaec9d7c06b822d38c720cf588adfda748860a940adf51634b6788f298c552de40183b5a203b2bbe8b7dd147f0bb5bc97080a12efbb631c8888cb31a99cc4706eb3711865b8ea818c10126e4d818b542e9dbf9ae8" +); + +describe("AttestationPool", function () { + /* eslint-disable @typescript-eslint/naming-convention */ + const config = createChainForkConfig({ + ...defaultChainConfig, + ELECTRA_FORK_EPOCH: 5, + DENEB_FORK_EPOCH: 4, + CAPELLA_FORK_EPOCH: 3, + BELLATRIX_FORK_EPOCH: 2, + ALTAIR_FORK_EPOCH: 1, + }); + const clockStub = getMockedClock(); + vi.spyOn(clockStub, "secFromSlot").mockReturnValue(0); + + const cutOffSecFromSlot = (2 / 3) * config.SECONDS_PER_SLOT; + + // Mock attestations + const electraAttestationData = { + ...ssz.phase0.AttestationData.defaultValue(), + slot: config.ELECTRA_FORK_EPOCH * SLOTS_PER_EPOCH, + }; + const electraAttestation = { + ...ssz.electra.Attestation.defaultValue(), + data: electraAttestationData, + signature: validSignature, + }; + const phase0AttestationData = {...ssz.phase0.AttestationData.defaultValue(), slot: GENESIS_SLOT}; + const phase0Attestation = { + ...ssz.phase0.Attestation.defaultValue(), + data: phase0AttestationData, + signature: validSignature, + }; + + let pool: AttestationPool; + + beforeEach(() => { + pool = new AttestationPool(config, clockStub, cutOffSecFromSlot); + }); + + it("add correct electra attestation", () => { + const committeeIndex = 0; + const attDataRootHex = toHexString(ssz.phase0.AttestationData.hashTreeRoot(electraAttestation.data)); + const outcome = pool.add(committeeIndex, electraAttestation, attDataRootHex); + + expect(outcome).equal(InsertOutcome.NewData); + expect(pool.getAggregate(electraAttestationData.slot, committeeIndex, attDataRootHex)).toEqual(electraAttestation); + }); + + it("add correct phase0 attestation", () => { + const committeeIndex = null; + const attDataRootHex = toHexString(ssz.phase0.AttestationData.hashTreeRoot(phase0Attestation.data)); + const outcome = pool.add(committeeIndex, phase0Attestation, attDataRootHex); + + expect(outcome).equal(InsertOutcome.NewData); + expect(pool.getAggregate(phase0AttestationData.slot, committeeIndex, attDataRootHex)).toEqual(phase0Attestation); + expect(pool.getAggregate(phase0AttestationData.slot, 10, attDataRootHex)).toEqual(phase0Attestation); + expect(pool.getAggregate(phase0AttestationData.slot, 42, attDataRootHex)).toEqual(phase0Attestation); + expect(pool.getAggregate(phase0AttestationData.slot, null, attDataRootHex)).toEqual(phase0Attestation); + }); + + it("add electra attestation without committee index", () => { + const committeeIndex = null; + const attDataRootHex = toHexString(ssz.phase0.AttestationData.hashTreeRoot(electraAttestation.data)); + + expect(() => pool.add(committeeIndex, electraAttestation, attDataRootHex)).toThrow(); + expect(pool.getAggregate(electraAttestationData.slot, committeeIndex, attDataRootHex)).toBeNull(); + }); + + it("add phase0 attestation with committee index", () => { + const committeeIndex = 0; + const attDataRootHex = toHexString(ssz.phase0.AttestationData.hashTreeRoot(phase0Attestation.data)); + const outcome = pool.add(committeeIndex, phase0Attestation, attDataRootHex); + + expect(outcome).equal(InsertOutcome.NewData); + expect(pool.getAggregate(phase0AttestationData.slot, committeeIndex, attDataRootHex)).toEqual(phase0Attestation); + expect(pool.getAggregate(phase0AttestationData.slot, 123, attDataRootHex)).toEqual(phase0Attestation); + expect(pool.getAggregate(phase0AttestationData.slot, 456, attDataRootHex)).toEqual(phase0Attestation); + expect(pool.getAggregate(phase0AttestationData.slot, null, attDataRootHex)).toEqual(phase0Attestation); + }); + + it("add electra attestation with phase0 slot", () => { + const electraAttestationDataWithPhase0Slot = {...ssz.phase0.AttestationData.defaultValue(), slot: GENESIS_SLOT}; + const attestation = { + ...ssz.electra.Attestation.defaultValue(), + data: electraAttestationDataWithPhase0Slot, + signature: validSignature, + }; + const attDataRootHex = toHexString(ssz.phase0.AttestationData.hashTreeRoot(electraAttestationDataWithPhase0Slot)); + + expect(() => pool.add(0, attestation, attDataRootHex)).toThrow(); + }); + + it("add phase0 attestation with electra slot", () => { + const phase0AttestationDataWithElectraSlot = { + ...ssz.phase0.AttestationData.defaultValue(), + slot: config.ELECTRA_FORK_EPOCH * SLOTS_PER_EPOCH, + }; + const attestation = { + ...ssz.phase0.Attestation.defaultValue(), + data: phase0AttestationDataWithElectraSlot, + signature: validSignature, + }; + const attDataRootHex = toHexString(ssz.phase0.AttestationData.hashTreeRoot(phase0AttestationDataWithElectraSlot)); + + expect(() => pool.add(0, attestation, attDataRootHex)).toThrow(); + }); +}); diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts index 4a1c3badae50..45d293ffbb33 100644 --- a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts @@ -1,6 +1,6 @@ import {BitArray} from "@chainsafe/ssz"; -import {describe, it} from "vitest"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {describe, expect, it} from "vitest"; +import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ssz} from "@lodestar/types"; // eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../../state-transition/test/perf/util.js"; @@ -9,14 +9,17 @@ import {IBeaconChain} from "../../../../../src/chain/index.js"; import { ApiAttestation, GossipAttestation, + getSeenAttDataKeyFromGossipAttestation, + getSeenAttDataKeyFromSignedAggregateAndProof, validateApiAttestation, validateAttestation, } from "../../../../../src/chain/validation/index.js"; -import {getSeenAttDataKeyPhase0} from "../../../../../src/util/sszBytes.js"; +import {getAttDataFromAttestationSerialized} from "../../../../../src/util/sszBytes.js"; import {memoOnce} from "../../../../utils/cache.js"; import {expectRejectedWithLodestarError} from "../../../../utils/errors.js"; import {AttestationValidDataOpts, getAttestationValidData} from "../../../../utils/validationData/attestation.js"; +// TODO: more tests for electra describe("validateAttestation", () => { const vc = 64; const stateSlot = 100; @@ -52,7 +55,7 @@ describe("validateAttestation", () => { const {chain, subnet} = getValidData(); await expectGossipError( chain, - {attestation: null, serializedData: Buffer.alloc(0), attSlot: 0, seenAttestationKey: "invalid"}, + {attestation: null, serializedData: Buffer.alloc(0), attSlot: 0, attDataBase64: "invalid"}, subnet, GossipErrorCode.INVALID_SERIALIZED_BYTES_ERROR_CODE ); @@ -72,7 +75,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, subnet, AttestationErrorCode.BAD_TARGET_EPOCH @@ -91,7 +94,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, subnet, AttestationErrorCode.PAST_SLOT @@ -110,7 +113,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, subnet, AttestationErrorCode.FUTURE_SLOT @@ -135,7 +138,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, subnet, AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET @@ -155,7 +158,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, subnet, AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET @@ -179,7 +182,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, subnet, AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT @@ -199,7 +202,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, subnet, AttestationErrorCode.INVALID_TARGET_ROOT @@ -226,7 +229,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, subnet, AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS @@ -245,7 +248,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, invalidSubnet, AttestationErrorCode.INVALID_SUBNET_ID @@ -265,7 +268,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, subnet, AttestationErrorCode.ATTESTATION_ALREADY_KNOWN @@ -287,7 +290,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - seenAttestationKey: getSeenAttDataKeyPhase0(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData), }, subnet, AttestationErrorCode.INVALID_SIGNATURE @@ -314,3 +317,53 @@ describe("validateAttestation", () => { await expectRejectedWithLodestarError(validateAttestation(fork, chain, attestationOrBytes, subnet), errorCode); } }); + +describe("getSeenAttDataKey", () => { + const slot = 100; + const index = 0; + const blockRoot = Buffer.alloc(32, 1); + + it("phase0", () => { + const attestationData = ssz.phase0.AttestationData.defaultValue(); + attestationData.slot = slot; + attestationData.index = index; + attestationData.beaconBlockRoot = blockRoot; + const attestation = ssz.phase0.Attestation.defaultValue(); + attestation.data = attestationData; + const attDataBase64 = Buffer.from(ssz.phase0.AttestationData.serialize(attestationData)).toString("base64"); + const attestationBytes = ssz.phase0.Attestation.serialize(attestation); + const gossipAttestation = {attDataBase64, serializedData: attestationBytes, attSlot: slot} as GossipAttestation; + + const signedAggregateAndProof = ssz.phase0.SignedAggregateAndProof.defaultValue(); + signedAggregateAndProof.message.aggregate.data.slot = slot; + signedAggregateAndProof.message.aggregate.data.index = index; + signedAggregateAndProof.message.aggregate.data.beaconBlockRoot = blockRoot; + const aggregateAndProofBytes = ssz.phase0.SignedAggregateAndProof.serialize(signedAggregateAndProof); + + expect(getSeenAttDataKeyFromGossipAttestation(ForkName.phase0, gossipAttestation)).toEqual( + getSeenAttDataKeyFromSignedAggregateAndProof(ForkName.phase0, aggregateAndProofBytes) + ); + }); + + it("electra", () => { + const attestationData = ssz.phase0.AttestationData.defaultValue(); + attestationData.slot = slot; + attestationData.index = index; + attestationData.beaconBlockRoot = blockRoot; + const attestation = ssz.electra.Attestation.defaultValue(); + attestation.data = attestationData; + const attDataBase64 = Buffer.from(ssz.phase0.AttestationData.serialize(attestationData)).toString("base64"); + const attestationBytes = ssz.electra.Attestation.serialize(attestation); + const gossipAttestation = {attDataBase64, serializedData: attestationBytes, attSlot: slot} as GossipAttestation; + + const signedAggregateAndProof = ssz.electra.SignedAggregateAndProof.defaultValue(); + signedAggregateAndProof.message.aggregate.data.slot = slot; + signedAggregateAndProof.message.aggregate.data.index = index; + signedAggregateAndProof.message.aggregate.data.beaconBlockRoot = blockRoot; + const aggregateAndProofBytes = ssz.electra.SignedAggregateAndProof.serialize(signedAggregateAndProof); + + expect(getSeenAttDataKeyFromGossipAttestation(ForkName.electra, gossipAttestation)).toEqual( + getSeenAttDataKeyFromSignedAggregateAndProof(ForkName.electra, aggregateAndProofBytes) + ); + }); +}); diff --git a/packages/beacon-node/test/unit/util/sszBytes.test.ts b/packages/beacon-node/test/unit/util/sszBytes.test.ts index 6fe6ae15c448..612eea5a4388 100644 --- a/packages/beacon-node/test/unit/util/sszBytes.test.ts +++ b/packages/beacon-node/test/unit/util/sszBytes.test.ts @@ -4,8 +4,8 @@ import {deneb, electra, Epoch, isElectraAttestation, phase0, RootHex, Slot, ssz} import {fromHex, toHex} from "@lodestar/utils"; import {ForkName, MAX_COMMITTEES_PER_SLOT} from "@lodestar/params"; import { - getSeenAttDataKeyPhase0, - getSeenAttDataKeyFromSignedAggregateAndProofPhase0, + getAttDataFromAttestationSerialized, + getAttDataFromSignedAggregateAndProofPhase0, getAggregationBitsFromAttestationSerialized as getAggregationBitsFromAttestationSerialized, getBlockRootFromAttestationSerialized, getBlockRootFromSignedAggregateAndProofSerialized, @@ -15,7 +15,8 @@ import { getSlotFromSignedBeaconBlockSerialized, getSlotFromBlobSidecarSerialized, getCommitteeBitsFromAttestationSerialized, - getSeenAttDataKeyFromSignedAggregateAndProofElectra, + getCommitteeBitsFromSignedAggregateAndProofElectra, + getAttDataFromSignedAggregateAndProofElectra, } from "../../../src/util/sszBytes.js"; describe("attestation SSZ serialized picking", () => { @@ -53,7 +54,9 @@ describe("attestation SSZ serialized picking", () => { expect(getAggregationBitsFromAttestationSerialized(ForkName.electra, bytes)?.toBoolArray()).toEqual( attestation.aggregationBits.toBoolArray() ); - expect(getCommitteeBitsFromAttestationSerialized(bytes)).toEqual(attestation.committeeBits); + expect(getCommitteeBitsFromAttestationSerialized(bytes)).toEqual( + Buffer.from(attestation.committeeBits.uint8Array).toString("base64") + ); expect(getSignatureFromAttestationSerialized(bytes)).toEqual(attestation.signature); } else { expect(getAggregationBitsFromAttestationSerialized(ForkName.phase0, bytes)?.toBoolArray()).toEqual( @@ -63,7 +66,7 @@ describe("attestation SSZ serialized picking", () => { } const attDataBase64 = ssz.phase0.AttestationData.serialize(attestation.data); - expect(getSeenAttDataKeyPhase0(bytes)).toBe(Buffer.from(attDataBase64).toString("base64")); + expect(getAttDataFromAttestationSerialized(bytes)).toBe(Buffer.from(attDataBase64).toString("base64")); }); } @@ -81,10 +84,10 @@ describe("attestation SSZ serialized picking", () => { } }); - it("getAttDataBase64FromAttestationSerialized - invalid data", () => { + it("getAttDataFromAttestationSerialized - invalid data", () => { const invalidAttDataBase64DataSizes = [0, 4, 100, 128, 131]; for (const size of invalidAttDataBase64DataSizes) { - expect(getSeenAttDataKeyPhase0(Buffer.alloc(size))).toBeNull(); + expect(getAttDataFromAttestationSerialized(Buffer.alloc(size))).toBeNull(); } }); @@ -128,9 +131,7 @@ describe("phase0 SignedAggregateAndProof SSZ serialized picking", () => { ); const attDataBase64 = ssz.phase0.AttestationData.serialize(signedAggregateAndProof.message.aggregate.data); - expect(getSeenAttDataKeyFromSignedAggregateAndProofPhase0(bytes)).toBe( - Buffer.from(attDataBase64).toString("base64") - ); + expect(getAttDataFromSignedAggregateAndProofPhase0(bytes)).toBe(Buffer.from(attDataBase64).toString("base64")); }); } @@ -151,7 +152,7 @@ describe("phase0 SignedAggregateAndProof SSZ serialized picking", () => { it("getAttDataBase64FromSignedAggregateAndProofSerialized - invalid data", () => { const invalidAttDataBase64DataSizes = [0, 4, 100, 128, 339]; for (const size of invalidAttDataBase64DataSizes) { - expect(getSeenAttDataKeyFromSignedAggregateAndProofPhase0(Buffer.alloc(size))).toBeNull(); + expect(getAttDataFromSignedAggregateAndProofPhase0(Buffer.alloc(size))).toBeNull(); } }); }); @@ -182,8 +183,11 @@ describe("electra SignedAggregateAndProof SSZ serialized picking", () => { const committeeBits = ssz.electra.CommitteeBits.serialize( signedAggregateAndProof.message.aggregate.committeeBits ); - const seenKey = Buffer.concat([attDataBase64, committeeBits]).toString("base64"); - expect(getSeenAttDataKeyFromSignedAggregateAndProofElectra(bytes)).toBe(seenKey); + + expect(getAttDataFromSignedAggregateAndProofElectra(bytes)).toBe(Buffer.from(attDataBase64).toString("base64")); + expect(getCommitteeBitsFromSignedAggregateAndProofElectra(bytes)).toBe( + Buffer.from(committeeBits).toString("base64") + ); }); } @@ -204,7 +208,7 @@ describe("electra SignedAggregateAndProof SSZ serialized picking", () => { it("getAttDataBase64FromSignedAggregateAndProofSerialized - invalid data", () => { const invalidAttDataBase64DataSizes = [0, 4, 100, 128, 339]; for (const size of invalidAttDataBase64DataSizes) { - expect(getSeenAttDataKeyFromSignedAggregateAndProofPhase0(Buffer.alloc(size))).toBeNull(); + expect(getAttDataFromSignedAggregateAndProofPhase0(Buffer.alloc(size))).toBeNull(); } }); it("getSlotFromSignedAggregateAndProofSerialized - invalid data - large slots", () => { diff --git a/packages/state-transition/src/block/processAttestationPhase0.ts b/packages/state-transition/src/block/processAttestationPhase0.ts index ab21841069ec..ba6bc9089693 100644 --- a/packages/state-transition/src/block/processAttestationPhase0.ts +++ b/packages/state-transition/src/block/processAttestationPhase0.ts @@ -87,7 +87,6 @@ export function validateAttestation(fork: ForkSeq, state: CachedBeaconStateAllFo if (fork >= ForkSeq.electra) { assert.equal(data.index, 0, `AttestationData.index must be zero: index=${data.index}`); const attestationElectra = attestation as electra.Attestation; - // TODO Electra: this should be obsolete soon when the spec switches to committeeIndices const committeeIndices = attestationElectra.committeeBits.getTrueBitIndexes(); if (committeeIndices.length === 0) { From 3918aae2a0b2aae0bf678b73d62af01c2f7a4ac1 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sat, 17 Aug 2024 18:44:52 +0100 Subject: [PATCH 078/259] fix: use attestation v1 endpoints pre-electra (#7024) * fix: use attestation v1 endpoints pre-electra * Adapt block attestations error message with pool apis --- .../src/api/impl/beacon/blocks/index.ts | 5 +- .../validator/src/services/attestation.ts | 29 ++++++-- .../test/unit/services/attestation.test.ts | 74 +++++++++++++------ 3 files changed, 76 insertions(+), 32 deletions(-) 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 89e8a20d4f86..65e7b9373a22 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -410,7 +410,10 @@ export function getBeaconBlockApi({ const fork = config.getForkName(block.message.slot); if (isForkPostElectra(fork)) { - throw new ApiError(400, `Use getBlockAttestationsV2 to retrieve electra+ block attestations fork=${fork}`); + throw new ApiError( + 400, + `Use getBlockAttestationsV2 to retrieve block attestations for post-electra fork=${fork}` + ); } return { diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index 604f4adeb47e..fc43b603c6b2 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -237,8 +237,11 @@ export class AttestationService { ...(this.opts?.disableAttestationGrouping && {index: attestationNoCommittee.index}), }; try { - // TODO Electra: Ensure calling V2 works in pre-electra - (await this.api.beacon.submitPoolAttestationsV2({signedAttestations})).assertOk(); + if (isPostElectra) { + (await this.api.beacon.submitPoolAttestationsV2({signedAttestations})).assertOk(); + } else { + (await this.api.beacon.submitPoolAttestations({signedAttestations})).assertOk(); + } this.logger.info("Published attestations", {...logCtx, count: signedAttestations.length}); this.metrics?.publishedAttestations.inc(signedAttestations.length); } catch (e) { @@ -264,6 +267,7 @@ export class AttestationService { duties: AttDutyAndProof[] ): Promise { const logCtx = {slot: attestation.slot, index: committeeIndex}; + const isPostElectra = this.config.getForkSeq(attestation.slot) >= ForkSeq.electra; // No validator is aggregator, skip if (duties.every(({selectionProof}) => selectionProof === null)) { @@ -271,11 +275,16 @@ export class AttestationService { } this.logger.verbose("Aggregating attestations", logCtx); - const res = await this.api.validator.getAggregatedAttestationV2({ - attestationDataRoot: ssz.phase0.AttestationData.hashTreeRoot(attestation), - slot: attestation.slot, - committeeIndex, - }); + const res = isPostElectra + ? await this.api.validator.getAggregatedAttestationV2({ + attestationDataRoot: ssz.phase0.AttestationData.hashTreeRoot(attestation), + slot: attestation.slot, + committeeIndex, + }) + : await this.api.validator.getAggregatedAttestation({ + attestationDataRoot: ssz.phase0.AttestationData.hashTreeRoot(attestation), + slot: attestation.slot, + }); const aggregate = res.value(); this.metrics?.numParticipantsInAggregate.observe(aggregate.aggregationBits.getTrueBitIndexes().length); @@ -302,7 +311,11 @@ export class AttestationService { if (signedAggregateAndProofs.length > 0) { try { - (await this.api.validator.publishAggregateAndProofsV2({signedAggregateAndProofs})).assertOk(); + if (isPostElectra) { + (await this.api.validator.publishAggregateAndProofsV2({signedAggregateAndProofs})).assertOk(); + } else { + (await this.api.validator.publishAggregateAndProofs({signedAggregateAndProofs})).assertOk(); + } this.logger.info("Published aggregateAndProofs", {...logCtx, count: signedAggregateAndProofs.length}); this.metrics?.publishedAggregates.inc(signedAggregateAndProofs.length); } catch (e) { diff --git a/packages/validator/test/unit/services/attestation.test.ts b/packages/validator/test/unit/services/attestation.test.ts index 591ac51fa05e..356503cbdd09 100644 --- a/packages/validator/test/unit/services/attestation.test.ts +++ b/packages/validator/test/unit/services/attestation.test.ts @@ -3,8 +3,8 @@ import {toHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; import {ssz} from "@lodestar/types"; import {routes} from "@lodestar/api"; -import {createChainForkConfig} from "@lodestar/config"; -import {config} from "@lodestar/config/default"; +import {ChainConfig, createChainForkConfig} from "@lodestar/config"; +import {config as defaultConfig} from "@lodestar/config/default"; import {ForkName} from "@lodestar/params"; import {AttestationService, AttestationServiceOpts} from "../../../src/services/attestation.js"; import {AttDutyAndProof} from "../../../src/services/attestationDuties.js"; @@ -52,16 +52,23 @@ describe("AttestationService", function () { vi.resetAllMocks(); }); - const testContexts: [string, AttestationServiceOpts][] = [ - ["With default configuration", {}], - ["With attestation grouping disabled", {disableAttestationGrouping: true}], - ["With distributed aggregation selection enabled", {distributedAggregationSelection: true}], + // eslint-disable-next-line @typescript-eslint/naming-convention + const electraConfig: Partial = {ELECTRA_FORK_EPOCH: 0}; + + const testContexts: [string, AttestationServiceOpts, Partial][] = [ + ["With default configuration", {}, {}], + ["With default configuration post-electra", {}, electraConfig], + ["With attestation grouping disabled", {disableAttestationGrouping: true}, {}], + ["With attestation grouping disabled post-electra", {disableAttestationGrouping: true}, electraConfig], + ["With distributed aggregation selection enabled", {distributedAggregationSelection: true}, {}], ]; - for (const [title, opts] of testContexts) { + for (const [title, opts, chainConfig] of testContexts) { describe(title, () => { it("Should produce, sign, and publish an attestation + aggregate", async () => { const clock = new ClockMock(); + const config = createChainForkConfig({...defaultConfig, ...chainConfig}); + const isPostElectra = chainConfig.ELECTRA_FORK_EPOCH === 0; const attestationService = new AttestationService( loggerVc, api, @@ -71,12 +78,16 @@ describe("AttestationService", function () { chainHeadTracker, syncingStatusTracker, null, - createChainForkConfig(config), + config, opts ); - const attestation = ssz.phase0.Attestation.defaultValue(); - const aggregate = ssz.phase0.SignedAggregateAndProof.defaultValue(); + const attestation = isPostElectra + ? ssz.electra.Attestation.defaultValue() + : ssz.phase0.Attestation.defaultValue(); + const aggregate = isPostElectra + ? ssz.electra.SignedAggregateAndProof.defaultValue() + : ssz.phase0.SignedAggregateAndProof.defaultValue(); const duties: AttDutyAndProof[] = [ { duty: { @@ -106,12 +117,17 @@ describe("AttestationService", function () { // Mock beacon's attestation and aggregates endpoints api.validator.produceAttestationData.mockResolvedValue(mockApiResponse({data: attestation.data})); - api.validator.getAggregatedAttestationV2.mockResolvedValue( - mockApiResponse({data: attestation, meta: {version: ForkName.phase0}}) - ); - - api.beacon.submitPoolAttestationsV2.mockResolvedValue(mockApiResponse({})); - api.validator.publishAggregateAndProofsV2.mockResolvedValue(mockApiResponse({})); + if (isPostElectra) { + api.validator.getAggregatedAttestationV2.mockResolvedValue( + mockApiResponse({data: attestation, meta: {version: ForkName.electra}}) + ); + api.beacon.submitPoolAttestationsV2.mockResolvedValue(mockApiResponse({})); + api.validator.publishAggregateAndProofsV2.mockResolvedValue(mockApiResponse({})); + } else { + api.validator.getAggregatedAttestation.mockResolvedValue(mockApiResponse({data: attestation})); + api.beacon.submitPoolAttestations.mockResolvedValue(mockApiResponse({})); + api.validator.publishAggregateAndProofs.mockResolvedValue(mockApiResponse({})); + } if (opts.distributedAggregationSelection) { // Mock distributed validator middleware client selections endpoint @@ -152,13 +168,25 @@ describe("AttestationService", function () { expect(api.validator.prepareBeaconCommitteeSubnet).toHaveBeenCalledWith({subscriptions: [subscription]}); } - // Must submit the attestation received through produceAttestationData() - expect(api.beacon.submitPoolAttestationsV2).toHaveBeenCalledOnce(); - expect(api.beacon.submitPoolAttestationsV2).toHaveBeenCalledWith({signedAttestations: [attestation]}); - - // Must submit the aggregate received through getAggregatedAttestationV2() then createAndSignAggregateAndProof() - expect(api.validator.publishAggregateAndProofsV2).toHaveBeenCalledOnce(); - expect(api.validator.publishAggregateAndProofsV2).toHaveBeenCalledWith({signedAggregateAndProofs: [aggregate]}); + if (isPostElectra) { + // Must submit the attestation received through produceAttestationData() + expect(api.beacon.submitPoolAttestationsV2).toHaveBeenCalledOnce(); + expect(api.beacon.submitPoolAttestationsV2).toHaveBeenCalledWith({signedAttestations: [attestation]}); + + // Must submit the aggregate received through getAggregatedAttestationV2() then createAndSignAggregateAndProof() + expect(api.validator.publishAggregateAndProofsV2).toHaveBeenCalledOnce(); + expect(api.validator.publishAggregateAndProofsV2).toHaveBeenCalledWith({ + signedAggregateAndProofs: [aggregate], + }); + } else { + // Must submit the attestation received through produceAttestationData() + expect(api.beacon.submitPoolAttestations).toHaveBeenCalledOnce(); + expect(api.beacon.submitPoolAttestations).toHaveBeenCalledWith({signedAttestations: [attestation]}); + + // Must submit the aggregate received through getAggregatedAttestation() then createAndSignAggregateAndProof() + expect(api.validator.publishAggregateAndProofs).toHaveBeenCalledOnce(); + expect(api.validator.publishAggregateAndProofs).toHaveBeenCalledWith({signedAggregateAndProofs: [aggregate]}); + } }); }); } From 5fd2d09368a22b4c080fb1189d94b739bc5ee64b Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 20 Aug 2024 16:57:00 +0530 Subject: [PATCH 079/259] fix: use correct partial withdrawal index to evaluate processing them --- packages/state-transition/src/block/processWithdrawals.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/state-transition/src/block/processWithdrawals.ts b/packages/state-transition/src/block/processWithdrawals.ts index 50113ef1741a..b06209167be3 100644 --- a/packages/state-transition/src/block/processWithdrawals.ts +++ b/packages/state-transition/src/block/processWithdrawals.ts @@ -105,9 +105,9 @@ export function getExpectedWithdrawals( if ( validator.exitEpoch === FAR_FUTURE_EPOCH && validator.effectiveBalance >= MIN_ACTIVATION_BALANCE && - balances.get(withdrawalIndex) > MIN_ACTIVATION_BALANCE + balances.get(withdrawal.index) > MIN_ACTIVATION_BALANCE ) { - const balanceOverMinActivationBalance = BigInt(balances.get(withdrawalIndex) - MIN_ACTIVATION_BALANCE); + const balanceOverMinActivationBalance = BigInt(balances.get(withdrawal.index) - MIN_ACTIVATION_BALANCE); const withdrawableBalance = balanceOverMinActivationBalance < withdrawal.amount ? balanceOverMinActivationBalance : withdrawal.amount; withdrawals.push({ From 23fb9fb442eb504f2ce52d1da8b45aeccdd7bc9a Mon Sep 17 00:00:00 2001 From: twoeths Date: Tue, 20 Aug 2024 20:00:35 +0700 Subject: [PATCH 080/259] fix: ssz v0.17.1 (#7035) * fix: work around for sliceFrom() api * Revert "fix: work around for sliceFrom() api" This reverts commit 7aa6678cd46b1fa770f00923003a311a9d7a65da. * fix: upgrade ssz --- packages/api/package.json | 2 +- packages/beacon-node/package.json | 2 +- packages/cli/package.json | 2 +- packages/config/package.json | 2 +- packages/db/package.json | 2 +- packages/fork-choice/package.json | 2 +- packages/light-client/package.json | 2 +- packages/state-transition/package.json | 2 +- packages/types/package.json | 2 +- packages/validator/package.json | 2 +- yarn.lock | 30 ++++++++++++++++++++------ 11 files changed, 34 insertions(+), 16 deletions(-) diff --git a/packages/api/package.json b/packages/api/package.json index 49bcbbc34f59..138964ed946a 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -71,7 +71,7 @@ }, "dependencies": { "@chainsafe/persistent-merkle-tree": "^0.8.0", - "@chainsafe/ssz": "^0.17.0", + "@chainsafe/ssz": "^0.17.1", "@lodestar/config": "^1.21.0", "@lodestar/params": "^1.21.0", "@lodestar/types": "^1.21.0", diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index b56e1f1bb3e3..b41450f12d34 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -103,7 +103,7 @@ "@chainsafe/libp2p-noise": "^15.0.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/prometheus-gc-stats": "^1.0.0", - "@chainsafe/ssz": "^0.17.0", + "@chainsafe/ssz": "^0.17.1", "@chainsafe/threads": "^1.11.1", "@ethersproject/abi": "^5.7.0", "@fastify/bearer-auth": "^9.0.0", diff --git a/packages/cli/package.json b/packages/cli/package.json index b14d6d5ccafe..bf8621344dc5 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -57,7 +57,7 @@ "@chainsafe/discv5": "^9.0.0", "@chainsafe/enr": "^3.0.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", - "@chainsafe/ssz": "^0.17.0", + "@chainsafe/ssz": "^0.17.1", "@chainsafe/threads": "^1.11.1", "@libp2p/crypto": "^4.1.0", "@libp2p/peer-id": "^4.1.0", diff --git a/packages/config/package.json b/packages/config/package.json index e306920aea49..45c462e19081 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -64,7 +64,7 @@ "blockchain" ], "dependencies": { - "@chainsafe/ssz": "^0.17.0", + "@chainsafe/ssz": "^0.17.1", "@lodestar/params": "^1.21.0", "@lodestar/types": "^1.21.0" } diff --git a/packages/db/package.json b/packages/db/package.json index a68e4e6f2a8f..1a31603b6791 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -35,7 +35,7 @@ "check-readme": "typescript-docs-verifier" }, "dependencies": { - "@chainsafe/ssz": "^0.17.0", + "@chainsafe/ssz": "^0.17.1", "@lodestar/config": "^1.21.0", "@lodestar/utils": "^1.21.0", "classic-level": "^1.4.1", diff --git a/packages/fork-choice/package.json b/packages/fork-choice/package.json index ad493292566d..dfe4c942832d 100644 --- a/packages/fork-choice/package.json +++ b/packages/fork-choice/package.json @@ -36,7 +36,7 @@ "check-readme": "typescript-docs-verifier" }, "dependencies": { - "@chainsafe/ssz": "^0.17.0", + "@chainsafe/ssz": "^0.17.1", "@lodestar/config": "^1.21.0", "@lodestar/params": "^1.21.0", "@lodestar/state-transition": "^1.21.0", diff --git a/packages/light-client/package.json b/packages/light-client/package.json index 0bc1a5529c85..1188732c8870 100644 --- a/packages/light-client/package.json +++ b/packages/light-client/package.json @@ -76,7 +76,7 @@ "@chainsafe/bls": "7.1.3", "@chainsafe/blst": "^0.2.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", - "@chainsafe/ssz": "^0.17.0", + "@chainsafe/ssz": "^0.17.1", "@lodestar/api": "^1.21.0", "@lodestar/config": "^1.21.0", "@lodestar/params": "^1.21.0", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index a892c5cace43..1dd43ef98f88 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -62,7 +62,7 @@ "@chainsafe/blst": "^2.0.3", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/persistent-ts": "^0.19.1", - "@chainsafe/ssz": "^0.17.0", + "@chainsafe/ssz": "^0.17.1", "@lodestar/config": "^1.21.0", "@lodestar/params": "^1.21.0", "@lodestar/types": "^1.21.0", diff --git a/packages/types/package.json b/packages/types/package.json index f29229485e99..861dbdbee0ef 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -73,7 +73,7 @@ }, "types": "lib/index.d.ts", "dependencies": { - "@chainsafe/ssz": "^0.17.0", + "@chainsafe/ssz": "^0.17.1", "@lodestar/params": "^1.21.0", "ethereum-cryptography": "^2.0.0" }, diff --git a/packages/validator/package.json b/packages/validator/package.json index 66de444c81b5..373e59817d2a 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -46,7 +46,7 @@ ], "dependencies": { "@chainsafe/blst": "^2.0.3", - "@chainsafe/ssz": "^0.17.0", + "@chainsafe/ssz": "^0.17.1", "@lodestar/api": "^1.21.0", "@lodestar/config": "^1.21.0", "@lodestar/db": "^1.21.0", diff --git a/yarn.lock b/yarn.lock index 7e2e3d8e6447..60e41c276e53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -594,10 +594,10 @@ "@chainsafe/as-sha256" "^0.4.1" "@chainsafe/persistent-merkle-tree" "^0.6.1" -"@chainsafe/ssz@^0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.17.0.tgz#b154260f6885693fd77bfb2fff43dd8c3fa37edd" - integrity sha512-DEzyH9vF4zz+Zqe2EMZuxXyxV5+7cmmLwljL3VC3ApzmyPORsprGJM7xLaUJu3oMRKMdBpR8UjRNkfB2ROQJzQ== +"@chainsafe/ssz@^0.17.1": + version "0.17.1" + resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.17.1.tgz#7986afbcad5e6971006d596fdb7dfa34bc195131" + integrity sha512-1ay46QqYcVTBvUnDXTPTi5WTiENu7tIxpZGMDpUWps1/nYBmh/We/UoCF/jO+o/fkcDD3p8xQPlHbcCfy+jyjA== dependencies: "@chainsafe/as-sha256" "0.5.0" "@chainsafe/persistent-merkle-tree" "0.8.0" @@ -12080,7 +12080,16 @@ string-argv@~0.3.1: 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", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -13655,7 +13664,7 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -13673,6 +13682,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From cb7878bb7374aa7486352087c66f8d78d51ea52d Mon Sep 17 00:00:00 2001 From: harkamal Date: Fri, 23 Aug 2024 14:42:14 +0530 Subject: [PATCH 081/259] chore: rebase fixes --- .../src/chain/opPools/aggregatedAttestationPool.ts | 2 +- packages/beacon-node/src/util/sszBytes.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts index e656915552b4..9a3e6622d1ff 100644 --- a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts @@ -1,5 +1,5 @@ import {aggregateSignatures, Signature} from "@chainsafe/blst"; -import {BitArray, toHexString} from "@chainsafe/ssz"; +import {BitArray} from "@chainsafe/ssz"; import { ForkName, ForkSeq, diff --git a/packages/beacon-node/src/util/sszBytes.ts b/packages/beacon-node/src/util/sszBytes.ts index 81821b5eb710..c27df1a0fbf3 100644 --- a/packages/beacon-node/src/util/sszBytes.ts +++ b/packages/beacon-node/src/util/sszBytes.ts @@ -202,7 +202,8 @@ export function getAttDataFromSignedAggregateAndProofElectra(data: Uint8Array): if (data.length < endIndex + SIGNATURE_SIZE + COMMITTEE_BITS_SIZE) { return null; } - return toBase64(data.subarray(startIndex, endIndex)); + attDataBuf.set(data.subarray(startIndex, endIndex)); + return attDataBuf.toString("base64"); } /** @@ -217,7 +218,8 @@ export function getCommitteeBitsFromSignedAggregateAndProofElectra(data: Uint8Ar return null; } - return toBase64(data.subarray(startIndex, endIndex)); + committeeBitsDataBuf.set(data.subarray(startIndex, endIndex)); + return committeeBitsDataBuf.toString("base64"); } /** From 8ccbed70c888007126644add3d488e5db0be0f18 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 23 Aug 2024 12:11:19 +0100 Subject: [PATCH 082/259] chore: fix api handler used during testing (#7047) --- packages/beacon-node/test/utils/node/validator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/test/utils/node/validator.ts b/packages/beacon-node/test/utils/node/validator.ts index 4ec60dcc8b4f..285fa13fd01f 100644 --- a/packages/beacon-node/test/utils/node/validator.ts +++ b/packages/beacon-node/test/utils/node/validator.ts @@ -97,7 +97,7 @@ export function getApiFromServerHandlers(api: BeaconApiMethods): ApiClient { return async (args: unknown) => { try { const apiResponse = new ApiResponse({} as any, null, new Response(null, {status: HttpStatusCode.OK})); - const result = await api(args, {}); + const result = await api.call(apiModule, args, {}); apiResponse.value = () => result.data; apiResponse.meta = () => result.meta; return apiResponse; From ed18ff005d4482d0c372aebb2762873a335fa578 Mon Sep 17 00:00:00 2001 From: twoeths Date: Tue, 27 Aug 2024 21:39:38 +0700 Subject: [PATCH 083/259] fix: improve processEffectiveBalanceUpdates (#7043) --- .../src/chain/historicalState/worker.ts | 4 +++ .../src/metrics/metrics/lodestar.ts | 4 +++ .../src/cache/epochTransitionCache.ts | 18 +++++++++-- packages/state-transition/src/epoch/index.ts | 3 +- .../epoch/processEffectiveBalanceUpdates.ts | 32 ++++++++++++------- .../src/epoch/processPendingConsolidations.ts | 4 +++ packages/state-transition/src/metrics.ts | 1 + .../test/perf/epoch/epochAltair.test.ts | 4 ++- .../test/perf/epoch/epochCapella.test.ts | 4 ++- .../test/perf/epoch/epochPhase0.test.ts | 4 ++- .../processEffectiveBalanceUpdates.test.ts | 4 ++- 11 files changed, 63 insertions(+), 19 deletions(-) diff --git a/packages/beacon-node/src/chain/historicalState/worker.ts b/packages/beacon-node/src/chain/historicalState/worker.ts index 9a9f9cc9cd0e..a07207cac5f5 100644 --- a/packages/beacon-node/src/chain/historicalState/worker.ts +++ b/packages/beacon-node/src/chain/historicalState/worker.ts @@ -82,6 +82,10 @@ if (metricsRegister) { buckets: [0.05, 0.1, 0.2, 0.5, 1, 1.5], labelNames: ["source"], }), + numEffectiveBalanceUpdates: metricsRegister.gauge({ + name: "lodestar_historical_state_stfn_num_effective_balance_updates_count", + help: "Count of effective balance updates in epoch transition", + }), preStateBalancesNodesPopulatedMiss: metricsRegister.gauge<{source: StateCloneSource}>({ name: "lodestar_historical_state_stfn_balances_nodes_populated_miss_total", help: "Total count state.balances nodesPopulated is false on stfn", diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index 6b4bdb111f41..a0cf0a185c2f 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -332,6 +332,10 @@ export function createLodestarMetrics( buckets: [0.05, 0.1, 0.2, 0.5, 1, 1.5], labelNames: ["source"], }), + numEffectiveBalanceUpdates: register.gauge({ + name: "lodestar_stfn_effective_balance_updates_count", + help: "Total count of effective balance updates", + }), preStateBalancesNodesPopulatedMiss: register.gauge<{source: StateCloneSource}>({ name: "lodestar_stfn_balances_nodes_populated_miss_total", help: "Total count state.balances nodesPopulated is false on stfn", diff --git a/packages/state-transition/src/cache/epochTransitionCache.ts b/packages/state-transition/src/cache/epochTransitionCache.ts index 280524ec7beb..6f27ad96d1c8 100644 --- a/packages/state-transition/src/cache/epochTransitionCache.ts +++ b/packages/state-transition/src/cache/epochTransitionCache.ts @@ -1,4 +1,4 @@ -import {Epoch, ValidatorIndex} from "@lodestar/types"; +import {Epoch, ValidatorIndex, phase0} from "@lodestar/types"; import {intDiv} from "@lodestar/utils"; import {EPOCHS_PER_SLASHINGS_VECTOR, FAR_FUTURE_EPOCH, ForkSeq, MIN_ACTIVATION_BALANCE} from "@lodestar/params"; @@ -127,6 +127,18 @@ export interface EpochTransitionCache { flags: number[]; + /** + * Validators in the current epoch, should use it for read-only value instead of accessing state.validators directly. + * Note that during epoch processing, validators could be updated so need to use it with care. + */ + validators: phase0.Validator[]; + + /** + * This is for electra only + * Validators that're switched to compounding during processPendingConsolidations(), not available in beforeProcessEpoch() + */ + newCompoundingValidators?: Set; + /** * balances array will be populated by processRewardsAndPenalties() and consumed by processEffectiveBalanceUpdates(). * processRewardsAndPenalties() already has a regular Javascript array of balances. @@ -481,7 +493,9 @@ export function beforeProcessEpoch( proposerIndices, inclusionDelays, flags, - + validators, + // will be assigned in processPendingConsolidations() + newCompoundingValidators: undefined, // Will be assigned in processRewardsAndPenalties() balances: undefined, }; diff --git a/packages/state-transition/src/epoch/index.ts b/packages/state-transition/src/epoch/index.ts index 85e7c348dad3..bfb415b9ed6a 100644 --- a/packages/state-transition/src/epoch/index.ts +++ b/packages/state-transition/src/epoch/index.ts @@ -150,8 +150,9 @@ export function processEpoch( const timer = metrics?.epochTransitionStepTime.startTimer({ step: EpochTransitionStep.processEffectiveBalanceUpdates, }); - processEffectiveBalanceUpdates(fork, state, cache); + const numUpdate = processEffectiveBalanceUpdates(fork, state, cache); timer?.(); + metrics?.numEffectiveBalanceUpdates.set(numUpdate); } processSlashingsReset(state, cache); diff --git a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts index fdbc99b9265e..0ea4b49dddf4 100644 --- a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts +++ b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts @@ -23,12 +23,14 @@ const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX; * * - On normal mainnet conditions 0 validators change their effective balance * - In case of big innactivity event a medium portion of validators may have their effectiveBalance updated + * + * Return number of validators updated */ export function processEffectiveBalanceUpdates( fork: ForkSeq, state: CachedBeaconStateAllForks, cache: EpochTransitionCache -): void { +): number { const HYSTERESIS_INCREMENT = EFFECTIVE_BALANCE_INCREMENT / HYSTERESIS_QUOTIENT; const DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER; const UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER; @@ -43,34 +45,38 @@ export function processEffectiveBalanceUpdates( // and updated in processPendingBalanceDeposits() and processPendingConsolidations() // so it's recycled here for performance. const balances = cache.balances ?? state.balances.getAll(); + const currentEpochValidators = cache.validators; + const newCompoundingValidators = cache.newCompoundingValidators ?? new Set(); + let numUpdate = 0; for (let i = 0, len = balances.length; i < len; i++) { const balance = balances[i]; // PERF: It's faster to access to get() every single element (4ms) than to convert to regular array then loop (9ms) let effectiveBalanceIncrement = effectiveBalanceIncrements[i]; let effectiveBalance = effectiveBalanceIncrement * EFFECTIVE_BALANCE_INCREMENT; - let effectiveBalanceLimit; + + let effectiveBalanceLimit: number; + if (fork < ForkSeq.electra) { + effectiveBalanceLimit = MAX_EFFECTIVE_BALANCE; + } else { + // from electra, effectiveBalanceLimit is per validator + const isCompoundingValidator = + hasCompoundingWithdrawalCredential(currentEpochValidators[i].withdrawalCredentials) || + newCompoundingValidators.has(i); + effectiveBalanceLimit = isCompoundingValidator ? MAX_EFFECTIVE_BALANCE_ELECTRA : MIN_ACTIVATION_BALANCE; + } if ( // Too big effectiveBalance > balance + DOWNWARD_THRESHOLD || // Too small. Check effectiveBalance < MAX_EFFECTIVE_BALANCE to prevent unnecessary updates - effectiveBalance + UPWARD_THRESHOLD < balance + (effectiveBalance < effectiveBalanceLimit && effectiveBalance + UPWARD_THRESHOLD < balance) ) { // Update the state tree // Should happen rarely, so it's fine to update the tree const validator = validators.get(i); - if (fork < ForkSeq.electra) { - effectiveBalanceLimit = MAX_EFFECTIVE_BALANCE; - } else { - // Electra or after - effectiveBalanceLimit = hasCompoundingWithdrawalCredential(validator.withdrawalCredentials) - ? MAX_EFFECTIVE_BALANCE_ELECTRA - : MIN_ACTIVATION_BALANCE; - } - effectiveBalance = Math.min(balance - (balance % EFFECTIVE_BALANCE_INCREMENT), effectiveBalanceLimit); validator.effectiveBalance = effectiveBalance; // Also update the fast cached version @@ -95,6 +101,7 @@ export function processEffectiveBalanceUpdates( effectiveBalanceIncrement = newEffectiveBalanceIncrement; effectiveBalanceIncrements[i] = effectiveBalanceIncrement; + numUpdate++; } // TODO: Do this in afterEpochTransitionCache, looping a Uint8Array should be very cheap @@ -105,4 +112,5 @@ export function processEffectiveBalanceUpdates( } cache.nextEpochTotalActiveBalanceByIncrement = nextEpochTotalActiveBalanceByIncrement; + return numUpdate; } diff --git a/packages/state-transition/src/epoch/processPendingConsolidations.ts b/packages/state-transition/src/epoch/processPendingConsolidations.ts index d6f760a6b27a..7d8548046e79 100644 --- a/packages/state-transition/src/epoch/processPendingConsolidations.ts +++ b/packages/state-transition/src/epoch/processPendingConsolidations.ts @@ -1,3 +1,4 @@ +import {ValidatorIndex} from "@lodestar/types"; import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; import {decreaseBalance, increaseBalance} from "../util/balance.js"; import {getActiveBalance} from "../util/validator.js"; @@ -20,6 +21,7 @@ export function processPendingConsolidations(state: CachedBeaconStateElectra, ca let nextPendingConsolidation = 0; const validators = state.validators; const cachedBalances = cache.balances; + const newCompoundingValidators = new Set(); for (const pendingConsolidation of state.pendingConsolidations.getAllReadonly()) { const {sourceIndex, targetIndex} = pendingConsolidation; @@ -35,6 +37,7 @@ export function processPendingConsolidations(state: CachedBeaconStateElectra, ca } // Churn any target excess active balance of target and raise its max switchToCompoundingValidator(state, targetIndex); + newCompoundingValidators.add(targetIndex); // Move active balance to target. Excess balance is withdrawable. const activeBalance = getActiveBalance(state, sourceIndex); decreaseBalance(state, sourceIndex, activeBalance); @@ -47,5 +50,6 @@ export function processPendingConsolidations(state: CachedBeaconStateElectra, ca nextPendingConsolidation++; } + cache.newCompoundingValidators = newCompoundingValidators; state.pendingConsolidations = state.pendingConsolidations.sliceFrom(nextPendingConsolidation); } diff --git a/packages/state-transition/src/metrics.ts b/packages/state-transition/src/metrics.ts index 48e0bc921876..a5e5463231fa 100644 --- a/packages/state-transition/src/metrics.ts +++ b/packages/state-transition/src/metrics.ts @@ -11,6 +11,7 @@ export type BeaconStateTransitionMetrics = { processBlockTime: Histogram; processBlockCommitTime: Histogram; stateHashTreeRootTime: Histogram<{source: StateHashTreeRootSource}>; + numEffectiveBalanceUpdates: Gauge; preStateBalancesNodesPopulatedMiss: Gauge<{source: StateCloneSource}>; preStateBalancesNodesPopulatedHit: Gauge<{source: StateCloneSource}>; preStateValidatorsNodesPopulatedMiss: Gauge<{source: StateCloneSource}>; diff --git a/packages/state-transition/test/perf/epoch/epochAltair.test.ts b/packages/state-transition/test/perf/epoch/epochAltair.test.ts index 39e0a1b4c5c3..15cde849ce9f 100644 --- a/packages/state-transition/test/perf/epoch/epochAltair.test.ts +++ b/packages/state-transition/test/perf/epoch/epochAltair.test.ts @@ -141,7 +141,9 @@ function benchmarkAltairEpochSteps(stateOg: LazyValue itBench({ id: `${stateId} - altair processEffectiveBalanceUpdates`, beforeEach: () => stateOg.value.clone(), - fn: (state) => processEffectiveBalanceUpdates(ForkSeq.altair, state, cache.value), + fn: (state) => { + processEffectiveBalanceUpdates(ForkSeq.altair, state, cache.value); + }, }); itBench({ diff --git a/packages/state-transition/test/perf/epoch/epochCapella.test.ts b/packages/state-transition/test/perf/epoch/epochCapella.test.ts index 5b8300df3f18..61bfad20b1ee 100644 --- a/packages/state-transition/test/perf/epoch/epochCapella.test.ts +++ b/packages/state-transition/test/perf/epoch/epochCapella.test.ts @@ -120,7 +120,9 @@ function benchmarkAltairEpochSteps(stateOg: LazyValue itBench({ id: `${stateId} - capella processEffectiveBalanceUpdates`, beforeEach: () => stateOg.value.clone(), - fn: (state) => processEffectiveBalanceUpdates(ForkSeq.capella, state, cache.value), + fn: (state) => { + processEffectiveBalanceUpdates(ForkSeq.capella, state, cache.value); + }, }); itBench({ diff --git a/packages/state-transition/test/perf/epoch/epochPhase0.test.ts b/packages/state-transition/test/perf/epoch/epochPhase0.test.ts index 411577878102..3af3d4d4a832 100644 --- a/packages/state-transition/test/perf/epoch/epochPhase0.test.ts +++ b/packages/state-transition/test/perf/epoch/epochPhase0.test.ts @@ -123,7 +123,9 @@ function benchmarkPhase0EpochSteps(stateOg: LazyValue itBench({ id: `${stateId} - phase0 processEffectiveBalanceUpdates`, beforeEach: () => stateOg.value.clone(), - fn: (state) => processEffectiveBalanceUpdates(ForkSeq.phase0, state, cache.value), + fn: (state) => { + processEffectiveBalanceUpdates(ForkSeq.phase0, state, cache.value); + }, }); itBench({ diff --git a/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts b/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts index d94daac9e59b..19f18df86c2e 100644 --- a/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts +++ b/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts @@ -36,7 +36,9 @@ describe("phase0 processEffectiveBalanceUpdates", () => { minRuns: 5, // Worst case is very slow before: () => getEffectiveBalanceTestData(vc, changeRatio), beforeEach: ({state, cache}) => ({state: state.clone(), cache}), - fn: ({state, cache}) => processEffectiveBalanceUpdates(ForkSeq.phase0, state, cache), + fn: ({state, cache}) => { + processEffectiveBalanceUpdates(ForkSeq.phase0, state, cache); + }, }); } }); From 7fe30b4627a1c0b02e9aead5858edee37aba1e61 Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Wed, 28 Aug 2024 12:51:47 -0400 Subject: [PATCH 084/259] fix: perf test relative import from state-transition (#7055) test: make import relative and add eslint-disable --- .../test/perf/chain/opPools/aggregatedAttestationPool.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts index ec66f6dd8905..63fc4ee2e12c 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -12,7 +12,8 @@ import {ExecutionStatus, ForkChoice, IForkChoiceStore, ProtoArray, DataAvailabil import {ssz} from "@lodestar/types"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {generatePerfTestCachedStateAltair} from "@lodestar/state-transition/test/perf/util.js"; +// eslint-disable-next-line import/no-relative-packages +import {generatePerfTestCachedStateAltair} from "../../../../../state-transition/test/perf/util.js"; import {AggregatedAttestationPool} from "../../../../src/chain/opPools/aggregatedAttestationPool.js"; import {computeAnchorCheckpoint} from "../../../../src/chain/initState.js"; From 03f7396af7ffcac67080c6544df5324f9c8411a4 Mon Sep 17 00:00:00 2001 From: g11tech Date: Thu, 29 Aug 2024 00:12:08 +0530 Subject: [PATCH 085/259] fix: use next epoch for pending balance/consolidations processing (#7053) --- packages/beacon-node/test/spec/specTestVersioning.ts | 2 +- packages/beacon-node/test/spec/utils/specTestIterator.ts | 3 ++- .../src/epoch/processPendingBalanceDeposits.ts | 5 ++--- .../src/epoch/processPendingConsolidations.ts | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/test/spec/specTestVersioning.ts b/packages/beacon-node/test/spec/specTestVersioning.ts index e97770e8146c..7229a0236d84 100644 --- a/packages/beacon-node/test/spec/specTestVersioning.ts +++ b/packages/beacon-node/test/spec/specTestVersioning.ts @@ -15,7 +15,7 @@ import {DownloadTestsOptions} from "@lodestar/spec-test-util/downloadTests"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const ethereumConsensusSpecsTests: DownloadTestsOptions = { - specVersion: "v1.5.0-alpha.3", + specVersion: "v1.5.0-alpha.5", // Target directory is the host package root: 'packages/*/spec-tests' outputDir: path.join(__dirname, "../../spec-tests"), specTestsRepoUrl: "https://github.com/ethereum/consensus-spec-tests", diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index ac0d70307d33..48a002580043 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -65,9 +65,10 @@ export const defaultSkipOpts: SkipOpts = { skippedTestSuites: [ /^capella\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, /^deneb\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, + /^electra\/light_client\/.*/, ], // TODO Electra: Review this test in the next spec test release - skippedTests: [/incorrect_not_enough_consolidation_churn_available/], + skippedTests: [/^deneb\/light_client\/sync\/.*electra_fork.*/], skippedRunners: ["merkle_proof", "networking"], }; diff --git a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts index 81da34349e53..bef3ec0b2724 100644 --- a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts @@ -2,7 +2,6 @@ import {FAR_FUTURE_EPOCH} from "@lodestar/params"; import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; import {increaseBalance} from "../util/balance.js"; import {getActivationExitChurnLimit} from "../util/validator.js"; -import {getCurrentEpoch} from "../util/epoch.js"; /** * Starting from Electra: @@ -14,8 +13,8 @@ import {getCurrentEpoch} from "../util/epoch.js"; * TODO Electra: Update ssz library to support batch push to `pendingBalanceDeposits` */ export function processPendingBalanceDeposits(state: CachedBeaconStateElectra, cache: EpochTransitionCache): void { + const nextEpoch = state.epochCtx.epoch + 1; const availableForProcessing = state.depositBalanceToConsume + BigInt(getActivationExitChurnLimit(state.epochCtx)); - const currentEpoch = getCurrentEpoch(state); let processedAmount = 0n; let nextDepositIndex = 0; const depositsToPostpone = []; @@ -28,7 +27,7 @@ export function processPendingBalanceDeposits(state: CachedBeaconStateElectra, c // Validator is exiting, postpone the deposit until after withdrawable epoch if (validator.exitEpoch < FAR_FUTURE_EPOCH) { - if (currentEpoch <= validator.withdrawableEpoch) { + if (nextEpoch <= validator.withdrawableEpoch) { depositsToPostpone.push(deposit); } else { // Deposited balance will never become active. Increase balance but do not consume churn diff --git a/packages/state-transition/src/epoch/processPendingConsolidations.ts b/packages/state-transition/src/epoch/processPendingConsolidations.ts index 7d8548046e79..28178a509bba 100644 --- a/packages/state-transition/src/epoch/processPendingConsolidations.ts +++ b/packages/state-transition/src/epoch/processPendingConsolidations.ts @@ -18,6 +18,7 @@ import {switchToCompoundingValidator} from "../util/electra.js"; * */ export function processPendingConsolidations(state: CachedBeaconStateElectra, cache: EpochTransitionCache): void { + const nextEpoch = state.epochCtx.epoch + 1; let nextPendingConsolidation = 0; const validators = state.validators; const cachedBalances = cache.balances; @@ -32,7 +33,7 @@ export function processPendingConsolidations(state: CachedBeaconStateElectra, ca continue; } - if (sourceValidator.withdrawableEpoch > state.epochCtx.epoch) { + if (sourceValidator.withdrawableEpoch > nextEpoch) { break; } // Churn any target excess active balance of target and raise its max From 21afb72525457b1ed8838f94da5ad03e94e4b6be Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 30 Aug 2024 08:29:08 +0100 Subject: [PATCH 086/259] chore: relax node version restriction in package.json (#7062) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 06fac0de8891..85d9662ab920 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "root", "private": true, "engines": { - "node": ">=20.1.0 <21 || >=22 <22.5" + "node": ">=20.1.0 <21 || >=22 <23" }, "packageManager": "yarn@1.22.22+sha256.c17d3797fb9a9115bf375e31bfd30058cac6bc9c3b8807a3d8cb2094794b51ca", "workspaces": [ From 19ac678d4be3b08152ad7ef9e030fbdd7692ff83 Mon Sep 17 00:00:00 2001 From: twoeths Date: Fri, 30 Aug 2024 19:22:29 +0700 Subject: [PATCH 087/259] feat: implement isomorphic utils for nodejs and browser (#7060) * feat: implement isomorphic utils for nodes and browser * fix: avoid async import * chore: revise toHexString() comment as in PR review Co-authored-by: Nico Flaig --------- Co-authored-by: Nico Flaig --- packages/utils/src/bytes.ts | 33 ++----------- packages/utils/src/bytes/browser.ts | 66 ++++++++++++++++++++++++++ packages/utils/src/bytes/index.ts | 14 ++++++ packages/utils/src/bytes/nodejs.ts | 33 +++++++++++++ packages/utils/src/index.ts | 1 + packages/utils/test/perf/bytes.test.ts | 38 +++++++++++++-- packages/utils/test/unit/bytes.test.ts | 23 ++++++++- 7 files changed, 173 insertions(+), 35 deletions(-) create mode 100644 packages/utils/src/bytes/browser.ts create mode 100644 packages/utils/src/bytes/index.ts create mode 100644 packages/utils/src/bytes/nodejs.ts diff --git a/packages/utils/src/bytes.ts b/packages/utils/src/bytes.ts index 820cf7d63300..6670b115ff8f 100644 --- a/packages/utils/src/bytes.ts +++ b/packages/utils/src/bytes.ts @@ -3,6 +3,9 @@ import {toBufferLE, toBigIntLE, toBufferBE, toBigIntBE} from "bigint-buffer"; type Endianness = "le" | "be"; const hexByByte: string[] = []; +/** + * @deprecated Use toHex() instead. + */ export function toHexString(bytes: Uint8Array): string { let hex = "0x"; for (const byte of bytes) { @@ -45,33 +48,3 @@ export function bytesToBigInt(value: Uint8Array, endianness: Endianness = "le"): } throw new Error("endianness must be either 'le' or 'be'"); } - -export function toHex(buffer: Uint8Array | Parameters[0]): string { - if (Buffer.isBuffer(buffer)) { - return "0x" + buffer.toString("hex"); - } else if (buffer instanceof Uint8Array) { - return "0x" + Buffer.from(buffer.buffer, buffer.byteOffset, buffer.length).toString("hex"); - } else { - return "0x" + Buffer.from(buffer).toString("hex"); - } -} - -// Shared buffer to convert root to hex -const rootBuf = Buffer.alloc(32); - -/** - * Convert a Uint8Array, length 32, to 0x-prefixed hex string - */ -export function toRootHex(root: Uint8Array): string { - if (root.length !== 32) { - throw Error(`Expect root to be 32 bytes, got ${root.length}`); - } - - rootBuf.set(root); - return `0x${rootBuf.toString("hex")}`; -} - -export function fromHex(hex: string): Uint8Array { - const b = Buffer.from(hex.replace("0x", ""), "hex"); - return new Uint8Array(b.buffer, b.byteOffset, b.length); -} diff --git a/packages/utils/src/bytes/browser.ts b/packages/utils/src/bytes/browser.ts new file mode 100644 index 000000000000..e6c04f79835f --- /dev/null +++ b/packages/utils/src/bytes/browser.ts @@ -0,0 +1,66 @@ +export function toHex(bytes: Uint8Array): string { + const charCodes = new Array(bytes.length * 2 + 2); + charCodes[0] = 48; + charCodes[1] = 120; + + for (let i = 0; i < bytes.length; i++) { + const byte = bytes[i]; + const first = (byte & 0xf0) >> 4; + const second = byte & 0x0f; + + // "0".charCodeAt(0) = 48 + // "a".charCodeAt(0) = 97 => delta = 87 + charCodes[2 + 2 * i] = first < 10 ? first + 48 : first + 87; + charCodes[2 + 2 * i + 1] = second < 10 ? second + 48 : second + 87; + } + return String.fromCharCode(...charCodes); +} + +const rootCharCodes = new Array(32 * 2 + 2); +// "0".charCodeAt(0) +rootCharCodes[0] = 48; +// "x".charCodeAt(0) +rootCharCodes[1] = 120; + +/** + * Convert a Uint8Array, length 32, to 0x-prefixed hex string + */ +export function toRootHex(root: Uint8Array): string { + if (root.length !== 32) { + throw Error(`Expect root to be 32 bytes, got ${root.length}`); + } + + for (let i = 0; i < root.length; i++) { + const byte = root[i]; + const first = (byte & 0xf0) >> 4; + const second = byte & 0x0f; + + // "0".charCodeAt(0) = 48 + // "a".charCodeAt(0) = 97 => delta = 87 + rootCharCodes[2 + 2 * i] = first < 10 ? first + 48 : first + 87; + rootCharCodes[2 + 2 * i + 1] = second < 10 ? second + 48 : second + 87; + } + return String.fromCharCode(...rootCharCodes); +} + +export function fromHex(hex: string): Uint8Array { + if (typeof hex !== "string") { + throw new Error(`hex argument type ${typeof hex} must be of type string`); + } + + if (hex.startsWith("0x")) { + hex = hex.slice(2); + } + + if (hex.length % 2 !== 0) { + throw new Error(`hex string length ${hex.length} must be multiple of 2`); + } + + const byteLen = hex.length / 2; + const bytes = new Uint8Array(byteLen); + for (let i = 0; i < byteLen; i++) { + const byte = parseInt(hex.slice(i * 2, (i + 1) * 2), 16); + bytes[i] = byte; + } + return bytes; +} diff --git a/packages/utils/src/bytes/index.ts b/packages/utils/src/bytes/index.ts new file mode 100644 index 000000000000..fe6a9fc40e54 --- /dev/null +++ b/packages/utils/src/bytes/index.ts @@ -0,0 +1,14 @@ +import {toHex as browserToHex, toRootHex as browserToRootHex, fromHex as browserFromHex} from "./browser.js"; +import {toHex as nodeToHex, toRootHex as nodeToRootHex, fromHex as nodeFromHex} from "./nodejs.js"; + +let toHex = browserToHex; +let toRootHex = browserToRootHex; +let fromHex = browserFromHex; + +if (typeof Buffer !== "undefined") { + toHex = nodeToHex; + toRootHex = nodeToRootHex; + fromHex = nodeFromHex; +} + +export {toHex, toRootHex, fromHex}; diff --git a/packages/utils/src/bytes/nodejs.ts b/packages/utils/src/bytes/nodejs.ts new file mode 100644 index 000000000000..7f0fe50d2a4a --- /dev/null +++ b/packages/utils/src/bytes/nodejs.ts @@ -0,0 +1,33 @@ +export function toHex(buffer: Uint8Array | Parameters[0]): string { + if (Buffer.isBuffer(buffer)) { + return "0x" + buffer.toString("hex"); + } else if (buffer instanceof Uint8Array) { + return "0x" + Buffer.from(buffer.buffer, buffer.byteOffset, buffer.length).toString("hex"); + } else { + return "0x" + Buffer.from(buffer).toString("hex"); + } +} + +// Shared buffer to convert root to hex +let rootBuf: Buffer | undefined; + +/** + * Convert a Uint8Array, length 32, to 0x-prefixed hex string + */ +export function toRootHex(root: Uint8Array): string { + if (root.length !== 32) { + throw Error(`Expect root to be 32 bytes, got ${root.length}`); + } + + if (rootBuf === undefined) { + rootBuf = Buffer.alloc(32); + } + + rootBuf.set(root); + return `0x${rootBuf.toString("hex")}`; +} + +export function fromHex(hex: string): Uint8Array { + const b = Buffer.from(hex.replace("0x", ""), "hex"); + return new Uint8Array(b.buffer, b.byteOffset, b.length); +} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 2057e50e07bc..13ea1ffb7e69 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -2,6 +2,7 @@ export * from "./yaml/index.js"; export * from "./assert.js"; export * from "./base64.js"; export * from "./bytes.js"; +export * from "./bytes/index.js"; export * from "./command.js"; export * from "./err.js"; export * from "./errors.js"; diff --git a/packages/utils/test/perf/bytes.test.ts b/packages/utils/test/perf/bytes.test.ts index 368758d12efe..649ea0b51e3e 100644 --- a/packages/utils/test/perf/bytes.test.ts +++ b/packages/utils/test/perf/bytes.test.ts @@ -1,12 +1,14 @@ import {itBench} from "@dapplion/benchmark"; -import {toHex, toRootHex} from "../../src/bytes.js"; +import {toHex, toRootHex} from "../../src/bytes/nodejs.js"; +import {toHex as browserToHex, toRootHex as browserToRootHex} from "../../src/bytes/browser.js"; +import {toHexString} from "../../src/bytes.js"; describe("bytes utils", function () { const runsFactor = 1000; const blockRoot = new Uint8Array(Array.from({length: 32}, (_, i) => i)); itBench({ - id: "block root to RootHex using toHex", + id: "nodejs block root to RootHex using toHex", fn: () => { for (let i = 0; i < runsFactor; i++) { toHex(blockRoot); @@ -16,7 +18,7 @@ describe("bytes utils", function () { }); itBench({ - id: "block root to RootHex using toRootHex", + id: "nodejs block root to RootHex using toRootHex", fn: () => { for (let i = 0; i < runsFactor; i++) { toRootHex(blockRoot); @@ -24,4 +26,34 @@ describe("bytes utils", function () { }, runsFactor, }); + + itBench({ + id: "browser block root to RootHex using the deprecated toHexString", + fn: () => { + for (let i = 0; i < runsFactor; i++) { + toHexString(blockRoot); + } + }, + runsFactor, + }); + + itBench({ + id: "browser block root to RootHex using toHex", + fn: () => { + for (let i = 0; i < runsFactor; i++) { + browserToHex(blockRoot); + } + }, + runsFactor, + }); + + itBench({ + id: "browser block root to RootHex using toRootHex", + fn: () => { + for (let i = 0; i < runsFactor; i++) { + browserToRootHex(blockRoot); + } + }, + runsFactor, + }); }); diff --git a/packages/utils/test/unit/bytes.test.ts b/packages/utils/test/unit/bytes.test.ts index 8410e667187a..aefa3e240954 100644 --- a/packages/utils/test/unit/bytes.test.ts +++ b/packages/utils/test/unit/bytes.test.ts @@ -1,5 +1,5 @@ import {describe, it, expect} from "vitest"; -import {intToBytes, bytesToInt, toHex, fromHex, toHexString} from "../../src/index.js"; +import {intToBytes, bytesToInt, toHex, fromHex, toHexString, toRootHex} from "../../src/index.js"; describe("intToBytes", () => { const zeroedArray = (length: number): number[] => Array.from({length}, () => 0); @@ -48,7 +48,7 @@ describe("bytesToInt", () => { }); describe("toHex", () => { - const testCases: {input: Buffer | Uint8Array | string; output: string}[] = [ + const testCases: {input: Uint8Array; output: string}[] = [ {input: Buffer.from("Hello, World!", "utf-8"), output: "0x48656c6c6f2c20576f726c6421"}, {input: new Uint8Array([72, 101, 108, 108, 111]), output: "0x48656c6c6f"}, {input: Buffer.from([72, 101, 108, 108, 111]), output: "0x48656c6c6f"}, @@ -61,6 +61,25 @@ describe("toHex", () => { } }); +describe("toRootHex", () => { + const testCases: {input: Uint8Array; output: string}[] = [ + { + input: new Uint8Array(Array.from({length: 32}, (_, i) => i)), + output: "0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + }, + { + input: new Uint8Array(Array.from({length: 32}, () => 0)), + output: "0x0000000000000000000000000000000000000000000000000000000000000000", + }, + ]; + + for (const {input, output} of testCases) { + it(`should convert root to hex string ${output}`, () => { + expect(toRootHex(input)).toBe(output); + }); + } +}); + describe("fromHex", () => { const testCases: {input: string; output: Buffer | Uint8Array}[] = [ { From ef99ed711437f8b86941fed6eb8b92010c91df3a Mon Sep 17 00:00:00 2001 From: twoeths Date: Wed, 4 Sep 2024 08:20:35 +0700 Subject: [PATCH 088/259] fix: toPubkeyHex (#7065) * feat: add toPubkeyHex util * feat: consume toPubkeyHex * fix: use toPubkeyHex instead of toHex * chore: remove redundant comments --- packages/api/src/builder/routes.ts | 3 +- .../validator/keymanager/keystoreCache.ts | 6 +- .../validator/slashingProtection/export.ts | 5 +- .../cli/src/cmds/validator/voluntaryExit.ts | 4 +- packages/flare/src/cmds/selfSlashAttester.ts | 4 +- packages/flare/src/cmds/selfSlashProposer.ts | 4 +- .../src/cache/syncCommitteeCache.ts | 5 +- packages/utils/src/bytes/browser.ts | 71 ++++++++++++------- packages/utils/src/bytes/index.ts | 18 ++++- packages/utils/src/bytes/nodejs.ts | 16 +++++ packages/utils/test/unit/bytes.test.ts | 21 +++++- .../src/services/attestationDuties.ts | 7 +- packages/validator/src/services/block.ts | 5 +- .../validator/src/services/blockDuties.ts | 9 ++- packages/validator/src/services/indices.ts | 5 +- .../src/services/syncCommitteeDuties.ts | 4 +- .../validator/src/services/validatorStore.ts | 9 +-- .../validator/src/slashingProtection/index.ts | 7 +- .../interchange/formats/completeV4.ts | 3 +- .../interchange/formats/v5.ts | 3 +- 20 files changed, 138 insertions(+), 71 deletions(-) diff --git a/packages/api/src/builder/routes.ts b/packages/api/src/builder/routes.ts index 297c4fc5e9a9..3d74101bb046 100644 --- a/packages/api/src/builder/routes.ts +++ b/packages/api/src/builder/routes.ts @@ -13,6 +13,7 @@ import { } from "@lodestar/types"; import {ForkName, isForkBlobs} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; +import {toPubkeyHex} from "@lodestar/utils"; import {Endpoint, RouteDefinitions, Schema} from "../utils/index.js"; import {MetaHeader, VersionCodec, VersionMeta} from "../utils/metadata.js"; @@ -105,7 +106,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ - params: {slot, parent_hash: toHexString(parentHash), pubkey: toHexString(proposerPubKey)}, + params: {slot, parent_hash: toHexString(parentHash), pubkey: toPubkeyHex(proposerPubKey)}, }), parseReq: ({params}) => ({ slot: params.slot, diff --git a/packages/cli/src/cmds/validator/keymanager/keystoreCache.ts b/packages/cli/src/cmds/validator/keymanager/keystoreCache.ts index 85b1702892ee..2997a6b6b113 100644 --- a/packages/cli/src/cmds/validator/keymanager/keystoreCache.ts +++ b/packages/cli/src/cmds/validator/keymanager/keystoreCache.ts @@ -3,7 +3,7 @@ import path from "node:path"; import {Keystore} from "@chainsafe/bls-keystore"; import {SecretKey} from "@chainsafe/blst"; import {SignerLocal, SignerType} from "@lodestar/validator"; -import {fromHex, toHex} from "@lodestar/utils"; +import {fromHex, toHex, toPubkeyHex} from "@lodestar/utils"; import {writeFile600Perm} from "../../../util/file.js"; import {lockFilepath, unlockFilepath} from "../../../util/lockfile.js"; import {LocalKeystoreDefinition} from "./interface.js"; @@ -42,9 +42,9 @@ export async function loadKeystoreCache( const secretKey = SecretKey.fromBytes(secretKeyBytes); const publicKey = secretKey.toPublicKey().toBytes(); - if (toHex(publicKey) !== toHex(fromHex(k.pubkey))) { + if (toPubkeyHex(publicKey) !== toPubkeyHex(fromHex(k.pubkey))) { throw new Error( - `Keystore ${k.uuid} does not match the expected pubkey. expected=${toHex(fromHex(k.pubkey))}, found=${toHex( + `Keystore ${k.uuid} does not match the expected pubkey. expected=${toPubkeyHex(fromHex(k.pubkey))}, found=${toHex( publicKey )}` ); diff --git a/packages/cli/src/cmds/validator/slashingProtection/export.ts b/packages/cli/src/cmds/validator/slashingProtection/export.ts index 7d1a4f8e6e2f..c18b020f5782 100644 --- a/packages/cli/src/cmds/validator/slashingProtection/export.ts +++ b/packages/cli/src/cmds/validator/slashingProtection/export.ts @@ -1,8 +1,7 @@ import path from "node:path"; -import {toHexString} from "@chainsafe/ssz"; import {InterchangeFormatVersion} from "@lodestar/validator"; import {getNodeLogger} from "@lodestar/logger/node"; -import {CliCommand} from "@lodestar/utils"; +import {CliCommand, toPubkeyHex} from "@lodestar/utils"; import {YargsError, ensure0xPrefix, isValidatePubkeyHex, writeFile600Perm} from "../../../util/index.js"; import {parseLoggerArgs} from "../../../util/logger.js"; import {GlobalArgs} from "../../../options/index.js"; @@ -86,7 +85,7 @@ export const exportCmd: CliCommand toHexString(pubkey) === pubkeyHex); + const existingPubkey = allPubkeys.find((pubkey) => toPubkeyHex(pubkey) === pubkeyHex); if (!existingPubkey) { logger.warn("Pubkey not found in slashing protection db", {pubkey: pubkeyHex}); } else { diff --git a/packages/cli/src/cmds/validator/voluntaryExit.ts b/packages/cli/src/cmds/validator/voluntaryExit.ts index 279076b619f2..a399a763662d 100644 --- a/packages/cli/src/cmds/validator/voluntaryExit.ts +++ b/packages/cli/src/cmds/validator/voluntaryExit.ts @@ -8,7 +8,7 @@ import { } from "@lodestar/state-transition"; import {createBeaconConfig, BeaconConfig} from "@lodestar/config"; import {phase0, ssz, ValidatorIndex, Epoch} from "@lodestar/types"; -import {CliCommand, fromHex, toHex} from "@lodestar/utils"; +import {CliCommand, fromHex, toPubkeyHex} from "@lodestar/utils"; import {externalSignerPostSignature, SignableMessageType, Signer, SignerType} from "@lodestar/validator"; import {ApiClient, getClient} from "@lodestar/api"; import {ensure0xPrefix, YargsError, wrapError} from "../../util/index.js"; @@ -209,7 +209,7 @@ async function resolveValidatorIndexes(client: ApiClient, signersToExit: SignerP const validators = (await client.beacon.getStateValidators({stateId: "head", validatorIds: pubkeys})).value(); - const dataByPubkey = new Map(validators.map((item) => [toHex(item.validator.pubkey), item])); + const dataByPubkey = new Map(validators.map((item) => [toPubkeyHex(item.validator.pubkey), item])); return signersToExit.map(({signer, pubkey}) => { const item = dataByPubkey.get(pubkey); diff --git a/packages/flare/src/cmds/selfSlashAttester.ts b/packages/flare/src/cmds/selfSlashAttester.ts index e29a956a9306..a37c6c765bd3 100644 --- a/packages/flare/src/cmds/selfSlashAttester.ts +++ b/packages/flare/src/cmds/selfSlashAttester.ts @@ -4,7 +4,7 @@ import {AttesterSlashing, phase0, ssz} from "@lodestar/types"; import {config as chainConfig} from "@lodestar/config/default"; import {createBeaconConfig, BeaconConfig} from "@lodestar/config"; import {DOMAIN_BEACON_ATTESTER, MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; -import {CliCommand, toHexString} from "@lodestar/utils"; +import {CliCommand, toPubkeyHex} from "@lodestar/utils"; import {computeSigningRoot} from "@lodestar/state-transition"; import {deriveSecretKeys, SecretKeysArgs, secretKeysOptions} from "../util/deriveSecretKeys.js"; @@ -90,7 +90,7 @@ export async function selfSlashAttesterHandler(args: SelfSlashArgs): Promise; @@ -82,7 +83,7 @@ function computeSyncCommitteeIndices( for (const pubkey of pubkeys) { const validatorIndex = pubkey2index.get(pubkey); if (validatorIndex === undefined) { - throw Error(`SyncCommittee pubkey is unknown ${toHexString(pubkey)}`); + throw Error(`SyncCommittee pubkey is unknown ${toPubkeyHex(pubkey)}`); } validatorIndices.push(validatorIndex); diff --git a/packages/utils/src/bytes/browser.ts b/packages/utils/src/bytes/browser.ts index e6c04f79835f..f610e2912c04 100644 --- a/packages/utils/src/bytes/browser.ts +++ b/packages/utils/src/bytes/browser.ts @@ -1,26 +1,20 @@ +// "0".charCodeAt(0) = 48 +const CHAR_CODE_0 = 48; +// "x".charCodeAt(0) = 120 +const CHAR_CODE_X = 120; + export function toHex(bytes: Uint8Array): string { const charCodes = new Array(bytes.length * 2 + 2); - charCodes[0] = 48; - charCodes[1] = 120; - - for (let i = 0; i < bytes.length; i++) { - const byte = bytes[i]; - const first = (byte & 0xf0) >> 4; - const second = byte & 0x0f; + charCodes[0] = CHAR_CODE_0; + charCodes[1] = CHAR_CODE_X; - // "0".charCodeAt(0) = 48 - // "a".charCodeAt(0) = 97 => delta = 87 - charCodes[2 + 2 * i] = first < 10 ? first + 48 : first + 87; - charCodes[2 + 2 * i + 1] = second < 10 ? second + 48 : second + 87; - } + bytesIntoCharCodes(bytes, charCodes); return String.fromCharCode(...charCodes); } const rootCharCodes = new Array(32 * 2 + 2); -// "0".charCodeAt(0) -rootCharCodes[0] = 48; -// "x".charCodeAt(0) -rootCharCodes[1] = 120; +rootCharCodes[0] = CHAR_CODE_0; +rootCharCodes[1] = CHAR_CODE_X; /** * Convert a Uint8Array, length 32, to 0x-prefixed hex string @@ -30,17 +24,24 @@ export function toRootHex(root: Uint8Array): string { throw Error(`Expect root to be 32 bytes, got ${root.length}`); } - for (let i = 0; i < root.length; i++) { - const byte = root[i]; - const first = (byte & 0xf0) >> 4; - const second = byte & 0x0f; + bytesIntoCharCodes(root, rootCharCodes); + return String.fromCharCode(...rootCharCodes); +} - // "0".charCodeAt(0) = 48 - // "a".charCodeAt(0) = 97 => delta = 87 - rootCharCodes[2 + 2 * i] = first < 10 ? first + 48 : first + 87; - rootCharCodes[2 + 2 * i + 1] = second < 10 ? second + 48 : second + 87; +const pubkeyCharCodes = new Array(48 * 2 + 2); +pubkeyCharCodes[0] = CHAR_CODE_0; +pubkeyCharCodes[1] = CHAR_CODE_X; + +/** + * Convert a Uint8Array, length 48, to 0x-prefixed hex string + */ +export function toPubkeyHex(pubkey: Uint8Array): string { + if (pubkey.length !== CHAR_CODE_0) { + throw Error(`Expect pubkey to be 48 bytes, got ${pubkey.length}`); } - return String.fromCharCode(...rootCharCodes); + + bytesIntoCharCodes(pubkey, pubkeyCharCodes); + return String.fromCharCode(...pubkeyCharCodes); } export function fromHex(hex: string): Uint8Array { @@ -64,3 +65,23 @@ export function fromHex(hex: string): Uint8Array { } return bytes; } + +/** + * Populate charCodes from bytes. Note that charCodes index 0 and 1 ("0x") are not populated. + */ +function bytesIntoCharCodes(bytes: Uint8Array, charCodes: number[]): void { + if (bytes.length * 2 + 2 !== charCodes.length) { + throw Error(`Expect charCodes to be of length ${bytes.length * 2 + 2}, got ${charCodes.length}`); + } + + for (let i = 0; i < bytes.length; i++) { + const byte = bytes[i]; + const first = (byte & 0xf0) >> 4; + const second = byte & 0x0f; + + // "0".charCodeAt(0) = 48 + // "a".charCodeAt(0) = 97 => delta = 87 + charCodes[2 + 2 * i] = first < 10 ? first + 48 : first + 87; + charCodes[2 + 2 * i + 1] = second < 10 ? second + 48 : second + 87; + } +} diff --git a/packages/utils/src/bytes/index.ts b/packages/utils/src/bytes/index.ts index fe6a9fc40e54..a079764738b7 100644 --- a/packages/utils/src/bytes/index.ts +++ b/packages/utils/src/bytes/index.ts @@ -1,14 +1,26 @@ -import {toHex as browserToHex, toRootHex as browserToRootHex, fromHex as browserFromHex} from "./browser.js"; -import {toHex as nodeToHex, toRootHex as nodeToRootHex, fromHex as nodeFromHex} from "./nodejs.js"; +import { + toHex as browserToHex, + toRootHex as browserToRootHex, + fromHex as browserFromHex, + toPubkeyHex as browserToPubkeyHex, +} from "./browser.js"; +import { + toHex as nodeToHex, + toRootHex as nodeToRootHex, + fromHex as nodeFromHex, + toPubkeyHex as nodeToPubkeyHex, +} from "./nodejs.js"; let toHex = browserToHex; let toRootHex = browserToRootHex; +let toPubkeyHex = browserToPubkeyHex; let fromHex = browserFromHex; if (typeof Buffer !== "undefined") { toHex = nodeToHex; toRootHex = nodeToRootHex; + toPubkeyHex = nodeToPubkeyHex; fromHex = nodeFromHex; } -export {toHex, toRootHex, fromHex}; +export {toHex, toRootHex, toPubkeyHex, fromHex}; diff --git a/packages/utils/src/bytes/nodejs.ts b/packages/utils/src/bytes/nodejs.ts index 7f0fe50d2a4a..636f49bd8e76 100644 --- a/packages/utils/src/bytes/nodejs.ts +++ b/packages/utils/src/bytes/nodejs.ts @@ -27,6 +27,22 @@ export function toRootHex(root: Uint8Array): string { return `0x${rootBuf.toString("hex")}`; } +// Shared buffer to convert pubkey to hex +let pubkeyBuf: Buffer | undefined; + +export function toPubkeyHex(pubkey: Uint8Array): string { + if (pubkey.length !== 48) { + throw Error(`Expect pubkey to be 48 bytes, got ${pubkey.length}`); + } + + if (pubkeyBuf === undefined) { + pubkeyBuf = Buffer.alloc(48); + } + + pubkeyBuf.set(pubkey); + return `0x${pubkeyBuf.toString("hex")}`; +} + export function fromHex(hex: string): Uint8Array { const b = Buffer.from(hex.replace("0x", ""), "hex"); return new Uint8Array(b.buffer, b.byteOffset, b.length); diff --git a/packages/utils/test/unit/bytes.test.ts b/packages/utils/test/unit/bytes.test.ts index aefa3e240954..05789b839cfd 100644 --- a/packages/utils/test/unit/bytes.test.ts +++ b/packages/utils/test/unit/bytes.test.ts @@ -1,5 +1,5 @@ import {describe, it, expect} from "vitest"; -import {intToBytes, bytesToInt, toHex, fromHex, toHexString, toRootHex} from "../../src/index.js"; +import {intToBytes, bytesToInt, toHex, fromHex, toHexString, toRootHex, toPubkeyHex} from "../../src/index.js"; describe("intToBytes", () => { const zeroedArray = (length: number): number[] => Array.from({length}, () => 0); @@ -80,6 +80,25 @@ describe("toRootHex", () => { } }); +describe("toPubkeyHex", () => { + const testCases: {input: Uint8Array; output: string}[] = [ + { + input: new Uint8Array(Array.from({length: 48}, (_, i) => i)), + output: "0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + }, + { + input: new Uint8Array(Array.from({length: 48}, () => 0)), + output: "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + ]; + + for (const {input, output} of testCases) { + it(`should convert root to hex string ${output}`, () => { + expect(toPubkeyHex(input)).toBe(output); + }); + } +}); + describe("fromHex", () => { const testCases: {input: string; output: Buffer | Uint8Array}[] = [ { diff --git a/packages/validator/src/services/attestationDuties.ts b/packages/validator/src/services/attestationDuties.ts index ea82bf0a4c72..83838afe1492 100644 --- a/packages/validator/src/services/attestationDuties.ts +++ b/packages/validator/src/services/attestationDuties.ts @@ -1,6 +1,5 @@ -import {toHexString} from "@chainsafe/ssz"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {sleep} from "@lodestar/utils"; +import {sleep, toPubkeyHex} from "@lodestar/utils"; import {computeEpochAtSlot, isAggregatorFromCommitteeLength, isStartSlotOfEpoch} from "@lodestar/state-transition"; import {BLSSignature, Epoch, Slot, ValidatorIndex, RootHex} from "@lodestar/types"; import {ApiClient, routes} from "@lodestar/api"; @@ -97,7 +96,7 @@ export class AttestationDutiesService { removeDutiesForKey(pubkey: PubkeyHex): void { for (const [epoch, attDutiesAtEpoch] of this.dutiesByIndexByEpoch) { for (const [vIndex, attDutyAndProof] of attDutiesAtEpoch.dutiesByIndex) { - if (toHexString(attDutyAndProof.duty.pubkey) === pubkey) { + if (toPubkeyHex(attDutyAndProof.duty.pubkey) === pubkey) { attDutiesAtEpoch.dutiesByIndex.delete(vIndex); if (attDutiesAtEpoch.dutiesByIndex.size === 0) { this.dutiesByIndexByEpoch.delete(epoch); @@ -244,7 +243,7 @@ export class AttestationDutiesService { const attesterDuties = res.value(); const {dependentRoot} = res.meta(); const relevantDuties = attesterDuties.filter((duty) => { - const pubkeyHex = toHexString(duty.pubkey); + const pubkeyHex = toPubkeyHex(duty.pubkey); return this.validatorStore.hasVotingPubkey(pubkeyHex) && this.validatorStore.isDoppelgangerSafe(pubkeyHex); }); diff --git a/packages/validator/src/services/block.ts b/packages/validator/src/services/block.ts index 7792ef85be95..c3acf19c1669 100644 --- a/packages/validator/src/services/block.ts +++ b/packages/validator/src/services/block.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import { BLSPubkey, Slot, @@ -15,7 +14,7 @@ import { } from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {ForkPreBlobs, ForkBlobs, ForkSeq, ForkExecution, ForkName} from "@lodestar/params"; -import {extendError, prettyBytes, prettyWeiToEth} from "@lodestar/utils"; +import {extendError, prettyBytes, prettyWeiToEth, toPubkeyHex} from "@lodestar/utils"; import {ApiClient, routes} from "@lodestar/api"; import {IClock, LoggerVc} from "../util/index.js"; import {PubkeyHex} from "../types.js"; @@ -110,7 +109,7 @@ export class BlockProposingService { /** Produce a block at the given slot for pubkey */ private async createAndPublishBlock(pubkey: BLSPubkey, slot: Slot): Promise { - const pubkeyHex = toHexString(pubkey); + const pubkeyHex = toPubkeyHex(pubkey); const logCtx = {slot, validator: prettyBytes(pubkeyHex)}; // Wrap with try catch here to re-use `logCtx` diff --git a/packages/validator/src/services/blockDuties.ts b/packages/validator/src/services/blockDuties.ts index 3282987f5d9e..d0e16f60e816 100644 --- a/packages/validator/src/services/blockDuties.ts +++ b/packages/validator/src/services/blockDuties.ts @@ -1,8 +1,7 @@ -import {toHexString} from "@chainsafe/ssz"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {BLSPubkey, Epoch, RootHex, Slot} from "@lodestar/types"; import {ApiClient, routes} from "@lodestar/api"; -import {sleep} from "@lodestar/utils"; +import {sleep, toPubkeyHex} from "@lodestar/utils"; import {ChainConfig} from "@lodestar/config"; import {IClock, differenceHex, LoggerVc} from "../util/index.js"; import {PubkeyHex} from "../types.js"; @@ -67,7 +66,7 @@ export class BlockDutiesService { if (dutyAtEpoch) { for (const proposer of dutyAtEpoch.data) { if (proposer.slot === slot) { - publicKeys.set(toHexString(proposer.pubkey), proposer.pubkey); + publicKeys.set(toPubkeyHex(proposer.pubkey), proposer.pubkey); } } } @@ -78,7 +77,7 @@ export class BlockDutiesService { removeDutiesForKey(pubkey: PubkeyHex): void { for (const blockDutyAtEpoch of this.proposers.values()) { blockDutyAtEpoch.data = blockDutyAtEpoch.data.filter((proposer) => { - return toHexString(proposer.pubkey) !== pubkey; + return toPubkeyHex(proposer.pubkey) !== pubkey; }); } } @@ -187,7 +186,7 @@ export class BlockDutiesService { const proposerDuties = res.value(); const {dependentRoot} = res.meta(); const relevantDuties = proposerDuties.filter((duty) => { - const pubkeyHex = toHexString(duty.pubkey); + const pubkeyHex = toPubkeyHex(duty.pubkey); return this.validatorStore.hasVotingPubkey(pubkeyHex) && this.validatorStore.isDoppelgangerSafe(pubkeyHex); }); diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index c6ef40b473e5..ec5155322918 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -1,6 +1,5 @@ -import {toHexString} from "@chainsafe/ssz"; import {ValidatorIndex} from "@lodestar/types"; -import {Logger, MapDef} from "@lodestar/utils"; +import {Logger, MapDef, toPubkeyHex} from "@lodestar/utils"; import {ApiClient, routes} from "@lodestar/api"; import {batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; @@ -135,7 +134,7 @@ export class IndicesService { const status = statusToSimpleStatusMapping(validator.status); allValidatorStatuses.set(status, allValidatorStatuses.getOrDefault(status) + 1); - const pubkeyHex = toHexString(validator.validator.pubkey); + const pubkeyHex = toPubkeyHex(validator.validator.pubkey); if (!this.pubkey2index.has(pubkeyHex)) { this.logger.info("Validator seen on beacon chain", { validatorIndex: validator.index, diff --git a/packages/validator/src/services/syncCommitteeDuties.ts b/packages/validator/src/services/syncCommitteeDuties.ts index dd663528f751..ea448add15ec 100644 --- a/packages/validator/src/services/syncCommitteeDuties.ts +++ b/packages/validator/src/services/syncCommitteeDuties.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; import { computeEpochAtSlot, @@ -10,6 +9,7 @@ import { import {ChainForkConfig} from "@lodestar/config"; import {BLSSignature, Epoch, Slot, SyncPeriod, ValidatorIndex} from "@lodestar/types"; import {ApiClient, routes} from "@lodestar/api"; +import {toPubkeyHex} from "@lodestar/utils"; import {IClock, LoggerVc} from "../util/index.js"; import {PubkeyHex} from "../types.js"; import {Metrics} from "../metrics.js"; @@ -287,7 +287,7 @@ export class SyncCommitteeDutiesService { // Using `alreadyWarnedReorg` avoids excessive logs. // TODO: Use memory-efficient toHexString() - const pubkeyHex = toHexString(duty.pubkey); + const pubkeyHex = toPubkeyHex(duty.pubkey); dutiesByIndex.set(validatorIndex, {duty: {pubkey: pubkeyHex, validatorIndex, subnets}}); } diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index fa9d855aa24a..c6130f1fab95 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -42,6 +42,7 @@ import { SignedAggregateAndProof, } from "@lodestar/types"; import {routes} from "@lodestar/api"; +import {toPubkeyHex} from "@lodestar/utils"; import {ISlashingProtection} from "../slashingProtection/index.js"; import {PubkeyHex} from "../types.js"; import {externalSignerPostSignature, SignableMessageType, SignableMessage} from "../util/externalSignerClient.js"; @@ -723,7 +724,7 @@ export class ValidatorStore { regAttributes: {feeRecipient: Eth1Address; gasLimit: number}, slot: Slot ): Promise { - const pubkeyHex = typeof pubkeyMaybeHex === "string" ? pubkeyMaybeHex : toHexString(pubkeyMaybeHex); + const pubkeyHex = typeof pubkeyMaybeHex === "string" ? pubkeyMaybeHex : toPubkeyHex(pubkeyMaybeHex); const {feeRecipient, gasLimit} = regAttributes; const regFullKey = `${feeRecipient}-${gasLimit}`; const validatorData = this.validators.get(pubkeyHex); @@ -748,7 +749,7 @@ export class ValidatorStore { signableMessage: SignableMessage ): Promise { // TODO: Refactor indexing to not have to run toHexString() on the pubkey every time - const pubkeyHex = typeof pubkey === "string" ? pubkey : toHexString(pubkey); + const pubkeyHex = typeof pubkey === "string" ? pubkey : toPubkeyHex(pubkey); const signer = this.validators.get(pubkeyHex)?.signer; if (!signer) { @@ -787,7 +788,7 @@ export class ValidatorStore { private getSignerAndPubkeyHex(pubkey: BLSPubkeyMaybeHex): [Signer, string] { // TODO: Refactor indexing to not have to run toHexString() on the pubkey every time - const pubkeyHex = typeof pubkey === "string" ? pubkey : toHexString(pubkey); + const pubkeyHex = typeof pubkey === "string" ? pubkey : toPubkeyHex(pubkey); const signer = this.validators.get(pubkeyHex)?.signer; if (!signer) { throw Error(`Validator pubkey ${pubkeyHex} not known`); @@ -813,7 +814,7 @@ export class ValidatorStore { } private assertDoppelgangerSafe(pubKey: PubkeyHex | BLSPubkey): void { - const pubkeyHex = typeof pubKey === "string" ? pubKey : toHexString(pubKey); + const pubkeyHex = typeof pubKey === "string" ? pubKey : toPubkeyHex(pubKey); if (!this.isDoppelgangerSafe(pubkeyHex)) { throw new Error(`Doppelganger state for key ${pubkeyHex} is not safe`); } diff --git a/packages/validator/src/slashingProtection/index.ts b/packages/validator/src/slashingProtection/index.ts index dedbccf6cf94..bc57b0e51c13 100644 --- a/packages/validator/src/slashingProtection/index.ts +++ b/packages/validator/src/slashingProtection/index.ts @@ -1,6 +1,5 @@ -import {toHexString} from "@chainsafe/ssz"; import {BLSPubkey, Epoch, Root} from "@lodestar/types"; -import {Logger} from "@lodestar/utils"; +import {Logger, toPubkeyHex} from "@lodestar/utils"; import {LodestarValidatorDatabaseController} from "../types.js"; import {uniqueVectorArr} from "../slashingProtection/utils.js"; import {BlockBySlotRepository, SlashingProtectionBlockService} from "./block/index.js"; @@ -63,7 +62,7 @@ export class SlashingProtection implements ISlashingProtection { async importInterchange(interchange: Interchange, genesisValidatorsRoot: Root, logger?: Logger): Promise { const {data} = parseInterchange(interchange, genesisValidatorsRoot); for (const validator of data) { - logger?.info("Importing slashing protection", {pubkey: toHexString(validator.pubkey)}); + logger?.info("Importing slashing protection", {pubkey: toPubkeyHex(validator.pubkey)}); await this.blockService.importBlocks(validator.pubkey, validator.signedBlocks); await this.attestationService.importAttestations(validator.pubkey, validator.signedAttestations); } @@ -77,7 +76,7 @@ export class SlashingProtection implements ISlashingProtection { ): Promise { const validatorData: InterchangeLodestar["data"] = []; for (const pubkey of pubkeys) { - logger?.info("Exporting slashing protection", {pubkey: toHexString(pubkey)}); + logger?.info("Exporting slashing protection", {pubkey: toPubkeyHex(pubkey)}); validatorData.push({ pubkey, signedBlocks: await this.blockService.exportBlocks(pubkey), diff --git a/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts b/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts index 26d7f44f2e83..66aa31c52194 100644 --- a/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts +++ b/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {toPubkeyHex} from "@lodestar/utils"; import {InterchangeLodestar} from "../types.js"; import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js"; @@ -93,7 +94,7 @@ export function serializeInterchangeCompleteV4({ genesis_validators_root: toHexString(genesisValidatorsRoot), }, data: data.map((validator) => ({ - pubkey: toHexString(validator.pubkey), + pubkey: toPubkeyHex(validator.pubkey), signed_blocks: validator.signedBlocks.map((block) => ({ slot: numToString(block.slot), signing_root: toOptionalHexString(block.signingRoot), diff --git a/packages/validator/src/slashingProtection/interchange/formats/v5.ts b/packages/validator/src/slashingProtection/interchange/formats/v5.ts index c70dc84b1ed0..1c7f67b706a5 100644 --- a/packages/validator/src/slashingProtection/interchange/formats/v5.ts +++ b/packages/validator/src/slashingProtection/interchange/formats/v5.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {toPubkeyHex} from "@lodestar/utils"; import {InterchangeLodestar} from "../types.js"; import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js"; @@ -88,7 +89,7 @@ export function serializeInterchangeV5({data, genesisValidatorsRoot}: Interchang genesis_validators_root: toHexString(genesisValidatorsRoot), }, data: data.map((validator) => ({ - pubkey: toHexString(validator.pubkey), + pubkey: toPubkeyHex(validator.pubkey), signed_blocks: validator.signedBlocks.map((block) => ({ slot: numToString(block.slot), signing_root: toOptionalHexString(block.signingRoot), From 681bdcd775990d788c8674d6376b18778f6f588f Mon Sep 17 00:00:00 2001 From: twoeths Date: Wed, 4 Sep 2024 08:21:12 +0700 Subject: [PATCH 089/259] fix: improve performance of getExpectedWithdrawals (#7045) * fix: improve performance of getExpectedWithdrawals * chore: use isPostElectra variable * chore: check pre-capella --- .../src/block/processWithdrawals.ts | 47 +++++++++++++--- packages/state-transition/src/util/electra.ts | 55 +------------------ 2 files changed, 41 insertions(+), 61 deletions(-) diff --git a/packages/state-transition/src/block/processWithdrawals.ts b/packages/state-transition/src/block/processWithdrawals.ts index b06209167be3..185ddd80eb32 100644 --- a/packages/state-transition/src/block/processWithdrawals.ts +++ b/packages/state-transition/src/block/processWithdrawals.ts @@ -7,6 +7,7 @@ import { MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP, FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, + MAX_EFFECTIVE_BALANCE, } from "@lodestar/params"; import {toRootHex} from "@lodestar/utils"; @@ -14,9 +15,9 @@ import {CachedBeaconStateCapella, CachedBeaconStateElectra} from "../types.js"; import { decreaseBalance, getValidatorMaxEffectiveBalance, + hasEth1WithdrawalCredential, + hasExecutionWithdrawalCredential, isCapellaPayloadHeader, - isFullyWithdrawableValidator, - isPartiallyWithdrawableValidator, } from "../util/index.js"; export function processWithdrawals( @@ -24,6 +25,8 @@ export function processWithdrawals( state: CachedBeaconStateCapella | CachedBeaconStateElectra, payload: capella.FullOrBlindedExecutionPayload ): void { + // partialWithdrawalsCount is withdrawals coming from EL since electra (EIP-7002) + // TODO - electra: may switch to executionWithdrawalsCount const {withdrawals: expectedWithdrawals, partialWithdrawalsCount} = getExpectedWithdrawals(fork, state); const numWithdrawals = expectedWithdrawals.length; @@ -86,16 +89,33 @@ export function getExpectedWithdrawals( sampledValidators: number; partialWithdrawalsCount: number; } { + if (fork < ForkSeq.capella) { + throw new Error(`getExpectedWithdrawals not supported at forkSeq=${fork} < ForkSeq.capella`); + } + const epoch = state.epochCtx.epoch; let withdrawalIndex = state.nextWithdrawalIndex; const {validators, balances, nextWithdrawalValidatorIndex} = state; const withdrawals: capella.Withdrawal[] = []; + const isPostElectra = fork >= ForkSeq.electra; - if (fork >= ForkSeq.electra) { + if (isPostElectra) { const stateElectra = state as CachedBeaconStateElectra; - for (const withdrawal of stateElectra.pendingPartialWithdrawals.getAllReadonly()) { + // MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP = 8, PENDING_PARTIAL_WITHDRAWALS_LIMIT: 134217728 so we should only call getAllReadonly() if it makes sense + // pendingPartialWithdrawals comes from EIP-7002 smart contract where it takes fee so it's more likely than not validator is in correct condition to withdraw + // also we may break early if withdrawableEpoch > epoch + const allPendingPartialWithdrawals = + stateElectra.pendingPartialWithdrawals.length <= MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP + ? stateElectra.pendingPartialWithdrawals.getAllReadonly() + : null; + + // EIP-7002: Execution layer triggerable withdrawals + for (let i = 0; i < stateElectra.pendingPartialWithdrawals.length; i++) { + const withdrawal = allPendingPartialWithdrawals + ? allPendingPartialWithdrawals[i] + : stateElectra.pendingPartialWithdrawals.getReadonly(i); if (withdrawal.withdrawableEpoch > epoch || withdrawals.length === MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP) { break; } @@ -121,6 +141,7 @@ export function getExpectedWithdrawals( } } + // partialWithdrawalsCount is withdrawals coming from EL since electra (EIP-7002) const partialWithdrawalsCount = withdrawals.length; const bound = Math.min(validators.length, MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP); let n = 0; @@ -132,13 +153,18 @@ export function getExpectedWithdrawals( const validator = validators.getReadonly(validatorIndex); const balance = balances.get(validatorIndex); + const {withdrawableEpoch, withdrawalCredentials, effectiveBalance} = validator; + const hasWithdrawableCredentials = isPostElectra + ? hasExecutionWithdrawalCredential(withdrawalCredentials) + : hasEth1WithdrawalCredential(withdrawalCredentials); // early skip for balance = 0 as its now more likely that validator has exited/slahed with // balance zero than not have withdrawal credentials set - if (balance === 0) { + if (balance === 0 || !hasWithdrawableCredentials) { continue; } - if (isFullyWithdrawableValidator(fork, validator, balance, epoch)) { + // capella full withdrawal + if (withdrawableEpoch <= epoch) { withdrawals.push({ index: withdrawalIndex, validatorIndex, @@ -146,12 +172,17 @@ export function getExpectedWithdrawals( amount: BigInt(balance), }); withdrawalIndex++; - } else if (isPartiallyWithdrawableValidator(fork, validator, balance)) { + } else if ( + effectiveBalance === + (isPostElectra ? getValidatorMaxEffectiveBalance(withdrawalCredentials) : MAX_EFFECTIVE_BALANCE) && + balance > effectiveBalance + ) { + // capella partial withdrawal withdrawals.push({ index: withdrawalIndex, validatorIndex, address: validator.withdrawalCredentials.subarray(12), - amount: BigInt(balance - getValidatorMaxEffectiveBalance(validator.withdrawalCredentials)), + amount: BigInt(balance - effectiveBalance), }); withdrawalIndex++; } diff --git a/packages/state-transition/src/util/electra.ts b/packages/state-transition/src/util/electra.ts index 63f74bc96cc9..ac34da6407de 100644 --- a/packages/state-transition/src/util/electra.ts +++ b/packages/state-transition/src/util/electra.ts @@ -1,17 +1,8 @@ -import { - COMPOUNDING_WITHDRAWAL_PREFIX, - FAR_FUTURE_EPOCH, - ForkSeq, - MAX_EFFECTIVE_BALANCE, - MIN_ACTIVATION_BALANCE, -} from "@lodestar/params"; -import {ValidatorIndex, phase0, ssz} from "@lodestar/types"; +import {COMPOUNDING_WITHDRAWAL_PREFIX, FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE} from "@lodestar/params"; +import {ValidatorIndex, ssz} from "@lodestar/types"; import {CachedBeaconStateElectra} from "../types.js"; -import {getValidatorMaxEffectiveBalance} from "./validator.js"; import {hasEth1WithdrawalCredential} from "./capella.js"; -type ValidatorInfo = Pick; - export function hasCompoundingWithdrawalCredential(withdrawalCredentials: Uint8Array): boolean { return withdrawalCredentials[0] === COMPOUNDING_WITHDRAWAL_PREFIX; } @@ -22,48 +13,6 @@ export function hasExecutionWithdrawalCredential(withdrawalCredentials: Uint8Arr ); } -export function isFullyWithdrawableValidator( - fork: ForkSeq, - validatorCredential: ValidatorInfo, - balance: number, - epoch: number -): boolean { - const {withdrawableEpoch, withdrawalCredentials} = validatorCredential; - - if (fork < ForkSeq.capella) { - throw new Error(`isFullyWithdrawableValidator not supported at forkSeq=${fork} < ForkSeq.capella`); - } - const hasWithdrawableCredentials = - fork >= ForkSeq.electra - ? hasExecutionWithdrawalCredential(withdrawalCredentials) - : hasEth1WithdrawalCredential(withdrawalCredentials); - - return hasWithdrawableCredentials && withdrawableEpoch <= epoch && balance > 0; -} - -export function isPartiallyWithdrawableValidator( - fork: ForkSeq, - validatorCredential: ValidatorInfo, - balance: number -): boolean { - const {effectiveBalance, withdrawalCredentials} = validatorCredential; - - if (fork < ForkSeq.capella) { - throw new Error(`isPartiallyWithdrawableValidator not supported at forkSeq=${fork} < ForkSeq.capella`); - } - const hasWithdrawableCredentials = - fork >= ForkSeq.electra - ? hasExecutionWithdrawalCredential(withdrawalCredentials) - : hasEth1WithdrawalCredential(withdrawalCredentials); - - const validatorMaxEffectiveBalance = - fork >= ForkSeq.electra ? getValidatorMaxEffectiveBalance(withdrawalCredentials) : MAX_EFFECTIVE_BALANCE; - const hasMaxEffectiveBalance = effectiveBalance === validatorMaxEffectiveBalance; - const hasExcessBalance = balance > validatorMaxEffectiveBalance; - - return hasWithdrawableCredentials && hasMaxEffectiveBalance && hasExcessBalance; -} - export function switchToCompoundingValidator(state: CachedBeaconStateElectra, index: ValidatorIndex): void { const validator = state.validators.get(index); From 4e22884db58ac119fdb0e59424841c92d4322ae9 Mon Sep 17 00:00:00 2001 From: twoeths Date: Wed, 4 Sep 2024 08:21:48 +0700 Subject: [PATCH 090/259] fix: improve regen state (#7033) * fix: improve regen state * fix: check for null block returned from db * feat: track state.hashTreeRoot() in regen.getState() * fix: transfer cache when regen state * fix: add caller as label to regenGetState metrics --- packages/beacon-node/src/chain/regen/regen.ts | 70 +++++++++++++++---- .../stateCache/persistentCheckpointsCache.ts | 4 ++ .../src/metrics/metrics/lodestar.ts | 28 ++++++++ .../state-transition/src/stateTransition.ts | 1 + 4 files changed, 91 insertions(+), 12 deletions(-) diff --git a/packages/beacon-node/src/chain/regen/regen.ts b/packages/beacon-node/src/chain/regen/regen.ts index 409c12c77b21..04cf5b40b494 100644 --- a/packages/beacon-node/src/chain/regen/regen.ts +++ b/packages/beacon-node/src/chain/regen/regen.ts @@ -1,5 +1,5 @@ import {fromHexString} from "@chainsafe/ssz"; -import {phase0, Slot, RootHex, BeaconBlock} from "@lodestar/types"; +import {phase0, Slot, RootHex, BeaconBlock, SignedBeaconBlock} from "@lodestar/types"; import { CachedBeaconStateAllForks, computeEpochAtSlot, @@ -8,6 +8,7 @@ import { DataAvailableStatus, processSlots, stateTransition, + StateHashTreeRootSource, } from "@lodestar/state-transition"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {Logger, toRootHex} from "@lodestar/utils"; @@ -145,7 +146,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { */ async getState( stateRoot: RootHex, - _rCaller: RegenCaller, + caller: RegenCaller, opts?: StateCloneOpts, // internal option, don't want to expose to external caller allowDiskReload = false @@ -156,6 +157,13 @@ export class StateRegenerator implements IStateRegeneratorInternal { return cachedStateCtx; } + // in block gossip validation (getPreState() call), dontTransferCache is specified as true because we only want to transfer cache in verifyBlocksStateTransitionOnly() + // but here we want to process blocks as fast as possible so force to transfer cache in this case + if (opts && allowDiskReload) { + // if there is no `opts` specified, it already means "false" + opts.dontTransferCache = false; + } + // Otherwise we have to use the fork choice to traverse backwards, block by block, // searching the state caches // then replay blocks forward to the desired stateRoot @@ -166,6 +174,8 @@ export class StateRegenerator implements IStateRegeneratorInternal { const blocksToReplay = [block]; let state: CachedBeaconStateAllForks | null = null; const {checkpointStateCache} = this.modules; + + const getSeedStateTimer = this.modules.metrics?.regenGetState.getSeedState.startTimer({caller}); // iterateAncestorBlocks only returns ancestor blocks, not the block itself for (const b of this.modules.forkChoice.iterateAncestorBlocks(block.blockRoot)) { state = this.modules.blockStateCache.get(b.stateRoot, opts); @@ -181,6 +191,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { } blocksToReplay.push(b); } + getSeedStateTimer?.(); if (state === null) { throw new RegenError({ @@ -188,19 +199,50 @@ export class StateRegenerator implements IStateRegeneratorInternal { }); } + const blockCount = blocksToReplay.length; const MAX_EPOCH_TO_PROCESS = 5; - if (blocksToReplay.length > MAX_EPOCH_TO_PROCESS * SLOTS_PER_EPOCH) { + if (blockCount > MAX_EPOCH_TO_PROCESS * SLOTS_PER_EPOCH) { throw new RegenError({ code: RegenErrorCode.TOO_MANY_BLOCK_PROCESSED, stateRoot, }); } - const replaySlots = blocksToReplay.map((b) => b.slot).join(","); - this.modules.logger.debug("Replaying blocks to get state", {stateRoot, replaySlots}); - for (const b of blocksToReplay.reverse()) { - const block = await this.modules.db.block.get(fromHexString(b.blockRoot)); - if (!block) { + this.modules.metrics?.regenGetState.blockCount.observe({caller}, blockCount); + + const replaySlots = new Array(blockCount); + const blockPromises = new Array>(blockCount); + + const protoBlocksAsc = blocksToReplay.reverse(); + for (const [i, protoBlock] of protoBlocksAsc.entries()) { + replaySlots[i] = protoBlock.slot; + blockPromises[i] = this.modules.db.block.get(fromHexString(protoBlock.blockRoot)); + } + + const logCtx = {stateRoot, replaySlots: replaySlots.join(",")}; + this.modules.logger.debug("Replaying blocks to get state", logCtx); + + const loadBlocksTimer = this.modules.metrics?.regenGetState.loadBlocks.startTimer({caller}); + const blockOrNulls = await Promise.all(blockPromises); + loadBlocksTimer?.(); + + const blocksByRoot = new Map(); + for (const [i, blockOrNull] of blockOrNulls.entries()) { + // checking early here helps prevent unneccessary state transition below + if (blockOrNull === null) { + throw new RegenError({ + code: RegenErrorCode.BLOCK_NOT_IN_DB, + blockRoot: protoBlocksAsc[i].blockRoot, + }); + } + blocksByRoot.set(protoBlocksAsc[i].blockRoot, blockOrNull); + } + + const stateTransitionTimer = this.modules.metrics?.regenGetState.stateTransition.startTimer({caller}); + for (const b of protoBlocksAsc) { + const block = blocksByRoot.get(b.blockRoot); + // just to make compiler happy, we checked in the above for loop already + if (block === undefined) { throw new RegenError({ code: RegenErrorCode.BLOCK_NOT_IN_DB, blockRoot: b.blockRoot, @@ -224,7 +266,12 @@ export class StateRegenerator implements IStateRegeneratorInternal { this.modules.metrics ); + const hashTreeRootTimer = this.modules.metrics?.stateHashTreeRootTime.startTimer({ + source: StateHashTreeRootSource.regenState, + }); const stateRoot = toRootHex(state.hashTreeRoot()); + hashTreeRootTimer?.(); + if (b.stateRoot !== stateRoot) { throw new RegenError({ slot: b.slot, @@ -238,9 +285,6 @@ export class StateRegenerator implements IStateRegeneratorInternal { // also with allowDiskReload flag, we "reload" it to the state cache too this.modules.blockStateCache.add(state); } - - // this avoids keeping our node busy processing blocks - await nextEventLoop(); } catch (e) { throw new RegenError({ code: RegenErrorCode.STATE_TRANSITION_ERROR, @@ -248,7 +292,9 @@ export class StateRegenerator implements IStateRegeneratorInternal { }); } } - this.modules.logger.debug("Replayed blocks to get state", {stateRoot, replaySlots}); + stateTransitionTimer?.(); + + this.modules.logger.debug("Replayed blocks to get state", {...logCtx, stateSlot: state.slot}); return state; } diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index b315beba46d9..823f066abcd6 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -229,6 +229,10 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { newCachedState.commit(); const stateRoot = toRootHex(newCachedState.hashTreeRoot()); timer?.(); + + // load all cache in order for consumers (usually regen.getState()) to process blocks faster + newCachedState.validators.getAllReadonlyValues(); + newCachedState.balances.getAll(); this.logger.debug("Reload: cached state load successful", { ...logMeta, stateSlot: newCachedState.slot, diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index a0cf0a185c2f..55d43922d936 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -1413,6 +1413,34 @@ export function createLodestarMetrics( help: "UnhandledPromiseRejection total count", }), + // regen.getState metrics + regenGetState: { + blockCount: register.histogram<{caller: RegenCaller}>({ + name: "lodestar_regen_get_state_block_count", + help: "Block count in regen.getState", + labelNames: ["caller"], + buckets: [4, 8, 16, 32, 64], + }), + getSeedState: register.histogram<{caller: RegenCaller}>({ + name: "lodestar_regen_get_state_get_seed_state_seconds", + help: "Duration of get seed state in regen.getState", + labelNames: ["caller"], + buckets: [0.1, 0.5, 1, 2, 3, 4], + }), + loadBlocks: register.histogram<{caller: RegenCaller}>({ + name: "lodestar_regen_get_state_load_blocks_seconds", + help: "Duration of load blocks in regen.getState", + labelNames: ["caller"], + buckets: [0.1, 0.5, 1, 2, 3, 4], + }), + stateTransition: register.histogram<{caller: RegenCaller}>({ + name: "lodestar_regen_get_state_state_transition_seconds", + help: "Duration of state transition in regen.getState", + labelNames: ["caller"], + buckets: [0.1, 0.5, 1, 2, 3, 4], + }), + }, + // Precompute next epoch transition precomputeNextEpochTransition: { count: register.counter<{result: string}>({ diff --git a/packages/state-transition/src/stateTransition.ts b/packages/state-transition/src/stateTransition.ts index 40e87c8d07d2..3b97f19282a4 100644 --- a/packages/state-transition/src/stateTransition.ts +++ b/packages/state-transition/src/stateTransition.ts @@ -54,6 +54,7 @@ export enum StateHashTreeRootSource { blockTransition = "block_transition", prepareNextSlot = "prepare_next_slot", prepareNextEpoch = "prepare_next_epoch", + regenState = "regen_state", computeNewStateRoot = "compute_new_state_root", } From fe6c4acbfcc6ee3027b1c4833706b415417e448e Mon Sep 17 00:00:00 2001 From: twoeths Date: Thu, 5 Sep 2024 08:34:43 +0700 Subject: [PATCH 091/259] feat: archive state using BufferPool if provided (#7042) * fix: archive state using BufferPool if provided * chore: fix comment --- .../src/chain/archiver/archiveStates.ts | 14 ++++- .../beacon-node/src/chain/archiver/index.ts | 2 +- packages/beacon-node/src/chain/chain.ts | 6 +- packages/beacon-node/src/chain/interface.ts | 2 + .../beacon-node/src/chain/serializeState.ts | 33 +++++++++++ .../stateCache/persistentCheckpointsCache.ts | 59 ++++++------------- .../src/metrics/metrics/lodestar.ts | 11 ++-- packages/beacon-node/src/util/bufferPool.ts | 20 ++++--- .../test/unit/util/bufferPool.test.ts | 10 ++-- 9 files changed, 94 insertions(+), 63 deletions(-) create mode 100644 packages/beacon-node/src/chain/serializeState.ts diff --git a/packages/beacon-node/src/chain/archiver/archiveStates.ts b/packages/beacon-node/src/chain/archiver/archiveStates.ts index 2231cd3ff513..53f2033d80e8 100644 --- a/packages/beacon-node/src/chain/archiver/archiveStates.ts +++ b/packages/beacon-node/src/chain/archiver/archiveStates.ts @@ -6,6 +6,8 @@ import {CheckpointWithHex} from "@lodestar/fork-choice"; import {IBeaconDb} from "../../db/index.js"; import {IStateRegenerator} from "../regen/interface.js"; import {getStateSlotFromBytes} from "../../util/multifork.js"; +import {serializeState} from "../serializeState.js"; +import {AllocSource, BufferPool} from "../../util/bufferPool.js"; /** * Minimum number of epochs between single temp archived states @@ -30,7 +32,8 @@ export class StatesArchiver { private readonly regen: IStateRegenerator, private readonly db: IBeaconDb, private readonly logger: Logger, - private readonly opts: StatesArchiverOpts + private readonly opts: StatesArchiverOpts, + private readonly bufferPool?: BufferPool | null ) {} /** @@ -95,8 +98,13 @@ export class StatesArchiver { await this.db.stateArchive.putBinary(slot, finalizedStateOrBytes); this.logger.verbose("Archived finalized state bytes", {epoch: finalized.epoch, slot, root: rootHex}); } else { - // state - await this.db.stateArchive.put(finalizedStateOrBytes.slot, finalizedStateOrBytes); + // serialize state using BufferPool if provided + await serializeState( + finalizedStateOrBytes, + AllocSource.ARCHIVE_STATE, + (stateBytes) => this.db.stateArchive.putBinary(finalizedStateOrBytes.slot, stateBytes), + this.bufferPool + ); // don't delete states before the finalized state, auto-prune will take care of it this.logger.verbose("Archived finalized state", { epoch: finalized.epoch, diff --git a/packages/beacon-node/src/chain/archiver/index.ts b/packages/beacon-node/src/chain/archiver/index.ts index ee0711e05e4b..294c2281e19b 100644 --- a/packages/beacon-node/src/chain/archiver/index.ts +++ b/packages/beacon-node/src/chain/archiver/index.ts @@ -48,7 +48,7 @@ export class Archiver { opts: ArchiverOpts ) { this.archiveBlobEpochs = opts.archiveBlobEpochs; - this.statesArchiver = new StatesArchiver(chain.regen, db, logger, opts); + this.statesArchiver = new StatesArchiver(chain.regen, db, logger, opts, chain.bufferPool); this.prevFinalized = chain.forkChoice.getFinalizedCheckpoint(); this.jobQueue = new JobItemQueue<[CheckpointWithHex], void>(this.processFinalizedCheckpoint, { maxLength: PROCESS_FINALIZED_CHECKPOINT_QUEUE_LEN, diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index b410a1e84655..8dbb49798538 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -119,6 +119,7 @@ export class BeaconChain implements IBeaconChain { readonly config: BeaconConfig; readonly logger: Logger; readonly metrics: Metrics | null; + readonly bufferPool: BufferPool | null; readonly anchorStateLatestBlockSlot: Slot; @@ -272,6 +273,9 @@ export class BeaconChain implements IBeaconChain { const blockStateCache = this.opts.nHistoricalStates ? new FIFOBlockStateCache(this.opts, {metrics}) : new BlockStateCacheImpl({metrics}); + this.bufferPool = this.opts.nHistoricalStates + ? new BufferPool(anchorState.type.tree_serializedSize(anchorState.node), metrics) + : null; const checkpointStateCache = this.opts.nHistoricalStates ? new PersistentCheckpointStateCache( { @@ -280,7 +284,7 @@ export class BeaconChain implements IBeaconChain { clock, shufflingCache: this.shufflingCache, blockStateCache, - bufferPool: new BufferPool(anchorState.type.tree_serializedSize(anchorState.node), metrics), + bufferPool: this.bufferPool, datastore: fileDataStore ? // debug option if we want to investigate any issues with the DB new FileCPStateDatastore() diff --git a/packages/beacon-node/src/chain/interface.ts b/packages/beacon-node/src/chain/interface.ts index ca13dc604ea0..5185662eaa4f 100644 --- a/packages/beacon-node/src/chain/interface.ts +++ b/packages/beacon-node/src/chain/interface.ts @@ -30,6 +30,7 @@ import {IEth1ForBlockProduction} from "../eth1/index.js"; import {IExecutionEngine, IExecutionBuilder} from "../execution/index.js"; import {Metrics} from "../metrics/metrics.js"; import {IClock} from "../util/clock.js"; +import {BufferPool} from "../util/bufferPool.js"; import {ChainEventEmitter} from "./emitter.js"; import {IStateRegenerator, RegenCaller} from "./regen/index.js"; import {IBlsVerifier} from "./bls/index.js"; @@ -86,6 +87,7 @@ export interface IBeaconChain { readonly config: BeaconConfig; readonly logger: Logger; readonly metrics: Metrics | null; + readonly bufferPool: BufferPool | null; /** The initial slot that the chain is started with */ readonly anchorStateLatestBlockSlot: Slot; diff --git a/packages/beacon-node/src/chain/serializeState.ts b/packages/beacon-node/src/chain/serializeState.ts new file mode 100644 index 000000000000..cbb2ecd18cff --- /dev/null +++ b/packages/beacon-node/src/chain/serializeState.ts @@ -0,0 +1,33 @@ +import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import {AllocSource, BufferPool} from "../util/bufferPool.js"; + +type ProcessStateBytesFn = (stateBytes: Uint8Array) => Promise; + +/* + * Serialize state using the BufferPool if provided. + */ +export async function serializeState( + state: CachedBeaconStateAllForks, + source: AllocSource, + processFn: ProcessStateBytesFn, + bufferPool?: BufferPool | null +): Promise { + const size = state.type.tree_serializedSize(state.node); + let stateBytes: Uint8Array | null = null; + if (bufferPool) { + const bufferWithKey = bufferPool.alloc(size, source); + if (bufferWithKey) { + stateBytes = bufferWithKey.buffer; + const dataView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength); + state.serializeToBytes({uint8Array: stateBytes, dataView}, 0); + } + } + + if (!stateBytes) { + // we already have metrics in BufferPool so no need to do it here + stateBytes = state.serialize(); + } + + return processFn(stateBytes); + // release the buffer back to the pool automatically +} diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 823f066abcd6..190b79e58cd6 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -8,8 +8,9 @@ import {INTERVALS_PER_SLOT} from "@lodestar/params"; import {Metrics} from "../../metrics/index.js"; import {IClock} from "../../util/clock.js"; import {ShufflingCache} from "../shufflingCache.js"; -import {BufferPool, BufferWithKey} from "../../util/bufferPool.js"; +import {AllocSource, BufferPool, BufferWithKey} from "../../util/bufferPool.js"; import {StateCloneOpts} from "../regen/interface.js"; +import {serializeState} from "../serializeState.js"; import {MapTracker} from "./mapMetrics.js"; import {CPStateDatastore, DatastoreKey, datastoreKeyToCheckpoint} from "./datastore/index.js"; import {CheckpointHex, CacheItemType, CheckpointStateCache, BlockStateCache} from "./types.js"; @@ -29,7 +30,7 @@ type PersistentCheckpointStateCacheModules = { shufflingCache: ShufflingCache; datastore: CPStateDatastore; blockStateCache: BlockStateCache; - bufferPool?: BufferPool; + bufferPool?: BufferPool | null; }; /** checkpoint serialized as a string */ @@ -106,7 +107,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { private readonly datastore: CPStateDatastore; private readonly shufflingCache: ShufflingCache; private readonly blockStateCache: BlockStateCache; - private readonly bufferPool?: BufferPool; + private readonly bufferPool?: BufferPool | null; constructor( { @@ -698,19 +699,20 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { // persist and do not update epochIndex this.metrics?.statePersistSecFromSlot.observe(this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0); const cpPersist = {epoch: epoch, root: fromHexString(rootHex)}; - { - const timer = this.metrics?.stateSerializeDuration.startTimer(); - // automatically free the buffer pool after this scope - using stateBytesWithKey = this.serializeState(state); - let stateBytes = stateBytesWithKey?.buffer; - if (stateBytes == null) { - // fallback logic to use regular way to get state ssz bytes - this.metrics?.persistedStateAllocCount.inc(); - stateBytes = state.serialize(); - } - timer?.(); - persistedKey = await this.datastore.write(cpPersist, stateBytes); - } + // It's not sustainable to allocate ~240MB for each state every epoch, so we use buffer pool to reuse the memory. + // As monitored on holesky as of Jan 2024: + // - This does not increase heap allocation while gc time is the same + // - It helps stabilize persist time and save ~300ms in average (1.5s vs 1.2s) + // - It also helps the state reload to save ~500ms in average (4.3s vs 3.8s) + // - Also `serializeState.test.ts` perf test shows a lot of differences allocating ~240MB once vs per state serialization + const timer = this.metrics?.stateSerializeDuration.startTimer(); + persistedKey = await serializeState( + state, + AllocSource.PERSISTENT_CHECKPOINTS_CACHE_STATE, + (stateBytes) => this.datastore.write(cpPersist, stateBytes), + this.bufferPool + ); + timer?.(); persistCount++; this.logger.verbose("Pruned checkpoint state from memory and persisted to disk", { ...logMeta, @@ -767,29 +769,6 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { }); } - /* - * It's not sustainable to allocate ~240MB for each state every epoch, so we use buffer pool to reuse the memory. - * As monitored on holesky as of Jan 2024: - * - This does not increase heap allocation while gc time is the same - * - It helps stabilize persist time and save ~300ms in average (1.5s vs 1.2s) - * - It also helps the state reload to save ~500ms in average (4.3s vs 3.8s) - * - Also `serializeState.test.ts` perf test shows a lot of differences allocating ~240MB once vs per state serialization - */ - private serializeState(state: CachedBeaconStateAllForks): BufferWithKey | null { - const size = state.type.tree_serializedSize(state.node); - if (this.bufferPool) { - const bufferWithKey = this.bufferPool.alloc(size); - if (bufferWithKey) { - const stateBytes = bufferWithKey.buffer; - const dataView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength); - state.serializeToBytes({uint8Array: stateBytes, dataView}, 0); - return bufferWithKey; - } - } - - return null; - } - /** * Serialize validators to bytes leveraging the buffer pool to save memory allocation. * - As monitored on holesky as of Jan 2024, it helps save ~500ms state reload time (4.3s vs 3.8s) @@ -800,7 +779,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { const type = state.type.fields.validators; const size = type.tree_serializedSize(state.validators.node); if (this.bufferPool) { - const bufferWithKey = this.bufferPool.alloc(size); + const bufferWithKey = this.bufferPool.alloc(size, AllocSource.PERSISTENT_CHECKPOINTS_CACHE_VALIDATORS); if (bufferWithKey) { const validatorsBytes = bufferWithKey.buffer; const dataView = new DataView(validatorsBytes.buffer, validatorsBytes.byteOffset, validatorsBytes.byteLength); diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index 55d43922d936..737a900e5f64 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -18,6 +18,7 @@ import {LodestarMetadata} from "../options.js"; import {RegistryMetricCreator} from "../utils/registryMetricCreator.js"; import {OpSource} from "../validatorMonitor.js"; import {CacheItemType} from "../../chain/stateCache/types.js"; +import {AllocSource} from "../../util/bufferPool.js"; export type LodestarMetrics = ReturnType; @@ -1165,13 +1166,15 @@ export function createLodestarMetrics( name: "lodestar_buffer_pool_length", help: "Buffer pool length", }), - hits: register.counter({ + hits: register.counter<{source: AllocSource}>({ name: "lodestar_buffer_pool_hits_total", help: "Total number of buffer pool hits", + labelNames: ["source"], }), - misses: register.counter({ + misses: register.counter<{source: AllocSource}>({ name: "lodestar_buffer_pool_misses_total", help: "Total number of buffer pool misses", + labelNames: ["source"], }), grows: register.counter({ name: "lodestar_buffer_pool_grows_total", @@ -1271,10 +1274,6 @@ export function createLodestarMetrics( name: "lodestar_cp_state_cache_persisted_state_remove_count", help: "Total number of persisted states removed", }), - persistedStateAllocCount: register.counter({ - name: "lodestar_cp_state_cache_persisted_state_alloc_count", - help: "Total number time to allocate memory for persisted state", - }), }, balancesCache: { diff --git a/packages/beacon-node/src/util/bufferPool.ts b/packages/beacon-node/src/util/bufferPool.ts index f9e18a6d64a5..e3cf10fa88b3 100644 --- a/packages/beacon-node/src/util/bufferPool.ts +++ b/packages/beacon-node/src/util/bufferPool.ts @@ -5,6 +5,12 @@ import {Metrics} from "../metrics/metrics.js"; */ const GROW_RATIO = 1.1; +export enum AllocSource { + PERSISTENT_CHECKPOINTS_CACHE_VALIDATORS = "persistent_checkpoints_cache_validators", + PERSISTENT_CHECKPOINTS_CACHE_STATE = "persistent_checkpoints_cache_state", + ARCHIVE_STATE = "archive_state", +} + /** * A simple implementation to manage a single buffer. * This is initially used for state serialization at every epoch and for state reload. @@ -36,24 +42,24 @@ export class BufferPool { * If the buffer is already in use, return null. * Grow the buffer if the requested size is larger than the current buffer. */ - alloc(size: number): BufferWithKey | null { - return this.doAlloc(size, false); + alloc(size: number, source: AllocSource): BufferWithKey | null { + return this.doAlloc(size, source, false); } /** * Same to alloc() but the buffer is not zeroed. */ - allocUnsafe(size: number): BufferWithKey | null { - return this.doAlloc(size, true); + allocUnsafe(size: number, source: AllocSource): BufferWithKey | null { + return this.doAlloc(size, source, true); } - private doAlloc(size: number, isUnsafe = false): BufferWithKey | null { + private doAlloc(size: number, source: AllocSource, isUnsafe = false): BufferWithKey | null { if (this.inUse) { - this.metrics?.misses.inc(); + this.metrics?.misses.inc({source}); return null; } this.inUse = true; - this.metrics?.hits.inc(); + this.metrics?.hits.inc({source}); this.currentKey += 1; if (size > this.buffer.length) { this.metrics?.grows.inc(); diff --git a/packages/beacon-node/test/unit/util/bufferPool.test.ts b/packages/beacon-node/test/unit/util/bufferPool.test.ts index 2c789c19f74d..ff66504ae65f 100644 --- a/packages/beacon-node/test/unit/util/bufferPool.test.ts +++ b/packages/beacon-node/test/unit/util/bufferPool.test.ts @@ -1,12 +1,12 @@ import {describe, it, expect} from "vitest"; -import {BufferPool} from "../../../src/util/bufferPool.js"; +import {AllocSource, BufferPool} from "../../../src/util/bufferPool.js"; describe("BufferPool", () => { const pool = new BufferPool(100); it("should increase length", () => { expect(pool.length).toEqual(110); - using mem = pool.alloc(200); + using mem = pool.alloc(200, AllocSource.PERSISTENT_CHECKPOINTS_CACHE_STATE); if (mem === null) { throw Error("Expected non-null mem"); } @@ -15,15 +15,15 @@ describe("BufferPool", () => { it("should not allow alloc if in use", () => { { - using mem = pool.alloc(20); + using mem = pool.alloc(20, AllocSource.PERSISTENT_CHECKPOINTS_CACHE_STATE); if (mem === null) { throw Error("Expected non-null mem"); } // in the same scope we can't allocate again - expect(pool.alloc(20)).toEqual(null); + expect(pool.alloc(20, AllocSource.PERSISTENT_CHECKPOINTS_CACHE_STATE)).toEqual(null); } // out of the scope we can allocate again - expect(pool.alloc(20)).not.toEqual(null); + expect(pool.alloc(20, AllocSource.PERSISTENT_CHECKPOINTS_CACHE_STATE)).not.toEqual(null); }); }); From b05c93e1471083d10fefda20c11514fd3afe94df Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 5 Sep 2024 02:35:10 +0100 Subject: [PATCH 092/259] feat: include more details in validator attestation logs (#7064) --- packages/validator/src/services/attestation.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index fc43b603c6b2..927bd3d92bb4 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -2,7 +2,7 @@ import {toHexString} from "@chainsafe/ssz"; import {BLSSignature, phase0, Slot, ssz, Attestation, SignedAggregateAndProof} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import {computeEpochAtSlot, isAggregatorFromCommitteeLength} from "@lodestar/state-transition"; -import {sleep} from "@lodestar/utils"; +import {prettyBytes, sleep} from "@lodestar/utils"; import {ApiClient, routes} from "@lodestar/api"; import {ChainForkConfig} from "@lodestar/config"; import {IClock, LoggerVc} from "../util/index.js"; @@ -242,7 +242,11 @@ export class AttestationService { } else { (await this.api.beacon.submitPoolAttestations({signedAttestations})).assertOk(); } - this.logger.info("Published attestations", {...logCtx, count: signedAttestations.length}); + this.logger.info("Published attestations", { + ...logCtx, + head: prettyBytes(headRootHex), + count: signedAttestations.length, + }); this.metrics?.publishedAttestations.inc(signedAttestations.length); } catch (e) { // Note: metric counts only 1 since we don't know how many signedAttestations are invalid @@ -286,7 +290,8 @@ export class AttestationService { slot: attestation.slot, }); const aggregate = res.value(); - this.metrics?.numParticipantsInAggregate.observe(aggregate.aggregationBits.getTrueBitIndexes().length); + const participants = aggregate.aggregationBits.getTrueBitIndexes().length; + this.metrics?.numParticipantsInAggregate.observe(participants); const signedAggregateAndProofs: SignedAggregateAndProof[] = []; @@ -316,7 +321,11 @@ export class AttestationService { } else { (await this.api.validator.publishAggregateAndProofs({signedAggregateAndProofs})).assertOk(); } - this.logger.info("Published aggregateAndProofs", {...logCtx, count: signedAggregateAndProofs.length}); + this.logger.info("Published aggregateAndProofs", { + ...logCtx, + participants, + count: signedAggregateAndProofs.length, + }); this.metrics?.publishedAggregates.inc(signedAggregateAndProofs.length); } catch (e) { this.logger.error("Error publishing aggregateAndProofs", logCtx, e as Error); From 0e79d29720185e180ff684162ffba188313e8df2 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:35:40 -0700 Subject: [PATCH 093/259] feat: rename getValidatorMaxEffectiveBalance (#7070) * Rename getValidatorMaxEffectiveBalance * Lint --- packages/state-transition/src/block/processWithdrawals.ts | 5 ++--- packages/state-transition/src/util/genesis.ts | 4 ++-- packages/state-transition/src/util/validator.ts | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/state-transition/src/block/processWithdrawals.ts b/packages/state-transition/src/block/processWithdrawals.ts index 185ddd80eb32..d4dfd47b4d94 100644 --- a/packages/state-transition/src/block/processWithdrawals.ts +++ b/packages/state-transition/src/block/processWithdrawals.ts @@ -14,7 +14,7 @@ import {toRootHex} from "@lodestar/utils"; import {CachedBeaconStateCapella, CachedBeaconStateElectra} from "../types.js"; import { decreaseBalance, - getValidatorMaxEffectiveBalance, + getMaxEffectiveBalance, hasEth1WithdrawalCredential, hasExecutionWithdrawalCredential, isCapellaPayloadHeader, @@ -173,8 +173,7 @@ export function getExpectedWithdrawals( }); withdrawalIndex++; } else if ( - effectiveBalance === - (isPostElectra ? getValidatorMaxEffectiveBalance(withdrawalCredentials) : MAX_EFFECTIVE_BALANCE) && + effectiveBalance === (isPostElectra ? getMaxEffectiveBalance(withdrawalCredentials) : MAX_EFFECTIVE_BALANCE) && balance > effectiveBalance ) { // capella partial withdrawal diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 02bcef00bb55..54507d0ef235 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -18,7 +18,7 @@ import {EpochCacheImmutableData} from "../cache/epochCache.js"; import {processDeposit} from "../block/processDeposit.js"; import {increaseBalance} from "../index.js"; import {computeEpochAtSlot} from "./epoch.js"; -import {getActiveValidatorIndices, getValidatorMaxEffectiveBalance} from "./validator.js"; +import {getActiveValidatorIndices, getMaxEffectiveBalance} from "./validator.js"; import {getTemporaryBlockHeader} from "./blockRoot.js"; import {newFilledArray} from "./array.js"; import {getNextSyncCommittee} from "./syncCommittee.js"; @@ -195,7 +195,7 @@ export function applyDeposits( const balance = balancesArr[i]; const effectiveBalance = Math.min( balance - (balance % EFFECTIVE_BALANCE_INCREMENT), - getValidatorMaxEffectiveBalance(validator.withdrawalCredentials) + getMaxEffectiveBalance(validator.withdrawalCredentials) ); validator.effectiveBalance = effectiveBalance; diff --git a/packages/state-transition/src/util/validator.ts b/packages/state-transition/src/util/validator.ts index 728f14587fde..ebad21d9d25c 100644 --- a/packages/state-transition/src/util/validator.ts +++ b/packages/state-transition/src/util/validator.ts @@ -75,7 +75,7 @@ export function getConsolidationChurnLimit(epochCtx: EpochCache): number { return getBalanceChurnLimit(epochCtx) - getActivationExitChurnLimit(epochCtx); } -export function getValidatorMaxEffectiveBalance(withdrawalCredentials: Uint8Array): number { +export function getMaxEffectiveBalance(withdrawalCredentials: Uint8Array): number { // Compounding withdrawal credential only available since Electra if (hasCompoundingWithdrawalCredential(withdrawalCredentials)) { return MAX_EFFECTIVE_BALANCE_ELECTRA; @@ -85,7 +85,7 @@ export function getValidatorMaxEffectiveBalance(withdrawalCredentials: Uint8Arra } export function getActiveBalance(state: CachedBeaconStateElectra, validatorIndex: ValidatorIndex): number { - const validatorMaxEffectiveBalance = getValidatorMaxEffectiveBalance( + const validatorMaxEffectiveBalance = getMaxEffectiveBalance( state.validators.getReadonly(validatorIndex).withdrawalCredentials ); From cbc00c7c16384fe9de82e6f4670792245efd0452 Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Mon, 9 Sep 2024 17:37:50 -0400 Subject: [PATCH 094/259] feat: add util to diff ssz objects (#7041) --- packages/utils/src/diff.ts | 232 ++++++++++++++++++++++++++++++++++++ packages/utils/src/index.ts | 1 + 2 files changed, 233 insertions(+) create mode 100644 packages/utils/src/diff.ts diff --git a/packages/utils/src/diff.ts b/packages/utils/src/diff.ts new file mode 100644 index 000000000000..204989016b46 --- /dev/null +++ b/packages/utils/src/diff.ts @@ -0,0 +1,232 @@ +/* eslint-disable no-console */ +import fs from "node:fs"; + +const primitiveTypeof = ["number", "string", "bigint", "boolean"]; +export type BufferType = Uint8Array | Uint32Array; +export type PrimitiveType = number | string | bigint | boolean | BufferType; +export type DiffableCollection = Record; +export type Diffable = PrimitiveType | Array | DiffableCollection; + +export interface Diff { + objectPath: string; + errorMessage?: string; + val1: Diffable; + val2: Diffable; +} + +export function diffUint8Array(val1: Uint8Array, val2: PrimitiveType, objectPath: string): Diff[] { + if (!(val2 instanceof Uint8Array)) { + return [ + { + objectPath, + errorMessage: `val1${objectPath} is a Uint8Array, but val2${objectPath} is not`, + val1, + val2, + }, + ]; + } + const hex1 = Buffer.from(val1).toString("hex"); + const hex2 = Buffer.from(val2).toString("hex"); + if (hex1 !== hex2) { + return [ + { + objectPath, + val1: `0x${hex1}`, + val2: `0x${hex2}`, + }, + ]; + } + return []; +} + +export function diffUint32Array(val1: Uint32Array, val2: PrimitiveType, objectPath: string): Diff[] { + if (!(val2 instanceof Uint32Array)) { + return [ + { + objectPath, + errorMessage: `val1${objectPath} is a Uint32Array, but val2${objectPath} is not`, + val1, + val2, + }, + ]; + } + const diffs: Diff[] = []; + val1.forEach((value, index) => { + const value2 = val2[index]; + if (value !== value2) { + diffs.push({ + objectPath: `${objectPath}[${index}]`, + val1: `0x${value.toString(16).padStart(8, "0")}`, + val2: value2 ? `0x${val2[index].toString(16).padStart(8, "0")}` : "undefined", + }); + } + }); + return diffs; +} + +function diffPrimitiveValue(val1: PrimitiveType, val2: PrimitiveType, objectPath: string): Diff[] { + if (val1 instanceof Uint8Array) { + return diffUint8Array(val1, val2, objectPath); + } + if (val1 instanceof Uint32Array) { + return diffUint32Array(val1, val2, objectPath); + } + + const diff = {objectPath, val1, val2} as Diff; + const type1 = typeof val1; + if (!primitiveTypeof.includes(type1)) { + diff.errorMessage = `val1${objectPath} is not a supported type`; + } + const type2 = typeof val2; + if (!primitiveTypeof.includes(type2)) { + diff.errorMessage = `val2${objectPath} is not a supported type`; + } + if (type1 !== type2) { + diff.errorMessage = `val1${objectPath} is not the same type as val2${objectPath}`; + } + if (val1 !== val2) { + return [diff]; + } + return []; +} + +function isPrimitiveValue(val: unknown): val is PrimitiveType { + if (Array.isArray(val)) return false; + if (typeof val === "object") { + return val instanceof Uint8Array || val instanceof Uint32Array; + } + return true; +} + +function isDiffable(val: unknown): val is Diffable { + return !(typeof val === "function" || typeof val === "symbol" || typeof val === "undefined" || val === null); +} + +export function getDiffs(val1: Diffable, val2: Diffable, objectPath: string): Diff[] { + if (isPrimitiveValue(val1)) { + if (!isPrimitiveValue(val2)) { + return [ + { + objectPath, + errorMessage: `val1${objectPath} is a primitive value and val2${objectPath} is not`, + val1, + val2, + }, + ]; + } + return diffPrimitiveValue(val1, val2, objectPath); + } + + const isArray = Array.isArray(val1); + let errorMessage: string | undefined; + if (isArray && !Array.isArray(val2)) { + errorMessage = `val1${objectPath} is an array and val2${objectPath} is not`; + } else if (typeof val1 === "object" && typeof val2 !== "object") { + errorMessage = `val1${objectPath} is a nested object and val2${objectPath} is not`; + } + if (errorMessage) { + return [ + { + objectPath, + errorMessage, + val1, + val2, + }, + ]; + } + + const diffs: Diff[] = []; + for (const [index, value] of Object.entries(val1)) { + if (!isDiffable(value)) { + diffs.push({objectPath, val1, val2, errorMessage: `val1${objectPath} is not Diffable`}); + continue; + } + const value2 = (val2 as DiffableCollection)[index]; + if (!isDiffable(value2)) { + diffs.push({objectPath, val1, val2, errorMessage: `val2${objectPath} is not Diffable`}); + continue; + } + const innerPath = isArray ? `${objectPath}[${index}]` : `${objectPath}.${index}`; + diffs.push(...getDiffs(value, value2, innerPath)); + } + return diffs; +} + +/** + * Find the different values on complex, nested objects. Outputs the path through the object to + * each value that does not match from val1 and val2. Optionally can output the values that differ. + * + * For objects that differ greatly, can write to a file instead of the terminal for analysis + * + * ## Example + * ```ts + * const obj1 = { + * key1: { + * key2: [ + * { key3: 1 }, + * { key3: new Uint8Array([1, 2, 3]) } + * ] + * }, + * key4: new Uint32Array([1, 2, 3]), + * key5: 362436 + * }; + * + * const obj2 = { + * key1: { + * key2: [ + * { key3: 1 }, + * { key3: new Uint8Array([1, 2, 4]) } + * ] + * }, + * key4: new Uint32Array([1, 2, 4]) + * key5: true + * }; + * + * diffObjects(obj1, obj2, true); + * + * + * ``` + * + * ## Output + * ```sh + * val.key1.key2[1].key3 + * - 0x010203 + * - 0x010204 + * val.key4[2] + * - 0x00000003 + * - 0x00000004 + * val.key5 + * val1.key5 is not the same type as val2.key5 + * - 362436 + * - true + * ``` + */ +export function diff(val1: unknown, val2: unknown, outputValues = false, filename?: string): void { + if (!isDiffable(val1)) { + console.log("val1 is not Diffable"); + return; + } + if (!isDiffable(val2)) { + console.log("val2 is not Diffable"); + return; + } + const diffs = getDiffs(val1, val2, ""); + let output = ""; + if (diffs.length) { + diffs.forEach((diff) => { + let diffOutput = `value${diff.objectPath}`; + if (diff.errorMessage) { + diffOutput += `\n ${diff.errorMessage}`; + } + if (outputValues) { + diffOutput += `\n - ${diff.val1.toString()}\n - ${diff.val2.toString()}\n`; + } + output += `${diffOutput}\n`; + }); + if (filename) { + fs.writeFileSync(filename, output); + } else { + console.log(output); + } + } +} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 13ea1ffb7e69..4e0be0c592a1 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -4,6 +4,7 @@ export * from "./base64.js"; export * from "./bytes.js"; export * from "./bytes/index.js"; export * from "./command.js"; +export * from "./diff.js"; export * from "./err.js"; export * from "./errors.js"; export * from "./format.js"; From 6c1e335a5734bba7e38f160e26d134300eb7cee3 Mon Sep 17 00:00:00 2001 From: twoeths Date: Tue, 10 Sep 2024 15:11:07 +0700 Subject: [PATCH 095/259] fix: single state tree at start up (#7056) * feat: use db state to load ws state * feat: log state size * fix: rename initStateFromAnchorState to checkAndPersistAnchorState * fix: only persist anchor state if it's cp state * fix: avoid redundant anchor state serialization --- packages/beacon-node/src/chain/initState.ts | 18 ++-- packages/beacon-node/src/index.ts | 4 +- .../cli/src/cmds/beacon/initBeaconState.ts | 101 ++++++++++++------ packages/cli/src/networks/index.ts | 35 ++++-- packages/state-transition/src/util/index.ts | 1 + .../src/util/loadState/index.ts | 2 +- .../src/util/loadState/loadState.ts | 19 ++++ .../test/unit/util/loadState.test.ts | 40 +++++++ packages/utils/src/bytes.ts | 20 ++++ packages/utils/test/unit/bytes.test.ts | 32 +++++- 10 files changed, 222 insertions(+), 50 deletions(-) create mode 100644 packages/state-transition/test/unit/util/loadState.test.ts diff --git a/packages/beacon-node/src/chain/initState.ts b/packages/beacon-node/src/chain/initState.ts index 19f0f1cc959d..e413bdff0f7d 100644 --- a/packages/beacon-node/src/chain/initState.ts +++ b/packages/beacon-node/src/chain/initState.ts @@ -37,17 +37,18 @@ export async function persistGenesisResult( export async function persistAnchorState( config: ChainForkConfig, db: IBeaconDb, - anchorState: BeaconStateAllForks + anchorState: BeaconStateAllForks, + anchorStateBytes: Uint8Array ): Promise { if (anchorState.slot === GENESIS_SLOT) { const genesisBlock = createGenesisBlock(config, anchorState); await Promise.all([ db.blockArchive.add(genesisBlock), db.block.add(genesisBlock), - db.stateArchive.add(anchorState), + db.stateArchive.putBinary(anchorState.slot, anchorStateBytes), ]); } else { - await db.stateArchive.add(anchorState); + await db.stateArchive.putBinary(anchorState.slot, anchorStateBytes); } } @@ -154,16 +155,17 @@ export async function initStateFromDb( /** * Initialize and persist an anchor state (either weak subjectivity or genesis) */ -export async function initStateFromAnchorState( +export async function checkAndPersistAnchorState( config: ChainForkConfig, db: IBeaconDb, logger: Logger, anchorState: BeaconStateAllForks, + anchorStateBytes: Uint8Array, { isWithinWeakSubjectivityPeriod, isCheckpointState, }: {isWithinWeakSubjectivityPeriod: boolean; isCheckpointState: boolean} -): Promise { +): Promise { const expectedFork = config.getForkInfo(computeStartSlotAtEpoch(anchorState.fork.epoch)); const expectedForkVersion = toHex(expectedFork.version); const stateFork = toHex(anchorState.fork.currentVersion); @@ -191,9 +193,9 @@ export async function initStateFromAnchorState( logger.warn("Checkpoint sync recommended, please use --help to see checkpoint sync options"); } - await persistAnchorState(config, db, anchorState); - - return anchorState; + if (isCheckpointState || anchorState.slot === GENESIS_SLOT) { + await persistAnchorState(config, db, anchorState, anchorStateBytes); + } } export function initBeaconMetrics(metrics: Metrics, state: BeaconStateAllForks): void { diff --git a/packages/beacon-node/src/index.ts b/packages/beacon-node/src/index.ts index aa555a1ab0ca..723b56d0b488 100644 --- a/packages/beacon-node/src/index.ts +++ b/packages/beacon-node/src/index.ts @@ -1,4 +1,4 @@ -export {initStateFromAnchorState, initStateFromDb, initStateFromEth1} from "./chain/index.js"; +export {checkAndPersistAnchorState, initStateFromDb, initStateFromEth1} from "./chain/index.js"; export {BeaconDb, type IBeaconDb} from "./db/index.js"; export {Eth1Provider, type IEth1Provider} from "./eth1/index.js"; export {createNodeJsLibp2p, type NodeJsLibp2pOpts} from "./network/index.js"; @@ -20,4 +20,4 @@ export {RestApiServer} from "./api/rest/base.js"; export type {RestApiServerOpts, RestApiServerModules, RestApiServerMetrics} from "./api/rest/base.js"; // Export type util for CLI - TEMP move to lodestar-types eventually -export {getStateTypeFromBytes} from "./util/multifork.js"; +export {getStateTypeFromBytes, getStateSlotFromBytes} from "./util/multifork.js"; diff --git a/packages/cli/src/cmds/beacon/initBeaconState.ts b/packages/cli/src/cmds/beacon/initBeaconState.ts index c8c444778991..67b578e9fdb9 100644 --- a/packages/cli/src/cmds/beacon/initBeaconState.ts +++ b/packages/cli/src/cmds/beacon/initBeaconState.ts @@ -1,15 +1,17 @@ import {ssz} from "@lodestar/types"; import {createBeaconConfig, BeaconConfig, ChainForkConfig} from "@lodestar/config"; -import {Logger} from "@lodestar/utils"; +import {Logger, formatBytes} from "@lodestar/utils"; import { isWithinWeakSubjectivityPeriod, ensureWithinWeakSubjectivityPeriod, BeaconStateAllForks, + loadState, + loadStateAndValidators, } from "@lodestar/state-transition"; import { IBeaconDb, IBeaconNodeOptions, - initStateFromAnchorState, + checkAndPersistAnchorState, initStateFromEth1, getStateTypeFromBytes, } from "@lodestar/beacon-node"; @@ -25,19 +27,23 @@ import { } from "../../networks/index.js"; import {BeaconArgs} from "./options.js"; +type StateWithBytes = {state: BeaconStateAllForks; stateBytes: Uint8Array}; + async function initAndVerifyWeakSubjectivityState( config: BeaconConfig, db: IBeaconDb, logger: Logger, - store: BeaconStateAllForks, - wsState: BeaconStateAllForks, + dbStateBytes: StateWithBytes, + wsStateBytes: StateWithBytes, wsCheckpoint: Checkpoint, opts: {ignoreWeakSubjectivityCheck?: boolean} = {} ): Promise<{anchorState: BeaconStateAllForks; wsCheckpoint: Checkpoint}> { + const dbState = dbStateBytes.state; + const wsState = wsStateBytes.state; // Check if the store's state and wsState are compatible if ( - store.genesisTime !== wsState.genesisTime || - !ssz.Root.equals(store.genesisValidatorsRoot, wsState.genesisValidatorsRoot) + dbState.genesisTime !== wsState.genesisTime || + !ssz.Root.equals(dbState.genesisValidatorsRoot, wsState.genesisValidatorsRoot) ) { throw new Error( "Db state and checkpoint state are not compatible, either clear the db or verify your checkpoint source" @@ -45,12 +51,12 @@ async function initAndVerifyWeakSubjectivityState( } // Pick the state which is ahead as an anchor to initialize the beacon chain - let anchorState = wsState; + let anchorState = wsStateBytes; let anchorCheckpoint = wsCheckpoint; let isCheckpointState = true; - if (store.slot > wsState.slot) { - anchorState = store; - anchorCheckpoint = getCheckpointFromState(store); + if (dbState.slot > wsState.slot) { + anchorState = dbStateBytes; + anchorCheckpoint = getCheckpointFromState(dbState); isCheckpointState = false; logger.verbose( "Db state is ahead of the provided checkpoint state, using the db state to initialize the beacon chain" @@ -59,19 +65,19 @@ async function initAndVerifyWeakSubjectivityState( // Throw error unless user explicitly asked not to, in testnets can happen that wss period is too small // that even some epochs of non finalization can cause finalized checkpoint to be out of valid range - const wssCheck = wrapFnError(() => ensureWithinWeakSubjectivityPeriod(config, anchorState, anchorCheckpoint)); + const wssCheck = wrapFnError(() => ensureWithinWeakSubjectivityPeriod(config, anchorState.state, anchorCheckpoint)); const isWithinWeakSubjectivityPeriod = wssCheck.err === null; if (!isWithinWeakSubjectivityPeriod && !opts.ignoreWeakSubjectivityCheck) { throw wssCheck.err; } - anchorState = await initStateFromAnchorState(config, db, logger, anchorState, { + await checkAndPersistAnchorState(config, db, logger, anchorState.state, anchorState.stateBytes, { isWithinWeakSubjectivityPeriod, isCheckpointState, }); // Return the latest anchorState but still return original wsCheckpoint to validate in backfill - return {anchorState, wsCheckpoint}; + return {anchorState: anchorState.state, wsCheckpoint}; } /** @@ -96,8 +102,20 @@ export async function initBeaconState( } // fetch the latest state stored in the db which will be used in all cases, if it exists, either // i) used directly as the anchor state - // ii) used during verification of a weak subjectivity state, - const lastDbState = await db.stateArchive.lastValue(); + // ii) used to load and verify a weak subjectivity state, + const lastDbSlot = await db.stateArchive.lastKey(); + const stateBytes = lastDbSlot !== null ? await db.stateArchive.getBinary(lastDbSlot) : null; + let lastDbState: BeaconStateAllForks | null = null; + let lastDbValidatorsBytes: Uint8Array | null = null; + let lastDbStateWithBytes: StateWithBytes | null = null; + if (stateBytes) { + logger.verbose("Found the last archived state", {slot: lastDbSlot, size: formatBytes(stateBytes.length)}); + const {state, validatorsBytes} = loadStateAndValidators(chainForkConfig, stateBytes); + lastDbState = state; + lastDbValidatorsBytes = validatorsBytes; + lastDbStateWithBytes = {state, stateBytes: stateBytes}; + } + if (lastDbState) { const config = createBeaconConfig(chainForkConfig, lastDbState.genesisValidatorsRoot); const wssCheck = isWithinWeakSubjectivityPeriod(config, lastDbState, getCheckpointFromState(lastDbState)); @@ -107,7 +125,9 @@ export async function initBeaconState( // Forcing to sync from checkpoint is only recommended if node is taking too long to sync from last db state. // It is important to remind the user to remove this flag again unless it is absolutely necessary. if (wssCheck) { - logger.warn("Forced syncing from checkpoint even though db state is within weak subjectivity period"); + logger.warn( + `Forced syncing from checkpoint even though db state at slot ${lastDbState.slot} is within weak subjectivity period` + ); logger.warn("Please consider removing --forceCheckpointSync flag unless absolutely necessary"); } } else { @@ -115,11 +135,15 @@ export async function initBeaconState( // - if no checkpoint sync args provided, or // - the lastDbState is within weak subjectivity period: if ((!args.checkpointState && !args.checkpointSyncUrl) || wssCheck) { - const anchorState = await initStateFromAnchorState(config, db, logger, lastDbState, { + if (stateBytes === null) { + // this never happens + throw Error(`There is no stateBytes for the lastDbState at slot ${lastDbState.slot}`); + } + await checkAndPersistAnchorState(config, db, logger, lastDbState, stateBytes, { isWithinWeakSubjectivityPeriod: wssCheck, isCheckpointState: false, }); - return {anchorState}; + return {anchorState: lastDbState}; } } } @@ -127,7 +151,8 @@ export async function initBeaconState( // See if we can sync state using checkpoint sync args or else start from genesis if (args.checkpointState) { return readWSState( - lastDbState, + lastDbStateWithBytes, + lastDbValidatorsBytes, { checkpointState: args.checkpointState, wssCheckpoint: args.wssCheckpoint, @@ -139,7 +164,8 @@ export async function initBeaconState( ); } else if (args.checkpointSyncUrl) { return fetchWSStateFromBeaconApi( - lastDbState, + lastDbStateWithBytes, + lastDbValidatorsBytes, { checkpointSyncUrl: args.checkpointSyncUrl, wssCheckpoint: args.wssCheckpoint, @@ -153,10 +179,10 @@ export async function initBeaconState( const genesisStateFile = args.genesisStateFile || getGenesisFileUrl(args.network || defaultNetwork); if (genesisStateFile && !args.forceGenesis) { const stateBytes = await downloadOrLoadFile(genesisStateFile); - let anchorState = getStateTypeFromBytes(chainForkConfig, stateBytes).deserializeToViewDU(stateBytes); + const anchorState = getStateTypeFromBytes(chainForkConfig, stateBytes).deserializeToViewDU(stateBytes); const config = createBeaconConfig(chainForkConfig, anchorState.genesisValidatorsRoot); const wssCheck = isWithinWeakSubjectivityPeriod(config, anchorState, getCheckpointFromState(anchorState)); - anchorState = await initStateFromAnchorState(config, db, logger, anchorState, { + await checkAndPersistAnchorState(config, db, logger, anchorState, stateBytes, { isWithinWeakSubjectivityPeriod: wssCheck, isCheckpointState: true, }); @@ -170,7 +196,8 @@ export async function initBeaconState( } async function readWSState( - lastDbState: BeaconStateAllForks | null, + lastDbStateBytes: StateWithBytes | null, + lastDbValidatorsBytes: Uint8Array | null, wssOpts: {checkpointState: string; wssCheckpoint?: string; ignoreWeakSubjectivityCheck?: boolean}, chainForkConfig: ChainForkConfig, db: IBeaconDb, @@ -180,19 +207,28 @@ async function readWSState( // if a weak subjectivity checkpoint has been provided, it is used for additional verification // otherwise, the state itself is used for verification (not bad, because the trusted state has been explicitly provided) const {checkpointState, wssCheckpoint, ignoreWeakSubjectivityCheck} = wssOpts; + const lastDbState = lastDbStateBytes?.state ?? null; const stateBytes = await downloadOrLoadFile(checkpointState); - const wsState = getStateTypeFromBytes(chainForkConfig, stateBytes).deserializeToViewDU(stateBytes); + let wsState: BeaconStateAllForks; + if (lastDbState && lastDbValidatorsBytes) { + // use lastDbState to load wsState if possible to share the same state tree + wsState = loadState(chainForkConfig, lastDbState, stateBytes, lastDbValidatorsBytes).state; + } else { + wsState = getStateTypeFromBytes(chainForkConfig, stateBytes).deserializeToViewDU(stateBytes); + } const config = createBeaconConfig(chainForkConfig, wsState.genesisValidatorsRoot); - const store = lastDbState ?? wsState; + const wsStateBytes = {state: wsState, stateBytes}; + const store = lastDbStateBytes ?? wsStateBytes; const checkpoint = wssCheckpoint ? getCheckpointFromArg(wssCheckpoint) : getCheckpointFromState(wsState); - return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsState, checkpoint, { + return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsStateBytes, checkpoint, { ignoreWeakSubjectivityCheck, }); } async function fetchWSStateFromBeaconApi( - lastDbState: BeaconStateAllForks | null, + lastDbStateBytes: StateWithBytes | null, + lastDbValidatorsBytes: Uint8Array | null, wssOpts: {checkpointSyncUrl: string; wssCheckpoint?: string; ignoreWeakSubjectivityCheck?: boolean}, chainForkConfig: ChainForkConfig, db: IBeaconDb, @@ -213,10 +249,15 @@ async function fetchWSStateFromBeaconApi( throw e; } - const {wsState, wsCheckpoint} = await fetchWeakSubjectivityState(chainForkConfig, logger, wssOpts); + const {wsState, wsStateBytes, wsCheckpoint} = await fetchWeakSubjectivityState(chainForkConfig, logger, wssOpts, { + lastDbState: lastDbStateBytes?.state ?? null, + lastDbValidatorsBytes, + }); + const config = createBeaconConfig(chainForkConfig, wsState.genesisValidatorsRoot); - const store = lastDbState ?? wsState; - return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsState, wsCheckpoint, { + const wsStateWithBytes = {state: wsState, stateBytes: wsStateBytes}; + const store = lastDbStateBytes ?? wsStateWithBytes; + return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsStateWithBytes, wsCheckpoint, { ignoreWeakSubjectivityCheck: wssOpts.ignoreWeakSubjectivityCheck, }); } diff --git a/packages/cli/src/networks/index.ts b/packages/cli/src/networks/index.ts index 2d605335b0e8..0831b78cd2f6 100644 --- a/packages/cli/src/networks/index.ts +++ b/packages/cli/src/networks/index.ts @@ -3,12 +3,17 @@ import got from "got"; import {ENR} from "@chainsafe/enr"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {HttpHeader, MediaType, WireFormat, getClient} from "@lodestar/api"; -import {getStateTypeFromBytes} from "@lodestar/beacon-node"; +import {getStateSlotFromBytes} from "@lodestar/beacon-node"; import {ChainConfig, ChainForkConfig} from "@lodestar/config"; import {Checkpoint} from "@lodestar/types/phase0"; import {Slot} from "@lodestar/types"; -import {fromHex, callFnWhenAwait, Logger} from "@lodestar/utils"; -import {BeaconStateAllForks, getLatestBlockRoot, computeCheckpointEpochAtStateSlot} from "@lodestar/state-transition"; +import {fromHex, callFnWhenAwait, Logger, formatBytes} from "@lodestar/utils"; +import { + BeaconStateAllForks, + getLatestBlockRoot, + computeCheckpointEpochAtStateSlot, + loadState, +} from "@lodestar/state-transition"; import {parseBootnodesFile} from "../util/format.js"; import * as mainnet from "./mainnet.js"; import * as dev from "./dev.js"; @@ -140,8 +145,12 @@ export function readBootnodes(bootnodesFilePath: string): string[] { export async function fetchWeakSubjectivityState( config: ChainForkConfig, logger: Logger, - {checkpointSyncUrl, wssCheckpoint}: {checkpointSyncUrl: string; wssCheckpoint?: string} -): Promise<{wsState: BeaconStateAllForks; wsCheckpoint: Checkpoint}> { + {checkpointSyncUrl, wssCheckpoint}: {checkpointSyncUrl: string; wssCheckpoint?: string}, + { + lastDbState, + lastDbValidatorsBytes, + }: {lastDbState: BeaconStateAllForks | null; lastDbValidatorsBytes: Uint8Array | null} +): Promise<{wsState: BeaconStateAllForks; wsStateBytes: Uint8Array; wsCheckpoint: Checkpoint}> { try { let wsCheckpoint: Checkpoint | null; let stateId: Slot | "finalized"; @@ -169,7 +178,7 @@ export async function fetchWeakSubjectivityState( } ); - const stateBytes = await callFnWhenAwait( + const wsStateBytes = await callFnWhenAwait( getStatePromise, () => logger.info("Download in progress, please wait..."), GET_STATE_LOG_INTERVAL @@ -177,13 +186,23 @@ export async function fetchWeakSubjectivityState( return res.ssz(); }); - logger.info("Download completed", {stateId}); + const wsSlot = getStateSlotFromBytes(wsStateBytes); + const logData = {stateId, size: formatBytes(wsStateBytes.length)}; + logger.info("Download completed", typeof stateId === "number" ? logData : {...logData, slot: wsSlot}); // It should not be required to get fork type from bytes but Checkpointz does not return // Eth-Consensus-Version header, see https://github.com/ethpandaops/checkpointz/issues/164 - const wsState = getStateTypeFromBytes(config, stateBytes).deserializeToViewDU(stateBytes); + let wsState: BeaconStateAllForks; + if (lastDbState && lastDbValidatorsBytes) { + // use lastDbState to load wsState if possible to share the same state tree + wsState = loadState(config, lastDbState, wsStateBytes, lastDbValidatorsBytes).state; + } else { + const stateType = config.getForkTypes(wsSlot).BeaconState; + wsState = stateType.deserializeToViewDU(wsStateBytes); + } return { wsState, + wsStateBytes, wsCheckpoint: wsCheckpoint ?? getCheckpointFromState(wsState), }; } catch (e) { diff --git a/packages/state-transition/src/util/index.ts b/packages/state-transition/src/util/index.ts index 6a839fbe103d..9b9916f1d49e 100644 --- a/packages/state-transition/src/util/index.ts +++ b/packages/state-transition/src/util/index.ts @@ -25,3 +25,4 @@ export * from "./validator.js"; export * from "./weakSubjectivity.js"; export * from "./deposit.js"; export * from "./electra.js"; +export * from "./loadState/index.js"; diff --git a/packages/state-transition/src/util/loadState/index.ts b/packages/state-transition/src/util/loadState/index.ts index 706de3c11540..78ffe7877c09 100644 --- a/packages/state-transition/src/util/loadState/index.ts +++ b/packages/state-transition/src/util/loadState/index.ts @@ -1 +1 @@ -export {loadState} from "./loadState.js"; +export {loadState, loadStateAndValidators} from "./loadState.js"; diff --git a/packages/state-transition/src/util/loadState/loadState.ts b/packages/state-transition/src/util/loadState/loadState.ts index dc9f8fe4fcab..6e3e9c6719fa 100644 --- a/packages/state-transition/src/util/loadState/loadState.ts +++ b/packages/state-transition/src/util/loadState/loadState.ts @@ -66,6 +66,25 @@ export function loadState( return {state: migratedState, modifiedValidators}; } +/** + * Load state and validators Uint8Array from state bytes. + */ +export function loadStateAndValidators( + chainForkConfig: ChainForkConfig, + stateBytes: Uint8Array +): {state: BeaconStateAllForks; validatorsBytes: Uint8Array} { + // stateType could be any types, casting just to make typescript happy + const stateType = getStateTypeFromBytes(chainForkConfig, stateBytes) as typeof ssz.phase0.BeaconState; + const state = stateType.deserializeToViewDU(stateBytes); + const dataView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength); + const fieldRanges = stateType.getFieldRanges(dataView, 0, stateBytes.length); + const allFields = Object.keys(stateType.fields); + const validatorFieldIndex = allFields.indexOf("validators"); + const validatorRange = fieldRanges[validatorFieldIndex]; + const validatorsBytes = stateBytes.subarray(validatorRange.start, validatorRange.end); + return {state, validatorsBytes}; +} + /** * This value is rarely changed as monitored 3 month state diffs on mainnet as of Sep 2023. * Reusing this data helps save hashTreeRoot time of state ~500ms diff --git a/packages/state-transition/test/unit/util/loadState.test.ts b/packages/state-transition/test/unit/util/loadState.test.ts new file mode 100644 index 000000000000..97a792a28adb --- /dev/null +++ b/packages/state-transition/test/unit/util/loadState.test.ts @@ -0,0 +1,40 @@ +import {describe, it, expect} from "vitest"; +import {ssz} from "@lodestar/types"; +import {mainnetChainConfig} from "@lodestar/config/networks"; +import {createChainForkConfig} from "@lodestar/config"; +import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {loadStateAndValidators} from "../../../src/util/loadState/loadState.js"; + +describe("loadStateAndValidators", () => { + const numValidator = 10; + const config = createChainForkConfig(mainnetChainConfig); + + const testCases: {name: ForkName; slot: number}[] = [ + {name: ForkName.phase0, slot: 100}, + {name: ForkName.altair, slot: mainnetChainConfig.ALTAIR_FORK_EPOCH * SLOTS_PER_EPOCH + 100}, + {name: ForkName.capella, slot: mainnetChainConfig.CAPELLA_FORK_EPOCH * SLOTS_PER_EPOCH + 100}, + {name: ForkName.deneb, slot: mainnetChainConfig.DENEB_FORK_EPOCH * SLOTS_PER_EPOCH + 100}, + ]; + + for (const {name, slot} of testCases) { + it(`fork: ${name}, slot: ${slot}`, () => { + const state = config.getForkTypes(slot).BeaconState.defaultViewDU(); + state.slot = slot; + for (let i = 0; i < numValidator; i++) { + const validator = ssz.phase0.Validator.defaultViewDU(); + validator.pubkey = Buffer.alloc(48, i); + state.validators.push(validator); + state.balances.push(32 * 1e9); + } + state.commit(); + + const stateBytes = state.serialize(); + const stateRoot = state.hashTreeRoot(); + const {state: loadedState, validatorsBytes} = loadStateAndValidators(config, stateBytes); + expect(loadedState.hashTreeRoot()).toEqual(stateRoot); + // serialize() somehow takes time, however comparing state root would be enough + // expect(loadedState.serialize()).toEqual(stateBytes); + expect(validatorsBytes).toEqual(state.validators.serialize()); + }); + } +}); diff --git a/packages/utils/src/bytes.ts b/packages/utils/src/bytes.ts index 6670b115ff8f..95bb62ebd548 100644 --- a/packages/utils/src/bytes.ts +++ b/packages/utils/src/bytes.ts @@ -48,3 +48,23 @@ export function bytesToBigInt(value: Uint8Array, endianness: Endianness = "le"): } throw new Error("endianness must be either 'le' or 'be'"); } + +export function formatBytes(bytes: number): string { + if (bytes < 0) { + throw new Error("bytes must be a positive number, got " + bytes); + } + + if (bytes === 0) { + return "0 Bytes"; + } + + // size of a kb + const k = 1024; + + // only support up to GB + const units = ["Bytes", "KB", "MB", "GB"]; + const i = Math.min(Math.floor(Math.log(bytes) / Math.log(k)), units.length - 1); + const formattedSize = (bytes / Math.pow(k, i)).toFixed(2); + + return `${formattedSize} ${units[i]}`; +} diff --git a/packages/utils/test/unit/bytes.test.ts b/packages/utils/test/unit/bytes.test.ts index 05789b839cfd..af4df6652f13 100644 --- a/packages/utils/test/unit/bytes.test.ts +++ b/packages/utils/test/unit/bytes.test.ts @@ -1,5 +1,14 @@ import {describe, it, expect} from "vitest"; -import {intToBytes, bytesToInt, toHex, fromHex, toHexString, toRootHex, toPubkeyHex} from "../../src/index.js"; +import { + intToBytes, + bytesToInt, + toHex, + fromHex, + toHexString, + toRootHex, + toPubkeyHex, + formatBytes, +} from "../../src/index.js"; describe("intToBytes", () => { const zeroedArray = (length: number): number[] => Array.from({length}, () => 0); @@ -135,3 +144,24 @@ describe("toHexString", () => { }); } }); + +describe("formatBytes", () => { + const testCases: {input: number; output: string}[] = [ + {input: 0, output: "0 Bytes"}, + {input: 1, output: "1.00 Bytes"}, + {input: 1024, output: "1.00 KB"}, + {input: 1024 + 0.12 * 1024, output: "1.12 KB"}, + {input: 1024 * 1024, output: "1.00 MB"}, + {input: 1024 * 1024 + 0.12 * (1024 * 1024), output: "1.12 MB"}, + {input: 1024 * 1024 * 1024, output: "1.00 GB"}, + {input: 1024 * 1024 * 1024 + 0.12 * 1024 * 1024 * 1024, output: "1.12 GB"}, + // too big + {input: 1024 * 1024 * 1024 * 1024, output: "1024.00 GB"}, + ]; + + for (const {input, output} of testCases) { + it(`should format ${input} bytes as ${output}`, () => { + expect(formatBytes(input)).toBe(output); + }); + } +}); From 94288e9f2d6d7f6d49b0a58c7dfdc7495de7849f Mon Sep 17 00:00:00 2001 From: Phil Ngo Date: Tue, 10 Sep 2024 12:47:50 -0400 Subject: [PATCH 096/259] chore: bump package versions to 1.22.0 --- lerna.json | 2 +- packages/api/package.json | 10 +++++----- packages/beacon-node/package.json | 26 +++++++++++++------------- packages/cli/package.json | 26 +++++++++++++------------- packages/config/package.json | 6 +++--- packages/db/package.json | 8 ++++---- packages/flare/package.json | 14 +++++++------- packages/fork-choice/package.json | 12 ++++++------ packages/light-client/package.json | 12 ++++++------ packages/logger/package.json | 6 +++--- packages/params/package.json | 2 +- packages/prover/package.json | 18 +++++++++--------- packages/reqresp/package.json | 12 ++++++------ packages/spec-test-util/package.json | 4 ++-- packages/state-transition/package.json | 10 +++++----- packages/test-utils/package.json | 6 +++--- packages/types/package.json | 4 ++-- packages/utils/package.json | 2 +- packages/validator/package.json | 18 +++++++++--------- 19 files changed, 99 insertions(+), 99 deletions(-) diff --git a/lerna.json b/lerna.json index 043a5c48569a..0ffc65fe5402 100644 --- a/lerna.json +++ b/lerna.json @@ -4,7 +4,7 @@ ], "npmClient": "yarn", "useNx": true, - "version": "1.21.0", + "version": "1.22.0", "stream": true, "command": { "version": { diff --git a/packages/api/package.json b/packages/api/package.json index 138964ed946a..d2f8a621f02e 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -72,10 +72,10 @@ "dependencies": { "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/ssz": "^0.17.1", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", "eventsource": "^2.0.2", "qs": "^6.11.1" }, diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index b41450f12d34..ade89ebc6cc1 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -119,18 +119,18 @@ "@libp2p/peer-id-factory": "^4.1.0", "@libp2p/prometheus-metrics": "^3.0.21", "@libp2p/tcp": "9.0.23", - "@lodestar/api": "^1.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/db": "^1.21.0", - "@lodestar/fork-choice": "^1.21.0", - "@lodestar/light-client": "^1.21.0", - "@lodestar/logger": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/reqresp": "^1.21.0", - "@lodestar/state-transition": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", - "@lodestar/validator": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/db": "^1.22.0", + "@lodestar/fork-choice": "^1.22.0", + "@lodestar/light-client": "^1.22.0", + "@lodestar/logger": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/reqresp": "^1.22.0", + "@lodestar/state-transition": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", + "@lodestar/validator": "^1.22.0", "@multiformats/multiaddr": "^12.1.3", "c-kzg": "^2.1.2", "datastore-core": "^9.1.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index bf8621344dc5..579725eba04e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@chainsafe/lodestar", - "version": "1.21.0", + "version": "1.22.0", "description": "Command line interface for lodestar", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -62,17 +62,17 @@ "@libp2p/crypto": "^4.1.0", "@libp2p/peer-id": "^4.1.0", "@libp2p/peer-id-factory": "^4.1.0", - "@lodestar/api": "^1.21.0", - "@lodestar/beacon-node": "^1.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/db": "^1.21.0", - "@lodestar/light-client": "^1.21.0", - "@lodestar/logger": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/state-transition": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", - "@lodestar/validator": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/beacon-node": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/db": "^1.22.0", + "@lodestar/light-client": "^1.22.0", + "@lodestar/logger": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/state-transition": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", + "@lodestar/validator": "^1.22.0", "@multiformats/multiaddr": "^12.1.3", "deepmerge": "^4.3.1", "ethers": "^6.7.0", @@ -88,7 +88,7 @@ "yargs": "^17.7.1" }, "devDependencies": { - "@lodestar/test-utils": "^1.21.0", + "@lodestar/test-utils": "^1.22.0", "@types/debug": "^4.1.7", "@types/got": "^9.6.12", "@types/inquirer": "^9.0.3", diff --git a/packages/config/package.json b/packages/config/package.json index 45c462e19081..adf21542a890 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/config", - "version": "1.21.0", + "version": "1.22.0", "description": "Chain configuration required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -65,7 +65,7 @@ ], "dependencies": { "@chainsafe/ssz": "^0.17.1", - "@lodestar/params": "^1.21.0", - "@lodestar/types": "^1.21.0" + "@lodestar/params": "^1.22.0", + "@lodestar/types": "^1.22.0" } } diff --git a/packages/db/package.json b/packages/db/package.json index 1a31603b6791..0e3a2c847d4b 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/db", - "version": "1.21.0", + "version": "1.22.0", "description": "DB modules of Lodestar", "author": "ChainSafe Systems", "homepage": "https://github.com/ChainSafe/lodestar#readme", @@ -36,12 +36,12 @@ }, "dependencies": { "@chainsafe/ssz": "^0.17.1", - "@lodestar/config": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/config": "^1.22.0", + "@lodestar/utils": "^1.22.0", "classic-level": "^1.4.1", "it-all": "^3.0.4" }, "devDependencies": { - "@lodestar/logger": "^1.21.0" + "@lodestar/logger": "^1.22.0" } } diff --git a/packages/flare/package.json b/packages/flare/package.json index 461147274591..3a11e9b49ebf 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/flare", - "version": "1.21.0", + "version": "1.22.0", "description": "Beacon chain debugging tool", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -60,12 +60,12 @@ "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", "@chainsafe/blst": "^2.0.3", - "@lodestar/api": "^1.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/state-transition": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/state-transition": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.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 dfe4c942832d..728036b365d3 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.21.0", + "version": "1.22.0", "type": "module", "exports": "./lib/index.js", "types": "./lib/index.d.ts", @@ -37,11 +37,11 @@ }, "dependencies": { "@chainsafe/ssz": "^0.17.1", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/state-transition": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0" + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/state-transition": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0" }, "keywords": [ "ethereum", diff --git a/packages/light-client/package.json b/packages/light-client/package.json index 1188732c8870..940a78ae66d5 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -77,11 +77,11 @@ "@chainsafe/blst": "^0.2.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/ssz": "^0.17.1", - "@lodestar/api": "^1.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", "mitt": "^3.0.0" }, "devDependencies": { diff --git a/packages/logger/package.json b/packages/logger/package.json index 1ab176dbfd93..196fb306a8b0 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -66,14 +66,14 @@ }, "types": "lib/index.d.ts", "dependencies": { - "@lodestar/utils": "^1.21.0", + "@lodestar/utils": "^1.22.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.21.0", + "@lodestar/test-utils": "^1.22.0", "@types/triple-beam": "^1.3.2", "triple-beam": "^1.3.0" }, diff --git a/packages/params/package.json b/packages/params/package.json index c246918959e4..c281f97a41ec 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/params", - "version": "1.21.0", + "version": "1.22.0", "description": "Chain parameters required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", diff --git a/packages/prover/package.json b/packages/prover/package.json index 974125e2a17f..6a31b5b1baa0 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.21.0", + "version": "1.22.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.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/light-client": "^1.21.0", - "@lodestar/logger": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/light-client": "^1.22.0", + "@lodestar/logger": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.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.21.0", + "@lodestar/test-utils": "^1.22.0", "@types/http-proxy": "^1.17.10", "@types/yargs": "^17.0.24", "axios": "^1.3.4", diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index 1b9d99b000a8..44dcb8048f99 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -54,9 +54,9 @@ "dependencies": { "@chainsafe/fast-crc32c": "^4.1.1", "@libp2p/interface": "^1.3.0", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/utils": "^1.22.0", "it-all": "^3.0.4", "it-pipe": "^3.0.1", "snappy": "^7.2.2", @@ -65,8 +65,8 @@ "uint8arraylist": "^2.4.7" }, "devDependencies": { - "@lodestar/logger": "^1.21.0", - "@lodestar/types": "^1.21.0", + "@lodestar/logger": "^1.22.0", + "@lodestar/types": "^1.22.0", "libp2p": "1.4.3" }, "peerDependencies": { diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index 166df67a7409..b4aabf0140e8 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.21.0", + "version": "1.22.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.21.0", + "@lodestar/utils": "^1.22.0", "axios": "^1.3.4", "rimraf": "^4.4.1", "snappyjs": "^0.7.0", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 1dd43ef98f88..2df87a522a63 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -63,10 +63,10 @@ "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/persistent-ts": "^0.19.1", "@chainsafe/ssz": "^0.17.1", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", "bigint-buffer": "^1.1.5", "immutable": "^4.3.2" }, diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 6c8c9e62894f..5bf61891a9d5 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.21.0", + "version": "1.22.0", "description": "Test utilities reused across other packages", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -59,8 +59,8 @@ "dependencies": { "@chainsafe/bls-keystore": "^3.1.0", "@chainsafe/blst": "^2.0.3", - "@lodestar/params": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/params": "^1.22.0", + "@lodestar/utils": "^1.22.0", "axios": "^1.3.4", "testcontainers": "^10.2.1", "tmp": "^0.2.1", diff --git a/packages/types/package.json b/packages/types/package.json index 861dbdbee0ef..f3e034ec1b35 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -74,7 +74,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/ssz": "^0.17.1", - "@lodestar/params": "^1.21.0", + "@lodestar/params": "^1.22.0", "ethereum-cryptography": "^2.0.0" }, "keywords": [ diff --git a/packages/utils/package.json b/packages/utils/package.json index 492c65606dfb..0723f5f1815c 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.21.0", + "version": "1.22.0", "type": "module", "exports": "./lib/index.js", "files": [ diff --git a/packages/validator/package.json b/packages/validator/package.json index 373e59817d2a..65ed656f010d 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/validator", - "version": "1.21.0", + "version": "1.22.0", "description": "A Typescript implementation of the validator client", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -47,17 +47,17 @@ "dependencies": { "@chainsafe/blst": "^2.0.3", "@chainsafe/ssz": "^0.17.1", - "@lodestar/api": "^1.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/db": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/state-transition": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/db": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/state-transition": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", "strict-event-emitter-types": "^2.0.0" }, "devDependencies": { - "@lodestar/test-utils": "^1.21.0", + "@lodestar/test-utils": "^1.22.0", "bigint-buffer": "^1.1.5", "rimraf": "^4.4.1" } From 9f4bf50408fe51cf783a475ab6f0d2db40850753 Mon Sep 17 00:00:00 2001 From: twoeths Date: Thu, 12 Sep 2024 08:34:15 +0700 Subject: [PATCH 097/259] fix: avoid toHexString() (#7075) * fix: avoid toHexString() * fix: use toRootHex and toPubkeyHex where applicable --- packages/api/src/beacon/routes/proof.ts | 7 ++++--- packages/api/src/beacon/routes/validator.ts | 15 ++++++++------- packages/api/src/builder/routes.ts | 6 +++--- packages/api/src/utils/serdes.ts | 5 +++-- .../beacon-node/src/chain/blocks/importBlock.ts | 7 +++---- packages/beacon-node/src/chain/opPools/opPool.ts | 6 +++--- .../src/chain/stateCache/datastore/file.ts | 9 +++++---- .../stateCache/persistentCheckpointsCache.ts | 12 ++++++------ .../beacon-node/src/eth1/provider/eth1Provider.ts | 5 ++--- packages/beacon-node/src/eth1/provider/utils.ts | 8 ++++---- packages/beacon-node/src/eth1/utils/eth1Vote.ts | 1 - .../network/peers/utils/assertPeerRelevance.ts | 5 ++--- .../cli/src/cmds/validator/keymanager/server.ts | 4 ++-- packages/config/package.json | 1 + packages/config/src/chainConfig/json.ts | 5 +++-- packages/config/src/genesisConfig/index.ts | 4 ++-- packages/fork-choice/src/forkChoice/forkChoice.ts | 5 ++--- packages/fork-choice/src/protoArray/protoArray.ts | 4 ++-- packages/light-client/src/index.ts | 6 +++--- packages/logger/src/utils/json.ts | 6 +++--- .../src/block/processBlsToExecutionChange.ts | 7 +++---- .../src/block/processExecutionPayload.ts | 9 ++++----- .../src/block/processWithdrawalRequest.ts | 6 +++--- packages/utils/src/format.ts | 8 ++++---- packages/validator/src/services/attestation.ts | 5 ++--- packages/validator/src/services/validatorStore.ts | 14 +++++++------- .../interchange/formats/completeV4.ts | 6 +++--- .../slashingProtection/interchange/formats/v5.ts | 6 +++--- .../validator/src/slashingProtection/utils.ts | 7 ++++--- packages/validator/src/util/difference.ts | 6 +++--- .../validator/src/util/externalSignerClient.ts | 11 ++++++----- packages/validator/src/validator.ts | 9 ++++----- 32 files changed, 107 insertions(+), 108 deletions(-) diff --git a/packages/api/src/beacon/routes/proof.ts b/packages/api/src/beacon/routes/proof.ts index 5c20a0194fc5..a48caf02c9e7 100644 --- a/packages/api/src/beacon/routes/proof.ts +++ b/packages/api/src/beacon/routes/proof.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {CompactMultiProof, ProofType} from "@chainsafe/persistent-merkle-tree"; -import {ByteListType, ContainerType, fromHexString, toHexString} from "@chainsafe/ssz"; +import {ByteListType, ContainerType, fromHexString} from "@chainsafe/ssz"; +import {toHex} from "@lodestar/utils"; import {ChainForkConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; @@ -45,7 +46,7 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({params: {state_id: stateId}, query: {format: toHexString(descriptor)}}), + writeReq: ({stateId, descriptor}) => ({params: {state_id: stateId}, query: {format: toHex(descriptor)}}), parseReq: ({params, query}) => ({stateId: params.state_id, descriptor: fromHexString(query.format)}), schema: {params: {state_id: Schema.StringRequired}, query: {format: Schema.StringRequired}}, }, @@ -63,7 +64,7 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({params: {block_id: blockId}, query: {format: toHexString(descriptor)}}), + writeReq: ({blockId, descriptor}) => ({params: {block_id: blockId}, query: {format: toHex(descriptor)}}), parseReq: ({params, query}) => ({blockId: params.block_id, descriptor: fromHexString(query.format)}), schema: {params: {block_id: Schema.StringRequired}, query: {format: Schema.StringRequired}}, }, diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index 664caf44a2c4..3acbfec3e800 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {ContainerType, fromHexString, toHexString, Type, ValueOf} from "@chainsafe/ssz"; +import {ContainerType, fromHexString, Type, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {isForkBlobs, isForkPostElectra} from "@lodestar/params"; import { @@ -20,6 +20,7 @@ import { Attestation, sszTypesFor, } from "@lodestar/types"; +import {toHex, toRootHex} from "@lodestar/utils"; import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import {fromGraffitiHex, toBoolean, toGraffitiHex} from "../../utils/serdes.js"; import {getExecutionForkTypes, toForkName} from "../../utils/fork.js"; @@ -623,7 +624,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ params: {slot}, query: { - randao_reveal: toHexString(randaoReveal), + randao_reveal: toHex(randaoReveal), graffiti: toGraffitiHex(graffiti), fee_recipient: feeRecipient, builder_selection: builderSelection, @@ -674,7 +675,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ params: {slot}, query: { - randao_reveal: toHexString(randaoReveal), + randao_reveal: toHex(randaoReveal), graffiti: toGraffitiHex(graffiti), skip_randao_verification: writeSkipRandaoVerification(skipRandaoVerification), fee_recipient: feeRecipient, @@ -765,7 +766,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ params: {slot}, - query: {randao_reveal: toHexString(randaoReveal), graffiti: toGraffitiHex(graffiti)}, + query: {randao_reveal: toHex(randaoReveal), graffiti: toGraffitiHex(graffiti)}, }), parseReq: ({params, query}) => ({ slot: params.slot, @@ -805,7 +806,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ - query: {slot, subcommittee_index: subcommitteeIndex, beacon_block_root: toHexString(beaconBlockRoot)}, + query: {slot, subcommittee_index: subcommitteeIndex, beacon_block_root: toRootHex(beaconBlockRoot)}, }), parseReq: ({query}) => ({ slot: query.slot, @@ -830,7 +831,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ - query: {attestation_data_root: toHexString(attestationDataRoot), slot}, + query: {attestation_data_root: toRootHex(attestationDataRoot), slot}, }), parseReq: ({query}) => ({ attestationDataRoot: fromHexString(query.attestation_data_root), @@ -853,7 +854,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ - query: {attestation_data_root: toHexString(attestationDataRoot), slot, committee_index: committeeIndex}, + query: {attestation_data_root: toHex(attestationDataRoot), slot, committee_index: committeeIndex}, }), parseReq: ({query}) => ({ attestationDataRoot: fromHexString(query.attestation_data_root), diff --git a/packages/api/src/builder/routes.ts b/packages/api/src/builder/routes.ts index 3d74101bb046..ffed5a91824c 100644 --- a/packages/api/src/builder/routes.ts +++ b/packages/api/src/builder/routes.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {fromHexString} from "@chainsafe/ssz"; import { ssz, bellatrix, @@ -13,7 +13,7 @@ import { } from "@lodestar/types"; import {ForkName, isForkBlobs} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; -import {toPubkeyHex} from "@lodestar/utils"; +import {toPubkeyHex, toRootHex} from "@lodestar/utils"; import {Endpoint, RouteDefinitions, Schema} from "../utils/index.js"; import {MetaHeader, VersionCodec, VersionMeta} from "../utils/metadata.js"; @@ -106,7 +106,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ - params: {slot, parent_hash: toHexString(parentHash), pubkey: toPubkeyHex(proposerPubKey)}, + params: {slot, parent_hash: toRootHex(parentHash), pubkey: toPubkeyHex(proposerPubKey)}, }), parseReq: ({params}) => ({ slot: params.slot, diff --git a/packages/api/src/utils/serdes.ts b/packages/api/src/utils/serdes.ts index 233d7db9e7f8..8fc746ac8264 100644 --- a/packages/api/src/utils/serdes.ts +++ b/packages/api/src/utils/serdes.ts @@ -1,4 +1,5 @@ -import {fromHexString, JsonPath, toHexString} from "@chainsafe/ssz"; +import {fromHexString, JsonPath} from "@chainsafe/ssz"; +import {toHex} from "@lodestar/utils"; /** * Serialize proof path to JSON. @@ -82,7 +83,7 @@ export function toGraffitiHex(utf8?: string): string | undefined { return undefined; } - const hex = toHexString(new TextEncoder().encode(utf8)); + const hex = toHex(new TextEncoder().encode(utf8)); if (hex.length > GRAFFITI_HEX_LENGTH) { // remove characters from the end if hex string is too long diff --git a/packages/beacon-node/src/chain/blocks/importBlock.ts b/packages/beacon-node/src/chain/blocks/importBlock.ts index de5ecf607d95..4c46bdae53ee 100644 --- a/packages/beacon-node/src/chain/blocks/importBlock.ts +++ b/packages/beacon-node/src/chain/blocks/importBlock.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import {capella, ssz, altair, BeaconBlock} from "@lodestar/types"; import {ForkLightClient, ForkSeq, INTERVALS_PER_SLOT, MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params"; import { @@ -10,7 +9,7 @@ import { } from "@lodestar/state-transition"; import {routes} from "@lodestar/api"; import {ForkChoiceError, ForkChoiceErrorCode, EpochDifference, AncestorStatus} from "@lodestar/fork-choice"; -import {isErrorAborted, toRootHex} from "@lodestar/utils"; +import {isErrorAborted, toHex, toRootHex} from "@lodestar/utils"; import {ZERO_HASH_HEX} from "../../constants/index.js"; import {toCheckpointHex} from "../stateCache/index.js"; import {isOptimisticBlock} from "../../util/forkChoice.js"; @@ -433,8 +432,8 @@ export async function importBlock( blockRoot: blockRootHex, slot: blockSlot, index, - kzgCommitment: toHexString(kzgCommitment), - versionedHash: toHexString(kzgCommitmentToVersionedHash(kzgCommitment)), + kzgCommitment: toHex(kzgCommitment), + versionedHash: toHex(kzgCommitmentToVersionedHash(kzgCommitment)), }); } } diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index a2180a718fee..dc3fee0ac8a8 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -1,4 +1,4 @@ -import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {fromHexString} from "@chainsafe/ssz"; import { CachedBeaconStateAllForks, computeEpochAtSlot, @@ -16,7 +16,7 @@ import { ForkSeq, MAX_ATTESTER_SLASHINGS_ELECTRA, } from "@lodestar/params"; -import {toRootHex} from "@lodestar/utils"; +import {toHex, toRootHex} from "@lodestar/utils"; import {Epoch, phase0, capella, ssz, ValidatorIndex, SignedBeaconBlock, AttesterSlashing} from "@lodestar/types"; import {IBeaconDb} from "../../db/index.js"; import {SignedBLSToExecutionChangeVersioned} from "../../util/types.js"; @@ -88,7 +88,7 @@ export class OpPool { key: fromHexString(key), value: value.attesterSlashing, })), - toHexString + toHex ), persistDiff( db.proposerSlashing, diff --git a/packages/beacon-node/src/chain/stateCache/datastore/file.ts b/packages/beacon-node/src/chain/stateCache/datastore/file.ts index 6529d12f84db..8a07df90d168 100644 --- a/packages/beacon-node/src/chain/stateCache/datastore/file.ts +++ b/packages/beacon-node/src/chain/stateCache/datastore/file.ts @@ -1,6 +1,7 @@ import path from "node:path"; -import {toHexString, fromHexString} from "@chainsafe/ssz"; +import {fromHexString} from "@chainsafe/ssz"; import {phase0, ssz} from "@lodestar/types"; +import {toHex} from "@lodestar/utils"; import {ensureDir, readFile, readFileNames, removeFile, writeIfNotExist} from "../../../util/file.js"; import {CPStateDatastore, DatastoreKey} from "./types.js"; @@ -28,18 +29,18 @@ export class FileCPStateDatastore implements CPStateDatastore { async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array): Promise { const serializedCheckpoint = ssz.phase0.Checkpoint.serialize(cpKey); - const filePath = path.join(this.folderPath, toHexString(serializedCheckpoint)); + const filePath = path.join(this.folderPath, toHex(serializedCheckpoint)); await writeIfNotExist(filePath, stateBytes); return serializedCheckpoint; } async remove(serializedCheckpoint: DatastoreKey): Promise { - const filePath = path.join(this.folderPath, toHexString(serializedCheckpoint)); + const filePath = path.join(this.folderPath, toHex(serializedCheckpoint)); await removeFile(filePath); } async read(serializedCheckpoint: DatastoreKey): Promise { - const filePath = path.join(this.folderPath, toHexString(serializedCheckpoint)); + const filePath = path.join(this.folderPath, toHex(serializedCheckpoint)); return readFile(filePath); } diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 190b79e58cd6..c919c3c86233 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -1,7 +1,7 @@ -import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {fromHexString} from "@chainsafe/ssz"; import {phase0, Epoch, RootHex} from "@lodestar/types"; import {CachedBeaconStateAllForks, computeStartSlotAtEpoch, getBlockRootAtSlot} from "@lodestar/state-transition"; -import {Logger, MapDef, sleep, toRootHex} from "@lodestar/utils"; +import {Logger, MapDef, sleep, toHex, toRootHex} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {loadCachedBeaconState} from "@lodestar/state-transition"; import {INTERVALS_PER_SLOT} from "@lodestar/params"; @@ -193,7 +193,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { return stateOrStateBytesData?.clone(opts?.dontTransferCache) ?? null; } const {persistedKey, stateBytes} = stateOrStateBytesData; - const logMeta = {persistedKey: toHexString(persistedKey)}; + const logMeta = {persistedKey: toHex(persistedKey)}; this.logger.debug("Reload: read state successful", logMeta); this.metrics?.stateReloadSecFromSlot.observe(this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0); const seedState = this.findSeedStateToReload(cp); @@ -341,7 +341,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { this.logger.verbose("Added checkpoint state to memory but a persisted key existed", { epoch: cp.epoch, rootHex: cpHex.rootHex, - persistedKey: toHexString(persistedKey), + persistedKey: toHex(persistedKey), }); } else { this.cache.set(key, {type: CacheItemType.inMemory, state}); @@ -688,7 +688,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { stateSlot: state.slot, rootHex, epochBoundaryHex, - persistedKey: persistedKey ? toHexString(persistedKey) : "", + persistedKey: persistedKey ? toHex(persistedKey) : "", }; if (persistedRootHexes.has(rootHex)) { @@ -716,7 +716,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { persistCount++; this.logger.verbose("Pruned checkpoint state from memory and persisted to disk", { ...logMeta, - persistedKey: toHexString(persistedKey), + persistedKey: toHex(persistedKey), }); } // overwrite cpKey, this means the state is deleted from memory diff --git a/packages/beacon-node/src/eth1/provider/eth1Provider.ts b/packages/beacon-node/src/eth1/provider/eth1Provider.ts index 3af909cd132e..c86991eb7d15 100644 --- a/packages/beacon-node/src/eth1/provider/eth1Provider.ts +++ b/packages/beacon-node/src/eth1/provider/eth1Provider.ts @@ -1,7 +1,6 @@ -import {toHexString} from "@chainsafe/ssz"; import {phase0} from "@lodestar/types"; import {ChainConfig} from "@lodestar/config"; -import {fromHex, isErrorAborted, createElapsedTimeTracker, toPrintableUrl} from "@lodestar/utils"; +import {fromHex, isErrorAborted, createElapsedTimeTracker, toPrintableUrl, toHex} from "@lodestar/utils"; import {Logger} from "@lodestar/logger"; import {FetchError, isFetchError} from "@lodestar/api"; @@ -72,7 +71,7 @@ export class Eth1Provider implements IEth1Provider { ) { this.logger = opts.logger; this.deployBlock = opts.depositContractDeployBlock ?? 0; - this.depositContractAddress = toHexString(config.DEPOSIT_CONTRACT_ADDRESS); + this.depositContractAddress = toHex(config.DEPOSIT_CONTRACT_ADDRESS); const providerUrls = opts.providerUrls ?? DEFAULT_PROVIDER_URLS; this.rpc = new JsonRpcHttpClient(providerUrls, { diff --git a/packages/beacon-node/src/eth1/provider/utils.ts b/packages/beacon-node/src/eth1/provider/utils.ts index 506e4e48711a..cddf48c40d5a 100644 --- a/packages/beacon-node/src/eth1/provider/utils.ts +++ b/packages/beacon-node/src/eth1/provider/utils.ts @@ -1,6 +1,6 @@ -import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {fromHexString} from "@chainsafe/ssz"; import {RootHex} from "@lodestar/types"; -import {bytesToBigInt, bigIntToBytes} from "@lodestar/utils"; +import {bytesToBigInt, bigIntToBytes, toHex} from "@lodestar/utils"; import {ErrorParseJson} from "./jsonRpcHttpClient.js"; /** QUANTITY as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API */ @@ -32,7 +32,7 @@ export function bytesToHex(bytes: Uint8Array): string { return "0x" + bytes[0].toString(16); } - return toHexString(bytes); + return toHex(bytes); } /** @@ -100,7 +100,7 @@ export function bytesToQuantity(bytes: Uint8Array): QUANTITY { * - WRONG: 004200 (must be prefixed 0x) */ export function bytesToData(bytes: Uint8Array): DATA { - return toHexString(bytes); + return toHex(bytes); } /** diff --git a/packages/beacon-node/src/eth1/utils/eth1Vote.ts b/packages/beacon-node/src/eth1/utils/eth1Vote.ts index cdc8fa04163e..7a4e3ddca9b6 100644 --- a/packages/beacon-node/src/eth1/utils/eth1Vote.ts +++ b/packages/beacon-node/src/eth1/utils/eth1Vote.ts @@ -120,7 +120,6 @@ function getKeysWithMaxValue(map: Map): T[] { * ✓ pickEth1Vote - max votes 37.89912 ops/s 26.38583 ms/op - 29 runs 1.27 s */ function getEth1DataKey(eth1Data: phase0.Eth1Data): string { - // return toHexString(ssz.phase0.Eth1Data.hashTreeRoot(eth1Data)); return fastSerializeEth1Data(eth1Data); } diff --git a/packages/beacon-node/src/network/peers/utils/assertPeerRelevance.ts b/packages/beacon-node/src/network/peers/utils/assertPeerRelevance.ts index 96e35e9d317d..e588b1ae0308 100644 --- a/packages/beacon-node/src/network/peers/utils/assertPeerRelevance.ts +++ b/packages/beacon-node/src/network/peers/utils/assertPeerRelevance.ts @@ -1,6 +1,5 @@ -import {toHexString} from "@chainsafe/ssz"; import {ForkDigest, Root, Slot, phase0, ssz} from "@lodestar/types"; -import {toRootHex} from "@lodestar/utils"; +import {toHex, toRootHex} from "@lodestar/utils"; // TODO: Why this value? (From Lighthouse) const FUTURE_SLOT_TOLERANCE = 1; @@ -79,7 +78,7 @@ export function isZeroRoot(root: Root): boolean { export function renderIrrelevantPeerType(type: IrrelevantPeerType): string { switch (type.code) { case IrrelevantPeerCode.INCOMPATIBLE_FORKS: - return `INCOMPATIBLE_FORKS ours: ${toHexString(type.ours)} theirs: ${toHexString(type.theirs)}`; + return `INCOMPATIBLE_FORKS ours: ${toHex(type.ours)} theirs: ${toHex(type.theirs)}`; case IrrelevantPeerCode.DIFFERENT_CLOCKS: return `DIFFERENT_CLOCKS slotDiff: ${type.slotDiff}`; case IrrelevantPeerCode.DIFFERENT_FINALIZED: diff --git a/packages/cli/src/cmds/validator/keymanager/server.ts b/packages/cli/src/cmds/validator/keymanager/server.ts index 03880c8b8842..cca1a1f3b76b 100644 --- a/packages/cli/src/cmds/validator/keymanager/server.ts +++ b/packages/cli/src/cmds/validator/keymanager/server.ts @@ -1,10 +1,10 @@ import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; -import {toHexString} from "@chainsafe/ssz"; import {RestApiServer, RestApiServerOpts, RestApiServerModules} from "@lodestar/beacon-node"; import {KeymanagerApiMethods, registerRoutes} from "@lodestar/api/keymanager/server"; import {ChainForkConfig} from "@lodestar/config"; +import {toHex} from "@lodestar/utils"; import {writeFile600Perm} from "../../../util/index.js"; export type KeymanagerRestApiServerOpts = RestApiServerOpts & { @@ -50,7 +50,7 @@ export class KeymanagerRestApiServer extends RestApiServer { if (opts.isAuthEnabled) { // Generate a new token if token file does not exist or file do exist, but is empty - bearerToken = readFileIfExists(apiTokenPath) ?? `api-token-${toHexString(crypto.randomBytes(32))}`; + bearerToken = readFileIfExists(apiTokenPath) ?? `api-token-${toHex(crypto.randomBytes(32))}`; writeFile600Perm(apiTokenPath, bearerToken, {encoding: "utf8"}); } diff --git a/packages/config/package.json b/packages/config/package.json index 45c462e19081..d13713d376c6 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -66,6 +66,7 @@ "dependencies": { "@chainsafe/ssz": "^0.17.1", "@lodestar/params": "^1.21.0", + "@lodestar/utils": "^1.21.0", "@lodestar/types": "^1.21.0" } } diff --git a/packages/config/src/chainConfig/json.ts b/packages/config/src/chainConfig/json.ts index 4e61333cbdee..887409cd4c5b 100644 --- a/packages/config/src/chainConfig/json.ts +++ b/packages/config/src/chainConfig/json.ts @@ -1,4 +1,5 @@ -import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {fromHexString} from "@chainsafe/ssz"; +import {toHex} from "@lodestar/utils"; import {ChainConfig, chainConfigTypes, SpecValue, SpecValueTypeName} from "./types.js"; const MAX_UINT64_JSON = "18446744073709551615"; @@ -69,7 +70,7 @@ export function serializeSpecValue(value: SpecValue, typeName: SpecValueTypeName if (!(value instanceof Uint8Array)) { throw Error(`Invalid value ${value.toString()} expected Uint8Array`); } - return toHexString(value); + return toHex(value); case "string": if (typeof value !== "string") { diff --git a/packages/config/src/genesisConfig/index.ts b/packages/config/src/genesisConfig/index.ts index 52fdd03880a6..d2dfae2a8e08 100644 --- a/packages/config/src/genesisConfig/index.ts +++ b/packages/config/src/genesisConfig/index.ts @@ -1,6 +1,6 @@ -import {toHexString} from "@chainsafe/ssz"; import {ForkName, SLOTS_PER_EPOCH, DOMAIN_VOLUNTARY_EXIT} from "@lodestar/params"; import {DomainType, ForkDigest, phase0, Root, Slot, ssz, Version} from "@lodestar/types"; +import {toHex} from "@lodestar/utils"; import {ChainForkConfig} from "../beaconConfig.js"; import {ForkDigestHex, CachedGenesis} from "./types.js"; export type {ForkDigestContext} from "./types.js"; @@ -139,7 +139,7 @@ function computeForkDataRoot(currentVersion: Version, genesisValidatorsRoot: Roo } function toHexStringNoPrefix(hex: string | Uint8Array): string { - return strip0xPrefix(typeof hex === "string" ? hex : toHexString(hex)); + return strip0xPrefix(typeof hex === "string" ? hex : toHex(hex)); } function strip0xPrefix(hex: string): string { diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index 2405a442c8cd..6ae3f52e7d3a 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import {Logger, fromHex, toRootHex} from "@lodestar/utils"; import {SLOTS_PER_HISTORICAL_ROOT, SLOTS_PER_EPOCH, INTERVALS_PER_SLOT} from "@lodestar/params"; import {bellatrix, Slot, ValidatorIndex, phase0, ssz, RootHex, Epoch, Root, BeaconBlock} from "@lodestar/types"; @@ -643,7 +642,7 @@ export class ForkChoice implements IForkChoice { ...(isExecutionBlockBodyType(block.body) && isExecutionStateType(state) && isExecutionEnabled(state, block) ? { - executionPayloadBlockHash: toHexString(block.body.executionPayload.blockHash), + executionPayloadBlockHash: toRootHex(block.body.executionPayload.blockHash), executionPayloadNumber: block.body.executionPayload.blockNumber, executionStatus: this.getPostMergeExecStatus(executionStatus), dataAvailabilityStatus, @@ -1484,7 +1483,7 @@ export function assertValidTerminalPowBlock( // powBock.blockHash is hex, so we just pick the corresponding root if (!ssz.Root.equals(block.body.executionPayload.parentHash, config.TERMINAL_BLOCK_HASH)) throw new Error( - `Invalid terminal block hash, expected: ${toHexString(config.TERMINAL_BLOCK_HASH)}, actual: ${toHexString( + `Invalid terminal block hash, expected: ${toRootHex(config.TERMINAL_BLOCK_HASH)}, actual: ${toRootHex( block.body.executionPayload.parentHash )}` ); diff --git a/packages/fork-choice/src/protoArray/protoArray.ts b/packages/fork-choice/src/protoArray/protoArray.ts index eaa86b2f0ee1..0b793d2be099 100644 --- a/packages/fork-choice/src/protoArray/protoArray.ts +++ b/packages/fork-choice/src/protoArray/protoArray.ts @@ -1,8 +1,8 @@ -import {toHexString} from "@chainsafe/ssz"; import {Epoch, RootHex, Slot} from "@lodestar/types"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {GENESIS_EPOCH} from "@lodestar/params"; +import {toRootHex} from "@lodestar/utils"; import {ForkChoiceError, ForkChoiceErrorCode} from "../forkChoice/errors.js"; import {ProtoBlock, ProtoNode, HEX_ZERO_HASH, ExecutionStatus, LVHExecResponse} from "./interface.js"; import {ProtoArrayError, ProtoArrayErrorCode, LVHExecError, LVHExecErrorCode} from "./errors.js"; @@ -10,7 +10,7 @@ import {ProtoArrayError, ProtoArrayErrorCode, LVHExecError, LVHExecErrorCode} fr export const DEFAULT_PRUNE_THRESHOLD = 0; type ProposerBoost = {root: RootHex; score: number}; -const ZERO_HASH_HEX = toHexString(Buffer.alloc(32, 0)); +const ZERO_HASH_HEX = toRootHex(Buffer.alloc(32, 0)); export class ProtoArray { // Do not attempt to prune the tree unless it has at least this many nodes. diff --git a/packages/light-client/src/index.ts b/packages/light-client/src/index.ts index 16ecf1adf939..03be60eca05d 100644 --- a/packages/light-client/src/index.ts +++ b/packages/light-client/src/index.ts @@ -1,5 +1,5 @@ import mitt from "mitt"; -import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {fromHexString} from "@chainsafe/ssz"; import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD} from "@lodestar/params"; import { LightClientBootstrap, @@ -13,7 +13,7 @@ import { SyncPeriod, } from "@lodestar/types"; import {createBeaconConfig, BeaconConfig, ChainForkConfig} from "@lodestar/config"; -import {isErrorAborted, sleep} from "@lodestar/utils"; +import {isErrorAborted, sleep, toRootHex} from "@lodestar/utils"; import {getCurrentSlot, slotWithFutureTolerance, timeUntilNextEpoch} from "./utils/clock.js"; import {chunkifyInclusiveRange} from "./utils/chunkify.js"; import {LightclientEmitter, LightclientEvent} from "./events.js"; @@ -162,7 +162,7 @@ export class Lightclient { const {transport, checkpointRoot} = args; // Fetch bootstrap state with proof at the trusted block root - const {data: bootstrap} = await transport.getBootstrap(toHexString(checkpointRoot)); + const {data: bootstrap} = await transport.getBootstrap(toRootHex(checkpointRoot)); validateLightClientBootstrap(args.config, checkpointRoot, bootstrap); diff --git a/packages/logger/src/utils/json.ts b/packages/logger/src/utils/json.ts index f6f2d85487c7..7408de582dd1 100644 --- a/packages/logger/src/utils/json.ts +++ b/packages/logger/src/utils/json.ts @@ -1,4 +1,4 @@ -import {LodestarError, mapValues, toHexString} from "@lodestar/utils"; +import {LodestarError, mapValues, toHex} from "@lodestar/utils"; const MAX_DEPTH = 0; @@ -29,7 +29,7 @@ export function logCtxToJson(arg: unknown, depth = 0, fromError = false): LogDat if (arg === null) return "null"; if (arg instanceof Uint8Array) { - return toHexString(arg); + return toHex(arg); } // For any type that may include recursiveness break early at the first level @@ -90,7 +90,7 @@ export function logCtxToString(arg: unknown, depth = 0, fromError = false): stri if (arg === null) return "null"; if (arg instanceof Uint8Array) { - return toHexString(arg); + return toHex(arg); } // For any type that may include recursiveness break early at the first level diff --git a/packages/state-transition/src/block/processBlsToExecutionChange.ts b/packages/state-transition/src/block/processBlsToExecutionChange.ts index 1cc3706a756f..be79f06f3f21 100644 --- a/packages/state-transition/src/block/processBlsToExecutionChange.ts +++ b/packages/state-transition/src/block/processBlsToExecutionChange.ts @@ -1,7 +1,8 @@ -import {toHexString, byteArrayEquals} from "@chainsafe/ssz"; +import {byteArrayEquals} from "@chainsafe/ssz"; import {digest} from "@chainsafe/as-sha256"; import {capella} from "@lodestar/types"; import {BLS_WITHDRAWAL_PREFIX, ETH1_ADDRESS_WITHDRAWAL_PREFIX} from "@lodestar/params"; +import {toHex} from "@lodestar/utils"; import {verifyBlsToExecutionChangeSignature} from "../signatureSets/index.js"; import {CachedBeaconStateCapella} from "../types.js"; @@ -60,9 +61,7 @@ export function isValidBlsToExecutionChange( return { valid: false, error: Error( - `Invalid withdrawalCredentials expected=${toHexString(withdrawalCredentials)} actual=${toHexString( - digestCredentials - )}` + `Invalid withdrawalCredentials expected=${toHex(withdrawalCredentials)} actual=${toHex(digestCredentials)}` ), }; } diff --git a/packages/state-transition/src/block/processExecutionPayload.ts b/packages/state-transition/src/block/processExecutionPayload.ts index 3c28a400d3bf..3d70e46d40fd 100644 --- a/packages/state-transition/src/block/processExecutionPayload.ts +++ b/packages/state-transition/src/block/processExecutionPayload.ts @@ -1,6 +1,7 @@ -import {toHexString, byteArrayEquals} from "@chainsafe/ssz"; +import {byteArrayEquals} from "@chainsafe/ssz"; import {BeaconBlockBody, BlindedBeaconBlockBody, deneb, isExecutionPayload} from "@lodestar/types"; import {ForkSeq, MAX_BLOBS_PER_BLOCK} from "@lodestar/params"; +import {toHex, toRootHex} from "@lodestar/utils"; import {CachedBeaconStateBellatrix, CachedBeaconStateCapella} from "../types.js"; import {getRandaoMix} from "../util/index.js"; import { @@ -23,7 +24,7 @@ export function processExecutionPayload( const {latestExecutionPayloadHeader} = state; if (!byteArrayEquals(payload.parentHash, latestExecutionPayloadHeader.blockHash)) { throw Error( - `Invalid execution payload parentHash ${toHexString(payload.parentHash)} latest blockHash ${toHexString( + `Invalid execution payload parentHash ${toRootHex(payload.parentHash)} latest blockHash ${toRootHex( latestExecutionPayloadHeader.blockHash )}` ); @@ -33,9 +34,7 @@ export function processExecutionPayload( // Verify random const expectedRandom = getRandaoMix(state, state.epochCtx.epoch); if (!byteArrayEquals(payload.prevRandao, expectedRandom)) { - throw Error( - `Invalid execution payload random ${toHexString(payload.prevRandao)} expected=${toHexString(expectedRandom)}` - ); + throw Error(`Invalid execution payload random ${toHex(payload.prevRandao)} expected=${toHex(expectedRandom)}`); } // Verify timestamp diff --git a/packages/state-transition/src/block/processWithdrawalRequest.ts b/packages/state-transition/src/block/processWithdrawalRequest.ts index cff1ea03bd80..0587a06ee179 100644 --- a/packages/state-transition/src/block/processWithdrawalRequest.ts +++ b/packages/state-transition/src/block/processWithdrawalRequest.ts @@ -1,4 +1,3 @@ -import {toHexString} from "@chainsafe/ssz"; import {electra, phase0, ssz} from "@lodestar/types"; import { FAR_FUTURE_EPOCH, @@ -8,6 +7,7 @@ import { ForkSeq, } from "@lodestar/params"; +import {toHex} from "@lodestar/utils"; import {CachedBeaconStateElectra} from "../types.js"; import {hasCompoundingWithdrawalCredential, hasExecutionWithdrawalCredential} from "../util/electra.js"; import {getPendingBalanceToWithdraw, isActiveValidator} from "../util/validator.js"; @@ -85,8 +85,8 @@ function isValidatorEligibleForWithdrawOrExit( state: CachedBeaconStateElectra ): boolean { const {withdrawalCredentials} = validator; - const addressStr = toHexString(withdrawalCredentials.subarray(12)); - const sourceAddressStr = toHexString(sourceAddress); + const addressStr = toHex(withdrawalCredentials.subarray(12)); + const sourceAddressStr = toHex(sourceAddress); const {epoch: currentEpoch, config} = state.epochCtx; return ( diff --git a/packages/utils/src/format.ts b/packages/utils/src/format.ts index 8bd8a40273f1..5567eb89cc68 100644 --- a/packages/utils/src/format.ts +++ b/packages/utils/src/format.ts @@ -1,4 +1,4 @@ -import {toHexString} from "./bytes.js"; +import {toRootHex} from "./bytes/index.js"; import {ETH_TO_WEI} from "./ethConversion.js"; /** @@ -6,7 +6,7 @@ import {ETH_TO_WEI} from "./ethConversion.js"; * 4 bytes can represent 4294967296 values, so the chance of collision is low */ export function prettyBytes(root: Uint8Array | string): string { - const str = typeof root === "string" ? root : toHexString(root); + const str = typeof root === "string" ? root : toRootHex(root); return `${str.slice(0, 6)}…${str.slice(-4)}`; } @@ -15,7 +15,7 @@ export function prettyBytes(root: Uint8Array | string): string { * Paired with block numbers or slots, it can still act as a decent identify-able format */ export function prettyBytesShort(root: Uint8Array | string): string { - const str = typeof root === "string" ? root : toHexString(root); + const str = typeof root === "string" ? root : toRootHex(root); return `${str.slice(0, 6)}…`; } @@ -25,7 +25,7 @@ export function prettyBytesShort(root: Uint8Array | string): string { * values on explorers like beaconcha.in while improving readability of logs */ export function truncBytes(root: Uint8Array | string): string { - const str = typeof root === "string" ? root : toHexString(root); + const str = typeof root === "string" ? root : toRootHex(root); return str.slice(0, 14); } diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index 927bd3d92bb4..7f0dffa3e970 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -1,8 +1,7 @@ -import {toHexString} from "@chainsafe/ssz"; import {BLSSignature, phase0, Slot, ssz, Attestation, SignedAggregateAndProof} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import {computeEpochAtSlot, isAggregatorFromCommitteeLength} from "@lodestar/state-transition"; -import {prettyBytes, sleep} from "@lodestar/utils"; +import {prettyBytes, sleep, toRootHex} from "@lodestar/utils"; import {ApiClient, routes} from "@lodestar/api"; import {ChainForkConfig} from "@lodestar/config"; import {IClock, LoggerVc} from "../util/index.js"; @@ -195,7 +194,7 @@ export class AttestationService { duties: AttDutyAndProof[] ): Promise { const signedAttestations: Attestation[] = []; - const headRootHex = toHexString(attestationNoCommittee.beaconBlockRoot); + const headRootHex = toRootHex(attestationNoCommittee.beaconBlockRoot); const currentEpoch = computeEpochAtSlot(slot); const isPostElectra = currentEpoch >= this.config.ELECTRA_FORK_EPOCH; diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index c6130f1fab95..b64917ec03ae 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -1,4 +1,4 @@ -import {BitArray, fromHexString, toHexString} from "@chainsafe/ssz"; +import {BitArray, fromHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; import { computeEpochAtSlot, @@ -42,7 +42,7 @@ import { SignedAggregateAndProof, } from "@lodestar/types"; import {routes} from "@lodestar/api"; -import {toPubkeyHex} from "@lodestar/utils"; +import {toPubkeyHex, toRootHex} from "@lodestar/utils"; import {ISlashingProtection} from "../slashingProtection/index.js"; import {PubkeyHex} from "../types.js"; import {externalSignerPostSignature, SignableMessageType, SignableMessage} from "../util/externalSignerClient.js"; @@ -459,8 +459,8 @@ export class ValidatorStore { logger?.debug("Signing the block proposal", { slot: signingSlot, - blockRoot: toHexString(blockRoot), - signingRoot: toHexString(signingRoot), + blockRoot: toRootHex(blockRoot), + signingRoot: toRootHex(signingRoot), }); try { @@ -748,7 +748,7 @@ export class ValidatorStore { signingSlot: Slot, signableMessage: SignableMessage ): Promise { - // TODO: Refactor indexing to not have to run toHexString() on the pubkey every time + // TODO: Refactor indexing to not have to run toHex() on the pubkey every time const pubkeyHex = typeof pubkey === "string" ? pubkey : toPubkeyHex(pubkey); const signer = this.validators.get(pubkeyHex)?.signer; @@ -787,7 +787,7 @@ export class ValidatorStore { } private getSignerAndPubkeyHex(pubkey: BLSPubkeyMaybeHex): [Signer, string] { - // TODO: Refactor indexing to not have to run toHexString() on the pubkey every time + // TODO: Refactor indexing to not have to run toHex() on the pubkey every time const pubkeyHex = typeof pubkey === "string" ? pubkey : toPubkeyHex(pubkey); const signer = this.validators.get(pubkeyHex)?.signer; if (!signer) { @@ -824,7 +824,7 @@ export class ValidatorStore { function getSignerPubkeyHex(signer: Signer): PubkeyHex { switch (signer.type) { case SignerType.Local: - return toHexString(signer.secretKey.toPublicKey().toBytes()); + return toPubkeyHex(signer.secretKey.toPublicKey().toBytes()); case SignerType.Remote: if (!isValidatePubkeyHex(signer.pubkey)) { diff --git a/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts b/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts index 66aa31c52194..d1e9475daa0e 100644 --- a/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts +++ b/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString, toHexString} from "@chainsafe/ssz"; -import {toPubkeyHex} from "@lodestar/utils"; +import {fromHexString} from "@chainsafe/ssz"; +import {toPubkeyHex, toRootHex} from "@lodestar/utils"; import {InterchangeLodestar} from "../types.js"; import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js"; @@ -91,7 +91,7 @@ export function serializeInterchangeCompleteV4({ metadata: { interchange_format: "complete", interchange_format_version: "4", - genesis_validators_root: toHexString(genesisValidatorsRoot), + genesis_validators_root: toRootHex(genesisValidatorsRoot), }, data: data.map((validator) => ({ pubkey: toPubkeyHex(validator.pubkey), diff --git a/packages/validator/src/slashingProtection/interchange/formats/v5.ts b/packages/validator/src/slashingProtection/interchange/formats/v5.ts index 1c7f67b706a5..20d11aefe91a 100644 --- a/packages/validator/src/slashingProtection/interchange/formats/v5.ts +++ b/packages/validator/src/slashingProtection/interchange/formats/v5.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString, toHexString} from "@chainsafe/ssz"; -import {toPubkeyHex} from "@lodestar/utils"; +import {fromHexString} from "@chainsafe/ssz"; +import {toPubkeyHex, toRootHex} from "@lodestar/utils"; import {InterchangeLodestar} from "../types.js"; import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js"; @@ -86,7 +86,7 @@ export function serializeInterchangeV5({data, genesisValidatorsRoot}: Interchang return { metadata: { interchange_format_version: "5", - genesis_validators_root: toHexString(genesisValidatorsRoot), + genesis_validators_root: toRootHex(genesisValidatorsRoot), }, data: data.map((validator) => ({ pubkey: toPubkeyHex(validator.pubkey), diff --git a/packages/validator/src/slashingProtection/utils.ts b/packages/validator/src/slashingProtection/utils.ts index f1fc0f24b9ae..294036981b14 100644 --- a/packages/validator/src/slashingProtection/utils.ts +++ b/packages/validator/src/slashingProtection/utils.ts @@ -1,5 +1,6 @@ -import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {fromHexString} from "@chainsafe/ssz"; import {Epoch, Root, ssz} from "@lodestar/types"; +import {toHex, toRootHex} from "@lodestar/utils"; export const blsPubkeyLen = 48; export const ZERO_ROOT = ssz.Root.defaultValue(); @@ -17,7 +18,7 @@ export function fromOptionalHexString(hex: string | undefined): Root { } export function toOptionalHexString(root: Root): string | undefined { - return isEqualRoot(root, ZERO_ROOT) ? undefined : toHexString(root); + return isEqualRoot(root, ZERO_ROOT) ? undefined : toRootHex(root); } /** @@ -34,7 +35,7 @@ export function minEpoch(epochs: Epoch[]): Epoch | null { export function uniqueVectorArr(buffers: Uint8Array[]): Uint8Array[] { const bufferStr = new Set(); return buffers.filter((buffer) => { - const str = toHexString(buffer); + const str = toHex(buffer); const seen = bufferStr.has(str); bufferStr.add(str); return !seen; diff --git a/packages/validator/src/util/difference.ts b/packages/validator/src/util/difference.ts index bafc6ff8f42f..b8c3c5e7b089 100644 --- a/packages/validator/src/util/difference.ts +++ b/packages/validator/src/util/difference.ts @@ -1,10 +1,10 @@ -import {toHexString} from "@chainsafe/ssz"; import {Root} from "@lodestar/types"; +import {toHex} from "@lodestar/utils"; /** * Return items included in `next` but not in `prev` */ export function differenceHex(prev: T[], next: T[]): T[] { - const existing = new Set(prev.map((item) => toHexString(item))); - return next.filter((item) => !existing.has(toHexString(item))); + const existing = new Set(prev.map((item) => toHex(item))); + return next.filter((item) => !existing.has(toHex(item))); } diff --git a/packages/validator/src/util/externalSignerClient.ts b/packages/validator/src/util/externalSignerClient.ts index dc1d0d0f1dd5..4fd615ce5280 100644 --- a/packages/validator/src/util/externalSignerClient.ts +++ b/packages/validator/src/util/externalSignerClient.ts @@ -1,4 +1,4 @@ -import {ContainerType, toHexString, ValueOf} from "@chainsafe/ssz"; +import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {fetch} from "@lodestar/api"; import {phase0, altair, capella, BeaconBlock, BlindedBeaconBlock} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; @@ -6,6 +6,7 @@ import {ValidatorRegistrationV1} from "@lodestar/types/bellatrix"; import {BeaconConfig} from "@lodestar/config"; import {computeEpochAtSlot, blindedOrFullBlockToHeader} from "@lodestar/state-transition"; import {Epoch, Root, RootHex, Slot, ssz} from "@lodestar/types"; +import {toHex, toRootHex} from "@lodestar/utils"; import {PubkeyHex} from "../types.js"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -131,17 +132,17 @@ export async function externalSignerPostSignature( const requestObj = serializerSignableMessagePayload(config, signableMessage) as Web3SignerSerializedRequest; requestObj.type = signableMessage.type; - requestObj.signingRoot = toHexString(signingRoot); + requestObj.signingRoot = toRootHex(signingRoot); if (requiresForkInfo[signableMessage.type]) { const forkInfo = config.getForkInfo(signingSlot); requestObj.fork_info = { fork: { - previous_version: toHexString(forkInfo.prevVersion), - current_version: toHexString(forkInfo.version), + previous_version: toHex(forkInfo.prevVersion), + current_version: toHex(forkInfo.version), epoch: String(computeEpochAtSlot(signingSlot)), }, - genesis_validators_root: toHexString(config.genesisValidatorsRoot), + genesis_validators_root: toRootHex(config.genesisValidatorsRoot), }; } diff --git a/packages/validator/src/validator.ts b/packages/validator/src/validator.ts index 8ec8f3330af2..980e64f7eac2 100644 --- a/packages/validator/src/validator.ts +++ b/packages/validator/src/validator.ts @@ -1,8 +1,7 @@ -import {toHexString} from "@chainsafe/ssz"; import {BLSPubkey, phase0, ssz} from "@lodestar/types"; import {createBeaconConfig, BeaconConfig, ChainForkConfig} from "@lodestar/config"; import {Genesis} from "@lodestar/types/phase0"; -import {Logger, toPrintableUrl} from "@lodestar/utils"; +import {Logger, toPrintableUrl, toRootHex} from "@lodestar/utils"; import {getClient, ApiClient, routes, ApiRequestInit, defaultInit} from "@lodestar/api"; import {computeEpochAtSlot, getCurrentSlot} from "@lodestar/state-transition"; import {Clock, IClock} from "./util/clock.js"; @@ -397,14 +396,14 @@ async function assertEqualGenesis(opts: ValidatorOptions, genesis: Genesis): Pro if (!ssz.Root.equals(genesisValidatorsRoot, nodeGenesisValidatorRoot)) { // this happens when the existing validator db served another network before opts.logger.error("Not the same genesisValidatorRoot", { - expected: toHexString(nodeGenesisValidatorRoot), - actual: toHexString(genesisValidatorsRoot), + expected: toRootHex(nodeGenesisValidatorRoot), + actual: toRootHex(genesisValidatorsRoot), }); throw new NotEqualParamsError("Not the same genesisValidatorRoot"); } } else { await metaDataRepository.setGenesisValidatorsRoot(nodeGenesisValidatorRoot); - opts.logger.info("Persisted genesisValidatorRoot", toHexString(nodeGenesisValidatorRoot)); + opts.logger.info("Persisted genesisValidatorRoot", toRootHex(nodeGenesisValidatorRoot)); } const nodeGenesisTime = genesis.genesisTime; From d6e8c057d23fcb2e6f8ed1c13d27dbdc6a52e1d0 Mon Sep 17 00:00:00 2001 From: twoeths Date: Fri, 13 Sep 2024 20:07:32 +0700 Subject: [PATCH 098/259] chore: avoid fromHexString (#7080) * fix: fromHexString() to fromHex() * fix: throw error for NodeJS fromHex() if malformed string * fix: correct hex value in sim test --- packages/api/src/beacon/routes/proof.ts | 8 ++++---- packages/api/src/beacon/routes/validator.ts | 16 ++++++++-------- packages/api/src/builder/routes.ts | 7 +++---- packages/api/src/utils/serdes.ts | 6 +++--- .../src/chain/archiver/archiveBlocks.ts | 9 ++++----- packages/beacon-node/src/chain/chain.ts | 16 ++++++++-------- packages/beacon-node/src/chain/opPools/opPool.ts | 5 ++--- packages/beacon-node/src/chain/regen/regen.ts | 5 ++--- .../src/chain/stateCache/datastore/file.ts | 5 ++--- .../stateCache/persistentCheckpointsCache.ts | 7 +++---- packages/beacon-node/src/eth1/index.ts | 4 ++-- packages/beacon-node/src/eth1/provider/utils.ts | 5 ++--- .../src/eth1/utils/depositContract.ts | 10 +++++----- .../beacon-node/src/network/core/networkCore.ts | 5 ++--- .../reqresp/beaconBlocksMaybeBlobsByRoot.ts | 4 ++-- packages/beacon-node/src/sync/unknownBlock.ts | 7 +++---- packages/cli/src/cmds/lightclient/handler.ts | 4 ++-- .../src/cmds/validator/blsToExecutionChange.ts | 7 +++---- .../cli/src/cmds/validator/keymanager/impl.ts | 5 ++--- packages/cli/src/util/format.ts | 4 ++-- .../utils/crucible/assertions/blobsAssertion.ts | 2 +- .../config/src/chainConfig/configs/mainnet.ts | 2 +- .../config/src/chainConfig/configs/minimal.ts | 2 +- packages/config/src/chainConfig/json.ts | 5 ++--- .../config/src/chainConfig/networks/chiado.ts | 2 +- .../config/src/chainConfig/networks/ephemery.ts | 2 +- .../config/src/chainConfig/networks/gnosis.ts | 2 +- .../config/src/chainConfig/networks/holesky.ts | 2 +- .../config/src/chainConfig/networks/mainnet.ts | 2 +- .../config/src/chainConfig/networks/sepolia.ts | 2 +- packages/light-client/src/index.ts | 5 ++--- .../state-transition/src/cache/epochCache.ts | 5 ++--- packages/utils/src/bytes/nodejs.ts | 14 +++++++++++++- .../validator/src/services/chainHeaderTracker.ts | 5 ++--- .../src/services/doppelgangerService.ts | 5 ++--- .../validator/src/services/externalSignerSync.ts | 5 ++--- .../validator/src/services/validatorStore.ts | 10 +++++----- .../interchange/formats/completeV4.ts | 7 +++---- .../slashingProtection/interchange/formats/v5.ts | 7 +++---- .../validator/src/slashingProtection/utils.ts | 5 ++--- 40 files changed, 111 insertions(+), 119 deletions(-) diff --git a/packages/api/src/beacon/routes/proof.ts b/packages/api/src/beacon/routes/proof.ts index a48caf02c9e7..2ef4dad15e81 100644 --- a/packages/api/src/beacon/routes/proof.ts +++ b/packages/api/src/beacon/routes/proof.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {CompactMultiProof, ProofType} from "@chainsafe/persistent-merkle-tree"; -import {ByteListType, ContainerType, fromHexString} from "@chainsafe/ssz"; -import {toHex} from "@lodestar/utils"; +import {ByteListType, ContainerType} from "@chainsafe/ssz"; +import {fromHex, toHex} from "@lodestar/utils"; import {ChainForkConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; @@ -47,7 +47,7 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({params: {state_id: stateId}, query: {format: toHex(descriptor)}}), - parseReq: ({params, query}) => ({stateId: params.state_id, descriptor: fromHexString(query.format)}), + parseReq: ({params, query}) => ({stateId: params.state_id, descriptor: fromHex(query.format)}), schema: {params: {state_id: Schema.StringRequired}, query: {format: Schema.StringRequired}}, }, resp: { @@ -65,7 +65,7 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({params: {block_id: blockId}, query: {format: toHex(descriptor)}}), - parseReq: ({params, query}) => ({blockId: params.block_id, descriptor: fromHexString(query.format)}), + parseReq: ({params, query}) => ({blockId: params.block_id, descriptor: fromHex(query.format)}), schema: {params: {block_id: Schema.StringRequired}, query: {format: Schema.StringRequired}}, }, resp: { diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index 3acbfec3e800..a9a1423e4da2 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {ContainerType, fromHexString, Type, ValueOf} from "@chainsafe/ssz"; +import {ContainerType, Type, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {isForkBlobs, isForkPostElectra} from "@lodestar/params"; import { @@ -20,7 +20,7 @@ import { Attestation, sszTypesFor, } from "@lodestar/types"; -import {toHex, toRootHex} from "@lodestar/utils"; +import {fromHex, toHex, toRootHex} from "@lodestar/utils"; import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import {fromGraffitiHex, toBoolean, toGraffitiHex} from "../../utils/serdes.js"; import {getExecutionForkTypes, toForkName} from "../../utils/fork.js"; @@ -633,7 +633,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ slot: params.slot, - randaoReveal: fromHexString(query.randao_reveal), + randaoReveal: fromHex(query.randao_reveal), graffiti: fromGraffitiHex(query.graffiti), feeRecipient: query.fee_recipient, builderSelection: query.builder_selection as BuilderSelection, @@ -687,7 +687,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ slot: params.slot, - randaoReveal: fromHexString(query.randao_reveal), + randaoReveal: fromHex(query.randao_reveal), graffiti: fromGraffitiHex(query.graffiti), skipRandaoVerification: parseSkipRandaoVerification(query.skip_randao_verification), feeRecipient: query.fee_recipient, @@ -770,7 +770,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ slot: params.slot, - randaoReveal: fromHexString(query.randao_reveal), + randaoReveal: fromHex(query.randao_reveal), graffiti: fromGraffitiHex(query.graffiti), }), schema: { @@ -811,7 +811,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ slot: query.slot, subcommitteeIndex: query.subcommittee_index, - beaconBlockRoot: fromHexString(query.beacon_block_root), + beaconBlockRoot: fromHex(query.beacon_block_root), }), schema: { query: { @@ -834,7 +834,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ - attestationDataRoot: fromHexString(query.attestation_data_root), + attestationDataRoot: fromHex(query.attestation_data_root), slot: query.slot, }), schema: { @@ -857,7 +857,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ - attestationDataRoot: fromHexString(query.attestation_data_root), + attestationDataRoot: fromHex(query.attestation_data_root), slot: query.slot, committeeIndex: query.committee_index, }), diff --git a/packages/api/src/builder/routes.ts b/packages/api/src/builder/routes.ts index ffed5a91824c..7459e46abd0b 100644 --- a/packages/api/src/builder/routes.ts +++ b/packages/api/src/builder/routes.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString} from "@chainsafe/ssz"; import { ssz, bellatrix, @@ -13,7 +12,7 @@ import { } from "@lodestar/types"; import {ForkName, isForkBlobs} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; -import {toPubkeyHex, toRootHex} from "@lodestar/utils"; +import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; import {Endpoint, RouteDefinitions, Schema} from "../utils/index.js"; import {MetaHeader, VersionCodec, VersionMeta} from "../utils/metadata.js"; @@ -110,8 +109,8 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions ({ slot: params.slot, - parentHash: fromHexString(params.parent_hash), - proposerPubkey: fromHexString(params.pubkey), + parentHash: fromHex(params.parent_hash), + proposerPubkey: fromHex(params.pubkey), }), schema: { params: {slot: Schema.UintRequired, parent_hash: Schema.StringRequired, pubkey: Schema.StringRequired}, diff --git a/packages/api/src/utils/serdes.ts b/packages/api/src/utils/serdes.ts index 8fc746ac8264..282c2514e00d 100644 --- a/packages/api/src/utils/serdes.ts +++ b/packages/api/src/utils/serdes.ts @@ -1,5 +1,5 @@ -import {fromHexString, JsonPath} from "@chainsafe/ssz"; -import {toHex} from "@lodestar/utils"; +import {JsonPath} from "@chainsafe/ssz"; +import {fromHex, toHex} from "@lodestar/utils"; /** * Serialize proof path to JSON. @@ -103,7 +103,7 @@ export function fromGraffitiHex(hex?: string): string | undefined { return undefined; } try { - return new TextDecoder("utf8").decode(fromHexString(hex)); + return new TextDecoder("utf8").decode(fromHex(hex)); } catch { // allow malformed graffiti hex string return hex; diff --git a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts index ed6dd5bfc091..8e1ac456579a 100644 --- a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts +++ b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts @@ -1,7 +1,6 @@ -import {fromHexString} from "@chainsafe/ssz"; import {Epoch, Slot, RootHex} from "@lodestar/types"; import {IForkChoice} from "@lodestar/fork-choice"; -import {Logger, toRootHex} from "@lodestar/utils"; +import {Logger, fromHex, toRootHex} from "@lodestar/utils"; import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {KeyValue} from "@lodestar/db"; @@ -48,7 +47,7 @@ export async function archiveBlocks( const finalizedCanonicalBlockRoots: BlockRootSlot[] = finalizedCanonicalBlocks.map((block) => ({ slot: block.slot, - root: fromHexString(block.blockRoot), + root: fromHex(block.blockRoot), })); if (finalizedCanonicalBlockRoots.length > 0) { @@ -68,7 +67,7 @@ export async function archiveBlocks( // deleteNonCanonicalBlocks // loop through forkchoice single time - const nonCanonicalBlockRoots = finalizedNonCanonicalBlocks.map((summary) => fromHexString(summary.blockRoot)); + const nonCanonicalBlockRoots = finalizedNonCanonicalBlocks.map((summary) => fromHex(summary.blockRoot)); if (nonCanonicalBlockRoots.length > 0) { await db.block.batchDelete(nonCanonicalBlockRoots); logger.verbose("Deleted non canonical blocks from hot DB", { @@ -144,7 +143,7 @@ async function migrateBlocksFromHotToColdDb(db: IBeaconDb, blocks: BlockRootSlot value: blockBuffer, slot: block.slot, blockRoot: block.root, - // TODO: Benchmark if faster to slice Buffer or fromHexString() + // TODO: Benchmark if faster to slice Buffer or fromHex() parentRoot: getParentRootFromSignedBlock(blockBuffer), }; }) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 8dbb49798538..ee70231c7d40 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import {CompositeTypeAny, fromHexString, TreeView, Type} from "@chainsafe/ssz"; +import {CompositeTypeAny, TreeView, Type} from "@chainsafe/ssz"; import { BeaconStateAllForks, CachedBeaconStateAllForks, @@ -35,7 +35,7 @@ import { } from "@lodestar/types"; import {CheckpointWithHex, ExecutionStatus, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice"; import {ProcessShutdownCallback} from "@lodestar/validator"; -import {Logger, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toRootHex} from "@lodestar/utils"; +import {Logger, fromHex, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toRootHex} from "@lodestar/utils"; import {ForkSeq, GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; import {GENESIS_EPOCH, ZERO_HASH} from "../constants/index.js"; @@ -521,7 +521,7 @@ export class BeaconChain implements IBeaconChain { }; } - const data = await this.db.stateArchive.getByRoot(fromHexString(stateRoot)); + const data = await this.db.stateArchive.getByRoot(fromHex(stateRoot)); return data && {state: data, executionOptimistic: false, finalized: true}; } @@ -568,7 +568,7 @@ export class BeaconChain implements IBeaconChain { // Unfinalized slot, attempt to find in fork-choice const block = this.forkChoice.getCanonicalBlockAtSlot(slot); if (block) { - const data = await this.db.block.get(fromHexString(block.blockRoot)); + const data = await this.db.block.get(fromHex(block.blockRoot)); if (data) { return {block: data, executionOptimistic: isOptimisticBlock(block), finalized: false}; } @@ -587,7 +587,7 @@ export class BeaconChain implements IBeaconChain { ): Promise<{block: SignedBeaconBlock; executionOptimistic: boolean; finalized: boolean} | null> { const block = this.forkChoice.getBlockHex(root); if (block) { - const data = await this.db.block.get(fromHexString(root)); + const data = await this.db.block.get(fromHex(root)); if (data) { return {block: data, executionOptimistic: isOptimisticBlock(block), finalized: false}; } @@ -595,7 +595,7 @@ export class BeaconChain implements IBeaconChain { // TODO: Add a lock to the archiver to have deterministic behavior on where are blocks } - const data = await this.db.blockArchive.getByRoot(fromHexString(root)); + const data = await this.db.blockArchive.getByRoot(fromHex(root)); return data && {block: data, executionOptimistic: false, finalized: true}; } @@ -768,7 +768,7 @@ export class BeaconChain implements IBeaconChain { finalizedRoot: finalizedCheckpoint.epoch === GENESIS_EPOCH ? ZERO_HASH : finalizedCheckpoint.root, finalizedEpoch: finalizedCheckpoint.epoch, // TODO: PERFORMANCE: Memoize to prevent re-computing every time - headRoot: fromHexString(head.blockRoot), + headRoot: fromHex(head.blockRoot), headSlot: head.slot, }; } @@ -1120,7 +1120,7 @@ export class BeaconChain implements IBeaconChain { // TODO: Improve using regen here const {blockRoot, stateRoot, slot} = this.forkChoice.getHead(); const headState = this.regen.getStateSync(stateRoot); - const headBlock = await this.db.block.get(fromHexString(blockRoot)); + const headBlock = await this.db.block.get(fromHex(blockRoot)); if (headBlock == null) { throw Error(`Head block ${slot} ${headBlock} is not available in database`); } diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index dc3fee0ac8a8..ee66591e9aef 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -1,4 +1,3 @@ -import {fromHexString} from "@chainsafe/ssz"; import { CachedBeaconStateAllForks, computeEpochAtSlot, @@ -16,7 +15,7 @@ import { ForkSeq, MAX_ATTESTER_SLASHINGS_ELECTRA, } from "@lodestar/params"; -import {toHex, toRootHex} from "@lodestar/utils"; +import {fromHex, toHex, toRootHex} from "@lodestar/utils"; import {Epoch, phase0, capella, ssz, ValidatorIndex, SignedBeaconBlock, AttesterSlashing} from "@lodestar/types"; import {IBeaconDb} from "../../db/index.js"; import {SignedBLSToExecutionChangeVersioned} from "../../util/types.js"; @@ -85,7 +84,7 @@ export class OpPool { persistDiff( db.attesterSlashing, Array.from(this.attesterSlashings.entries()).map(([key, value]) => ({ - key: fromHexString(key), + key: fromHex(key), value: value.attesterSlashing, })), toHex diff --git a/packages/beacon-node/src/chain/regen/regen.ts b/packages/beacon-node/src/chain/regen/regen.ts index 04cf5b40b494..08fda70d9184 100644 --- a/packages/beacon-node/src/chain/regen/regen.ts +++ b/packages/beacon-node/src/chain/regen/regen.ts @@ -1,4 +1,3 @@ -import {fromHexString} from "@chainsafe/ssz"; import {phase0, Slot, RootHex, BeaconBlock, SignedBeaconBlock} from "@lodestar/types"; import { CachedBeaconStateAllForks, @@ -11,7 +10,7 @@ import { StateHashTreeRootSource, } from "@lodestar/state-transition"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; -import {Logger, toRootHex} from "@lodestar/utils"; +import {Logger, fromHex, toRootHex} from "@lodestar/utils"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; import {Metrics} from "../../metrics/index.js"; @@ -216,7 +215,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { const protoBlocksAsc = blocksToReplay.reverse(); for (const [i, protoBlock] of protoBlocksAsc.entries()) { replaySlots[i] = protoBlock.slot; - blockPromises[i] = this.modules.db.block.get(fromHexString(protoBlock.blockRoot)); + blockPromises[i] = this.modules.db.block.get(fromHex(protoBlock.blockRoot)); } const logCtx = {stateRoot, replaySlots: replaySlots.join(",")}; diff --git a/packages/beacon-node/src/chain/stateCache/datastore/file.ts b/packages/beacon-node/src/chain/stateCache/datastore/file.ts index 8a07df90d168..f487079ae443 100644 --- a/packages/beacon-node/src/chain/stateCache/datastore/file.ts +++ b/packages/beacon-node/src/chain/stateCache/datastore/file.ts @@ -1,7 +1,6 @@ import path from "node:path"; -import {fromHexString} from "@chainsafe/ssz"; import {phase0, ssz} from "@lodestar/types"; -import {toHex} from "@lodestar/utils"; +import {fromHex, toHex} from "@lodestar/utils"; import {ensureDir, readFile, readFileNames, removeFile, writeIfNotExist} from "../../../util/file.js"; import {CPStateDatastore, DatastoreKey} from "./types.js"; @@ -48,6 +47,6 @@ export class FileCPStateDatastore implements CPStateDatastore { const fileNames = await readFileNames(this.folderPath); return fileNames .filter((fileName) => fileName.startsWith("0x") && fileName.length === CHECKPOINT_FILE_NAME_LENGTH) - .map((fileName) => fromHexString(fileName)); + .map((fileName) => fromHex(fileName)); } } diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index c919c3c86233..d8769374a29c 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -1,7 +1,6 @@ -import {fromHexString} from "@chainsafe/ssz"; import {phase0, Epoch, RootHex} from "@lodestar/types"; import {CachedBeaconStateAllForks, computeStartSlotAtEpoch, getBlockRootAtSlot} from "@lodestar/state-transition"; -import {Logger, MapDef, sleep, toHex, toRootHex} from "@lodestar/utils"; +import {Logger, MapDef, fromHex, sleep, toHex, toRootHex} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {loadCachedBeaconState} from "@lodestar/state-transition"; import {INTERVALS_PER_SLOT} from "@lodestar/params"; @@ -657,7 +656,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { let persistCount = 0; const epochBoundarySlot = computeStartSlotAtEpoch(epoch); const epochBoundaryRoot = - epochBoundarySlot === state.slot ? fromHexString(blockRootHex) : getBlockRootAtSlot(state, epochBoundarySlot); + epochBoundarySlot === state.slot ? fromHex(blockRootHex) : getBlockRootAtSlot(state, epochBoundarySlot); const epochBoundaryHex = toRootHex(epochBoundaryRoot); const prevEpochRoot = toRootHex(getBlockRootAtSlot(state, epochBoundarySlot - 1)); @@ -698,7 +697,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { } else { // persist and do not update epochIndex this.metrics?.statePersistSecFromSlot.observe(this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0); - const cpPersist = {epoch: epoch, root: fromHexString(rootHex)}; + const cpPersist = {epoch: epoch, root: fromHex(rootHex)}; // It's not sustainable to allocate ~240MB for each state every epoch, so we use buffer pool to reuse the memory. // As monitored on holesky as of Jan 2024: // - This does not increase heap allocation while gc time is the same diff --git a/packages/beacon-node/src/eth1/index.ts b/packages/beacon-node/src/eth1/index.ts index a8ba55c54141..7b2ec17496d3 100644 --- a/packages/beacon-node/src/eth1/index.ts +++ b/packages/beacon-node/src/eth1/index.ts @@ -1,6 +1,6 @@ -import {fromHexString} from "@chainsafe/ssz"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {Root} from "@lodestar/types"; +import {fromHex} from "@lodestar/utils"; import {IEth1ForBlockProduction, Eth1DataAndDeposits, IEth1Provider, PowMergeBlock, TDProgress} from "./interface.js"; import {Eth1DepositDataTracker, Eth1DepositDataTrackerModules} from "./eth1DepositDataTracker.js"; import {Eth1MergeBlockTracker, Eth1MergeBlockTrackerModules} from "./eth1MergeBlockTracker.js"; @@ -92,7 +92,7 @@ export class Eth1ForBlockProduction implements IEth1ForBlockProduction { async getTerminalPowBlock(): Promise { const block = await this.eth1MergeBlockTracker.getTerminalPowBlock(); - return block && fromHexString(block.blockHash); + return block && fromHex(block.blockHash); } getPowBlock(powBlockHash: string): Promise { diff --git a/packages/beacon-node/src/eth1/provider/utils.ts b/packages/beacon-node/src/eth1/provider/utils.ts index cddf48c40d5a..096f1d7233c8 100644 --- a/packages/beacon-node/src/eth1/provider/utils.ts +++ b/packages/beacon-node/src/eth1/provider/utils.ts @@ -1,6 +1,5 @@ -import {fromHexString} from "@chainsafe/ssz"; import {RootHex} from "@lodestar/types"; -import {bytesToBigInt, bigIntToBytes, toHex} from "@lodestar/utils"; +import {bytesToBigInt, bigIntToBytes, toHex, fromHex} from "@lodestar/utils"; import {ErrorParseJson} from "./jsonRpcHttpClient.js"; /** QUANTITY as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API */ @@ -108,7 +107,7 @@ export function bytesToData(bytes: Uint8Array): DATA { */ export function dataToBytes(hex: DATA, fixedLength: number | null): Uint8Array { try { - const bytes = fromHexString(hex); + const bytes = fromHex(hex); if (fixedLength != null && bytes.length !== fixedLength) { throw Error(`Wrong data length ${bytes.length} expected ${fixedLength}`); } diff --git a/packages/beacon-node/src/eth1/utils/depositContract.ts b/packages/beacon-node/src/eth1/utils/depositContract.ts index 7247fe8cebaf..b576a3d5f61c 100644 --- a/packages/beacon-node/src/eth1/utils/depositContract.ts +++ b/packages/beacon-node/src/eth1/utils/depositContract.ts @@ -1,6 +1,6 @@ import {Interface} from "@ethersproject/abi"; -import {fromHexString} from "@chainsafe/ssz"; import {phase0, ssz} from "@lodestar/types"; +import {fromHex} from "@lodestar/utils"; const depositEventFragment = "event DepositEvent(bytes pubkey, bytes withdrawal_credentials, bytes amount, bytes signature, bytes index)"; @@ -23,15 +23,15 @@ export function parseDepositLog(log: {blockNumber: number; data: string; topics: blockNumber: log.blockNumber, index: parseHexNumLittleEndian(values.index), depositData: { - pubkey: fromHexString(values.pubkey), - withdrawalCredentials: fromHexString(values.withdrawal_credentials), + pubkey: fromHex(values.pubkey), + withdrawalCredentials: fromHex(values.withdrawal_credentials), amount: parseHexNumLittleEndian(values.amount), - signature: fromHexString(values.signature), + signature: fromHex(values.signature), }, }; } function parseHexNumLittleEndian(hex: string): number { // Can't use parseInt() because amount is a hex string in little endian - return ssz.UintNum64.deserialize(fromHexString(hex)); + return ssz.UintNum64.deserialize(fromHex(hex)); } diff --git a/packages/beacon-node/src/network/core/networkCore.ts b/packages/beacon-node/src/network/core/networkCore.ts index 07b346bc29e4..83ef4c4fb063 100644 --- a/packages/beacon-node/src/network/core/networkCore.ts +++ b/packages/beacon-node/src/network/core/networkCore.ts @@ -2,13 +2,12 @@ import {Connection, PeerId} from "@libp2p/interface"; import {multiaddr} from "@multiformats/multiaddr"; import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/dist/src/score/peer-score.js"; -import {fromHexString} from "@chainsafe/ssz"; import {ENR} from "@chainsafe/enr"; import {routes} from "@lodestar/api"; import {BeaconConfig} from "@lodestar/config"; import type {LoggerNode} from "@lodestar/logger/node"; import {Epoch, phase0} from "@lodestar/types"; -import {withTimeout} from "@lodestar/utils"; +import {fromHex, withTimeout} from "@lodestar/utils"; import {ForkName} from "@lodestar/params"; import {ResponseIncoming} from "@lodestar/reqresp"; import {Libp2p} from "../interface.js"; @@ -195,7 +194,7 @@ export class NetworkCore implements INetworkCore { await gossip.start(); const enr = opts.discv5?.enr; - const nodeId = enr ? fromHexString(ENR.decodeTxt(enr).nodeId) : null; + const nodeId = enr ? fromHex(ENR.decodeTxt(enr).nodeId) : null; const attnetsService = new AttnetsService(config, clock, gossip, metadata, logger, metrics, nodeId, opts); const syncnetsService = new SyncnetsService(config, clock, gossip, metadata, logger, metrics, opts); diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts index 2b802ab1edd9..b53addab9b43 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts @@ -1,7 +1,7 @@ -import {fromHexString} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {phase0, deneb} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; +import {fromHex} from "@lodestar/utils"; import { BlockInput, BlockInputType, @@ -66,7 +66,7 @@ export async function unavailableBeaconBlobsByRoot( // resolve the block if thats unavailable let block, blobsCache, blockBytes, resolveAvailability, cachedData; if (unavailableBlockInput.block === null) { - const allBlocks = await network.sendBeaconBlocksByRoot(peerId, [fromHexString(unavailableBlockInput.blockRootHex)]); + const allBlocks = await network.sendBeaconBlocksByRoot(peerId, [fromHex(unavailableBlockInput.blockRootHex)]); block = allBlocks[0].data; blockBytes = allBlocks[0].bytes; cachedData = unavailableBlockInput.cachedData; diff --git a/packages/beacon-node/src/sync/unknownBlock.ts b/packages/beacon-node/src/sync/unknownBlock.ts index d985847d450f..a172b5d723db 100644 --- a/packages/beacon-node/src/sync/unknownBlock.ts +++ b/packages/beacon-node/src/sync/unknownBlock.ts @@ -1,6 +1,5 @@ -import {fromHexString} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; -import {Logger, pruneSetToMax, toRootHex} from "@lodestar/utils"; +import {Logger, fromHex, pruneSetToMax, toRootHex} from "@lodestar/utils"; import {Root, RootHex, deneb} from "@lodestar/types"; import {INTERVALS_PER_SLOT} from "@lodestar/params"; import {sleep} from "@lodestar/utils"; @@ -288,7 +287,7 @@ export class UnknownBlockSync { let res; if (block.blockInput === null) { - res = await wrapError(this.fetchUnknownBlockRoot(fromHexString(block.blockRootHex), connectedPeers)); + res = await wrapError(this.fetchUnknownBlockRoot(fromHex(block.blockRootHex), connectedPeers)); } else { res = await wrapError(this.fetchUnavailableBlockInput(block.blockInput, connectedPeers)); } @@ -519,7 +518,7 @@ export class UnknownBlockSync { if (unavailableBlockInput.block === null) { blockRootHex = unavailableBlockInput.blockRootHex; - blockRoot = fromHexString(blockRootHex); + blockRoot = fromHex(blockRootHex); } else { const unavailableBlock = unavailableBlockInput.block; blockRoot = this.config diff --git a/packages/cli/src/cmds/lightclient/handler.ts b/packages/cli/src/cmds/lightclient/handler.ts index a8e3d7333f98..5af8f84d8959 100644 --- a/packages/cli/src/cmds/lightclient/handler.ts +++ b/packages/cli/src/cmds/lightclient/handler.ts @@ -1,9 +1,9 @@ import path from "node:path"; -import {fromHexString} from "@chainsafe/ssz"; import {getClient} from "@lodestar/api"; import {Lightclient} from "@lodestar/light-client"; import {LightClientRestTransport} from "@lodestar/light-client/transport"; import {getNodeLogger} from "@lodestar/logger/node"; +import {fromHex} from "@lodestar/utils"; import {getBeaconConfigFromArgs} from "../../config/beaconParams.js"; import {getGlobalPaths} from "../../paths/global.js"; import {parseLoggerArgs} from "../../util/logger.js"; @@ -28,7 +28,7 @@ export async function lightclientHandler(args: ILightClientArgs & GlobalArgs): P genesisTime, genesisValidatorsRoot, }, - checkpointRoot: fromHexString(args.checkpointRoot), + checkpointRoot: fromHex(args.checkpointRoot), transport: new LightClientRestTransport(api), }); diff --git a/packages/cli/src/cmds/validator/blsToExecutionChange.ts b/packages/cli/src/cmds/validator/blsToExecutionChange.ts index 3a2fabcc37eb..dc55647fda80 100644 --- a/packages/cli/src/cmds/validator/blsToExecutionChange.ts +++ b/packages/cli/src/cmds/validator/blsToExecutionChange.ts @@ -1,11 +1,10 @@ -import {fromHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; import {computeSigningRoot} from "@lodestar/state-transition"; import {DOMAIN_BLS_TO_EXECUTION_CHANGE, ForkName} from "@lodestar/params"; import {createBeaconConfig} from "@lodestar/config"; import {ssz, capella} from "@lodestar/types"; import {getClient} from "@lodestar/api"; -import {CliCommand} from "@lodestar/utils"; +import {CliCommand, fromHex} from "@lodestar/utils"; import {GlobalArgs} from "../../options/index.js"; import {getBeaconConfigFromArgs} from "../../config/index.js"; @@ -67,13 +66,13 @@ like to choose for BLS To Execution Change.", throw new Error(`Validator pubkey ${publicKey} not found in state`); } - const blsPrivkey = SecretKey.fromBytes(fromHexString(args.fromBlsPrivkey)); + const blsPrivkey = SecretKey.fromBytes(fromHex(args.fromBlsPrivkey)); const fromBlsPubkey = blsPrivkey.toPublicKey().toBytes(); const blsToExecutionChange: capella.BLSToExecutionChange = { validatorIndex: validator.index, fromBlsPubkey, - toExecutionAddress: fromHexString(args.toExecutionAddress), + toExecutionAddress: fromHex(args.toExecutionAddress), }; const signatureFork = ForkName.phase0; diff --git a/packages/cli/src/cmds/validator/keymanager/impl.ts b/packages/cli/src/cmds/validator/keymanager/impl.ts index 2915c125eac2..d965b2af5075 100644 --- a/packages/cli/src/cmds/validator/keymanager/impl.ts +++ b/packages/cli/src/cmds/validator/keymanager/impl.ts @@ -1,5 +1,4 @@ import {Keystore} from "@chainsafe/bls-keystore"; -import {fromHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; import { DeleteRemoteKeyStatus, @@ -21,7 +20,7 @@ import {KeymanagerApiMethods as Api} from "@lodestar/api/keymanager/server"; import {Interchange, SignerType, Validator} from "@lodestar/validator"; import {ApiError} from "@lodestar/api/server"; import {Epoch} from "@lodestar/types"; -import {isValidHttpUrl} from "@lodestar/utils"; +import {fromHex, isValidHttpUrl} from "@lodestar/utils"; import {getPubkeyHexFromKeystore, isValidatePubkeyHex} from "../../../util/format.js"; import {parseFeeRecipient} from "../../../util/index.js"; import {DecryptKeystoresThreadPool} from "./decryptKeystores/index.js"; @@ -224,7 +223,7 @@ export class KeymanagerApi implements Api { } } - const pubkeysBytes = pubkeys.map((pubkeyHex) => fromHexString(pubkeyHex)); + const pubkeysBytes = pubkeys.map((pubkeyHex) => fromHex(pubkeyHex)); const interchangeV5 = await this.validator.exportInterchange(pubkeysBytes, { version: "5", diff --git a/packages/cli/src/util/format.ts b/packages/cli/src/util/format.ts index 01c2753193a4..a86ca0662a9f 100644 --- a/packages/cli/src/util/format.ts +++ b/packages/cli/src/util/format.ts @@ -1,5 +1,5 @@ import {PublicKey} from "@chainsafe/blst"; -import {fromHexString} from "@chainsafe/ssz"; +import {fromHex} from "@lodestar/utils"; /** * 0x prefix a string if not prefixed already @@ -50,7 +50,7 @@ export function parseRange(range: string): number[] { export function assertValidPubkeysHex(pubkeysHex: string[]): void { for (const pubkeyHex of pubkeysHex) { - const pubkeyBytes = fromHexString(pubkeyHex); + const pubkeyBytes = fromHex(pubkeyHex); PublicKey.fromBytes(pubkeyBytes, true); } } diff --git a/packages/cli/test/utils/crucible/assertions/blobsAssertion.ts b/packages/cli/test/utils/crucible/assertions/blobsAssertion.ts index dece5bc58ce8..50c9ed13f972 100644 --- a/packages/cli/test/utils/crucible/assertions/blobsAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/blobsAssertion.ts @@ -35,7 +35,7 @@ export function createBlobsAssertion( gasLimit: "0xc350", maxPriorityFeePerGas: "0x3b9aca00", maxFeePerGas: "0x3ba26b20", - maxFeePerBlobGas: "0x3e8", + maxFeePerBlobGas: "0x3e", value: "0x10000", nonce: `0x${(nonce ?? 0).toString(16)}`, blobVersionedHashes, diff --git a/packages/config/src/chainConfig/configs/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts index 741ddc99f8cd..e5792a87ac70 100644 --- a/packages/config/src/chainConfig/configs/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString as b} from "@chainsafe/ssz"; +import {fromHex as b} from "@lodestar/utils"; import {PresetName} from "@lodestar/params"; import {ChainConfig} from "../types.js"; diff --git a/packages/config/src/chainConfig/configs/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts index 26f49cc3e47d..53229d283511 100644 --- a/packages/config/src/chainConfig/configs/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString as b} from "@chainsafe/ssz"; +import {fromHex as b} from "@lodestar/utils"; import {PresetName} from "@lodestar/params"; import {ChainConfig} from "../types.js"; diff --git a/packages/config/src/chainConfig/json.ts b/packages/config/src/chainConfig/json.ts index 887409cd4c5b..78db9230c836 100644 --- a/packages/config/src/chainConfig/json.ts +++ b/packages/config/src/chainConfig/json.ts @@ -1,5 +1,4 @@ -import {fromHexString} from "@chainsafe/ssz"; -import {toHex} from "@lodestar/utils"; +import {fromHex, toHex} from "@lodestar/utils"; import {ChainConfig, chainConfigTypes, SpecValue, SpecValueTypeName} from "./types.js"; const MAX_UINT64_JSON = "18446744073709551615"; @@ -96,7 +95,7 @@ export function deserializeSpecValue(valueStr: unknown, typeName: SpecValueTypeN return BigInt(valueStr); case "bytes": - return fromHexString(valueStr); + return fromHex(valueStr); case "string": return valueStr; diff --git a/packages/config/src/chainConfig/networks/chiado.ts b/packages/config/src/chainConfig/networks/chiado.ts index 43b13a210dac..d96bd7510c65 100644 --- a/packages/config/src/chainConfig/networks/chiado.ts +++ b/packages/config/src/chainConfig/networks/chiado.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString as b} from "@chainsafe/ssz"; +import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; import {gnosisChainConfig as gnosis} from "./gnosis.js"; diff --git a/packages/config/src/chainConfig/networks/ephemery.ts b/packages/config/src/chainConfig/networks/ephemery.ts index 29e3f7b92d01..6fefc1800bfc 100644 --- a/packages/config/src/chainConfig/networks/ephemery.ts +++ b/packages/config/src/chainConfig/networks/ephemery.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString as b} from "@chainsafe/ssz"; +import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; diff --git a/packages/config/src/chainConfig/networks/gnosis.ts b/packages/config/src/chainConfig/networks/gnosis.ts index 8034e478fd28..2f58ffd4d045 100644 --- a/packages/config/src/chainConfig/networks/gnosis.ts +++ b/packages/config/src/chainConfig/networks/gnosis.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString as b} from "@chainsafe/ssz"; +import {fromHex as b} from "@lodestar/utils"; import {PresetName} from "@lodestar/params"; import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; diff --git a/packages/config/src/chainConfig/networks/holesky.ts b/packages/config/src/chainConfig/networks/holesky.ts index 187543b871f2..16c462a9468e 100644 --- a/packages/config/src/chainConfig/networks/holesky.ts +++ b/packages/config/src/chainConfig/networks/holesky.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString as b} from "@chainsafe/ssz"; +import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; diff --git a/packages/config/src/chainConfig/networks/mainnet.ts b/packages/config/src/chainConfig/networks/mainnet.ts index 24584ad8442b..c137c578fc0e 100644 --- a/packages/config/src/chainConfig/networks/mainnet.ts +++ b/packages/config/src/chainConfig/networks/mainnet.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString as b} from "@chainsafe/ssz"; +import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; diff --git a/packages/config/src/chainConfig/networks/sepolia.ts b/packages/config/src/chainConfig/networks/sepolia.ts index 51102cfafa7d..39e72a24f3f6 100644 --- a/packages/config/src/chainConfig/networks/sepolia.ts +++ b/packages/config/src/chainConfig/networks/sepolia.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString as b} from "@chainsafe/ssz"; +import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; diff --git a/packages/light-client/src/index.ts b/packages/light-client/src/index.ts index 03be60eca05d..5ec0dd73b469 100644 --- a/packages/light-client/src/index.ts +++ b/packages/light-client/src/index.ts @@ -1,5 +1,4 @@ import mitt from "mitt"; -import {fromHexString} from "@chainsafe/ssz"; import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD} from "@lodestar/params"; import { LightClientBootstrap, @@ -13,7 +12,7 @@ import { SyncPeriod, } from "@lodestar/types"; import {createBeaconConfig, BeaconConfig, ChainForkConfig} from "@lodestar/config"; -import {isErrorAborted, sleep, toRootHex} from "@lodestar/utils"; +import {fromHex, isErrorAborted, sleep, toRootHex} from "@lodestar/utils"; import {getCurrentSlot, slotWithFutureTolerance, timeUntilNextEpoch} from "./utils/clock.js"; import {chunkifyInclusiveRange} from "./utils/chunkify.js"; import {LightclientEmitter, LightclientEvent} from "./events.js"; @@ -120,7 +119,7 @@ export class Lightclient { this.genesisTime = genesisData.genesisTime; this.genesisValidatorsRoot = typeof genesisData.genesisValidatorsRoot === "string" - ? fromHexString(genesisData.genesisValidatorsRoot) + ? fromHex(genesisData.genesisValidatorsRoot) : genesisData.genesisValidatorsRoot; this.config = createBeaconConfig(config, this.genesisValidatorsRoot); diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index af6e976e9089..ba8ec9b05ab5 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -1,6 +1,5 @@ import {PublicKey} from "@chainsafe/blst"; import * as immutable from "immutable"; -import {fromHexString} from "@chainsafe/ssz"; import { BLSSignature, CommitteeIndex, @@ -25,7 +24,7 @@ import { SLOTS_PER_EPOCH, WEIGHT_DENOMINATOR, } from "@lodestar/params"; -import {LodestarError} from "@lodestar/utils"; +import {LodestarError, fromHex} from "@lodestar/utils"; import { computeActivationExitEpoch, computeEpochAtSlot, @@ -964,7 +963,7 @@ export class EpochCache { } this.pubkey2index.set(pubkey, index); - const pubkeyBytes = pubkey instanceof Uint8Array ? pubkey : fromHexString(pubkey); + const pubkeyBytes = pubkey instanceof Uint8Array ? pubkey : fromHex(pubkey); this.index2pubkey[index] = PublicKey.fromBytes(pubkeyBytes); // Optimize for aggregation } diff --git a/packages/utils/src/bytes/nodejs.ts b/packages/utils/src/bytes/nodejs.ts index 636f49bd8e76..4cf8e78c67c6 100644 --- a/packages/utils/src/bytes/nodejs.ts +++ b/packages/utils/src/bytes/nodejs.ts @@ -44,6 +44,18 @@ export function toPubkeyHex(pubkey: Uint8Array): string { } export function fromHex(hex: string): Uint8Array { - const b = Buffer.from(hex.replace("0x", ""), "hex"); + if (typeof hex !== "string") { + throw new Error(`hex argument type ${typeof hex} must be of type string`); + } + + if (hex.startsWith("0x")) { + hex = hex.slice(2); + } + + if (hex.length % 2 !== 0) { + throw new Error(`hex string length ${hex.length} must be multiple of 2`); + } + + const b = Buffer.from(hex, "hex"); return new Uint8Array(b.buffer, b.byteOffset, b.length); } diff --git a/packages/validator/src/services/chainHeaderTracker.ts b/packages/validator/src/services/chainHeaderTracker.ts index 845743264d0b..1c0b0d9a56d8 100644 --- a/packages/validator/src/services/chainHeaderTracker.ts +++ b/packages/validator/src/services/chainHeaderTracker.ts @@ -1,6 +1,5 @@ -import {fromHexString} from "@chainsafe/ssz"; import {ApiClient, routes} from "@lodestar/api"; -import {Logger} from "@lodestar/utils"; +import {Logger, fromHex} from "@lodestar/utils"; import {Slot, Root, RootHex} from "@lodestar/types"; import {GENESIS_SLOT} from "@lodestar/params"; import {ValidatorEvent, ValidatorEventEmitter} from "./emitter.js"; @@ -64,7 +63,7 @@ export class ChainHeaderTracker { const {message} = event; const {slot, block, previousDutyDependentRoot, currentDutyDependentRoot} = message; this.headBlockSlot = slot; - this.headBlockRoot = fromHexString(block); + this.headBlockRoot = fromHex(block); const headEventData = { slot: this.headBlockSlot, diff --git a/packages/validator/src/services/doppelgangerService.ts b/packages/validator/src/services/doppelgangerService.ts index 5435c5aed37f..e167ee1d5028 100644 --- a/packages/validator/src/services/doppelgangerService.ts +++ b/packages/validator/src/services/doppelgangerService.ts @@ -1,7 +1,6 @@ -import {fromHexString} from "@chainsafe/ssz"; import {Epoch, ValidatorIndex} from "@lodestar/types"; import {ApiClient, routes} from "@lodestar/api"; -import {Logger, sleep, truncBytes} from "@lodestar/utils"; +import {Logger, fromHex, sleep, truncBytes} from "@lodestar/utils"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {ISlashingProtection} from "../slashingProtection/index.js"; import {ProcessShutdownCallback, PubkeyHex} from "../types.js"; @@ -69,7 +68,7 @@ export class DoppelgangerService { if (remainingEpochs > 0) { const previousEpoch = currentEpoch - 1; const attestedInPreviousEpoch = await this.slashingProtection.hasAttestedInEpoch( - fromHexString(pubkeyHex), + fromHex(pubkeyHex), previousEpoch ); diff --git a/packages/validator/src/services/externalSignerSync.ts b/packages/validator/src/services/externalSignerSync.ts index 2f1880dda1bb..2f6828d9e09b 100644 --- a/packages/validator/src/services/externalSignerSync.ts +++ b/packages/validator/src/services/externalSignerSync.ts @@ -1,8 +1,7 @@ -import {fromHexString} from "@chainsafe/ssz"; import {PublicKey} from "@chainsafe/blst"; import {ChainForkConfig} from "@lodestar/config"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {toPrintableUrl} from "@lodestar/utils"; +import {fromHex, toPrintableUrl} from "@lodestar/utils"; import {LoggerVc} from "../util/index.js"; import {externalSignerGetKeys} from "../util/externalSignerClient.js"; @@ -77,7 +76,7 @@ export function pollExternalSignerPubkeys( function assertValidPubkeysHex(pubkeysHex: string[]): void { for (const pubkeyHex of pubkeysHex) { - const pubkeyBytes = fromHexString(pubkeyHex); + const pubkeyBytes = fromHex(pubkeyHex); PublicKey.fromBytes(pubkeyBytes, true); } } diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index b64917ec03ae..6da4f597d87c 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -1,4 +1,4 @@ -import {BitArray, fromHexString} from "@chainsafe/ssz"; +import {BitArray} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; import { computeEpochAtSlot, @@ -42,7 +42,7 @@ import { SignedAggregateAndProof, } from "@lodestar/types"; import {routes} from "@lodestar/api"; -import {toPubkeyHex, toRootHex} from "@lodestar/utils"; +import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; import {ISlashingProtection} from "../slashingProtection/index.js"; import {PubkeyHex} from "../types.js"; import {externalSignerPostSignature, SignableMessageType, SignableMessage} from "../util/externalSignerClient.js"; @@ -693,8 +693,8 @@ export class ValidatorStore { regAttributes: {feeRecipient: Eth1Address; gasLimit: number}, _slot: Slot ): Promise { - const pubkey = typeof pubkeyMaybeHex === "string" ? fromHexString(pubkeyMaybeHex) : pubkeyMaybeHex; - const feeRecipient = fromHexString(regAttributes.feeRecipient); + const pubkey = typeof pubkeyMaybeHex === "string" ? fromHex(pubkeyMaybeHex) : pubkeyMaybeHex; + const feeRecipient = fromHex(regAttributes.feeRecipient); const {gasLimit} = regAttributes; const validatorRegistration: bellatrix.ValidatorRegistrationV1 = { @@ -775,7 +775,7 @@ export class ValidatorStore { signingSlot, signableMessage ); - return fromHexString(signatureHex); + return fromHex(signatureHex); } catch (e) { this.metrics?.remoteSignErrors.inc(); throw e; diff --git a/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts b/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts index d1e9475daa0e..b43ced6c80d3 100644 --- a/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts +++ b/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString} from "@chainsafe/ssz"; -import {toPubkeyHex, toRootHex} from "@lodestar/utils"; +import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; import {InterchangeLodestar} from "../types.js"; import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js"; @@ -110,9 +109,9 @@ export function serializeInterchangeCompleteV4({ export function parseInterchangeCompleteV4(interchange: InterchangeCompleteV4): InterchangeLodestar { return { - genesisValidatorsRoot: fromHexString(interchange.metadata.genesis_validators_root), + genesisValidatorsRoot: fromHex(interchange.metadata.genesis_validators_root), data: interchange.data.map((validator) => ({ - pubkey: fromHexString(validator.pubkey), + pubkey: fromHex(validator.pubkey), signedBlocks: validator.signed_blocks.map((block) => ({ slot: parseInt(block.slot, 10), signingRoot: fromOptionalHexString(block.signing_root), diff --git a/packages/validator/src/slashingProtection/interchange/formats/v5.ts b/packages/validator/src/slashingProtection/interchange/formats/v5.ts index 20d11aefe91a..838ba76c1a57 100644 --- a/packages/validator/src/slashingProtection/interchange/formats/v5.ts +++ b/packages/validator/src/slashingProtection/interchange/formats/v5.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {fromHexString} from "@chainsafe/ssz"; -import {toPubkeyHex, toRootHex} from "@lodestar/utils"; +import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; import {InterchangeLodestar} from "../types.js"; import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js"; @@ -105,9 +104,9 @@ export function serializeInterchangeV5({data, genesisValidatorsRoot}: Interchang export function parseInterchangeV5(interchange: InterchangeV5): InterchangeLodestar { return { - genesisValidatorsRoot: fromHexString(interchange.metadata.genesis_validators_root), + genesisValidatorsRoot: fromHex(interchange.metadata.genesis_validators_root), data: interchange.data.map((validator) => ({ - pubkey: fromHexString(validator.pubkey), + pubkey: fromHex(validator.pubkey), signedBlocks: validator.signed_blocks.map((block) => ({ slot: parseInt(block.slot, 10), signingRoot: fromOptionalHexString(block.signing_root), diff --git a/packages/validator/src/slashingProtection/utils.ts b/packages/validator/src/slashingProtection/utils.ts index 294036981b14..adc93bdafee5 100644 --- a/packages/validator/src/slashingProtection/utils.ts +++ b/packages/validator/src/slashingProtection/utils.ts @@ -1,6 +1,5 @@ -import {fromHexString} from "@chainsafe/ssz"; import {Epoch, Root, ssz} from "@lodestar/types"; -import {toHex, toRootHex} from "@lodestar/utils"; +import {fromHex, toHex, toRootHex} from "@lodestar/utils"; export const blsPubkeyLen = 48; export const ZERO_ROOT = ssz.Root.defaultValue(); @@ -14,7 +13,7 @@ export function isEqualNonZeroRoot(root1: Root, root2: Root): boolean { } export function fromOptionalHexString(hex: string | undefined): Root { - return hex ? fromHexString(hex) : ZERO_ROOT; + return hex ? fromHex(hex) : ZERO_ROOT; } export function toOptionalHexString(root: Root): string | undefined { From 295690b89611da4e9bdc551afcd47dda49642462 Mon Sep 17 00:00:00 2001 From: g11tech Date: Sat, 14 Sep 2024 14:44:11 +0530 Subject: [PATCH 099/259] fix: use bigint gwei type for amount in requests instead of num 64 (#7085) * fix: use bigint gwei type for amount in requests instead of num 64 * revert deposit amount to uintnum64 as unlikely to get a high amount * fix --- packages/beacon-node/src/execution/engine/types.ts | 2 +- packages/types/src/electra/sszTypes.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 63cb4da88b6c..139fc6822780 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -461,7 +461,7 @@ export function deserializeWithdrawalRequest(withdrawalRequest: WithdrawalReques return { sourceAddress: dataToBytes(withdrawalRequest.sourceAddress, 20), validatorPubkey: dataToBytes(withdrawalRequest.validatorPubkey, 48), - amount: quantityToNum(withdrawalRequest.amount), + amount: quantityToBigint(withdrawalRequest.amount), }; } diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 31844aac86cc..c0485597686a 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -116,6 +116,8 @@ export const DepositRequest = new ContainerType( { pubkey: BLSPubkey, withdrawalCredentials: Bytes32, + // this is actually gwei uintbn64 type, but super unlikely to get a high amount here + // to warrant a bn type amount: UintNum64, signature: BLSSignature, index: DepositIndex, @@ -129,7 +131,7 @@ export const WithdrawalRequest = new ContainerType( { sourceAddress: ExecutionAddress, validatorPubkey: BLSPubkey, - amount: UintNum64, + amount: Gwei, }, {typeName: "WithdrawalRequest", jsonCase: "eth2"} ); From 43b41afd341b14777fa4ed352ae1460bea843553 Mon Sep 17 00:00:00 2001 From: twoeths Date: Mon, 16 Sep 2024 17:58:55 +0700 Subject: [PATCH 100/259] chore: metrics for regen getState() (#7086) --- dashboards/lodestar_state_cache_regen.json | 491 ++++++++++++++++++++- 1 file changed, 480 insertions(+), 11 deletions(-) diff --git a/dashboards/lodestar_state_cache_regen.json b/dashboards/lodestar_state_cache_regen.json index e7f6336eaeb9..426cde226022 100644 --- a/dashboards/lodestar_state_cache_regen.json +++ b/dashboards/lodestar_state_cache_regen.json @@ -1333,7 +1333,7 @@ "options": { "mode": "exclude", "names": [ - "count_per_epoch" + "sec_from_slot" ], "prefix": "All except:", "readOnly": true @@ -1610,7 +1610,32 @@ }, "mappings": [] }, - "overrides": [] + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "from_persistent" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] }, "gridPos": { "h": 8, @@ -1705,7 +1730,32 @@ }, "mappings": [] }, - "overrides": [] + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "state_reload_validator_serialization" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] }, "gridPos": { "h": 8, @@ -1827,7 +1877,32 @@ }, "mappings": [] }, - "overrides": [] + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "getState" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] }, "gridPos": { "h": 8, @@ -2445,6 +2520,400 @@ "title": "Error rate (grouped by caller)", "type": "timeseries" }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 82 + }, + "id": 60, + "panels": [], + "title": "Regen - getState", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 83 + }, + "id": 61, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "rate(lodestar_regen_get_state_get_seed_state_seconds_sum[$rate_interval])\n/\nrate(lodestar_regen_get_state_get_seed_state_seconds_count[$rate_interval])", + "instant": false, + "legendFormat": "{{caller}}", + "range": true, + "refId": "A" + } + ], + "title": "Get seed state duration", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 83 + }, + "id": 62, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "rate(lodestar_regen_get_state_load_blocks_seconds_sum[$rate_interval])\n/\nrate(lodestar_regen_get_state_load_blocks_seconds_count[$rate_interval])", + "instant": false, + "legendFormat": "{{caller}}", + "range": true, + "refId": "A" + } + ], + "title": "Load blocks duration", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "unit": "s" + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "validateGossipBlock" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 91 + }, + "id": 63, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "rate(lodestar_regen_get_state_state_transition_seconds_sum[$rate_interval])\n/\nrate(lodestar_regen_get_state_state_transition_seconds_count[$rate_interval])", + "instant": false, + "legendFormat": "{{caller}}", + "range": true, + "refId": "A" + } + ], + "title": "State transition duration", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [] + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "validateGossipBlock" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 91 + }, + "id": 64, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "rate(lodestar_regen_get_state_block_count_sum[$rate_interval])\n/\nrate(lodestar_regen_get_state_block_count_count[$rate_interval])", + "instant": false, + "legendFormat": "{{caller}}", + "range": true, + "refId": "A" + } + ], + "title": "Reprocessed block count", + "type": "timeseries" + }, { "collapsed": false, "datasource": { @@ -2455,7 +2924,7 @@ "h": 1, "w": 24, "x": 0, - "y": 82 + "y": 99 }, "id": 54, "panels": [], @@ -2523,7 +2992,7 @@ "h": 7, "w": 12, "x": 0, - "y": 83 + "y": 100 }, "id": 42, "options": { @@ -2608,7 +3077,7 @@ "h": 7, "w": 6, "x": 12, - "y": 83 + "y": 100 }, "id": 44, "options": { @@ -2692,7 +3161,7 @@ "h": 7, "w": 6, "x": 18, - "y": 83 + "y": 100 }, "id": 48, "options": { @@ -2776,7 +3245,7 @@ "h": 7, "w": 12, "x": 0, - "y": 90 + "y": 107 }, "id": 46, "options": { @@ -2860,7 +3329,7 @@ "h": 7, "w": 6, "x": 12, - "y": 90 + "y": 107 }, "id": 50, "options": { @@ -2944,7 +3413,7 @@ "h": 7, "w": 6, "x": 18, - "y": 90 + "y": 107 }, "id": 52, "options": { From d3d61af6bd33b92ce7d767953ea80cdeecd686cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:47:05 +0100 Subject: [PATCH 101/259] chore(deps): bump path-to-regexp from 6.2.2 to 6.3.0 (#7082) Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) from 6.2.2 to 6.3.0. - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v6.2.2...v6.3.0) --- updated-dependencies: - dependency-name: path-to-regexp dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 60e41c276e53..7eb7a89c33dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10647,9 +10647,9 @@ path-scurry@^1.11.1: minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-to-regexp@^6.2.0: - version "6.2.2" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.2.tgz#324377a83e5049cbecadc5554d6a63a9a4866b36" - integrity sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw== + version "6.3.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.3.0.tgz#2b6a26a337737a8e1416f9272ed0766b1c0389f4" + integrity sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ== path-type@^3.0.0: version "3.0.0" From 67a35f8e76642661287aeec86115e5b19b51fdbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:47:51 +0100 Subject: [PATCH 102/259] chore(deps): bump express from 4.19.2 to 4.21.0 in /docs (#7078) Bumps [express](https://github.com/expressjs/express) from 4.19.2 to 4.21.0. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0) --- updated-dependencies: - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/yarn.lock | 95 ++++++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/docs/yarn.lock b/docs/yarn.lock index 41966c013183..c39bab969363 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -3136,10 +3136,10 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -body-parser@1.20.2: - version "1.20.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -3149,7 +3149,7 @@ body-parser@1.20.2: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" + qs "6.13.0" raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -4454,6 +4454,11 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + enhanced-resolve@^5.15.0: version "5.15.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.1.tgz#384391e025f099e67b4b00bfd7f0906a408214e1" @@ -4659,36 +4664,36 @@ execa@^5.0.0: strip-final-newline "^2.0.0" express@^4.17.3: - version "4.19.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" - integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.2" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.2.0" + finalhandler "1.3.1" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.10" proxy-addr "~2.0.7" - qs "6.11.0" + qs "6.13.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.2" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -4783,13 +4788,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -6345,10 +6350,10 @@ memfs@^3.1.2, memfs@^3.4.3: dependencies: fs-monkey "^1.0.4" -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" @@ -7426,10 +7431,10 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== path-to-regexp@2.2.1: version "2.2.1" @@ -7854,12 +7859,12 @@ pupa@^3.1.0: dependencies: escape-goat "^4.0.0" -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" queue-microtask@^1.2.2: version "1.2.3" @@ -8458,10 +8463,10 @@ semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.5.4: dependencies: lru-cache "^6.0.0" -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -8511,15 +8516,15 @@ serve-index@^1.9.1: mime-types "~2.1.17" parseurl "~1.3.2" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" + send "0.19.0" set-function-length@^1.2.1: version "1.2.1" @@ -8581,7 +8586,7 @@ shelljs@^0.8.5: interpret "^1.0.0" rechoir "^0.6.2" -side-channel@^1.0.4: +side-channel@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== From 9fe72391bea93f7f88b7b739006844352d929cad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:51:12 +0100 Subject: [PATCH 103/259] chore(deps): bump micromatch from 4.0.5 to 4.0.8 (#7058) Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.5 to 4.0.8. - [Release notes](https://github.com/micromatch/micromatch/releases) - [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/micromatch/compare/4.0.5...4.0.8) --- updated-dependencies: - dependency-name: micromatch dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7eb7a89c33dd..f9fa36847af9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4506,7 +4506,14 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@~3.0.2: +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -6768,6 +6775,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + find-my-way@^8.0.0: version "8.1.0" resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-8.1.0.tgz#cc05e8e4b145322299d0de0a839b5be528c2083e" @@ -9274,11 +9288,11 @@ micro-ftch@^0.3.1: integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" miller-rabin@^4.0.0: From 1bb98ed6db16e2d1ec2fb9f1f9a0ea8fafba7aac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:38:42 +0000 Subject: [PATCH 104/259] chore(deps): bump webpack from 5.90.3 to 5.94.0 in /docs (#7059) Bumps [webpack](https://github.com/webpack/webpack) from 5.90.3 to 5.94.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.90.3...v5.94.0) --- updated-dependencies: - dependency-name: webpack dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/yarn.lock | 167 ++++++++++++++++++++++--------------------------- 1 file changed, 75 insertions(+), 92 deletions(-) diff --git a/docs/yarn.lock b/docs/yarn.lock index c39bab969363..06e7cf388568 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -2430,22 +2430,6 @@ dependencies: "@types/ms" "*" -"@types/eslint-scope@^3.7.3": - version "3.7.7" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" - integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "8.56.5" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.5.tgz#94b88cab77588fcecdd0771a6d576fa1c0af9d02" - integrity sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - "@types/estree-jsx@^1.0.0": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz#858a88ea20f34fe65111f005a689fa1ebf70dc18" @@ -2536,7 +2520,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -2736,10 +2720,10 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" - integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== +"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" + integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== dependencies: "@webassemblyjs/helper-numbers" "1.11.6" "@webassemblyjs/helper-wasm-bytecode" "1.11.6" @@ -2754,10 +2738,10 @@ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== -"@webassemblyjs/helper-buffer@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" - integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== +"@webassemblyjs/helper-buffer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" + integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== "@webassemblyjs/helper-numbers@1.11.6": version "1.11.6" @@ -2773,15 +2757,15 @@ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== -"@webassemblyjs/helper-wasm-section@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" - integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== +"@webassemblyjs/helper-wasm-section@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" + integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-gen" "1.12.1" "@webassemblyjs/ieee754@1.11.6": version "1.11.6" @@ -2802,59 +2786,59 @@ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== -"@webassemblyjs/wasm-edit@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" - integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== +"@webassemblyjs/wasm-edit@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" + integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/helper-wasm-section" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - "@webassemblyjs/wasm-opt" "1.11.6" - "@webassemblyjs/wasm-parser" "1.11.6" - "@webassemblyjs/wast-printer" "1.11.6" - -"@webassemblyjs/wasm-gen@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" - integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== - dependencies: - "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-opt" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + "@webassemblyjs/wast-printer" "1.12.1" + +"@webassemblyjs/wasm-gen@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" + integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== + dependencies: + "@webassemblyjs/ast" "1.12.1" "@webassemblyjs/helper-wasm-bytecode" "1.11.6" "@webassemblyjs/ieee754" "1.11.6" "@webassemblyjs/leb128" "1.11.6" "@webassemblyjs/utf8" "1.11.6" -"@webassemblyjs/wasm-opt@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" - integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== +"@webassemblyjs/wasm-opt@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" + integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - "@webassemblyjs/wasm-parser" "1.11.6" + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" -"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" - integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== +"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" + integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== dependencies: - "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/ast" "1.12.1" "@webassemblyjs/helper-api-error" "1.11.6" "@webassemblyjs/helper-wasm-bytecode" "1.11.6" "@webassemblyjs/ieee754" "1.11.6" "@webassemblyjs/leb128" "1.11.6" "@webassemblyjs/utf8" "1.11.6" -"@webassemblyjs/wast-printer@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" - integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== +"@webassemblyjs/wast-printer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" + integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== dependencies: - "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/ast" "1.12.1" "@xtuc/long" "4.2.2" "@xtuc/ieee754@^1.2.0": @@ -2875,10 +2859,10 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-import-assertions@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" - integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== acorn-jsx@^5.0.0: version "5.3.2" @@ -4459,10 +4443,10 @@ encodeurl@~2.0.0: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== -enhanced-resolve@^5.15.0: - version "5.15.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.1.tgz#384391e025f099e67b4b00bfd7f0906a408214e1" - integrity sha512-3d3JRbwsCLJsYgvb6NuWEG44jjPSOMuS73L/6+7BZuoKm3W+qXnSoIYVHi8dG7Qcg4inAY4jbzkZ7MnskePeDg== +enhanced-resolve@^5.17.1: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -5076,7 +5060,7 @@ graceful-fs@4.2.10: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -9251,10 +9235,10 @@ vfile@^6.0.0, vfile@^6.0.1: unist-util-stringify-position "^4.0.0" vfile-message "^4.0.0" -watchpack@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== +watchpack@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da" + integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" @@ -9357,25 +9341,24 @@ webpack-sources@^3.2.2, webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.88.1: - version "5.90.3" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.90.3.tgz#37b8f74d3ded061ba789bb22b31e82eed75bd9ac" - integrity sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA== + version "5.94.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f" + integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg== dependencies: - "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.5" - "@webassemblyjs/ast" "^1.11.5" - "@webassemblyjs/wasm-edit" "^1.11.5" - "@webassemblyjs/wasm-parser" "^1.11.5" + "@webassemblyjs/ast" "^1.12.1" + "@webassemblyjs/wasm-edit" "^1.12.1" + "@webassemblyjs/wasm-parser" "^1.12.1" acorn "^8.7.1" - acorn-import-assertions "^1.9.0" + acorn-import-attributes "^1.9.5" browserslist "^4.21.10" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.15.0" + enhanced-resolve "^5.17.1" es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" glob-to-regexp "^0.4.1" - graceful-fs "^4.2.9" + graceful-fs "^4.2.11" json-parse-even-better-errors "^2.3.1" loader-runner "^4.2.0" mime-types "^2.1.27" @@ -9383,7 +9366,7 @@ webpack@^5.88.1: schema-utils "^3.2.0" tapable "^2.1.1" terser-webpack-plugin "^5.3.10" - watchpack "^2.4.0" + watchpack "^2.4.1" webpack-sources "^3.2.3" webpackbar@^5.0.2: From 2fcecd61f51d076769d4146611e898ec83690948 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 22:28:24 +0100 Subject: [PATCH 105/259] chore(deps): bump dompurify from 3.0.9 to 3.1.6 in /docs (#7088) Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.0.9 to 3.1.6. - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/3.0.9...3.1.6) --- updated-dependencies: - dependency-name: dompurify dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/yarn.lock b/docs/yarn.lock index 06e7cf388568..27123932fe26 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -4346,9 +4346,9 @@ domhandler@^5.0.2, domhandler@^5.0.3: domelementtype "^2.3.0" dompurify@^3.0.5: - version "3.0.9" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.0.9.tgz#b3f362f24b99f53498c75d43ecbd784b0b3ad65e" - integrity sha512-uyb4NDIvQ3hRn6NiC+SIFaP4mJ/MdXlvtunaqK9Bn6dD3RuB/1S/gasEjDHD8eiaqdSael2vBv+hOs7Y+jhYOQ== + version "3.1.6" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.1.6.tgz#43c714a94c6a7b8801850f82e756685300a027e2" + integrity sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ== domutils@^2.5.2, domutils@^2.8.0: version "2.8.0" From 25837f61fed8089ebb8e06e505fea8e7a48b614e Mon Sep 17 00:00:00 2001 From: Phil Ngo Date: Tue, 17 Sep 2024 14:45:18 -0400 Subject: [PATCH 106/259] Merge branch 'stable' into unstable --- lerna.json | 2 +- packages/api/package.json | 10 +++++----- packages/beacon-node/package.json | 26 +++++++++++++------------- packages/cli/package.json | 26 +++++++++++++------------- packages/config/package.json | 8 ++++---- packages/db/package.json | 8 ++++---- packages/flare/package.json | 14 +++++++------- packages/fork-choice/package.json | 12 ++++++------ packages/light-client/package.json | 12 ++++++------ packages/logger/package.json | 6 +++--- packages/params/package.json | 2 +- packages/prover/package.json | 18 +++++++++--------- packages/reqresp/package.json | 12 ++++++------ packages/spec-test-util/package.json | 4 ++-- packages/state-transition/package.json | 10 +++++----- packages/test-utils/package.json | 6 +++--- packages/types/package.json | 4 ++-- packages/utils/package.json | 2 +- packages/validator/package.json | 18 +++++++++--------- 19 files changed, 100 insertions(+), 100 deletions(-) diff --git a/lerna.json b/lerna.json index 043a5c48569a..0ffc65fe5402 100644 --- a/lerna.json +++ b/lerna.json @@ -4,7 +4,7 @@ ], "npmClient": "yarn", "useNx": true, - "version": "1.21.0", + "version": "1.22.0", "stream": true, "command": { "version": { diff --git a/packages/api/package.json b/packages/api/package.json index 138964ed946a..d2f8a621f02e 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -72,10 +72,10 @@ "dependencies": { "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/ssz": "^0.17.1", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", "eventsource": "^2.0.2", "qs": "^6.11.1" }, diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index b41450f12d34..ade89ebc6cc1 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -119,18 +119,18 @@ "@libp2p/peer-id-factory": "^4.1.0", "@libp2p/prometheus-metrics": "^3.0.21", "@libp2p/tcp": "9.0.23", - "@lodestar/api": "^1.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/db": "^1.21.0", - "@lodestar/fork-choice": "^1.21.0", - "@lodestar/light-client": "^1.21.0", - "@lodestar/logger": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/reqresp": "^1.21.0", - "@lodestar/state-transition": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", - "@lodestar/validator": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/db": "^1.22.0", + "@lodestar/fork-choice": "^1.22.0", + "@lodestar/light-client": "^1.22.0", + "@lodestar/logger": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/reqresp": "^1.22.0", + "@lodestar/state-transition": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", + "@lodestar/validator": "^1.22.0", "@multiformats/multiaddr": "^12.1.3", "c-kzg": "^2.1.2", "datastore-core": "^9.1.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index bf8621344dc5..579725eba04e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@chainsafe/lodestar", - "version": "1.21.0", + "version": "1.22.0", "description": "Command line interface for lodestar", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -62,17 +62,17 @@ "@libp2p/crypto": "^4.1.0", "@libp2p/peer-id": "^4.1.0", "@libp2p/peer-id-factory": "^4.1.0", - "@lodestar/api": "^1.21.0", - "@lodestar/beacon-node": "^1.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/db": "^1.21.0", - "@lodestar/light-client": "^1.21.0", - "@lodestar/logger": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/state-transition": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", - "@lodestar/validator": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/beacon-node": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/db": "^1.22.0", + "@lodestar/light-client": "^1.22.0", + "@lodestar/logger": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/state-transition": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", + "@lodestar/validator": "^1.22.0", "@multiformats/multiaddr": "^12.1.3", "deepmerge": "^4.3.1", "ethers": "^6.7.0", @@ -88,7 +88,7 @@ "yargs": "^17.7.1" }, "devDependencies": { - "@lodestar/test-utils": "^1.21.0", + "@lodestar/test-utils": "^1.22.0", "@types/debug": "^4.1.7", "@types/got": "^9.6.12", "@types/inquirer": "^9.0.3", diff --git a/packages/config/package.json b/packages/config/package.json index d13713d376c6..f257db65cf6e 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/config", - "version": "1.21.0", + "version": "1.22.0", "description": "Chain configuration required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -65,8 +65,8 @@ ], "dependencies": { "@chainsafe/ssz": "^0.17.1", - "@lodestar/params": "^1.21.0", - "@lodestar/utils": "^1.21.0", - "@lodestar/types": "^1.21.0" + "@lodestar/params": "^1.22.0", + "@lodestar/utils": "^1.22.0", + "@lodestar/types": "^1.22.0" } } diff --git a/packages/db/package.json b/packages/db/package.json index 1a31603b6791..0e3a2c847d4b 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/db", - "version": "1.21.0", + "version": "1.22.0", "description": "DB modules of Lodestar", "author": "ChainSafe Systems", "homepage": "https://github.com/ChainSafe/lodestar#readme", @@ -36,12 +36,12 @@ }, "dependencies": { "@chainsafe/ssz": "^0.17.1", - "@lodestar/config": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/config": "^1.22.0", + "@lodestar/utils": "^1.22.0", "classic-level": "^1.4.1", "it-all": "^3.0.4" }, "devDependencies": { - "@lodestar/logger": "^1.21.0" + "@lodestar/logger": "^1.22.0" } } diff --git a/packages/flare/package.json b/packages/flare/package.json index 461147274591..3a11e9b49ebf 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/flare", - "version": "1.21.0", + "version": "1.22.0", "description": "Beacon chain debugging tool", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -60,12 +60,12 @@ "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", "@chainsafe/blst": "^2.0.3", - "@lodestar/api": "^1.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/state-transition": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/state-transition": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.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 dfe4c942832d..728036b365d3 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.21.0", + "version": "1.22.0", "type": "module", "exports": "./lib/index.js", "types": "./lib/index.d.ts", @@ -37,11 +37,11 @@ }, "dependencies": { "@chainsafe/ssz": "^0.17.1", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/state-transition": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0" + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/state-transition": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0" }, "keywords": [ "ethereum", diff --git a/packages/light-client/package.json b/packages/light-client/package.json index 1188732c8870..940a78ae66d5 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -77,11 +77,11 @@ "@chainsafe/blst": "^0.2.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/ssz": "^0.17.1", - "@lodestar/api": "^1.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", "mitt": "^3.0.0" }, "devDependencies": { diff --git a/packages/logger/package.json b/packages/logger/package.json index 1ab176dbfd93..196fb306a8b0 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -66,14 +66,14 @@ }, "types": "lib/index.d.ts", "dependencies": { - "@lodestar/utils": "^1.21.0", + "@lodestar/utils": "^1.22.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.21.0", + "@lodestar/test-utils": "^1.22.0", "@types/triple-beam": "^1.3.2", "triple-beam": "^1.3.0" }, diff --git a/packages/params/package.json b/packages/params/package.json index c246918959e4..c281f97a41ec 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/params", - "version": "1.21.0", + "version": "1.22.0", "description": "Chain parameters required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", diff --git a/packages/prover/package.json b/packages/prover/package.json index 974125e2a17f..6a31b5b1baa0 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.21.0", + "version": "1.22.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.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/light-client": "^1.21.0", - "@lodestar/logger": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/light-client": "^1.22.0", + "@lodestar/logger": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.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.21.0", + "@lodestar/test-utils": "^1.22.0", "@types/http-proxy": "^1.17.10", "@types/yargs": "^17.0.24", "axios": "^1.3.4", diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index 1b9d99b000a8..44dcb8048f99 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -54,9 +54,9 @@ "dependencies": { "@chainsafe/fast-crc32c": "^4.1.1", "@libp2p/interface": "^1.3.0", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/utils": "^1.22.0", "it-all": "^3.0.4", "it-pipe": "^3.0.1", "snappy": "^7.2.2", @@ -65,8 +65,8 @@ "uint8arraylist": "^2.4.7" }, "devDependencies": { - "@lodestar/logger": "^1.21.0", - "@lodestar/types": "^1.21.0", + "@lodestar/logger": "^1.22.0", + "@lodestar/types": "^1.22.0", "libp2p": "1.4.3" }, "peerDependencies": { diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index 166df67a7409..b4aabf0140e8 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.21.0", + "version": "1.22.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.21.0", + "@lodestar/utils": "^1.22.0", "axios": "^1.3.4", "rimraf": "^4.4.1", "snappyjs": "^0.7.0", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 1dd43ef98f88..2df87a522a63 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -63,10 +63,10 @@ "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/persistent-ts": "^0.19.1", "@chainsafe/ssz": "^0.17.1", - "@lodestar/config": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/config": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", "bigint-buffer": "^1.1.5", "immutable": "^4.3.2" }, diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 6c8c9e62894f..5bf61891a9d5 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.21.0", + "version": "1.22.0", "description": "Test utilities reused across other packages", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -59,8 +59,8 @@ "dependencies": { "@chainsafe/bls-keystore": "^3.1.0", "@chainsafe/blst": "^2.0.3", - "@lodestar/params": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/params": "^1.22.0", + "@lodestar/utils": "^1.22.0", "axios": "^1.3.4", "testcontainers": "^10.2.1", "tmp": "^0.2.1", diff --git a/packages/types/package.json b/packages/types/package.json index 861dbdbee0ef..f3e034ec1b35 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.21.0", + "version": "1.22.0", "type": "module", "exports": { ".": { @@ -74,7 +74,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/ssz": "^0.17.1", - "@lodestar/params": "^1.21.0", + "@lodestar/params": "^1.22.0", "ethereum-cryptography": "^2.0.0" }, "keywords": [ diff --git a/packages/utils/package.json b/packages/utils/package.json index 492c65606dfb..0723f5f1815c 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.21.0", + "version": "1.22.0", "type": "module", "exports": "./lib/index.js", "files": [ diff --git a/packages/validator/package.json b/packages/validator/package.json index 373e59817d2a..65ed656f010d 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/validator", - "version": "1.21.0", + "version": "1.22.0", "description": "A Typescript implementation of the validator client", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -47,17 +47,17 @@ "dependencies": { "@chainsafe/blst": "^2.0.3", "@chainsafe/ssz": "^0.17.1", - "@lodestar/api": "^1.21.0", - "@lodestar/config": "^1.21.0", - "@lodestar/db": "^1.21.0", - "@lodestar/params": "^1.21.0", - "@lodestar/state-transition": "^1.21.0", - "@lodestar/types": "^1.21.0", - "@lodestar/utils": "^1.21.0", + "@lodestar/api": "^1.22.0", + "@lodestar/config": "^1.22.0", + "@lodestar/db": "^1.22.0", + "@lodestar/params": "^1.22.0", + "@lodestar/state-transition": "^1.22.0", + "@lodestar/types": "^1.22.0", + "@lodestar/utils": "^1.22.0", "strict-event-emitter-types": "^2.0.0" }, "devDependencies": { - "@lodestar/test-utils": "^1.21.0", + "@lodestar/test-utils": "^1.22.0", "bigint-buffer": "^1.1.5", "rimraf": "^4.4.1" } From 8da003e0f18523a1e6093177a147815365bd37e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 22:02:41 +0100 Subject: [PATCH 107/259] chore(deps-dev): bump vite from 5.3.4 to 5.3.6 (#7090) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.3.4 to 5.3.6. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v5.3.6/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v5.3.6/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index f9fa36847af9..5ed1b898f00c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13136,9 +13136,9 @@ vite-plugin-top-level-await@^1.4.2: uuid "^10.0.0" vite@^5.0.0, vite@^5.3.4: - version "5.3.4" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.3.4.tgz#b36ebd47c8a5e3a8727046375d5f10bf9fdf8715" - integrity sha512-Cw+7zL3ZG9/NZBB8C+8QbQZmR54GwqIz+WMI4b3JgdYJvX+ny9AjJXqkGQlDXSXRP9rP0B4tbciRMOVEKulVOA== + version "5.3.6" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.3.6.tgz#e097c0a7b79adb2e60bec9ef7907354f09d027bd" + integrity sha512-es78AlrylO8mTVBygC0gTC0FENv0C6T496vvd33ydbjF/mIi9q3XQ9A3NWo5qLGFKywvz10J26813OkLvcQleA== dependencies: esbuild "^0.21.3" postcss "^8.4.39" From fd6e23edab7cf3ca70aa596aaeb440908fb28bc6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:18:54 +0100 Subject: [PATCH 108/259] chore(deps): bump find-my-way from 8.1.0 to 8.2.2 (#7093) Bumps [find-my-way](https://github.com/delvedor/find-my-way) from 8.1.0 to 8.2.2. - [Release notes](https://github.com/delvedor/find-my-way/releases) - [Commits](https://github.com/delvedor/find-my-way/compare/v8.1.0...v8.2.2) --- updated-dependencies: - dependency-name: find-my-way dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index 5ed1b898f00c..38e6bae97d60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6783,13 +6783,13 @@ fill-range@^7.1.1: to-regex-range "^5.0.1" find-my-way@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-8.1.0.tgz#cc05e8e4b145322299d0de0a839b5be528c2083e" - integrity sha512-41QwjCGcVTODUmLLqTMeoHeiozbMXYMAE1CKFiDyi9zVZ2Vjh0yz3MF0WQZoIb+cmzP/XlbFjlF2NtJmvZHznA== + version "8.2.2" + resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-8.2.2.tgz#f3e78bc6ead2da4fdaa201335da3228600ed0285" + integrity sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA== dependencies: fast-deep-equal "^3.1.3" fast-querystring "^1.0.0" - safe-regex2 "^2.0.0" + safe-regex2 "^3.1.0" find-up@5.0.0, find-up@^5.0.0: version "5.0.0" @@ -11358,10 +11358,10 @@ restore-cursor@^4.0.0: onetime "^5.1.0" signal-exit "^3.0.2" -ret@~0.2.0: - version "0.2.2" - resolved "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz" - integrity sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ== +ret@~0.4.0: + version "0.4.3" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.4.3.tgz#5243fa30e704a2e78a9b9b1e86079e15891aa85c" + integrity sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ== retry@^0.12.0: version "0.12.0" @@ -11550,12 +11550,12 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -safe-regex2@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz" - integrity sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ== +safe-regex2@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-3.1.0.tgz#fd7ec23908e2c730e1ce7359a5b72883a87d2763" + integrity sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug== dependencies: - ret "~0.2.0" + ret "~0.4.0" safe-stable-stringify@^2.3.1: version "2.4.2" From bb40ef7eb77f9441ec66ab8f1fdf6664240bb1a3 Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Wed, 18 Sep 2024 15:09:07 -0400 Subject: [PATCH 109/259] feat: add electra support for light-client (#7063) * Add constant * Use constants * Remove ZERO_NEXT_SYNC_COMMITTEE_BRANCH * Add normalizeMerkleBranch * add getId to CheckpointHeaderRepository * fix: light-client unit tests * chore: lint * Fix normalizeMerkleBranch * Enable LC spec test * fix spec test --------- Co-authored-by: NC <17676176+ensi321@users.noreply.github.com> --- .../src/chain/lightClient/proofs.ts | 14 +++++--- .../lightclientCheckpointHeader.ts | 4 +++ .../beacon-node/src/network/reqresp/types.ts | 23 ++++++++++--- .../test/spec/utils/specTestIterator.ts | 5 ++- packages/light-client/src/spec/index.ts | 6 ++-- packages/light-client/src/spec/utils.ts | 32 +++++++++++++++++-- .../src/spec/validateLightClientBootstrap.ts | 8 +++-- .../src/spec/validateLightClientUpdate.ts | 16 ++++++---- .../src/utils/normalizeMerkleBranch.ts | 15 +++++++++ packages/light-client/src/validation.ts | 23 ++++++++++--- packages/light-client/test/unit/utils.test.ts | 16 ++++++++++ packages/params/src/index.ts | 6 ++-- packages/types/src/electra/sszTypes.ts | 20 ++++++------ packages/types/src/utils/typeguards.ts | 9 ++++++ 14 files changed, 155 insertions(+), 42 deletions(-) create mode 100644 packages/light-client/src/utils/normalizeMerkleBranch.ts diff --git a/packages/beacon-node/src/chain/lightClient/proofs.ts b/packages/beacon-node/src/chain/lightClient/proofs.ts index 87ad4544ec69..8d273e30ae5c 100644 --- a/packages/beacon-node/src/chain/lightClient/proofs.ts +++ b/packages/beacon-node/src/chain/lightClient/proofs.ts @@ -1,6 +1,11 @@ import {Tree} from "@chainsafe/persistent-merkle-tree"; -import {BeaconStateAllForks} from "@lodestar/state-transition"; -import {FINALIZED_ROOT_GINDEX, BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX, ForkExecution} from "@lodestar/params"; +import {BeaconStateAllForks, CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import { + FINALIZED_ROOT_GINDEX, + BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX, + ForkExecution, + FINALIZED_ROOT_GINDEX_ELECTRA, +} from "@lodestar/params"; import {BeaconBlockBody, SSZTypesFor, ssz} from "@lodestar/types"; import {SyncCommitteeWitness} from "./types.js"; @@ -40,9 +45,10 @@ export function getCurrentSyncCommitteeBranch(syncCommitteesWitness: SyncCommitt return [syncCommitteesWitness.nextSyncCommitteeRoot, ...syncCommitteesWitness.witness]; } -export function getFinalizedRootProof(state: BeaconStateAllForks): Uint8Array[] { +export function getFinalizedRootProof(state: CachedBeaconStateAllForks): Uint8Array[] { state.commit(); - return new Tree(state.node).getSingleProof(BigInt(FINALIZED_ROOT_GINDEX)); + const finalizedRootGindex = state.epochCtx.isPostElectra() ? FINALIZED_ROOT_GINDEX_ELECTRA : FINALIZED_ROOT_GINDEX; + return new Tree(state.node).getSingleProof(BigInt(finalizedRootGindex)); } export function getBlockBodyExecutionHeaderProof( diff --git a/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts b/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts index 78f165bb975c..22d6559792eb 100644 --- a/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts +++ b/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts @@ -25,4 +25,8 @@ export class CheckpointHeaderRepository extends Repository; @@ -48,10 +61,10 @@ type ResponseBodyByMethod = { [ReqRespMethod.BeaconBlocksByRoot]: SignedBeaconBlock; [ReqRespMethod.BlobSidecarsByRange]: deneb.BlobSidecar; [ReqRespMethod.BlobSidecarsByRoot]: deneb.BlobSidecar; - [ReqRespMethod.LightClientBootstrap]: altair.LightClientBootstrap; - [ReqRespMethod.LightClientUpdatesByRange]: altair.LightClientUpdate; - [ReqRespMethod.LightClientFinalityUpdate]: altair.LightClientFinalityUpdate; - [ReqRespMethod.LightClientOptimisticUpdate]: altair.LightClientOptimisticUpdate; + [ReqRespMethod.LightClientBootstrap]: LightClientBootstrap; + [ReqRespMethod.LightClientUpdatesByRange]: LightClientUpdate; + [ReqRespMethod.LightClientFinalityUpdate]: LightClientFinalityUpdate; + [ReqRespMethod.LightClientOptimisticUpdate]: LightClientOptimisticUpdate; }; /** Request SSZ type for each method and ForkName */ diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index 48a002580043..d8b4f9c0574c 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -65,10 +65,9 @@ export const defaultSkipOpts: SkipOpts = { skippedTestSuites: [ /^capella\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, /^deneb\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, - /^electra\/light_client\/.*/, + /^electra\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, ], - // TODO Electra: Review this test in the next spec test release - skippedTests: [/^deneb\/light_client\/sync\/.*electra_fork.*/], + skippedTests: [], skippedRunners: ["merkle_proof", "networking"], }; diff --git a/packages/light-client/src/spec/index.ts b/packages/light-client/src/spec/index.ts index fc1a431129e8..0934e15b1c17 100644 --- a/packages/light-client/src/spec/index.ts +++ b/packages/light-client/src/spec/index.ts @@ -10,7 +10,7 @@ import { import {computeSyncPeriodAtSlot} from "../utils/index.js"; import {getSyncCommitteeAtPeriod, processLightClientUpdate, ProcessUpdateOpts} from "./processLightClientUpdate.js"; import {ILightClientStore, LightClientStore, LightClientStoreEvents} from "./store.js"; -import {ZERO_FINALITY_BRANCH, ZERO_HEADER, ZERO_NEXT_SYNC_COMMITTEE_BRANCH, ZERO_SYNC_COMMITTEE} from "./utils.js"; +import {ZERO_FINALITY_BRANCH, ZERO_HEADER, ZERO_SYNC_COMMITTEE, getZeroSyncCommitteeBranch} from "./utils.js"; export {isBetterUpdate, toLightClientUpdateSummary} from "./isBetterUpdate.js"; export type {LightClientUpdateSummary} from "./isBetterUpdate.js"; @@ -37,7 +37,7 @@ export class LightclientSpec { this.onUpdate(currentSlot, { attestedHeader: finalityUpdate.attestedHeader, nextSyncCommittee: ZERO_SYNC_COMMITTEE, - nextSyncCommitteeBranch: ZERO_NEXT_SYNC_COMMITTEE_BRANCH, + nextSyncCommitteeBranch: getZeroSyncCommitteeBranch(this.config.getForkName(finalityUpdate.signatureSlot)), finalizedHeader: finalityUpdate.finalizedHeader, finalityBranch: finalityUpdate.finalityBranch, syncAggregate: finalityUpdate.syncAggregate, @@ -49,7 +49,7 @@ export class LightclientSpec { this.onUpdate(currentSlot, { attestedHeader: optimisticUpdate.attestedHeader, nextSyncCommittee: ZERO_SYNC_COMMITTEE, - nextSyncCommitteeBranch: ZERO_NEXT_SYNC_COMMITTEE_BRANCH, + nextSyncCommitteeBranch: getZeroSyncCommitteeBranch(this.config.getForkName(optimisticUpdate.signatureSlot)), finalizedHeader: {beacon: ZERO_HEADER}, finalityBranch: ZERO_FINALITY_BRANCH, syncAggregate: optimisticUpdate.syncAggregate, diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 3e59cb14cfa0..872aa5d9f910 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -7,6 +7,9 @@ import { ForkName, BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, BLOCK_BODY_EXECUTION_PAYLOAD_INDEX as EXECUTION_PAYLOAD_INDEX, + NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, + isForkPostElectra, + FINALIZED_ROOT_DEPTH_ELECTRA, } from "@lodestar/params"; import { ssz, @@ -17,17 +20,18 @@ import { LightClientUpdate, BeaconBlockHeader, SyncCommittee, + isElectraLightClientUpdate, } from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {isValidMerkleBranch, computeEpochAtSlot, computeSyncPeriodAtSlot} from "../utils/index.js"; +import {normalizeMerkleBranch} from "../utils/normalizeMerkleBranch.js"; import {LightClientStore} from "./store.js"; export const GENESIS_SLOT = 0; export const ZERO_HASH = new Uint8Array(32); export const ZERO_PUBKEY = new Uint8Array(48); export const ZERO_SYNC_COMMITTEE = ssz.altair.SyncCommittee.defaultValue(); -export const ZERO_NEXT_SYNC_COMMITTEE_BRANCH = Array.from({length: NEXT_SYNC_COMMITTEE_DEPTH}, () => ZERO_HASH); export const ZERO_HEADER = ssz.phase0.BeaconBlockHeader.defaultValue(); export const ZERO_FINALITY_BRANCH = Array.from({length: FINALIZED_ROOT_DEPTH}, () => ZERO_HASH); /** From https://notes.ethereum.org/@vbuterin/extended_light_client_protocol#Optimistic-head-determining-function */ @@ -41,10 +45,19 @@ export function getSafetyThreshold(maxActiveParticipants: number): number { return Math.floor(maxActiveParticipants / SAFETY_THRESHOLD_FACTOR); } +export function getZeroSyncCommitteeBranch(fork: ForkName): Uint8Array[] { + const nextSyncCommitteeDepth = isForkPostElectra(fork) + ? NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA + : NEXT_SYNC_COMMITTEE_DEPTH; + + return Array.from({length: nextSyncCommitteeDepth}, () => ZERO_HASH); +} + export function isSyncCommitteeUpdate(update: LightClientUpdate): boolean { return ( // Fast return for when constructing full LightClientUpdate from partial updates - update.nextSyncCommitteeBranch !== ZERO_NEXT_SYNC_COMMITTEE_BRANCH && + update.nextSyncCommitteeBranch !== + getZeroSyncCommitteeBranch(isElectraLightClientUpdate(update) ? ForkName.electra : ForkName.altair) && update.nextSyncCommitteeBranch.some((branch) => !byteArrayEquals(branch, ZERO_HASH)) ); } @@ -160,7 +173,8 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: LightC if (epoch < config.ELECTRA_FORK_EPOCH) { if ( (header as LightClientHeader).execution.depositRequestsRoot !== undefined || - (header as LightClientHeader).execution.withdrawalRequestsRoot !== undefined + (header as LightClientHeader).execution.withdrawalRequestsRoot !== undefined || + (header as LightClientHeader).execution.consolidationRequestsRoot !== undefined ) { return false; } @@ -184,6 +198,14 @@ export function upgradeLightClientUpdate( ): LightClientUpdate { update.attestedHeader = upgradeLightClientHeader(config, targetFork, update.attestedHeader); update.finalizedHeader = upgradeLightClientHeader(config, targetFork, update.finalizedHeader); + update.nextSyncCommitteeBranch = normalizeMerkleBranch( + update.nextSyncCommitteeBranch, + isForkPostElectra(targetFork) ? NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA : NEXT_SYNC_COMMITTEE_DEPTH + ); + update.finalityBranch = normalizeMerkleBranch( + update.finalityBranch, + isForkPostElectra(targetFork) ? FINALIZED_ROOT_DEPTH_ELECTRA : FINALIZED_ROOT_DEPTH + ); return update; } @@ -195,6 +217,10 @@ export function upgradeLightClientFinalityUpdate( ): LightClientFinalityUpdate { finalityUpdate.attestedHeader = upgradeLightClientHeader(config, targetFork, finalityUpdate.attestedHeader); finalityUpdate.finalizedHeader = upgradeLightClientHeader(config, targetFork, finalityUpdate.finalizedHeader); + finalityUpdate.finalityBranch = normalizeMerkleBranch( + finalityUpdate.finalityBranch, + isForkPostElectra(targetFork) ? FINALIZED_ROOT_DEPTH_ELECTRA : FINALIZED_ROOT_DEPTH + ); return finalityUpdate; } diff --git a/packages/light-client/src/spec/validateLightClientBootstrap.ts b/packages/light-client/src/spec/validateLightClientBootstrap.ts index 30540da24bd1..2eafea0791f0 100644 --- a/packages/light-client/src/spec/validateLightClientBootstrap.ts +++ b/packages/light-client/src/spec/validateLightClientBootstrap.ts @@ -2,11 +2,14 @@ import {byteArrayEquals} from "@chainsafe/ssz"; import {LightClientBootstrap, Root, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {toHex} from "@lodestar/utils"; +import {isForkPostElectra} from "@lodestar/params"; import {isValidMerkleBranch} from "../utils/verifyMerkleBranch.js"; import {isValidLightClientHeader} from "./utils.js"; const CURRENT_SYNC_COMMITTEE_INDEX = 22; const CURRENT_SYNC_COMMITTEE_DEPTH = 5; +const CURRENT_SYNC_COMMITTEE_INDEX_ELECTRA = 22; +const CURRENT_SYNC_COMMITTEE_DEPTH_ELECTRA = 6; export function validateLightClientBootstrap( config: ChainForkConfig, @@ -14,6 +17,7 @@ export function validateLightClientBootstrap( bootstrap: LightClientBootstrap ): void { const headerRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(bootstrap.header.beacon); + const fork = config.getForkName(bootstrap.header.beacon.slot); if (!isValidLightClientHeader(config, bootstrap.header)) { throw Error("Bootstrap Header is not Valid Light Client Header"); @@ -27,8 +31,8 @@ export function validateLightClientBootstrap( !isValidMerkleBranch( ssz.altair.SyncCommittee.hashTreeRoot(bootstrap.currentSyncCommittee), bootstrap.currentSyncCommitteeBranch, - CURRENT_SYNC_COMMITTEE_DEPTH, - CURRENT_SYNC_COMMITTEE_INDEX, + isForkPostElectra(fork) ? CURRENT_SYNC_COMMITTEE_DEPTH_ELECTRA : CURRENT_SYNC_COMMITTEE_DEPTH, + isForkPostElectra(fork) ? CURRENT_SYNC_COMMITTEE_INDEX_ELECTRA : CURRENT_SYNC_COMMITTEE_INDEX, bootstrap.header.beacon.stateRoot ) ) { diff --git a/packages/light-client/src/spec/validateLightClientUpdate.ts b/packages/light-client/src/spec/validateLightClientUpdate.ts index fde760da3b05..9a5ea1985f16 100644 --- a/packages/light-client/src/spec/validateLightClientUpdate.ts +++ b/packages/light-client/src/spec/validateLightClientUpdate.ts @@ -1,15 +1,19 @@ import bls from "@chainsafe/bls"; import type {PublicKey, Signature} from "@chainsafe/bls/types"; -import {LightClientUpdate, Root, ssz} from "@lodestar/types"; +import {LightClientUpdate, Root, isElectraLightClientUpdate, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import { FINALIZED_ROOT_INDEX, FINALIZED_ROOT_DEPTH, - NEXT_SYNC_COMMITTEE_INDEX, NEXT_SYNC_COMMITTEE_DEPTH, MIN_SYNC_COMMITTEE_PARTICIPANTS, DOMAIN_SYNC_COMMITTEE, GENESIS_SLOT, + NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, + NEXT_SYNC_COMMITTEE_INDEX_ELECTRA, + NEXT_SYNC_COMMITTEE_INDEX, + FINALIZED_ROOT_DEPTH_ELECTRA, + FINALIZED_ROOT_INDEX_ELECTRA, } from "@lodestar/params"; import {getParticipantPubkeys, sumBits} from "../utils/utils.js"; import {isValidMerkleBranch} from "../utils/index.js"; @@ -78,8 +82,8 @@ export function validateLightClientUpdate( !isValidMerkleBranch( finalizedRoot, update.finalityBranch, - FINALIZED_ROOT_DEPTH, - FINALIZED_ROOT_INDEX, + isElectraLightClientUpdate(update) ? FINALIZED_ROOT_DEPTH_ELECTRA : FINALIZED_ROOT_DEPTH, + isElectraLightClientUpdate(update) ? FINALIZED_ROOT_INDEX_ELECTRA : FINALIZED_ROOT_INDEX, update.attestedHeader.beacon.stateRoot ) ) { @@ -98,8 +102,8 @@ export function validateLightClientUpdate( !isValidMerkleBranch( ssz.altair.SyncCommittee.hashTreeRoot(update.nextSyncCommittee), update.nextSyncCommitteeBranch, - NEXT_SYNC_COMMITTEE_DEPTH, - NEXT_SYNC_COMMITTEE_INDEX, + isElectraLightClientUpdate(update) ? NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA : NEXT_SYNC_COMMITTEE_DEPTH, + isElectraLightClientUpdate(update) ? NEXT_SYNC_COMMITTEE_INDEX_ELECTRA : NEXT_SYNC_COMMITTEE_INDEX, update.attestedHeader.beacon.stateRoot ) ) { diff --git a/packages/light-client/src/utils/normalizeMerkleBranch.ts b/packages/light-client/src/utils/normalizeMerkleBranch.ts new file mode 100644 index 000000000000..ae3309f8ff2e --- /dev/null +++ b/packages/light-client/src/utils/normalizeMerkleBranch.ts @@ -0,0 +1,15 @@ +import {ZERO_HASH} from "../spec/utils.js"; + +export const SYNC_COMMITTEES_DEPTH = 4; +export const SYNC_COMMITTEES_INDEX = 11; + +/** + * Given merkle branch ``branch``, extend its depth according to ``depth`` + * If given ``depth`` is less than the depth of ``branch``, it will return + * unmodified ``branch`` + */ +export function normalizeMerkleBranch(branch: Uint8Array[], depth: number): Uint8Array[] { + const numExtraDepth = depth - branch.length; + + return [...Array.from({length: numExtraDepth}, () => ZERO_HASH), ...branch]; +} diff --git a/packages/light-client/src/validation.ts b/packages/light-client/src/validation.ts index e7839f115153..c756d612f3e7 100644 --- a/packages/light-client/src/validation.ts +++ b/packages/light-client/src/validation.ts @@ -1,6 +1,14 @@ import bls from "@chainsafe/bls"; import type {PublicKey, Signature} from "@chainsafe/bls/types"; -import {altair, LightClientFinalityUpdate, LightClientUpdate, Root, Slot, ssz} from "@lodestar/types"; +import { + altair, + isElectraLightClientUpdate, + LightClientFinalityUpdate, + LightClientUpdate, + Root, + Slot, + ssz, +} from "@lodestar/types"; import { FINALIZED_ROOT_INDEX, FINALIZED_ROOT_DEPTH, @@ -8,6 +16,9 @@ import { NEXT_SYNC_COMMITTEE_DEPTH, MIN_SYNC_COMMITTEE_PARTICIPANTS, DOMAIN_SYNC_COMMITTEE, + NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, + FINALIZED_ROOT_DEPTH_ELECTRA, + NEXT_SYNC_COMMITTEE_INDEX_ELECTRA, } from "@lodestar/params"; import {BeaconConfig} from "@lodestar/config"; import {isValidMerkleBranch} from "./utils/verifyMerkleBranch.js"; @@ -39,7 +50,11 @@ export function assertValidLightClientUpdate( if (isFinalized) { assertValidFinalityProof(update); } else { - assertZeroHashes(update.finalityBranch, FINALIZED_ROOT_DEPTH, "finalityBranches"); + assertZeroHashes( + update.finalityBranch, + isElectraLightClientUpdate(update) ? FINALIZED_ROOT_DEPTH_ELECTRA : FINALIZED_ROOT_DEPTH, + "finalityBranches" + ); } // DIFF FROM SPEC: @@ -99,8 +114,8 @@ export function assertValidSyncCommitteeProof(update: LightClientUpdate): void { !isValidMerkleBranch( ssz.altair.SyncCommittee.hashTreeRoot(update.nextSyncCommittee), update.nextSyncCommitteeBranch, - NEXT_SYNC_COMMITTEE_DEPTH, - NEXT_SYNC_COMMITTEE_INDEX, + isElectraLightClientUpdate(update) ? NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA : NEXT_SYNC_COMMITTEE_DEPTH, + isElectraLightClientUpdate(update) ? NEXT_SYNC_COMMITTEE_INDEX_ELECTRA : NEXT_SYNC_COMMITTEE_INDEX, update.attestedHeader.beacon.stateRoot ) ) { diff --git a/packages/light-client/test/unit/utils.test.ts b/packages/light-client/test/unit/utils.test.ts index 91bfab113431..9913c6c462a4 100644 --- a/packages/light-client/test/unit/utils.test.ts +++ b/packages/light-client/test/unit/utils.test.ts @@ -1,6 +1,8 @@ import {describe, it, expect} from "vitest"; import {isValidMerkleBranch} from "../../src/utils/verifyMerkleBranch.js"; import {computeMerkleBranch} from "../utils/utils.js"; +import {normalizeMerkleBranch} from "../../src/utils/normalizeMerkleBranch.js"; +import {ZERO_HASH} from "../../src/spec/utils.js"; describe("utils", () => { it("constructMerkleBranch", () => { @@ -11,4 +13,18 @@ describe("utils", () => { expect(isValidMerkleBranch(leaf, proof, depth, index, root)).toBe(true); }); + it("normalizeMerkleBranch", () => { + const branch: Uint8Array[] = []; + const branchDepth = 5; + const newDepth = 7; + + for (let i = 0; i < branchDepth; i++) { + branch.push(new Uint8Array(Array.from({length: 32}, () => i))); + } + + const normalizedBranch = normalizeMerkleBranch(branch, newDepth); + const expectedNormalizedBranch = [ZERO_HASH, ZERO_HASH, ...branch]; + + expect(normalizedBranch).toEqual(expectedNormalizedBranch); + }); }); diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index e7fd5b976336..a44fd5d0e0cd 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -264,7 +264,9 @@ export const BLOBSIDECAR_FIXED_SIZE = ACTIVE_PRESET === PresetName.minimal ? 131 // Electra Misc export const UNSET_DEPOSIT_REQUESTS_START_INDEX = 2n ** 64n - 1n; export const FULL_EXIT_REQUEST_AMOUNT = 0; +export const FINALIZED_ROOT_GINDEX_ELECTRA = 169; +export const FINALIZED_ROOT_DEPTH_ELECTRA = 7; +export const FINALIZED_ROOT_INDEX_ELECTRA = 41; export const NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA = 87; export const NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA = 6; -export const FINALIZED_ROOT_DEPTH_ELECTRA = 7; -export const FINALIZED_ROOT_INDEX_ELECTRA = 169; +export const NEXT_SYNC_COMMITTEE_INDEX_ELECTRA = 23; diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index c0485597686a..522f7245cc1b 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -358,20 +358,20 @@ export const LightClientHeader = new ContainerType( export const LightClientBootstrap = new ContainerType( { - header: LightClientHeader, + header: LightClientHeader, // Modified in ELECTRA currentSyncCommittee: altairSsz.SyncCommittee, - currentSyncCommitteeBranch: new VectorCompositeType(Bytes32, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA), + currentSyncCommitteeBranch: new VectorCompositeType(Bytes32, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA), // Modified in ELECTRA }, {typeName: "LightClientBootstrap", jsonCase: "eth2"} ); export const LightClientUpdate = new ContainerType( { - attestedHeader: LightClientHeader, + attestedHeader: LightClientHeader, // Modified in ELECTRA nextSyncCommittee: altairSsz.SyncCommittee, - nextSyncCommitteeBranch: new VectorCompositeType(Bytes32, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA), - finalizedHeader: LightClientHeader, - finalityBranch: new VectorCompositeType(Bytes32, FINALIZED_ROOT_DEPTH_ELECTRA), + nextSyncCommitteeBranch: new VectorCompositeType(Bytes32, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA), // Modified in ELECTRA + finalizedHeader: LightClientHeader, // Modified in ELECTRA + finalityBranch: new VectorCompositeType(Bytes32, FINALIZED_ROOT_DEPTH_ELECTRA), // Modified in ELECTRA syncAggregate: altairSsz.SyncAggregate, signatureSlot: Slot, }, @@ -382,7 +382,7 @@ export const LightClientFinalityUpdate = new ContainerType( { attestedHeader: LightClientHeader, finalizedHeader: LightClientHeader, - finalityBranch: new VectorCompositeType(Bytes32, FINALIZED_ROOT_DEPTH_ELECTRA), + finalityBranch: new VectorCompositeType(Bytes32, FINALIZED_ROOT_DEPTH_ELECTRA), // Modified in ELECTRA syncAggregate: altairSsz.SyncAggregate, signatureSlot: Slot, }, @@ -391,7 +391,7 @@ export const LightClientFinalityUpdate = new ContainerType( export const LightClientOptimisticUpdate = new ContainerType( { - attestedHeader: LightClientHeader, + attestedHeader: LightClientHeader, // Modified in ELECTRA syncAggregate: altairSsz.SyncAggregate, signatureSlot: Slot, }, @@ -400,8 +400,8 @@ export const LightClientOptimisticUpdate = new ContainerType( export const LightClientStore = new ContainerType( { - snapshot: LightClientBootstrap, - validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), + snapshot: LightClientBootstrap, // Modified in ELECTRA + validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), // Modified in ELECTRA }, {typeName: "LightClientStore", jsonCase: "eth2"} ); diff --git a/packages/types/src/utils/typeguards.ts b/packages/types/src/utils/typeguards.ts index 72910645f6e1..a5f5b7808ae5 100644 --- a/packages/types/src/utils/typeguards.ts +++ b/packages/types/src/utils/typeguards.ts @@ -14,6 +14,7 @@ import { SignedBlockContents, BeaconBlock, Attestation, + LightClientUpdate, } from "../types.js"; export function isExecutionPayload( @@ -71,3 +72,11 @@ export function isSignedBlockContents( export function isElectraAttestation(attestation: Attestation): attestation is Attestation { return (attestation as Attestation).committeeBits !== undefined; } + +export function isElectraLightClientUpdate(update: LightClientUpdate): update is LightClientUpdate { + const updatePostElectra = update as LightClientUpdate; + return ( + updatePostElectra.attestedHeader.execution !== undefined && + updatePostElectra.attestedHeader.execution.depositRequestsRoot !== undefined + ); +} From 404f13abfd56a859a35c69f198178d5669d3867a Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sat, 21 Sep 2024 18:53:39 +0100 Subject: [PATCH 110/259] chore: update Teku holesky bootnode (#7099) --- packages/cli/src/networks/holesky.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/networks/holesky.ts b/packages/cli/src/networks/holesky.ts index b86f6b543582..63bc6e07f8f2 100644 --- a/packages/cli/src/networks/holesky.ts +++ b/packages/cli/src/networks/holesky.ts @@ -10,7 +10,7 @@ export const bootEnrs = [ "enr:-Ku4QPG7F72mbKx3gEQEx07wpYYusGDh-ni6SNkLvOS-hhN-BxIggN7tKlmalb0L5JPoAfqD-akTZ-gX06hFeBEz4WoBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpAhnTT-AQFwAP__________gmlkgnY0gmlwhJK-DYCJc2VjcDI1NmsxoQKLVXFOhp2uX6jeT0DvvDpPcU8FWMjQdR4wMuORMhpX24N1ZHCCIyk", "enr:-LK4QPxe-mDiSOtEB_Y82ozvxn9aQM07Ui8A-vQHNgYGMMthfsfOabaaTHhhJHFCBQQVRjBww_A5bM1rf8MlkJU_l68Eh2F0dG5ldHOIAADAAAAAAACEZXRoMpBpt9l0BAFwAAABAAAAAAAAgmlkgnY0gmlwhLKAiOmJc2VjcDI1NmsxoQJu6T9pclPObAzEVQ53DpVQqjadmVxdTLL-J3h9NFoCeIN0Y3CCIyiDdWRwgiMo", "enr:-Ly4QGbOw4xNel5EhmDsJJ-QhC9XycWtsetnWoZ0uRy381GHdHsNHJiCwDTOkb3S1Ade0SFQkWJX_pgb3g8Jfh93rvMBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpBpt9l0BAFwAAABAAAAAAAAgmlkgnY0gmlwhJK-DYCJc2VjcDI1NmsxoQOxKv9sv3zKF8GDewgFGGHKP5HCZZpPpTrwl9eXKAWGxIhzeW5jbmV0cwCDdGNwgiMog3VkcIIjKA", - "enr:-LS4QG0uV4qvcpJ-HFDJRGBmnlD3TJo7yc4jwK8iP7iKaTlfQ5kZvIDspLMJhk7j9KapuL9yyHaZmwTEZqr10k9XumyCEcmHYXR0bmV0c4gAAAAABgAAAIRldGgykGm32XQEAXAAAAEAAAAAAACCaWSCdjSCaXCErK4j-YlzZWNwMjU2azGhAgfWRBEJlb7gAhXIB5ePmjj2b8io0UpEenq1Kl9cxStJg3RjcIIjKIN1ZHCCIyg", + "enr:-KO4QCi3ZY4TM5KL7bAG6laSYiYelDWu0crvUjCXlyc_cwEfUpMIuARuMJYGxWe-UYYpHEw_aBbZ1u-4tHQ8imyI5uaCAsGEZXRoMpBprg6ZBQFwAP__________gmlkgnY0gmlwhKyuI_mJc2VjcDI1NmsxoQLoFG5-vuNX6N49vnkTBaA3ZsBDF8B30DGqWOGtRGz5w4N0Y3CCIyiDdWRwgiMo", "enr:-Le4QLoE1wFHSlGcm48a9ZESb_MRLqPPu6G0vHqu4MaUcQNDHS69tsy-zkN0K6pglyzX8m24mkb-LtBcbjAYdP1uxm4BhGV0aDKQabfZdAQBcAAAAQAAAAAAAIJpZIJ2NIJpcIQ5gR6Wg2lwNpAgAUHQBwEQAAAAAAAAADR-iXNlY3AyNTZrMaEDPMSNdcL92uNIyCsS177Z6KTXlbZakQqxv3aQcWawNXeDdWRwgiMohHVkcDaCI4I", "enr:-KG4QC9Wm32mtzB5Fbj2ri2TEKglHmIWgvwTQCvNHBopuwpNAi1X6qOsBg_Z1-Bee-kfSrhzUQZSgDUyfH5outUprtoBgmlkgnY0gmlwhHEel3eDaXA2kP6AAAAAAAAAAlBW__4Srr-Jc2VjcDI1NmsxoQO7KE63Z4eSI55S1Yn7q9_xFkJ1Wt-a3LgiXuKGs19s0YN1ZHCCIyiEdWRwNoIjKA", ]; From cd98c237683456be7959d752bbd7d10f8b02b8ec Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Sun, 22 Sep 2024 21:41:47 -0400 Subject: [PATCH 111/259] feat: async shuffling refactor (#6938) * feat: add ShufflingCache to EpochCache * fix: implementation in state-transition for EpochCache with ShufflingCache * feat: remove shufflingCache.processState * feat: implement ShufflingCache changes in beacon-node * feat: pass shufflingCache when loading cached state from db * test: fix state-transition tests for EpochCache changes * feat: Pass shufflingCache to EpochCache at startup * test: fix slot off by one for decision root in perf test * chore: use ?. syntax * chore: refactoring * feat: add comments and clean up afterProcessEpoch * fix: perf test slot incrementing * fix: remove MockShufflingCache * Revert "chore: refactoring" This reverts commit 104aa56d84ce3ca33d045705591767ef578dec3a. * refactor: shufflingCache getters * refactor: shufflingCache setters * refactor: build and getOrBuild * docs: add comments to ShufflingCache methods * chore: lint issues * test: update tests in beacon-node * chore: lint * feat: get shufflings from cache for API * feat: minTimeDelayToBuildShuffling cli flag * test: fix shufflingCache promise insertion test * fix: rebase conflicts * fix: changes from debugging sim tests * refactor: minimize changes in afterProcessEpoch * chore: fix lint * chore: fix check-types * chore: fix check-types * feat: add diff utility * fix: bug in spec tests from invalid nextActiveIndices * refactor: add/remove comments * refactor: remove this.activeIndicesLength from EpochCache * refactor: simplify shufflingCache.getSync * refactor: remove unnecessary undefined's * refactor: clean up ShufflingCache unit test * feat: add metrics for ShufflingCache * feat: add shufflingCache metrics to state-transition * chore: lint * fix: metric name clash * refactor: add comment about not having ShufflingCache in EpochCache * refactor: rename shuffling decision root functions * refactor: remove unused comment * feat: async add nextShuffling to EpochCache after its built * feat: make ShufflingCache.set private * feat: chance metrics to nextShufflingNotOnEpochCache instead of positive case * refactor: move diff to separate PR * chore: fix tests using shufflingCache.set method * feat: remove minTimeDelayToBuild * feat: return promise from insertPromise and then through build * fix: update metrics names and help field * feat: move build of shuffling to beforeProcessEpoch * feat: allow calc of pivot slot before slot increment * fix: calc of pivot slot before slot increment * Revert "fix: calc of pivot slot before slot increment" This reverts commit 5e65f7efa85fad169a6263d1bebc1b4f8d3701d4. * Revert "feat: allow calc of pivot slot before slot increment" This reverts commit ed850ee0ced72029b643db4e86d82600cfb7cf43. * feat: allow getting current block root for shuffling calculation * fix: get nextShufflingDecisionRoot directly from state.blockRoots * fix: convert toRootHex * docs: add comment about pulling decisionRoot directly from state * feat: add back metrics for regen attestation cache hit/miss * docs: fix docstring on shufflingCache.build * refactor: change validatorIndices to Uint32Array * refactor: remove comment and change variable name * fix: use toRootHex instead of toHexString * refactor: deduplicate moved function computeAnchorCheckpoint * fix: touch up metrics per PR comments * fix: merge conflict * chore: lint * refactor: add scope around activeIndices to GC arrays * feat: directly use Uint32Array instead of transcribing number array to Uint32Array * refactor: activeIndices per tuyen comment * refactor: rename to epochAfterNext * chore: review PR * feat: update no shuffling ApiError to 500 status * fix: add back unnecessary eslint directive. to be remove under separate PR * feat: update no shuffling ApiError to 500 status * docs: add comment about upcomingEpoch --------- Co-authored-by: Cayman Co-authored-by: Tuyen Nguyen --- .../src/api/impl/beacon/state/index.ts | 9 +- .../src/api/impl/validator/index.ts | 11 +- .../src/chain/blocks/importBlock.ts | 7 - packages/beacon-node/src/chain/chain.ts | 25 +- .../beacon-node/src/chain/forkChoice/index.ts | 2 +- packages/beacon-node/src/chain/initState.ts | 38 +- .../beacon-node/src/chain/shufflingCache.ts | 183 ++++++---- .../stateCache/persistentCheckpointsCache.ts | 15 +- .../src/metrics/metrics/lodestar.ts | 47 ++- .../src/node/utils/interop/state.ts | 1 + packages/beacon-node/src/node/utils/state.ts | 3 + .../beacon-node/src/sync/backfill/backfill.ts | 3 +- .../opPools/aggregatedAttestationPool.test.ts | 2 +- .../unit/chain/forkChoice/forkChoice.test.ts | 3 +- .../test/unit/chain/shufflingCache.test.ts | 42 +-- packages/beacon-node/test/utils/state.ts | 1 + .../test/utils/validationData/attestation.ts | 27 +- packages/params/src/index.ts | 2 + .../state-transition/src/cache/epochCache.ts | 336 +++++++++++++----- .../src/cache/epochTransitionCache.ts | 40 ++- .../state-transition/src/cache/stateCache.ts | 3 +- .../src/epoch/processSyncCommitteeUpdates.ts | 2 +- .../src/slot/upgradeStateToAltair.ts | 2 +- .../state-transition/src/stateTransition.ts | 19 + .../src/util/calculateCommitteeAssignments.ts | 43 +++ .../src/util/computeAnchorCheckpoint.ts | 38 ++ .../src/util/epochShuffling.ts | 83 ++++- packages/state-transition/src/util/index.ts | 2 + .../test/perf/epoch/epochAltair.test.ts | 6 +- .../test/perf/epoch/epochCapella.test.ts | 6 +- .../test/perf/epoch/epochPhase0.test.ts | 6 +- .../perf/util/loadState/loadState.test.ts | 6 +- .../test/perf/util/shufflings.test.ts | 15 +- .../test/unit/cachedBeaconState.test.ts | 34 +- 34 files changed, 700 insertions(+), 362 deletions(-) create mode 100644 packages/state-transition/src/util/calculateCommitteeAssignments.ts create mode 100644 packages/state-transition/src/util/computeAnchorCheckpoint.ts diff --git a/packages/beacon-node/src/api/impl/beacon/state/index.ts b/packages/beacon-node/src/api/impl/beacon/state/index.ts index 9d9646ee8cf3..77e2fd5aab46 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/index.ts @@ -202,7 +202,14 @@ export function getBeaconStateApi({ const epoch = filters.epoch ?? computeEpochAtSlot(state.slot); const startSlot = computeStartSlotAtEpoch(epoch); - const shuffling = stateCached.epochCtx.getShufflingAtEpoch(epoch); + const decisionRoot = stateCached.epochCtx.getShufflingDecisionRoot(epoch); + const shuffling = await chain.shufflingCache.get(epoch, decisionRoot); + if (!shuffling) { + throw new ApiError( + 500, + `No shuffling found to calculate committees for epoch: ${epoch} and decisionRoot: ${decisionRoot}` + ); + } const committees = shuffling.committees; const committeesFlat = committees.flatMap((slotCommittees, slotInEpoch) => { const slot = startSlot + slotInEpoch; diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index a17c1418809e..d2ce6672c89f 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -3,6 +3,7 @@ import {ApplicationMethods} from "@lodestar/api/server"; import { CachedBeaconStateAllForks, computeStartSlotAtEpoch, + calculateCommitteeAssignments, proposerShufflingDecisionRoot, attesterShufflingDecisionRoot, getBlockRootAtSlot, @@ -995,7 +996,15 @@ export function getValidatorApi( // Check that all validatorIndex belong to the state before calling getCommitteeAssignments() const pubkeys = getPubkeysForIndices(state.validators, indices); - const committeeAssignments = state.epochCtx.getCommitteeAssignments(epoch, indices); + const decisionRoot = state.epochCtx.getShufflingDecisionRoot(epoch); + const shuffling = await chain.shufflingCache.get(epoch, decisionRoot); + if (!shuffling) { + throw new ApiError( + 500, + `No shuffling found to calculate committee assignments for epoch: ${epoch} and decisionRoot: ${decisionRoot}` + ); + } + const committeeAssignments = calculateCommitteeAssignments(shuffling, indices); const duties: routes.validator.AttesterDuty[] = []; for (let i = 0, len = indices.length; i < len; i++) { const validatorIndex = indices[i]; diff --git a/packages/beacon-node/src/chain/blocks/importBlock.ts b/packages/beacon-node/src/chain/blocks/importBlock.ts index 4c46bdae53ee..d19d6a60c564 100644 --- a/packages/beacon-node/src/chain/blocks/importBlock.ts +++ b/packages/beacon-node/src/chain/blocks/importBlock.ts @@ -64,7 +64,6 @@ export async function importBlock( const blockRootHex = toRootHex(blockRoot); const currentEpoch = computeEpochAtSlot(this.forkChoice.getTime()); const blockEpoch = computeEpochAtSlot(blockSlot); - const parentEpoch = computeEpochAtSlot(parentBlockSlot); const prevFinalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch; const blockDelaySec = (fullyVerifiedBlock.seenTimestampSec - postState.genesisTime) % this.config.SECONDS_PER_SLOT; const recvToValLatency = Date.now() / 1000 - (opts.seenTimestampSec ?? Date.now() / 1000); @@ -335,12 +334,6 @@ export async function importBlock( this.logger.verbose("After importBlock caching postState without SSZ cache", {slot: postState.slot}); } - if (parentEpoch < blockEpoch) { - // current epoch and previous epoch are likely cached in previous states - this.shufflingCache.processState(postState, postState.epochCtx.nextShuffling.epoch); - this.logger.verbose("Processed shuffling for next epoch", {parentEpoch, blockEpoch, slot: blockSlot}); - } - if (blockSlot % SLOTS_PER_EPOCH === 0) { // Cache state to preserve epoch transition work const checkpointState = postState; diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index ee70231c7d40..0b0ac30edf40 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -13,6 +13,7 @@ import { PubkeyIndexMap, EpochShuffling, computeEndSlotAtEpoch, + computeAnchorCheckpoint, } from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; import { @@ -60,7 +61,6 @@ import { import {IChainOptions} from "./options.js"; import {QueuedStateRegenerator, RegenCaller} from "./regen/index.js"; import {initializeForkChoice} from "./forkChoice/index.js"; -import {computeAnchorCheckpoint} from "./initState.js"; import {IBlsVerifier, BlsSingleThreadVerifier, BlsMultiThreadWorkerPool} from "./bls/index.js"; import { SeenAttesters, @@ -246,7 +246,6 @@ export class BeaconChain implements IBeaconChain { this.beaconProposerCache = new BeaconProposerCache(opts); this.checkpointBalancesCache = new CheckpointBalancesCache(); - this.shufflingCache = new ShufflingCache(metrics, this.opts); // Restore state caches // anchorState may already by a CachedBeaconState. If so, don't create the cache again, since deserializing all @@ -261,9 +260,21 @@ export class BeaconChain implements IBeaconChain { pubkey2index: new PubkeyIndexMap(), index2pubkey: [], }); - this.shufflingCache.processState(cachedState, cachedState.epochCtx.previousShuffling.epoch); - this.shufflingCache.processState(cachedState, cachedState.epochCtx.currentShuffling.epoch); - this.shufflingCache.processState(cachedState, cachedState.epochCtx.nextShuffling.epoch); + + this.shufflingCache = cachedState.epochCtx.shufflingCache = new ShufflingCache(metrics, logger, this.opts, [ + { + shuffling: cachedState.epochCtx.previousShuffling, + decisionRoot: cachedState.epochCtx.previousDecisionRoot, + }, + { + shuffling: cachedState.epochCtx.currentShuffling, + decisionRoot: cachedState.epochCtx.currentDecisionRoot, + }, + { + shuffling: cachedState.epochCtx.nextShuffling, + decisionRoot: cachedState.epochCtx.nextDecisionRoot, + }, + ]); // Persist single global instance of state caches this.pubkey2index = cachedState.epochCtx.pubkey2index; @@ -902,8 +913,8 @@ export class BeaconChain implements IBeaconChain { state = await this.regen.getState(attHeadBlock.stateRoot, regenCaller); } - // resolve the promise to unblock other calls of the same epoch and dependent root - return this.shufflingCache.processState(state, attEpoch); + // should always be the current epoch of the active context so no need to await a result from the ShufflingCache + return state.epochCtx.getShufflingAtEpoch(attEpoch); } /** diff --git a/packages/beacon-node/src/chain/forkChoice/index.ts b/packages/beacon-node/src/chain/forkChoice/index.ts index d57b7f86cb98..346a4afe1e7f 100644 --- a/packages/beacon-node/src/chain/forkChoice/index.ts +++ b/packages/beacon-node/src/chain/forkChoice/index.ts @@ -14,10 +14,10 @@ import { getEffectiveBalanceIncrementsZeroInactive, isExecutionStateType, isMergeTransitionComplete, + computeAnchorCheckpoint, } from "@lodestar/state-transition"; import {Logger, toRootHex} from "@lodestar/utils"; -import {computeAnchorCheckpoint} from "../initState.js"; import {ChainEventEmitter} from "../emitter.js"; import {ChainEvent} from "../emitter.js"; import {GENESIS_SLOT} from "../../constants/index.js"; diff --git a/packages/beacon-node/src/chain/initState.ts b/packages/beacon-node/src/chain/initState.ts index e413bdff0f7d..311806fb1be7 100644 --- a/packages/beacon-node/src/chain/initState.ts +++ b/packages/beacon-node/src/chain/initState.ts @@ -1,15 +1,13 @@ import { - blockToHeader, computeEpochAtSlot, BeaconStateAllForks, CachedBeaconStateAllForks, - computeCheckpointEpochAtStateSlot, computeStartSlotAtEpoch, } from "@lodestar/state-transition"; -import {SignedBeaconBlock, phase0, ssz} from "@lodestar/types"; +import {SignedBeaconBlock} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {Logger, toHex, toRootHex} from "@lodestar/utils"; -import {GENESIS_SLOT, ZERO_HASH} from "../constants/index.js"; +import {GENESIS_SLOT} from "../constants/index.js"; import {IBeaconDb} from "../db/index.js"; import {Eth1Provider} from "../eth1/index.js"; import {Metrics} from "../metrics/index.js"; @@ -204,35 +202,3 @@ export function initBeaconMetrics(metrics: Metrics, state: BeaconStateAllForks): metrics.currentJustifiedEpoch.set(state.currentJustifiedCheckpoint.epoch); metrics.finalizedEpoch.set(state.finalizedCheckpoint.epoch); } - -export function computeAnchorCheckpoint( - config: ChainForkConfig, - anchorState: BeaconStateAllForks -): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader} { - let blockHeader; - let root; - const blockTypes = config.getForkTypes(anchorState.latestBlockHeader.slot); - - if (anchorState.latestBlockHeader.slot === GENESIS_SLOT) { - const block = blockTypes.BeaconBlock.defaultValue(); - block.stateRoot = anchorState.hashTreeRoot(); - blockHeader = blockToHeader(config, block); - root = ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader); - } else { - blockHeader = ssz.phase0.BeaconBlockHeader.clone(anchorState.latestBlockHeader); - if (ssz.Root.equals(blockHeader.stateRoot, ZERO_HASH)) { - blockHeader.stateRoot = anchorState.hashTreeRoot(); - } - root = ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader); - } - - return { - checkpoint: { - root, - // the checkpoint epoch = computeEpochAtSlot(anchorState.slot) + 1 if slot is not at epoch boundary - // this is similar to a process_slots() call - epoch: computeCheckpointEpochAtStateSlot(anchorState.slot), - }, - blockHeader, - }; -} diff --git a/packages/beacon-node/src/chain/shufflingCache.ts b/packages/beacon-node/src/chain/shufflingCache.ts index 12dd1bf3e9ae..6c42228b5356 100644 --- a/packages/beacon-node/src/chain/shufflingCache.ts +++ b/packages/beacon-node/src/chain/shufflingCache.ts @@ -1,9 +1,14 @@ -import {CachedBeaconStateAllForks, EpochShuffling, getShufflingDecisionBlock} from "@lodestar/state-transition"; -import {Epoch, RootHex, ssz} from "@lodestar/types"; -import {MapDef, pruneSetToMax, toRootHex} from "@lodestar/utils"; -import {GENESIS_SLOT} from "@lodestar/params"; +import { + BeaconStateAllForks, + EpochShuffling, + IShufflingCache, + ShufflingBuildProps, + computeEpochShuffling, +} from "@lodestar/state-transition"; +import {Epoch, RootHex} from "@lodestar/types"; +import {LodestarError, Logger, MapDef, pruneSetToMax} from "@lodestar/utils"; import {Metrics} from "../metrics/metrics.js"; -import {computeAnchorCheckpoint} from "./initState.js"; +import {callInNextEventLoop} from "../util/eventLoop.js"; /** * Same value to CheckpointBalancesCache, with the assumption that we don't have to use it for old epochs. In the worse case: @@ -31,6 +36,7 @@ type ShufflingCacheItem = { type PromiseCacheItem = { type: CacheItemType.promise; + timeInsertedMs: number; promise: Promise; resolveFn: (shuffling: EpochShuffling) => void; }; @@ -47,7 +53,7 @@ export type ShufflingCacheOpts = { * - if a shuffling is not available (which does not happen with default chain option of maxSkipSlots = 32), track a promise to make sure we don't compute the same shuffling twice * - skip computing shuffling when loading state bytes from disk */ -export class ShufflingCache { +export class ShufflingCache implements IShufflingCache { /** LRU cache implemented as a map, pruned every time we add an item */ private readonly itemsByDecisionRootByEpoch: MapDef> = new MapDef( () => new Map() @@ -56,8 +62,10 @@ export class ShufflingCache { private readonly maxEpochs: number; constructor( - private readonly metrics: Metrics | null = null, - opts: ShufflingCacheOpts = {} + readonly metrics: Metrics | null = null, + readonly logger: Logger | null = null, + opts: ShufflingCacheOpts = {}, + precalculatedShufflings?: {shuffling: EpochShuffling | null; decisionRoot: RootHex}[] ) { if (metrics) { metrics.shufflingCache.size.addCollect(() => @@ -68,66 +76,25 @@ export class ShufflingCache { } this.maxEpochs = opts.maxShufflingCacheEpochs ?? MAX_EPOCHS; - } - - /** - * Extract shuffling from state and add to cache - */ - processState(state: CachedBeaconStateAllForks, shufflingEpoch: Epoch): EpochShuffling { - const decisionBlockHex = getDecisionBlock(state, shufflingEpoch); - let shuffling: EpochShuffling; - switch (shufflingEpoch) { - case state.epochCtx.nextShuffling.epoch: - shuffling = state.epochCtx.nextShuffling; - break; - case state.epochCtx.currentShuffling.epoch: - shuffling = state.epochCtx.currentShuffling; - break; - case state.epochCtx.previousShuffling.epoch: - shuffling = state.epochCtx.previousShuffling; - break; - default: - throw new Error(`Shuffling not found from state ${state.slot} for epoch ${shufflingEpoch}`); - } - let cacheItem = this.itemsByDecisionRootByEpoch.getOrDefault(shufflingEpoch).get(decisionBlockHex); - if (cacheItem !== undefined) { - // update existing promise - if (isPromiseCacheItem(cacheItem)) { - // unblock consumers of this promise - cacheItem.resolveFn(shuffling); - // then update item type to shuffling - cacheItem = { - type: CacheItemType.shuffling, - shuffling, - }; - this.add(shufflingEpoch, decisionBlockHex, cacheItem); - // we updated type to CacheItemType.shuffling so the above fields are not used anyway - this.metrics?.shufflingCache.processStateUpdatePromise.inc(); - } else { - // ShufflingCacheItem, do nothing - this.metrics?.shufflingCache.processStateNoOp.inc(); + precalculatedShufflings?.map(({shuffling, decisionRoot}) => { + if (shuffling !== null) { + this.set(shuffling, decisionRoot); } - } else { - // not found, new shuffling - this.add(shufflingEpoch, decisionBlockHex, {type: CacheItemType.shuffling, shuffling}); - this.metrics?.shufflingCache.processStateInsertNew.inc(); - } - - return shuffling; + }); } /** * Insert a promise to make sure we don't regen state for the same shuffling. * Bound by MAX_SHUFFLING_PROMISE to make sure our node does not blow up. */ - insertPromise(shufflingEpoch: Epoch, decisionRootHex: RootHex): void { + insertPromise(epoch: Epoch, decisionRoot: RootHex): void { const promiseCount = Array.from(this.itemsByDecisionRootByEpoch.values()) .flatMap((innerMap) => Array.from(innerMap.values())) .filter((item) => isPromiseCacheItem(item)).length; if (promiseCount >= MAX_PROMISES) { throw new Error( - `Too many shuffling promises: ${promiseCount}, shufflingEpoch: ${shufflingEpoch}, decisionRootHex: ${decisionRootHex}` + `Too many shuffling promises: ${promiseCount}, shufflingEpoch: ${epoch}, decisionRootHex: ${decisionRoot}` ); } let resolveFn: ((shuffling: EpochShuffling) => void) | null = null; @@ -140,10 +107,11 @@ export class ShufflingCache { const cacheItem: PromiseCacheItem = { type: CacheItemType.promise, + timeInsertedMs: Date.now(), promise, resolveFn, }; - this.add(shufflingEpoch, decisionRootHex, cacheItem); + this.itemsByDecisionRootByEpoch.getOrDefault(epoch).set(decisionRoot, cacheItem); this.metrics?.shufflingCache.insertPromiseCount.inc(); } @@ -152,39 +120,95 @@ export class ShufflingCache { * If there's a promise, it means we are computing the same shuffling, so we wait for the promise to resolve. * Return null if we don't have a shuffling for this epoch and dependentRootHex. */ - async get(shufflingEpoch: Epoch, decisionRootHex: RootHex): Promise { - const cacheItem = this.itemsByDecisionRootByEpoch.getOrDefault(shufflingEpoch).get(decisionRootHex); + async get(epoch: Epoch, decisionRoot: RootHex): Promise { + const cacheItem = this.itemsByDecisionRootByEpoch.getOrDefault(epoch).get(decisionRoot); if (cacheItem === undefined) { + this.metrics?.shufflingCache.miss.inc(); return null; } if (isShufflingCacheItem(cacheItem)) { + this.metrics?.shufflingCache.hit.inc(); return cacheItem.shuffling; } else { - // promise + this.metrics?.shufflingCache.shufflingPromiseNotResolved.inc(); return cacheItem.promise; } } /** - * Same to get() function but synchronous. + * Gets a cached shuffling via the epoch and decision root. If the shuffling is not + * available it will build it synchronously and return the shuffling. + * + * NOTE: If a shuffling is already queued and not calculated it will build and resolve + * the promise but the already queued build will happen at some later time */ - getSync(shufflingEpoch: Epoch, decisionRootHex: RootHex): EpochShuffling | null { - const cacheItem = this.itemsByDecisionRootByEpoch.getOrDefault(shufflingEpoch).get(decisionRootHex); - if (cacheItem === undefined) { - return null; + getSync( + epoch: Epoch, + decisionRoot: RootHex, + buildProps?: T + ): T extends ShufflingBuildProps ? EpochShuffling : EpochShuffling | null { + const cacheItem = this.itemsByDecisionRootByEpoch.getOrDefault(epoch).get(decisionRoot); + if (!cacheItem) { + this.metrics?.shufflingCache.miss.inc(); + } else if (isShufflingCacheItem(cacheItem)) { + this.metrics?.shufflingCache.hit.inc(); + return cacheItem.shuffling; + } else if (buildProps) { + // TODO: (@matthewkeil) This should possible log a warning?? + this.metrics?.shufflingCache.shufflingPromiseNotResolvedAndThrownAway.inc(); + } else { + this.metrics?.shufflingCache.shufflingPromiseNotResolved.inc(); } - if (isShufflingCacheItem(cacheItem)) { - return cacheItem.shuffling; + let shuffling: EpochShuffling | null = null; + if (buildProps) { + const timer = this.metrics?.shufflingCache.shufflingCalculationTime.startTimer({source: "getSync"}); + shuffling = computeEpochShuffling(buildProps.state, buildProps.activeIndices, epoch); + timer?.(); + this.set(shuffling, decisionRoot); } + return shuffling as T extends ShufflingBuildProps ? EpochShuffling : EpochShuffling | null; + } - // ignore promise - return null; + /** + * Queue asynchronous build for an EpochShuffling, triggered from state-transition + */ + build(epoch: number, decisionRoot: string, state: BeaconStateAllForks, activeIndices: Uint32Array): void { + this.insertPromise(epoch, decisionRoot); + /** + * TODO: (@matthewkeil) This will get replaced by a proper build queue and a worker to do calculations + * on a NICE thread with a rust implementation + */ + callInNextEventLoop(() => { + const timer = this.metrics?.shufflingCache.shufflingCalculationTime.startTimer({source: "build"}); + const shuffling = computeEpochShuffling(state, activeIndices, epoch); + timer?.(); + this.set(shuffling, decisionRoot); + }); } - private add(shufflingEpoch: Epoch, decisionBlock: RootHex, cacheItem: CacheItem): void { - this.itemsByDecisionRootByEpoch.getOrDefault(shufflingEpoch).set(decisionBlock, cacheItem); + /** + * Add an EpochShuffling to the ShufflingCache. If a promise for the shuffling is present it will + * resolve the promise with the built shuffling + */ + private set(shuffling: EpochShuffling, decisionRoot: string): void { + const shufflingAtEpoch = this.itemsByDecisionRootByEpoch.getOrDefault(shuffling.epoch); + // if a pending shuffling promise exists, resolve it + const cacheItem = shufflingAtEpoch.get(decisionRoot); + if (cacheItem) { + if (isPromiseCacheItem(cacheItem)) { + cacheItem.resolveFn(shuffling); + this.metrics?.shufflingCache.shufflingPromiseResolutionTime.observe( + (Date.now() - cacheItem.timeInsertedMs) / 1000 + ); + } else { + this.metrics?.shufflingCache.shufflingBuiltMultipleTimes.inc(); + } + } + // set the shuffling + shufflingAtEpoch.set(decisionRoot, {type: CacheItemType.shuffling, shuffling}); + // prune the cache pruneSetToMax(this.itemsByDecisionRootByEpoch, this.maxEpochs); } } @@ -197,13 +221,14 @@ function isPromiseCacheItem(item: CacheItem): item is PromiseCacheItem { return item.type === CacheItemType.promise; } -/** - * Get the shuffling decision block root for the given epoch of given state - * - Special case close to genesis block, return the genesis block root - * - This is similar to forkchoice.getDependentRoot() function, otherwise we cannot get cached shuffing in attestation verification when syncing from genesis. - */ -function getDecisionBlock(state: CachedBeaconStateAllForks, epoch: Epoch): RootHex { - return state.slot > GENESIS_SLOT - ? getShufflingDecisionBlock(state, epoch) - : toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(computeAnchorCheckpoint(state.config, state).blockHeader)); +export enum ShufflingCacheErrorCode { + NO_SHUFFLING_FOUND = "SHUFFLING_CACHE_ERROR_NO_SHUFFLING_FOUND", } + +type ShufflingCacheErrorType = { + code: ShufflingCacheErrorCode.NO_SHUFFLING_FOUND; + epoch: Epoch; + decisionRoot: RootHex; +}; + +export class ShufflingCacheError extends LodestarError {} diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index d8769374a29c..74e85e6fa574 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -212,20 +212,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { } sszTimer?.(); const timer = this.metrics?.stateReloadDuration.startTimer(); - const newCachedState = loadCachedBeaconState( - seedState, - stateBytes, - { - shufflingGetter: (shufflingEpoch, decisionRootHex) => { - const shuffling = this.shufflingCache.getSync(shufflingEpoch, decisionRootHex); - if (shuffling == null) { - this.metrics?.stateReloadShufflingCacheMiss.inc(); - } - return shuffling; - }, - }, - validatorsBytes - ); + const newCachedState = loadCachedBeaconState(seedState, stateBytes, {}, validatorsBytes); newCachedState.commit(); const stateRoot = toRootHex(newCachedState.hashTreeRoot()); timer?.(); diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index 737a900e5f64..4b076471dcab 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -1297,22 +1297,45 @@ export function createLodestarMetrics( name: "lodestar_shuffling_cache_size", help: "Shuffling cache size", }), - processStateInsertNew: register.gauge({ - name: "lodestar_shuffling_cache_process_state_insert_new_total", - help: "Total number of times processState is called resulting a new shuffling", - }), - processStateUpdatePromise: register.gauge({ - name: "lodestar_shuffling_cache_process_state_update_promise_total", - help: "Total number of times processState is called resulting a promise being updated with shuffling", - }), - processStateNoOp: register.gauge({ - name: "lodestar_shuffling_cache_process_state_no_op_total", - help: "Total number of times processState is called resulting no changes", - }), insertPromiseCount: register.gauge({ name: "lodestar_shuffling_cache_insert_promise_count", help: "Total number of times insertPromise is called", }), + hit: register.gauge({ + name: "lodestar_shuffling_cache_hit_count", + help: "Count of shuffling cache hit", + }), + miss: register.gauge({ + name: "lodestar_shuffling_cache_miss_count", + help: "Count of shuffling cache miss", + }), + shufflingBuiltMultipleTimes: register.gauge({ + name: "lodestar_shuffling_cache_recalculated_shuffling_count", + help: "Count of shuffling that were build multiple times", + }), + shufflingPromiseNotResolvedAndThrownAway: register.gauge({ + name: "lodestar_shuffling_cache_promise_not_resolved_and_thrown_away_count", + help: "Count of shuffling cache promises that were discarded and the shuffling was built synchronously", + }), + shufflingPromiseNotResolved: register.gauge({ + name: "lodestar_shuffling_cache_promise_not_resolved_count", + help: "Count of shuffling cache promises that were requested before the promise was resolved", + }), + nextShufflingNotOnEpochCache: register.gauge({ + name: "lodestar_shuffling_cache_next_shuffling_not_on_epoch_cache", + help: "The next shuffling was not on the epoch cache before the epoch transition", + }), + shufflingPromiseResolutionTime: register.histogram({ + name: "lodestar_shuffling_cache_promise_resolution_time_seconds", + help: "Time from promise insertion until promise resolution when shuffling was ready in seconds", + buckets: [0.5, 1, 1.5, 2], + }), + shufflingCalculationTime: register.histogram<{source: "build" | "getSync"}>({ + name: "lodestar_shuffling_cache_shuffling_calculation_time_seconds", + help: "Run time of shuffling calculation", + buckets: [0.5, 0.75, 1, 1.25, 1.5], + labelNames: ["source"], + }), }, seenCache: { diff --git a/packages/beacon-node/src/node/utils/interop/state.ts b/packages/beacon-node/src/node/utils/interop/state.ts index 6528bd392bc7..fe26afef2013 100644 --- a/packages/beacon-node/src/node/utils/interop/state.ts +++ b/packages/beacon-node/src/node/utils/interop/state.ts @@ -20,6 +20,7 @@ export type InteropStateOpts = { withEth1Credentials?: boolean; }; +// TODO: (@matthewkeil) - Only used by initDevState. Consider combining into that function export function getInteropState( config: ChainForkConfig, { diff --git a/packages/beacon-node/src/node/utils/state.ts b/packages/beacon-node/src/node/utils/state.ts index 25bd77c82274..05da7042eef4 100644 --- a/packages/beacon-node/src/node/utils/state.ts +++ b/packages/beacon-node/src/node/utils/state.ts @@ -5,6 +5,9 @@ import {IBeaconDb} from "../../db/index.js"; import {interopDeposits} from "./interop/deposits.js"; import {getInteropState, InteropStateOpts} from "./interop/state.js"; +/** + * Builds state for `dev` command, for sim testing and some other tests + */ export function initDevState( config: ChainForkConfig, validatorCount: number, diff --git a/packages/beacon-node/src/sync/backfill/backfill.ts b/packages/beacon-node/src/sync/backfill/backfill.ts index 38258fde07fd..77d2836bdcc3 100644 --- a/packages/beacon-node/src/sync/backfill/backfill.ts +++ b/packages/beacon-node/src/sync/backfill/backfill.ts @@ -1,6 +1,6 @@ import {EventEmitter} from "events"; import {StrictEventEmitter} from "strict-event-emitter-types"; -import {BeaconStateAllForks, blockToHeader} from "@lodestar/state-transition"; +import {BeaconStateAllForks, blockToHeader, computeAnchorCheckpoint} from "@lodestar/state-transition"; import {BeaconConfig, ChainForkConfig} from "@lodestar/config"; import {phase0, Root, SignedBeaconBlock, Slot, ssz} from "@lodestar/types"; import {ErrorAborted, Logger, sleep, toRootHex} from "@lodestar/utils"; @@ -15,7 +15,6 @@ import {PeerIdStr} from "../../util/peerId.js"; import {shuffleOne} from "../../util/shuffle.js"; import {Metrics} from "../../metrics/metrics"; import {byteArrayEquals} from "../../util/bytes.js"; -import {computeAnchorCheckpoint} from "../../chain/initState.js"; import {verifyBlockProposerSignature, verifyBlockSequence, BackfillBlockHeader, BackfillBlock} from "./verify.js"; import {BackfillSyncError, BackfillSyncErrorCode} from "./errors.js"; /** diff --git a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts index 63fc4ee2e12c..45fc07281c3b 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -2,6 +2,7 @@ import {itBench} from "@dapplion/benchmark"; import {BitArray, toHexString} from "@chainsafe/ssz"; import { CachedBeaconStateAltair, + computeAnchorCheckpoint, computeEpochAtSlot, computeStartSlotAtEpoch, getBlockRootAtSlot, @@ -15,7 +16,6 @@ import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; // eslint-disable-next-line import/no-relative-packages import {generatePerfTestCachedStateAltair} from "../../../../../state-transition/test/perf/util.js"; import {AggregatedAttestationPool} from "../../../../src/chain/opPools/aggregatedAttestationPool.js"; -import {computeAnchorCheckpoint} from "../../../../src/chain/initState.js"; const vc = 1_500_000; diff --git a/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts b/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts index 6b96a0d1172f..611673086ce5 100644 --- a/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts +++ b/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts @@ -5,12 +5,13 @@ import {CheckpointWithHex, ExecutionStatus, ForkChoice, DataAvailabilityStatus} import {FAR_FUTURE_EPOCH, MAX_EFFECTIVE_BALANCE} from "@lodestar/params"; import { CachedBeaconStateAllForks, + computeAnchorCheckpoint, computeEpochAtSlot, getEffectiveBalanceIncrementsZeroed, } from "@lodestar/state-transition"; import {phase0, Slot, ssz, ValidatorIndex} from "@lodestar/types"; import {getTemporaryBlockHeader, processSlots} from "@lodestar/state-transition"; -import {ChainEventEmitter, computeAnchorCheckpoint, initializeForkChoice} from "../../../../src/chain/index.js"; +import {ChainEventEmitter, initializeForkChoice} from "../../../../src/chain/index.js"; import {generateSignedBlockAtSlot} from "../../../utils/typeGenerator.js"; import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; import {generateState} from "../../../utils/state.js"; diff --git a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts index 6295a993c072..62b02cbf2b12 100644 --- a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts +++ b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts @@ -1,6 +1,4 @@ import {describe, it, expect, beforeEach} from "vitest"; - -import {getShufflingDecisionBlock} from "@lodestar/state-transition"; // eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../state-transition/test/perf/util.js"; import {ShufflingCache} from "../../../src/chain/shufflingCache.js"; @@ -9,39 +7,43 @@ describe("ShufflingCache", function () { const vc = 64; const stateSlot = 100; const state = generateTestCachedBeaconStateOnlyValidators({vc, slot: stateSlot}); - const currentEpoch = state.epochCtx.currentShuffling.epoch; + const currentEpoch = state.epochCtx.epoch; + const currentDecisionRoot = state.epochCtx.currentDecisionRoot; let shufflingCache: ShufflingCache; beforeEach(() => { - shufflingCache = new ShufflingCache(null, {maxShufflingCacheEpochs: 1}); - shufflingCache.processState(state, currentEpoch); + shufflingCache = new ShufflingCache(null, null, {maxShufflingCacheEpochs: 1}, [ + { + shuffling: state.epochCtx.currentShuffling, + decisionRoot: currentDecisionRoot, + }, + ]); }); it("should get shuffling from cache", async function () { - const decisionRoot = getShufflingDecisionBlock(state, currentEpoch); - expect(await shufflingCache.get(currentEpoch, decisionRoot)).toEqual(state.epochCtx.currentShuffling); + expect(await shufflingCache.get(currentEpoch, currentDecisionRoot)).toEqual(state.epochCtx.currentShuffling); }); it("should bound by maxSize(=1)", async function () { - const decisionRoot = getShufflingDecisionBlock(state, currentEpoch); - expect(await shufflingCache.get(currentEpoch, decisionRoot)).toEqual(state.epochCtx.currentShuffling); + expect(await shufflingCache.get(currentEpoch, currentDecisionRoot)).toEqual(state.epochCtx.currentShuffling); // insert promises at the same epoch does not prune the cache shufflingCache.insertPromise(currentEpoch, "0x00"); - expect(await shufflingCache.get(currentEpoch, decisionRoot)).toEqual(state.epochCtx.currentShuffling); - // insert shufflings at other epochs does prune the cache - shufflingCache.processState(state, currentEpoch + 1); + expect(await shufflingCache.get(currentEpoch, currentDecisionRoot)).toEqual(state.epochCtx.currentShuffling); + // insert shuffling at other epochs does prune the cache + shufflingCache["set"](state.epochCtx.previousShuffling, state.epochCtx.previousDecisionRoot); // the current shuffling is not available anymore - expect(await shufflingCache.get(currentEpoch, decisionRoot)).toBeNull(); + expect(await shufflingCache.get(currentEpoch, currentDecisionRoot)).toBeNull(); }); it("should return shuffling from promise", async function () { - const nextDecisionRoot = getShufflingDecisionBlock(state, currentEpoch + 1); - shufflingCache.insertPromise(currentEpoch + 1, nextDecisionRoot); - const shufflingRequest0 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); - const shufflingRequest1 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); - shufflingCache.processState(state, currentEpoch + 1); - expect(await shufflingRequest0).toEqual(state.epochCtx.nextShuffling); - expect(await shufflingRequest1).toEqual(state.epochCtx.nextShuffling); + const previousEpoch = state.epochCtx.epoch - 1; + const previousDecisionRoot = state.epochCtx.previousDecisionRoot; + shufflingCache.insertPromise(previousEpoch, previousDecisionRoot); + const shufflingRequest0 = shufflingCache.get(previousEpoch, previousDecisionRoot); + const shufflingRequest1 = shufflingCache.get(previousEpoch, previousDecisionRoot); + shufflingCache["set"](state.epochCtx.previousShuffling, previousDecisionRoot); + expect(await shufflingRequest0).toEqual(state.epochCtx.previousShuffling); + expect(await shufflingRequest1).toEqual(state.epochCtx.previousShuffling); }); it("should support up to 2 promises at a time", async function () { diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index bb55adca1eb0..49a27435bdd7 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -106,6 +106,7 @@ export function generateState( /** * This generates state with default pubkey + * TODO: (@matthewkeil) - this is duplicated and exists in state-transition as well */ export function generateCachedState(opts?: TestBeaconState): CachedBeaconStateAllForks { const config = getConfig(ForkName.phase0); diff --git a/packages/beacon-node/test/utils/validationData/attestation.ts b/packages/beacon-node/test/utils/validationData/attestation.ts index c33d942dabc5..22f551cbb663 100644 --- a/packages/beacon-node/test/utils/validationData/attestation.ts +++ b/packages/beacon-node/test/utils/validationData/attestation.ts @@ -1,10 +1,5 @@ import {BitArray, toHexString} from "@chainsafe/ssz"; -import { - computeEpochAtSlot, - computeSigningRoot, - computeStartSlotAtEpoch, - getShufflingDecisionBlock, -} from "@lodestar/state-transition"; +import {computeEpochAtSlot, computeSigningRoot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {ProtoBlock, IForkChoice, ExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; import {phase0, Slot, ssz} from "@lodestar/types"; @@ -81,10 +76,20 @@ export function getAttestationValidData(opts: AttestationValidDataOpts): { dataAvailabilityStatus: DataAvailabilityStatus.PreData, }; - const shufflingCache = new ShufflingCache(); - shufflingCache.processState(state, state.epochCtx.currentShuffling.epoch); - shufflingCache.processState(state, state.epochCtx.nextShuffling.epoch); - const dependentRoot = getShufflingDecisionBlock(state, state.epochCtx.currentShuffling.epoch); + const shufflingCache = new ShufflingCache(null, null, {}, [ + { + shuffling: state.epochCtx.previousShuffling, + decisionRoot: state.epochCtx.previousDecisionRoot, + }, + { + shuffling: state.epochCtx.currentShuffling, + decisionRoot: state.epochCtx.currentDecisionRoot, + }, + { + shuffling: state.epochCtx.nextShuffling, + decisionRoot: state.epochCtx.nextDecisionRoot, + }, + ]); const forkChoice = { getBlock: (root) => { @@ -95,7 +100,7 @@ export function getAttestationValidData(opts: AttestationValidDataOpts): { if (rootHex !== toHexString(beaconBlockRoot)) return null; return headBlock; }, - getDependentRoot: () => dependentRoot, + getDependentRoot: () => state.epochCtx.currentDecisionRoot, } as Partial as IForkChoice; const committeeIndices = state.epochCtx.getBeaconCommittee(attSlot, attIndex); diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index a44fd5d0e0cd..dd5c24ac3a54 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -124,6 +124,8 @@ export const FAR_FUTURE_EPOCH = Infinity; export const BASE_REWARDS_PER_EPOCH = 4; export const DEPOSIT_CONTRACT_TREE_DEPTH = 2 ** 5; // 32 export const JUSTIFICATION_BITS_LENGTH = 4; +export const ZERO_HASH = Buffer.alloc(32, 0); +export const ZERO_HASH_HEX = "0x" + "00".repeat(32); // Withdrawal prefixes // Since the prefixes are just 1 byte, we define and use them as number diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index ba8ec9b05ab5..3783c7f91f0d 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -7,6 +7,7 @@ import { Slot, ValidatorIndex, phase0, + RootHex, SyncPeriod, Attestation, IndexedAttestation, @@ -37,12 +38,19 @@ import { computeProposers, getActivationChurnLimit, } from "../util/index.js"; -import {computeEpochShuffling, EpochShuffling, getShufflingDecisionBlock} from "../util/epochShuffling.js"; +import { + computeEpochShuffling, + EpochShuffling, + calculateShufflingDecisionRoot, + IShufflingCache, +} from "../util/epochShuffling.js"; import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {getTotalSlashingsByIncrement} from "../epoch/processSlashings.js"; +import {AttesterDuty, calculateCommitteeAssignments} from "../util/calculateCommitteeAssignments.js"; import {EpochCacheMetrics} from "../metrics.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; +import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; import { Index2PubkeyCache, PubkeyIndexMap, @@ -52,13 +60,13 @@ import { PubkeyHex, newUnfinalizedPubkeyIndexMap, } from "./pubkeyCache.js"; -import {BeaconStateAllForks, BeaconStateAltair, ShufflingGetter} from "./types.js"; import { computeSyncCommitteeCache, getSyncCommitteeCache, SyncCommitteeCache, SyncCommitteeCacheEmpty, } from "./syncCommitteeCache.js"; +import {CachedBeaconStateAllForks} from "./stateCache.js"; /** `= PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT)` */ export const PROPOSER_WEIGHT_FACTOR = PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT); @@ -67,12 +75,12 @@ export type EpochCacheImmutableData = { config: BeaconConfig; pubkey2index: PubkeyIndexMap; index2pubkey: Index2PubkeyCache; + shufflingCache?: IShufflingCache; }; export type EpochCacheOpts = { skipSyncCommitteeCache?: boolean; skipSyncPubkeys?: boolean; - shufflingGetter?: ShufflingGetter; }; /** Defers computing proposers by persisting only the seed, and dropping it once indexes are computed */ @@ -127,6 +135,11 @@ export class EpochCache { * Unique pubkey registry shared in the same fork. There should only exist one for the fork. */ unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; + /** + * ShufflingCache is passed in from `beacon-node` so should be available at runtime but may not be + * present during testing. + */ + shufflingCache?: IShufflingCache; /** * Indexes of the block proposers for the current epoch. @@ -145,6 +158,12 @@ export class EpochCache { */ proposersNextEpoch: ProposersDeferred; + /** + * Epoch decision roots to look up correct shuffling from the Shuffling Cache + */ + previousDecisionRoot: RootHex; + currentDecisionRoot: RootHex; + nextDecisionRoot: RootHex; /** * Shuffling of validator indexes. Immutable through the epoch, then it's replaced entirely. * Note: Per spec definition, shuffling will always be defined. They are never called before loadState() @@ -155,7 +174,12 @@ export class EpochCache { /** Same as previousShuffling */ currentShuffling: EpochShuffling; /** Same as previousShuffling */ - nextShuffling: EpochShuffling; + nextShuffling: EpochShuffling | null; + /** + * Cache nextActiveIndices so that in afterProcessEpoch the next shuffling can be build synchronously + * in case it is not built or the ShufflingCache is not available + */ + nextActiveIndices: Uint32Array; /** * Effective balances, for altair processAttestations() */ @@ -227,7 +251,6 @@ export class EpochCache { nextSyncCommitteeIndexed: SyncCommitteeCache; // TODO: Helper stats - epoch: Epoch; syncPeriod: SyncPeriod; /** * state.validators.length of every state at epoch boundary @@ -239,17 +262,28 @@ export class EpochCache { */ historicalValidatorLengths: immutable.List; + epoch: Epoch; + + get nextEpoch(): Epoch { + return this.epoch + 1; + } + constructor(data: { config: BeaconConfig; pubkey2index: PubkeyIndexMap; index2pubkey: Index2PubkeyCache; unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; + shufflingCache?: IShufflingCache; proposers: number[]; proposersPrevEpoch: number[] | null; proposersNextEpoch: ProposersDeferred; + previousDecisionRoot: RootHex; + currentDecisionRoot: RootHex; + nextDecisionRoot: RootHex; previousShuffling: EpochShuffling; currentShuffling: EpochShuffling; - nextShuffling: EpochShuffling; + nextShuffling: EpochShuffling | null; + nextActiveIndices: Uint32Array; effectiveBalanceIncrements: EffectiveBalanceIncrements; totalSlashingsByIncrement: number; syncParticipantReward: number; @@ -272,12 +306,17 @@ export class EpochCache { this.pubkey2index = data.pubkey2index; this.index2pubkey = data.index2pubkey; this.unfinalizedPubkey2index = data.unfinalizedPubkey2index; + this.shufflingCache = data.shufflingCache; this.proposers = data.proposers; this.proposersPrevEpoch = data.proposersPrevEpoch; this.proposersNextEpoch = data.proposersNextEpoch; + this.previousDecisionRoot = data.previousDecisionRoot; + this.currentDecisionRoot = data.currentDecisionRoot; + this.nextDecisionRoot = data.nextDecisionRoot; this.previousShuffling = data.previousShuffling; this.currentShuffling = data.currentShuffling; this.nextShuffling = data.nextShuffling; + this.nextActiveIndices = data.nextActiveIndices; this.effectiveBalanceIncrements = data.effectiveBalanceIncrements; this.totalSlashingsByIncrement = data.totalSlashingsByIncrement; this.syncParticipantReward = data.syncParticipantReward; @@ -305,7 +344,7 @@ export class EpochCache { */ static createFromState( state: BeaconStateAllForks, - {config, pubkey2index, index2pubkey}: EpochCacheImmutableData, + {config, pubkey2index, index2pubkey, shufflingCache}: EpochCacheImmutableData, opts?: EpochCacheOpts ): EpochCache { const currentEpoch = computeEpochAtSlot(state.slot); @@ -328,18 +367,18 @@ export class EpochCache { const effectiveBalanceIncrements = getEffectiveBalanceIncrementsWithLen(validatorCount); const totalSlashingsByIncrement = getTotalSlashingsByIncrement(state); - const previousActiveIndices: ValidatorIndex[] = []; - const currentActiveIndices: ValidatorIndex[] = []; - const nextActiveIndices: ValidatorIndex[] = []; + const previousActiveIndicesAsNumberArray: ValidatorIndex[] = []; + const currentActiveIndicesAsNumberArray: ValidatorIndex[] = []; + const nextActiveIndicesAsNumberArray: ValidatorIndex[] = []; // BeaconChain could provide a shuffling cache to avoid re-computing shuffling every epoch // in that case, we don't need to compute shufflings again - const previousShufflingDecisionBlock = getShufflingDecisionBlock(state, previousEpoch); - const cachedPreviousShuffling = opts?.shufflingGetter?.(previousEpoch, previousShufflingDecisionBlock); - const currentShufflingDecisionBlock = getShufflingDecisionBlock(state, currentEpoch); - const cachedCurrentShuffling = opts?.shufflingGetter?.(currentEpoch, currentShufflingDecisionBlock); - const nextShufflingDecisionBlock = getShufflingDecisionBlock(state, nextEpoch); - const cachedNextShuffling = opts?.shufflingGetter?.(nextEpoch, nextShufflingDecisionBlock); + const previousDecisionRoot = calculateShufflingDecisionRoot(config, state, previousEpoch); + const cachedPreviousShuffling = shufflingCache?.getSync(previousEpoch, previousDecisionRoot); + const currentDecisionRoot = calculateShufflingDecisionRoot(config, state, currentEpoch); + const cachedCurrentShuffling = shufflingCache?.getSync(currentEpoch, currentDecisionRoot); + const nextDecisionRoot = calculateShufflingDecisionRoot(config, state, nextEpoch); + const cachedNextShuffling = shufflingCache?.getSync(nextEpoch, nextDecisionRoot); for (let i = 0; i < validatorCount; i++) { const validator = validators[i]; @@ -350,17 +389,17 @@ export class EpochCache { // we only need to track active indices for previous, current and next epoch if we have to compute shufflings // skip doing that if we already have cached shufflings if (cachedPreviousShuffling == null && isActiveValidator(validator, previousEpoch)) { - previousActiveIndices.push(i); + previousActiveIndicesAsNumberArray.push(i); } if (isActiveValidator(validator, currentEpoch)) { if (cachedCurrentShuffling == null) { - currentActiveIndices.push(i); + currentActiveIndicesAsNumberArray.push(i); } // We track totalActiveBalanceIncrements as ETH to fit total network balance in a JS number (53 bits) totalActiveBalanceIncrements += effectiveBalanceIncrements[i]; } if (cachedNextShuffling == null && isActiveValidator(validator, nextEpoch)) { - nextActiveIndices.push(i); + nextActiveIndicesAsNumberArray.push(i); } const {exitEpoch} = validator; @@ -382,16 +421,48 @@ export class EpochCache { throw Error("totalActiveBalanceIncrements >= Number.MAX_SAFE_INTEGER. MAX_EFFECTIVE_BALANCE is too low."); } - const currentShuffling = - cachedCurrentShuffling ?? - computeEpochShuffling(state, currentActiveIndices, currentActiveIndices.length, currentEpoch); - const previousShuffling = - cachedPreviousShuffling ?? - (isGenesis - ? currentShuffling - : computeEpochShuffling(state, previousActiveIndices, previousActiveIndices.length, previousEpoch)); - const nextShuffling = - cachedNextShuffling ?? computeEpochShuffling(state, nextActiveIndices, nextActiveIndices.length, nextEpoch); + const nextActiveIndices = new Uint32Array(nextActiveIndicesAsNumberArray); + let previousShuffling: EpochShuffling; + let currentShuffling: EpochShuffling; + let nextShuffling: EpochShuffling; + + if (!shufflingCache) { + // Only for testing. shufflingCache should always be available in prod + previousShuffling = computeEpochShuffling( + state, + new Uint32Array(previousActiveIndicesAsNumberArray), + previousEpoch + ); + + currentShuffling = isGenesis + ? previousShuffling + : computeEpochShuffling(state, new Uint32Array(currentActiveIndicesAsNumberArray), currentEpoch); + + nextShuffling = computeEpochShuffling(state, nextActiveIndices, nextEpoch); + } else { + currentShuffling = cachedCurrentShuffling + ? cachedCurrentShuffling + : shufflingCache.getSync(currentEpoch, currentDecisionRoot, { + state, + activeIndices: new Uint32Array(currentActiveIndicesAsNumberArray), + }); + + previousShuffling = cachedPreviousShuffling + ? cachedPreviousShuffling + : isGenesis + ? currentShuffling + : shufflingCache.getSync(previousEpoch, previousDecisionRoot, { + state, + activeIndices: new Uint32Array(previousActiveIndicesAsNumberArray), + }); + + nextShuffling = cachedNextShuffling + ? cachedNextShuffling + : shufflingCache.getSync(nextEpoch, nextDecisionRoot, { + state, + activeIndices: nextActiveIndices, + }); + } const currentProposerSeed = getSeed(state, currentEpoch, DOMAIN_BEACON_PROPOSER); @@ -482,13 +553,18 @@ export class EpochCache { index2pubkey, // `createFromFinalizedState()` creates cache with empty unfinalizedPubkey2index. Be cautious to only pass in finalized state unfinalizedPubkey2index: newUnfinalizedPubkeyIndexMap(), + shufflingCache, proposers, // On first epoch, set to null to prevent unnecessary work since this is only used for metrics proposersPrevEpoch: null, proposersNextEpoch, + previousDecisionRoot, + currentDecisionRoot, + nextDecisionRoot, previousShuffling, currentShuffling, nextShuffling, + nextActiveIndices, effectiveBalanceIncrements, totalSlashingsByIncrement, syncParticipantReward, @@ -523,13 +599,18 @@ export class EpochCache { index2pubkey: this.index2pubkey, // No need to clone this reference. On each mutation the `unfinalizedPubkey2index` reference is replaced, @see `addPubkey` unfinalizedPubkey2index: this.unfinalizedPubkey2index, + shufflingCache: this.shufflingCache, // Immutable data proposers: this.proposers, proposersPrevEpoch: this.proposersPrevEpoch, proposersNextEpoch: this.proposersNextEpoch, + previousDecisionRoot: this.previousDecisionRoot, + currentDecisionRoot: this.currentDecisionRoot, + nextDecisionRoot: this.nextDecisionRoot, previousShuffling: this.previousShuffling, currentShuffling: this.currentShuffling, nextShuffling: this.nextShuffling, + nextActiveIndices: this.nextActiveIndices, // Uint8Array, requires cloning, but it is cloned only when necessary before an epoch transition // See EpochCache.beforeEpochTransition() effectiveBalanceIncrements: this.effectiveBalanceIncrements, @@ -555,46 +636,98 @@ export class EpochCache { /** * Called to re-use information, such as the shuffling of the next epoch, after transitioning into a - * new epoch. + * new epoch. Also handles pre-computation of values that may change during the upcoming epoch and + * that get used in the following epoch transition. Often those pre-computations are not used by the + * chain but are courtesy values that are served via the API for epoch look ahead of duties. + * + * Steps for afterProcessEpoch + * 1) update previous/current/next values of cached items */ afterProcessEpoch( - state: BeaconStateAllForks, + state: CachedBeaconStateAllForks, epochTransitionCache: { - indicesEligibleForActivationQueue: ValidatorIndex[]; - nextEpochShufflingActiveValidatorIndices: ValidatorIndex[]; - nextEpochShufflingActiveIndicesLength: number; + nextShufflingDecisionRoot: RootHex; + nextShufflingActiveIndices: Uint32Array; nextEpochTotalActiveBalanceByIncrement: number; } ): void { + // Because the slot was incremented before entering this function the "next epoch" is actually the "current epoch" + // in this context but that is not actually true because the state transition happens in the last 4 seconds of the + // epoch. For the context of this function "upcoming epoch" is used to denote the epoch that will begin after this + // function returns. The epoch that is "next" once the state transition is complete is referred to as the + // epochAfterUpcoming for the same reason to help minimize confusion. + const upcomingEpoch = this.nextEpoch; + const epochAfterUpcoming = upcomingEpoch + 1; + + // move current to previous this.previousShuffling = this.currentShuffling; - this.currentShuffling = this.nextShuffling; - const currEpoch = this.currentShuffling.epoch; - const nextEpoch = currEpoch + 1; - - this.nextShuffling = computeEpochShuffling( - state, - epochTransitionCache.nextEpochShufflingActiveValidatorIndices, - epochTransitionCache.nextEpochShufflingActiveIndicesLength, - nextEpoch - ); - - // Roll current proposers into previous proposers for metrics + this.previousDecisionRoot = this.currentDecisionRoot; this.proposersPrevEpoch = this.proposers; - const currentProposerSeed = getSeed(state, this.currentShuffling.epoch, DOMAIN_BEACON_PROPOSER); + // move next to current or calculate upcoming + this.currentDecisionRoot = this.nextDecisionRoot; + if (this.nextShuffling) { + // was already pulled from the ShufflingCache to the EpochCache (should be in most cases) + this.currentShuffling = this.nextShuffling; + } else { + this.shufflingCache?.metrics?.shufflingCache.nextShufflingNotOnEpochCache.inc(); + this.currentShuffling = + this.shufflingCache?.getSync(upcomingEpoch, this.currentDecisionRoot, { + state, + // have to use the "nextActiveIndices" that were saved in the last transition here to calculate + // the upcoming shuffling if it is not already built (similar condition to the below computation) + activeIndices: this.nextActiveIndices, + }) ?? + // allow for this case during testing where the ShufflingCache is not present, may affect perf testing + // so should be taken into account when structuring tests. Should not affect unit or other tests though + computeEpochShuffling(state, this.nextActiveIndices, upcomingEpoch); + } + const upcomingProposerSeed = getSeed(state, upcomingEpoch, DOMAIN_BEACON_PROPOSER); + // next epoch was moved to current epoch so use current here this.proposers = computeProposers( - this.config.getForkSeqAtEpoch(currEpoch), - currentProposerSeed, + this.config.getForkSeqAtEpoch(upcomingEpoch), + upcomingProposerSeed, this.currentShuffling, this.effectiveBalanceIncrements ); + // handle next values + this.nextDecisionRoot = epochTransitionCache.nextShufflingDecisionRoot; + this.nextActiveIndices = epochTransitionCache.nextShufflingActiveIndices; + if (this.shufflingCache) { + this.nextShuffling = null; + // This promise will resolve immediately after the synchronous code of the state-transition runs. Until + // the build is done on a worker thread it will be calculated immediately after the epoch transition + // completes. Once the work is done concurrently it should be ready by time this get runs so the promise + // will resolve directly on the next spin of the event loop because the epoch transition and shuffling take + // about the same time to calculate so theoretically its ready now. Do not await here though in case it + // is not ready yet as the transition must not be asynchronous. + this.shufflingCache + .get(epochAfterUpcoming, this.nextDecisionRoot) + .then((shuffling) => { + if (!shuffling) { + throw new Error("EpochShuffling not returned from get in afterProcessEpoch"); + } + this.nextShuffling = shuffling; + }) + .catch((err) => { + this.shufflingCache?.logger?.error( + "EPOCH_CONTEXT_SHUFFLING_BUILD_ERROR", + {epoch: epochAfterUpcoming, decisionRoot: epochTransitionCache.nextShufflingDecisionRoot}, + err + ); + }); + } else { + // Only for testing. shufflingCache should always be available in prod + this.nextShuffling = computeEpochShuffling(state, this.nextActiveIndices, epochAfterUpcoming); + } + // Only pre-compute the seed since it's very cheap. Do the expensive computeProposers() call only on demand. - this.proposersNextEpoch = {computed: false, seed: getSeed(state, this.nextShuffling.epoch, DOMAIN_BEACON_PROPOSER)}; + this.proposersNextEpoch = {computed: false, seed: getSeed(state, epochAfterUpcoming, DOMAIN_BEACON_PROPOSER)}; // TODO: DEDUPLICATE from createEpochCache // - // Precompute churnLimit for efficient initiateValidatorExit() during block proposing MUST be recompute everytime the + // Precompute churnLimit for efficient initiateValidatorExit() during block proposing MUST be recompute every time the // active validator indices set changes in size. Validators change active status only when: // - validator.activation_epoch is set. Only changes in process_registry_updates() if validator can be activated. If // the value changes it will be set to `epoch + 1 + MAX_SEED_LOOKAHEAD`. @@ -616,14 +749,14 @@ export class EpochCache { ); // Maybe advance exitQueueEpoch at the end of the epoch if there haven't been any exists for a while - const exitQueueEpoch = computeActivationExitEpoch(currEpoch); + const exitQueueEpoch = computeActivationExitEpoch(upcomingEpoch); if (exitQueueEpoch > this.exitQueueEpoch) { this.exitQueueEpoch = exitQueueEpoch; this.exitQueueChurn = 0; } this.totalActiveBalanceIncrements = epochTransitionCache.nextEpochTotalActiveBalanceByIncrement; - if (currEpoch >= this.config.ALTAIR_FORK_EPOCH) { + if (upcomingEpoch >= this.config.ALTAIR_FORK_EPOCH) { this.syncParticipantReward = computeSyncParticipantReward(this.totalActiveBalanceIncrements); this.syncProposerReward = Math.floor(this.syncParticipantReward * PROPOSER_WEIGHT_FACTOR); this.baseRewardPerIncrement = computeBaseRewardPerIncrement(this.totalActiveBalanceIncrements); @@ -644,7 +777,7 @@ export class EpochCache { // Only keep validatorLength for epochs after finalized cpState.epoch // eg. [100(epoch 1), 102(epoch 2)].push(104(epoch 3)), this.epoch = 3, finalized cp epoch = 1 // We keep the last (3 - 1) items = [102, 104] - if (currEpoch >= this.config.ELECTRA_FORK_EPOCH) { + if (upcomingEpoch >= this.config.ELECTRA_FORK_EPOCH) { this.historicalValidatorLengths = this.historicalValidatorLengths.push(state.validators.length); // If number of validatorLengths we want to keep exceeds the current list size, it implies @@ -786,7 +919,7 @@ export class EpochCache { const indexes = computeProposers( this.config.getForkSeqAtEpoch(this.epoch + 1), this.proposersNextEpoch.seed, - this.nextShuffling, + this.getShufflingAtEpoch(this.nextEpoch), this.effectiveBalanceIncrements ); this.proposersNextEpoch = {computed: true, indexes}; @@ -840,30 +973,8 @@ export class EpochCache { epoch: Epoch, requestedValidatorIndices: ValidatorIndex[] ): Map { - const requestedValidatorIndicesSet = new Set(requestedValidatorIndices); - const duties = new Map(); - - const epochCommittees = this.getShufflingAtEpoch(epoch).committees; - for (let epochSlot = 0; epochSlot < SLOTS_PER_EPOCH; epochSlot++) { - const slotCommittees = epochCommittees[epochSlot]; - for (let i = 0, committeesAtSlot = slotCommittees.length; i < committeesAtSlot; i++) { - for (let j = 0, committeeLength = slotCommittees[i].length; j < committeeLength; j++) { - const validatorIndex = slotCommittees[i][j]; - if (requestedValidatorIndicesSet.has(validatorIndex)) { - duties.set(validatorIndex, { - validatorIndex, - committeeLength, - committeesAtSlot, - validatorCommitteeIndex: j, - committeeIndex: i, - slot: epoch * SLOTS_PER_EPOCH + epochSlot, - }); - } - } - } - } - - return duties; + const shuffling = this.getShufflingAtEpoch(epoch); + return calculateCommitteeAssignments(shuffling, requestedValidatorIndices); } /** @@ -987,6 +1098,13 @@ export class EpochCache { getShufflingAtEpoch(epoch: Epoch): EpochShuffling { const shuffling = this.getShufflingAtEpochOrNull(epoch); if (shuffling === null) { + if (epoch === this.nextEpoch) { + throw new EpochCacheError({ + code: EpochCacheErrorCode.NEXT_SHUFFLING_NOT_AVAILABLE, + epoch: epoch, + decisionRoot: this.getShufflingDecisionRoot(this.nextEpoch), + }); + } throw new EpochCacheError({ code: EpochCacheErrorCode.COMMITTEE_EPOCH_OUT_OF_RANGE, currentEpoch: this.currentShuffling.epoch, @@ -997,15 +1115,37 @@ export class EpochCache { return shuffling; } + getShufflingDecisionRoot(epoch: Epoch): RootHex { + switch (epoch) { + case this.epoch - 1: + return this.previousDecisionRoot; + case this.epoch: + return this.currentDecisionRoot; + case this.nextEpoch: + return this.nextDecisionRoot; + default: + throw new EpochCacheError({ + code: EpochCacheErrorCode.DECISION_ROOT_EPOCH_OUT_OF_RANGE, + currentEpoch: this.epoch, + requestedEpoch: epoch, + }); + } + } + getShufflingAtEpochOrNull(epoch: Epoch): EpochShuffling | null { - if (epoch === this.previousShuffling.epoch) { - return this.previousShuffling; - } else if (epoch === this.currentShuffling.epoch) { - return this.currentShuffling; - } else if (epoch === this.nextShuffling.epoch) { - return this.nextShuffling; - } else { - return null; + switch (epoch) { + case this.epoch - 1: + return this.previousShuffling; + case this.epoch: + return this.currentShuffling; + case this.nextEpoch: + if (!this.nextShuffling) { + this.nextShuffling = + this.shufflingCache?.getSync(this.nextEpoch, this.getShufflingDecisionRoot(this.nextEpoch)) ?? null; + } + return this.nextShuffling; + default: + return null; } } @@ -1102,19 +1242,11 @@ function getEffectiveBalanceIncrementsByteLen(validatorCount: number): number { return 1024 * Math.ceil(validatorCount / 1024); } -// Copied from lodestar-api package to avoid depending on the package -type AttesterDuty = { - validatorIndex: ValidatorIndex; - committeeIndex: CommitteeIndex; - committeeLength: number; - committeesAtSlot: number; - validatorCommitteeIndex: number; - slot: Slot; -}; - export enum EpochCacheErrorCode { COMMITTEE_INDEX_OUT_OF_RANGE = "EPOCH_CONTEXT_ERROR_COMMITTEE_INDEX_OUT_OF_RANGE", COMMITTEE_EPOCH_OUT_OF_RANGE = "EPOCH_CONTEXT_ERROR_COMMITTEE_EPOCH_OUT_OF_RANGE", + DECISION_ROOT_EPOCH_OUT_OF_RANGE = "EPOCH_CONTEXT_ERROR_DECISION_ROOT_EPOCH_OUT_OF_RANGE", + NEXT_SHUFFLING_NOT_AVAILABLE = "EPOCH_CONTEXT_ERROR_NEXT_SHUFFLING_NOT_AVAILABLE", NO_SYNC_COMMITTEE = "EPOCH_CONTEXT_ERROR_NO_SYNC_COMMITTEE", PROPOSER_EPOCH_MISMATCH = "EPOCH_CONTEXT_ERROR_PROPOSER_EPOCH_MISMATCH", } @@ -1130,6 +1262,16 @@ type EpochCacheErrorType = requestedEpoch: Epoch; currentEpoch: Epoch; } + | { + code: EpochCacheErrorCode.DECISION_ROOT_EPOCH_OUT_OF_RANGE; + requestedEpoch: Epoch; + currentEpoch: Epoch; + } + | { + code: EpochCacheErrorCode.NEXT_SHUFFLING_NOT_AVAILABLE; + epoch: Epoch; + decisionRoot: RootHex; + } | { code: EpochCacheErrorCode.NO_SYNC_COMMITTEE; epoch: Epoch; diff --git a/packages/state-transition/src/cache/epochTransitionCache.ts b/packages/state-transition/src/cache/epochTransitionCache.ts index 6f27ad96d1c8..27b781e8a6a1 100644 --- a/packages/state-transition/src/cache/epochTransitionCache.ts +++ b/packages/state-transition/src/cache/epochTransitionCache.ts @@ -1,6 +1,12 @@ -import {Epoch, ValidatorIndex, phase0} from "@lodestar/types"; -import {intDiv} from "@lodestar/utils"; -import {EPOCHS_PER_SLASHINGS_VECTOR, FAR_FUTURE_EPOCH, ForkSeq, MIN_ACTIVATION_BALANCE} from "@lodestar/params"; +import {phase0, Epoch, RootHex, ValidatorIndex} from "@lodestar/types"; +import {intDiv, toRootHex} from "@lodestar/utils"; +import { + EPOCHS_PER_SLASHINGS_VECTOR, + FAR_FUTURE_EPOCH, + ForkSeq, + SLOTS_PER_HISTORICAL_ROOT, + MIN_ACTIVATION_BALANCE, +} from "@lodestar/params"; import { hasMarkers, @@ -155,12 +161,12 @@ export interface EpochTransitionCache { * | beforeProcessEpoch | calculate during the validator loop| * | afterEpochTransitionCache | read it | */ - nextEpochShufflingActiveValidatorIndices: ValidatorIndex[]; + nextShufflingActiveIndices: Uint32Array; /** - * We do not use up to `nextEpochShufflingActiveValidatorIndices.length`, use this to control that + * Shuffling decision root that gets set on the EpochCache in afterProcessEpoch */ - nextEpochShufflingActiveIndicesLength: number; + nextShufflingDecisionRoot: RootHex; /** * Altair specific, this is total active balances for the next epoch. @@ -360,6 +366,24 @@ export function beforeProcessEpoch( } } + // Trigger async build of shuffling for epoch after next (nextShuffling post epoch transition) + const epochAfterNext = state.epochCtx.nextEpoch + 1; + // cannot call calculateShufflingDecisionRoot here because spec prevent getting current slot + // as a decision block. we are part way through the transition though and this was added in + // process slot beforeProcessEpoch happens so it available and valid + const nextShufflingDecisionRoot = toRootHex(state.blockRoots.get(state.slot % SLOTS_PER_HISTORICAL_ROOT)); + const nextShufflingActiveIndices = new Uint32Array(nextEpochShufflingActiveIndicesLength); + if (nextEpochShufflingActiveIndicesLength > nextEpochShufflingActiveValidatorIndices.length) { + throw new Error( + `Invalid activeValidatorCount: ${nextEpochShufflingActiveIndicesLength} > ${nextEpochShufflingActiveValidatorIndices.length}` + ); + } + // only the first `activeValidatorCount` elements are copied to `activeIndices` + for (let i = 0; i < nextEpochShufflingActiveIndicesLength; i++) { + nextShufflingActiveIndices[i] = nextEpochShufflingActiveValidatorIndices[i]; + } + state.epochCtx.shufflingCache?.build(epochAfterNext, nextShufflingDecisionRoot, state, nextShufflingActiveIndices); + if (totalActiveStakeByIncrement < 1) { totalActiveStakeByIncrement = 1; } else if (totalActiveStakeByIncrement >= Number.MAX_SAFE_INTEGER) { @@ -483,8 +507,8 @@ export function beforeProcessEpoch( indicesEligibleForActivationQueue, indicesEligibleForActivation, indicesToEject, - nextEpochShufflingActiveValidatorIndices, - nextEpochShufflingActiveIndicesLength, + nextShufflingDecisionRoot, + nextShufflingActiveIndices, // to be updated in processEffectiveBalanceUpdates nextEpochTotalActiveBalanceByIncrement: 0, isActivePrevEpoch, diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 0435e8829d21..5412675352e9 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -175,7 +175,7 @@ export function loadCachedBeaconState { + const requestedValidatorIndicesSet = new Set(requestedValidatorIndices); + const duties = new Map(); + + const epochCommittees = epochShuffling.committees; + for (let epochSlot = 0; epochSlot < SLOTS_PER_EPOCH; epochSlot++) { + const slotCommittees = epochCommittees[epochSlot]; + for (let i = 0, committeesAtSlot = slotCommittees.length; i < committeesAtSlot; i++) { + for (let j = 0, committeeLength = slotCommittees[i].length; j < committeeLength; j++) { + const validatorIndex = slotCommittees[i][j]; + if (requestedValidatorIndicesSet.has(validatorIndex)) { + duties.set(validatorIndex, { + validatorIndex, + committeeLength, + committeesAtSlot, + validatorCommitteeIndex: j, + committeeIndex: i, + slot: epochShuffling.epoch * SLOTS_PER_EPOCH + epochSlot, + }); + } + } + } + } + + return duties; +} diff --git a/packages/state-transition/src/util/computeAnchorCheckpoint.ts b/packages/state-transition/src/util/computeAnchorCheckpoint.ts new file mode 100644 index 000000000000..e2efc18952c2 --- /dev/null +++ b/packages/state-transition/src/util/computeAnchorCheckpoint.ts @@ -0,0 +1,38 @@ +import {ChainForkConfig} from "@lodestar/config"; +import {ssz, phase0} from "@lodestar/types"; +import {GENESIS_SLOT, ZERO_HASH} from "@lodestar/params"; +import {BeaconStateAllForks} from "../types.js"; +import {blockToHeader} from "./blockRoot.js"; +import {computeCheckpointEpochAtStateSlot} from "./epoch.js"; + +export function computeAnchorCheckpoint( + config: ChainForkConfig, + anchorState: BeaconStateAllForks +): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader} { + let blockHeader; + let root; + const blockTypes = config.getForkTypes(anchorState.latestBlockHeader.slot); + + if (anchorState.latestBlockHeader.slot === GENESIS_SLOT) { + const block = blockTypes.BeaconBlock.defaultValue(); + block.stateRoot = anchorState.hashTreeRoot(); + blockHeader = blockToHeader(config, block); + root = ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader); + } else { + blockHeader = ssz.phase0.BeaconBlockHeader.clone(anchorState.latestBlockHeader); + if (ssz.Root.equals(blockHeader.stateRoot, ZERO_HASH)) { + blockHeader.stateRoot = anchorState.hashTreeRoot(); + } + root = ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader); + } + + return { + checkpoint: { + root, + // the checkpoint epoch = computeEpochAtSlot(anchorState.slot) + 1 if slot is not at epoch boundary + // this is similar to a process_slots() call + epoch: computeCheckpointEpochAtStateSlot(anchorState.slot), + }, + blockHeader, + }; +} diff --git a/packages/state-transition/src/util/epochShuffling.ts b/packages/state-transition/src/util/epochShuffling.ts index 856721d8d083..c26c62fd2079 100644 --- a/packages/state-transition/src/util/epochShuffling.ts +++ b/packages/state-transition/src/util/epochShuffling.ts @@ -1,16 +1,60 @@ -import {Epoch, RootHex, ValidatorIndex} from "@lodestar/types"; -import {intDiv, toRootHex} from "@lodestar/utils"; +import {Epoch, RootHex, ssz, ValidatorIndex} from "@lodestar/types"; +import {GaugeExtra, intDiv, Logger, NoLabels, toRootHex} from "@lodestar/utils"; import { DOMAIN_BEACON_ATTESTER, + GENESIS_SLOT, MAX_COMMITTEES_PER_SLOT, SLOTS_PER_EPOCH, TARGET_COMMITTEE_SIZE, } from "@lodestar/params"; +import {BeaconConfig} from "@lodestar/config"; import {BeaconStateAllForks} from "../types.js"; import {getSeed} from "./seed.js"; import {unshuffleList} from "./shuffle.js"; import {computeStartSlotAtEpoch} from "./epoch.js"; import {getBlockRootAtSlot} from "./blockRoot.js"; +import {computeAnchorCheckpoint} from "./computeAnchorCheckpoint.js"; + +export interface ShufflingBuildProps { + state: BeaconStateAllForks; + activeIndices: Uint32Array; +} + +export interface PublicShufflingCacheMetrics { + shufflingCache: { + nextShufflingNotOnEpochCache: GaugeExtra; + }; +} +export interface IShufflingCache { + metrics: PublicShufflingCacheMetrics | null; + logger: Logger | null; + /** + * Gets a cached shuffling via the epoch and decision root. If the state and + * activeIndices are passed and a shuffling is not available it will be built + * synchronously. If the state is not passed and the shuffling is not available + * nothing will be returned. + * + * NOTE: If a shuffling is already queued and not calculated it will build and resolve + * the promise but the already queued build will happen at some later time + */ + getSync( + epoch: Epoch, + decisionRoot: RootHex, + buildProps?: T + ): T extends ShufflingBuildProps ? EpochShuffling : EpochShuffling | null; + + /** + * Gets a cached shuffling via the epoch and decision root. Returns a promise + * for the shuffling if it hs not calculated yet. Returns null if a build has + * not been queued nor a shuffling was calculated. + */ + get(epoch: Epoch, decisionRoot: RootHex): Promise; + + /** + * Queue asynchronous build for an EpochShuffling + */ + build(epoch: Epoch, decisionRoot: RootHex, state: BeaconStateAllForks, activeIndices: Uint32Array): void; +} /** * Readonly interface for EpochShuffling. @@ -60,21 +104,13 @@ export function computeCommitteeCount(activeValidatorCount: number): number { export function computeEpochShuffling( state: BeaconStateAllForks, - activeIndices: ArrayLike, - activeValidatorCount: number, + activeIndices: Uint32Array, epoch: Epoch ): EpochShuffling { - const seed = getSeed(state, epoch, DOMAIN_BEACON_ATTESTER); + const activeValidatorCount = activeIndices.length; - if (activeValidatorCount > activeIndices.length) { - throw new Error(`Invalid activeValidatorCount: ${activeValidatorCount} > ${activeIndices.length}`); - } - // only the first `activeValidatorCount` elements are copied to `activeIndices` - const _activeIndices = new Uint32Array(activeValidatorCount); - for (let i = 0; i < activeValidatorCount; i++) { - _activeIndices[i] = activeIndices[i]; - } - const shuffling = _activeIndices.slice(); + const shuffling = activeIndices.slice(); + const seed = getSeed(state, epoch, DOMAIN_BEACON_ATTESTER); unshuffleList(shuffling, seed); const committeesPerSlot = computeCommitteeCount(activeValidatorCount); @@ -98,14 +134,29 @@ export function computeEpochShuffling( return { epoch, - activeIndices: _activeIndices, + activeIndices, shuffling, committees, committeesPerSlot, }; } -export function getShufflingDecisionBlock(state: BeaconStateAllForks, epoch: Epoch): RootHex { +function calculateDecisionRoot(state: BeaconStateAllForks, epoch: Epoch): RootHex { const pivotSlot = computeStartSlotAtEpoch(epoch - 1) - 1; return toRootHex(getBlockRootAtSlot(state, pivotSlot)); } + +/** + * Get the shuffling decision block root for the given epoch of given state + * - Special case close to genesis block, return the genesis block root + * - This is similar to forkchoice.getDependentRoot() function, otherwise we cannot get cached shuffing in attestation verification when syncing from genesis. + */ +export function calculateShufflingDecisionRoot( + config: BeaconConfig, + state: BeaconStateAllForks, + epoch: Epoch +): RootHex { + return state.slot > GENESIS_SLOT + ? calculateDecisionRoot(state, epoch) + : toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(computeAnchorCheckpoint(config, state).blockHeader)); +} diff --git a/packages/state-transition/src/util/index.ts b/packages/state-transition/src/util/index.ts index 9b9916f1d49e..5f8d9e5cdcfc 100644 --- a/packages/state-transition/src/util/index.ts +++ b/packages/state-transition/src/util/index.ts @@ -4,7 +4,9 @@ export * from "./attestation.js"; export * from "./attesterStatus.js"; export * from "./balance.js"; export * from "./blindedBlock.js"; +export * from "./calculateCommitteeAssignments.js"; export * from "./capella.js"; +export * from "./computeAnchorCheckpoint.js"; export * from "./execution.js"; export * from "./blockRoot.js"; export * from "./domain.js"; diff --git a/packages/state-transition/test/perf/epoch/epochAltair.test.ts b/packages/state-transition/test/perf/epoch/epochAltair.test.ts index 15cde849ce9f..5a10fd4d8bbd 100644 --- a/packages/state-transition/test/perf/epoch/epochAltair.test.ts +++ b/packages/state-transition/test/perf/epoch/epochAltair.test.ts @@ -46,6 +46,7 @@ describe(`altair processEpoch - ${stateId}`, () => { fn: (state) => { const cache = beforeProcessEpoch(state); processEpoch(fork, state as CachedBeaconStateAltair, cache); + state.slot++; state.epochCtx.afterProcessEpoch(state, cache); // Simulate root computation through the next block to account for changes // 74184 hash64 ops - 92.730 ms @@ -187,6 +188,9 @@ function benchmarkAltairEpochSteps(stateOg: LazyValue return {state, cache: cacheAfter}; }, beforeEach: ({state, cache}) => ({state: state.clone(), cache}), - fn: ({state, cache}) => state.epochCtx.afterProcessEpoch(state, cache), + fn: ({state, cache}) => { + state.slot++; + state.epochCtx.afterProcessEpoch(state, cache); + }, }); } diff --git a/packages/state-transition/test/perf/epoch/epochCapella.test.ts b/packages/state-transition/test/perf/epoch/epochCapella.test.ts index 61bfad20b1ee..a4daf308aaa0 100644 --- a/packages/state-transition/test/perf/epoch/epochCapella.test.ts +++ b/packages/state-transition/test/perf/epoch/epochCapella.test.ts @@ -46,6 +46,7 @@ describe(`capella processEpoch - ${stateId}`, () => { fn: (state) => { const cache = beforeProcessEpoch(state); processEpoch(fork, state as CachedBeaconStateCapella, cache); + state.slot++; state.epochCtx.afterProcessEpoch(state, cache); // Simulate root computation through the next block to account for changes // 74184 hash64 ops - 92.730 ms @@ -159,6 +160,9 @@ function benchmarkAltairEpochSteps(stateOg: LazyValue return {state, cache: cacheAfter}; }, beforeEach: ({state, cache}) => ({state: state.clone(), cache}), - fn: ({state, cache}) => state.epochCtx.afterProcessEpoch(state, cache), + fn: ({state, cache}) => { + state.slot++; + state.epochCtx.afterProcessEpoch(state, cache); + }, }); } diff --git a/packages/state-transition/test/perf/epoch/epochPhase0.test.ts b/packages/state-transition/test/perf/epoch/epochPhase0.test.ts index 3af3d4d4a832..5c19b347af62 100644 --- a/packages/state-transition/test/perf/epoch/epochPhase0.test.ts +++ b/packages/state-transition/test/perf/epoch/epochPhase0.test.ts @@ -43,6 +43,7 @@ describe(`phase0 processEpoch - ${stateId}`, () => { fn: (state) => { const cache = beforeProcessEpoch(state); processEpoch(fork, state as CachedBeaconStatePhase0, cache); + state.slot++; state.epochCtx.afterProcessEpoch(state, cache); // Simulate root computation through the next block to account for changes state.hashTreeRoot(); @@ -162,6 +163,9 @@ function benchmarkPhase0EpochSteps(stateOg: LazyValue return {state, cache: cacheAfter}; }, beforeEach: ({state, cache}) => ({state: state.clone(), cache}), - fn: ({state, cache}) => state.epochCtx.afterProcessEpoch(state, cache), + fn: ({state, cache}) => { + state.slot++; + state.epochCtx.afterProcessEpoch(state, cache); + }, }); } diff --git a/packages/state-transition/test/perf/util/loadState/loadState.test.ts b/packages/state-transition/test/perf/util/loadState/loadState.test.ts index a8a1b1399dc5..25b43e242d02 100644 --- a/packages/state-transition/test/perf/util/loadState/loadState.test.ts +++ b/packages/state-transition/test/perf/util/loadState/loadState.test.ts @@ -79,17 +79,15 @@ describe("loadState", function () { pubkey2index.set(pubkey, validatorIndex); index2pubkey[validatorIndex] = PublicKey.fromBytes(pubkey); } - // skip computimg shuffling in performance test because in reality we have a ShufflingCache - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - const shufflingGetter = () => seedState.epochCtx.currentShuffling; createCachedBeaconState( migratedState, { config: seedState.config, pubkey2index, index2pubkey, + shufflingCache: seedState.epochCtx.shufflingCache, }, - {skipSyncPubkeys: true, skipSyncCommitteeCache: true, shufflingGetter} + {skipSyncPubkeys: true, skipSyncCommitteeCache: true} ); }, }); diff --git a/packages/state-transition/test/perf/util/shufflings.test.ts b/packages/state-transition/test/perf/util/shufflings.test.ts index 24be96c4676d..41767c184349 100644 --- a/packages/state-transition/test/perf/util/shufflings.test.ts +++ b/packages/state-transition/test/perf/util/shufflings.test.ts @@ -27,17 +27,17 @@ describe("epoch shufflings", () => { itBench({ id: `computeProposers - vc ${numValidators}`, fn: () => { - const epochSeed = getSeed(state, state.epochCtx.nextShuffling.epoch, DOMAIN_BEACON_PROPOSER); + const epochSeed = getSeed(state, state.epochCtx.epoch, DOMAIN_BEACON_PROPOSER); const fork = state.config.getForkSeq(state.slot); - computeProposers(fork, epochSeed, state.epochCtx.nextShuffling, state.epochCtx.effectiveBalanceIncrements); + computeProposers(fork, epochSeed, state.epochCtx.currentShuffling, state.epochCtx.effectiveBalanceIncrements); }, }); itBench({ id: `computeEpochShuffling - vc ${numValidators}`, fn: () => { - const {activeIndices} = state.epochCtx.nextShuffling; - computeEpochShuffling(state, activeIndices, activeIndices.length, nextEpoch); + const {nextActiveIndices} = state.epochCtx; + computeEpochShuffling(state, nextActiveIndices, nextEpoch); }, }); @@ -45,12 +45,7 @@ describe("epoch shufflings", () => { id: `getNextSyncCommittee - vc ${numValidators}`, fn: () => { const fork = state.config.getForkSeq(state.slot); - getNextSyncCommittee( - fork, - state, - state.epochCtx.nextShuffling.activeIndices, - state.epochCtx.effectiveBalanceIncrements - ); + getNextSyncCommittee(fork, state, state.epochCtx.nextActiveIndices, state.epochCtx.effectiveBalanceIncrements); }, }); }); diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index 77c5da7a5f4a..092dda321610 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -1,6 +1,6 @@ import {fromHexString} from "@chainsafe/ssz"; import {describe, it, expect} from "vitest"; -import {Epoch, ssz, RootHex} from "@lodestar/types"; +import {ssz} from "@lodestar/types"; import {toHexString} from "@lodestar/utils"; import {config as defaultConfig} from "@lodestar/config/default"; import {createBeaconConfig, createChainForkConfig} from "@lodestar/config"; @@ -9,7 +9,6 @@ import {PubkeyIndexMap} from "../../src/cache/pubkeyCache.js"; import {createCachedBeaconState, loadCachedBeaconState} from "../../src/cache/stateCache.js"; import {interopPubkeysCached} from "../utils/interop.js"; import {modifyStateSameValidator, newStateWithValidators} from "../utils/capella.js"; -import {EpochShuffling, getShufflingDecisionBlock} from "../../src/util/epochShuffling.js"; describe("CachedBeaconState", () => { it("Clone and mutate", () => { @@ -189,42 +188,21 @@ describe("CachedBeaconState", () => { // confirm loadState() result const stateBytes = state.serialize(); - const newCachedState = loadCachedBeaconState(seedState, stateBytes, {skipSyncCommitteeCache: true}); + const newCachedState = loadCachedBeaconState(seedState, stateBytes, { + skipSyncCommitteeCache: true, + }); const newStateBytes = newCachedState.serialize(); expect(newStateBytes).toEqual(stateBytes); expect(newCachedState.hashTreeRoot()).toEqual(state.hashTreeRoot()); - const shufflingGetter = (shufflingEpoch: Epoch, dependentRoot: RootHex): EpochShuffling | null => { - if ( - shufflingEpoch === seedState.epochCtx.epoch - 1 && - dependentRoot === getShufflingDecisionBlock(seedState, shufflingEpoch) - ) { - return seedState.epochCtx.previousShuffling; - } - - if ( - shufflingEpoch === seedState.epochCtx.epoch && - dependentRoot === getShufflingDecisionBlock(seedState, shufflingEpoch) - ) { - return seedState.epochCtx.currentShuffling; - } - - if ( - shufflingEpoch === seedState.epochCtx.epoch + 1 && - dependentRoot === getShufflingDecisionBlock(seedState, shufflingEpoch) - ) { - return seedState.epochCtx.nextShuffling; - } - - return null; - }; const cachedState = createCachedBeaconState( state, { config, pubkey2index: new PubkeyIndexMap(), index2pubkey: [], + shufflingCache: seedState.epochCtx.shufflingCache, }, - {skipSyncCommitteeCache: true, shufflingGetter} + {skipSyncCommitteeCache: true} ); // validatorCountDelta < 0 is unrealistic and shuffling computation results in a different result if (validatorCountDelta >= 0) { From 0dceb831ca7c44ee8ebfdb667a793a042f0b93c4 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 23 Sep 2024 17:35:45 +0100 Subject: [PATCH 112/259] chore: clean up from electra review (#7102) --- packages/beacon-node/src/api/impl/validator/index.ts | 2 +- packages/beacon-node/src/metrics/metrics/beacon.ts | 2 +- packages/beacon-node/src/metrics/metrics/lodestar.ts | 4 ++-- packages/beacon-node/test/unit/util/sszBytes.test.ts | 2 +- packages/params/src/presets/mainnet.ts | 1 - packages/params/src/presets/minimal.ts | 1 - 6 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index d2ce6672c89f..4876975c1bea 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -1087,7 +1087,7 @@ export function getValidatorApi( await waitForSlot(slot); // Must never request for a future slot > currentSlot - const dataRootHex = toHex(attestationDataRoot); + const dataRootHex = toRootHex(attestationDataRoot); const aggregate = chain.attestationPool.getAggregate(slot, null, dataRootHex); const fork = chain.config.getForkName(slot); diff --git a/packages/beacon-node/src/metrics/metrics/beacon.ts b/packages/beacon-node/src/metrics/metrics/beacon.ts index 96bb6bea4174..949999dbb1f4 100644 --- a/packages/beacon-node/src/metrics/metrics/beacon.ts +++ b/packages/beacon-node/src/metrics/metrics/beacon.ts @@ -122,7 +122,7 @@ export function createBeaconMetrics(register: RegistryMetricCreator) { headState: { unfinalizedPubkeyCacheSize: register.gauge({ - name: "head_state_unfinalized_pubkey_cache_size", + name: "beacon_head_state_unfinalized_pubkey_cache_size", help: "Current size of the unfinalizedPubkey2Index cache in the head state", }), }, diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index 4b076471dcab..fb4ea61b6523 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -381,11 +381,11 @@ export function createLodestarMetrics( epochCache: { finalizedPubkeyDuplicateInsert: register.gauge({ - name: "lodestar_epoch_cache_finalized_pubkey_duplicate_insert", + name: "lodestar_epoch_cache_finalized_pubkey_duplicate_insert_total", help: "Total count of duplicate insert of finalized pubkeys", }), newUnFinalizedPubkey: register.gauge({ - name: "lodestar_epoch_cache_new_unfinalized_pubkey", + name: "lodestar_epoch_cache_new_unfinalized_pubkey_total", help: "Total count of unfinalized pubkeys added", }), }, diff --git a/packages/beacon-node/test/unit/util/sszBytes.test.ts b/packages/beacon-node/test/unit/util/sszBytes.test.ts index 612eea5a4388..8b72c31df6c8 100644 --- a/packages/beacon-node/test/unit/util/sszBytes.test.ts +++ b/packages/beacon-node/test/unit/util/sszBytes.test.ts @@ -6,7 +6,7 @@ import {ForkName, MAX_COMMITTEES_PER_SLOT} from "@lodestar/params"; import { getAttDataFromAttestationSerialized, getAttDataFromSignedAggregateAndProofPhase0, - getAggregationBitsFromAttestationSerialized as getAggregationBitsFromAttestationSerialized, + getAggregationBitsFromAttestationSerialized, getBlockRootFromAttestationSerialized, getBlockRootFromSignedAggregateAndProofSerialized, getSlotFromAttestationSerialized, diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index a4a88aac1f58..ca599e990df4 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -127,7 +127,6 @@ export const mainnetPreset: BeaconPreset = { MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 8, // 2**11 * 10**9 (= 2,048,000,000,000) Gwei MAX_EFFECTIVE_BALANCE_ELECTRA: 2048000000000, - // 2**16 (= 65536) MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: 4096, MIN_ACTIVATION_BALANCE: 32000000000, PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 97eff53cf013..5dc8fc10d803 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -128,7 +128,6 @@ export const minimalPreset: BeaconPreset = { MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 1, // 2**11 * 10**9 (= 2,048,000,000,000) Gwei MAX_EFFECTIVE_BALANCE_ELECTRA: 2048000000000, - // 2**16 (= 65536) MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: 4096, MIN_ACTIVATION_BALANCE: 32000000000, PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, From d0ba6bc3ccf203307bcbf0087d82749dff81699b Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 23 Sep 2024 21:54:20 +0100 Subject: [PATCH 113/259] chore: upgrade fastify to v5 (#7101) * chore: upgrade fastify to v5 * Upgrade fastify plugins * Clean up yarn lock --- packages/api/package.json | 2 +- packages/api/src/utils/schema.ts | 12 +- packages/api/src/utils/server/parser.ts | 14 +- packages/beacon-node/package.json | 10 +- packages/cli/package.json | 2 +- packages/light-client/package.json | 2 +- yarn.lock | 394 +++++++++++++----------- 7 files changed, 228 insertions(+), 208 deletions(-) diff --git a/packages/api/package.json b/packages/api/package.json index d2f8a621f02e..7d851d9513ba 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -83,7 +83,7 @@ "@types/eventsource": "^1.1.11", "@types/qs": "^6.9.7", "ajv": "^8.12.0", - "fastify": "^4.27.0" + "fastify": "^5.0.0" }, "keywords": [ "ethereum", diff --git a/packages/api/src/utils/schema.ts b/packages/api/src/utils/schema.ts index 2d086fd8dfa9..3f297db6f665 100644 --- a/packages/api/src/utils/schema.ts +++ b/packages/api/src/utils/schema.ts @@ -1,3 +1,4 @@ +import {MediaType} from "./headers.js"; import {Endpoint, HeaderParams, PathParams, QueryParams} from "./types.js"; // Reasoning: Allows to declare JSON schemas for server routes in a succinct typesafe way. @@ -91,7 +92,16 @@ export function getFastifySchema(schemaDef: Schem const schema: {params?: JsonSchemaObj; querystring?: JsonSchemaObj; headers?: JsonSchemaObj; body?: JsonSchema} = {}; if (schemaDef.body != null) { - schema.body = getJsonSchemaItem(schemaDef.body); + schema.body = { + content: { + [MediaType.json]: { + schema: getJsonSchemaItem(schemaDef.body), + }, + [MediaType.ssz]: { + schema: {}, + }, + }, + }; } if (schemaDef.params) { diff --git a/packages/api/src/utils/server/parser.ts b/packages/api/src/utils/server/parser.ts index fd668b63757e..3300575a4845 100644 --- a/packages/api/src/utils/server/parser.ts +++ b/packages/api/src/utils/server/parser.ts @@ -2,22 +2,10 @@ import type * as fastify from "fastify"; import {MediaType} from "../headers.js"; export function addSszContentTypeParser(server: fastify.FastifyInstance): void { - // Cache body schema symbol, does not change per request - let bodySchemaSymbol: symbol | undefined; - server.addContentTypeParser( MediaType.ssz, {parseAs: "buffer"}, - async (request: fastify.FastifyRequest, payload: Buffer) => { - if (bodySchemaSymbol === undefined) { - // Get body schema symbol to be able to access validation function - // https://github.com/fastify/fastify/blob/af2ccb5ff681c1d0ac22eb7314c6fa803f73c873/lib/symbols.js#L25 - bodySchemaSymbol = Object.getOwnPropertySymbols(request.context).find((s) => s.description === "body-schema"); - } - // JSON schema validation will be applied to `Buffer` object, it is required to override validation function - // See https://github.com/fastify/help/issues/1012, it is not possible right now to define a schema per content type - (request.context as unknown as Record)[bodySchemaSymbol as symbol] = () => true; - + async (_request: fastify.FastifyRequest, payload: Buffer) => { // We could just return the `Buffer` here which is a subclass of `Uint8Array` but downstream code does not require it // and it's better to convert it here to avoid unexpected behavior such as `Buffer.prototype.slice` not copying memory // See https://github.com/nodejs/node/issues/41588#issuecomment-1016269584 diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index ade89ebc6cc1..f101206bfd9e 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -106,10 +106,10 @@ "@chainsafe/ssz": "^0.17.1", "@chainsafe/threads": "^1.11.1", "@ethersproject/abi": "^5.7.0", - "@fastify/bearer-auth": "^9.0.0", - "@fastify/cors": "^8.2.1", - "@fastify/swagger": "^8.10.0", - "@fastify/swagger-ui": "^1.9.3", + "@fastify/bearer-auth": "^10.0.1", + "@fastify/cors": "^10.0.1", + "@fastify/swagger": "^9.0.0", + "@fastify/swagger-ui": "^5.0.1", "@libp2p/bootstrap": "^10.0.21", "@libp2p/identify": "^1.0.20", "@libp2p/interface": "^1.3.0", @@ -136,7 +136,7 @@ "datastore-core": "^9.1.1", "datastore-level": "^10.1.1", "deepmerge": "^4.3.1", - "fastify": "^4.27.0", + "fastify": "^5.0.0", "interface-datastore": "^8.2.7", "it-all": "^3.0.4", "it-pipe": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 579725eba04e..a5527a8eee87 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -94,6 +94,6 @@ "@types/inquirer": "^9.0.3", "@types/proper-lockfile": "^4.1.4", "@types/yargs": "^17.0.24", - "fastify": "^4.27.0" + "fastify": "^5.0.0" } } diff --git a/packages/light-client/package.json b/packages/light-client/package.json index 940a78ae66d5..2eda3a45d455 100644 --- a/packages/light-client/package.json +++ b/packages/light-client/package.json @@ -87,7 +87,7 @@ "devDependencies": { "@chainsafe/as-sha256": "^0.5.0", "@types/qs": "^6.9.7", - "fastify": "^4.27.0", + "fastify": "^5.0.0", "qs": "^6.11.1", "uint8arrays": "^5.0.1" }, diff --git a/yarn.lock b/yarn.lock index 38e6bae97d60..f546d770acd8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1285,108 +1285,104 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@fastify/accept-negotiator@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz#c1c66b3b771c09742a54dd5bc87c582f6b0630ff" - integrity sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ== +"@fastify/accept-negotiator@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@fastify/accept-negotiator/-/accept-negotiator-2.0.0.tgz#efce76b4d658e7ee669e681c2d79bffc9a654fdb" + integrity sha512-/Sce/kBzuTxIq5tJh85nVNOq9wKD8s+viIgX0fFMDBdw95gnpf53qmF1oBgJym3cPFliWUuSloVg/1w/rH0FcQ== -"@fastify/ajv-compiler@^3.5.0": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz#459bff00fefbf86c96ec30e62e933d2379e46670" - integrity sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA== +"@fastify/ajv-compiler@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-4.0.1.tgz#9567b4c09149a0f342e931c7196a8ed9dc292954" + integrity sha512-DxrBdgsjNLP0YM6W5Hd6/Fmj43S8zMKiFJYgi+Ri3htTGAowPVG/tG1wpnWLMjufEnehRivUCKZ1pLDIoZdTuw== dependencies: - ajv "^8.11.0" - ajv-formats "^2.1.1" - fast-uri "^2.0.0" + ajv "^8.12.0" + ajv-formats "^3.0.1" + fast-uri "^3.0.0" -"@fastify/bearer-auth@^9.0.0": - version "9.0.0" - resolved "https://registry.yarnpkg.com/@fastify/bearer-auth/-/bearer-auth-9.0.0.tgz#9a75abcb1d54751dc04e97b37db5363e325c0f90" - integrity sha512-I1egwg1LRdIvhjL/P+3UEfyK7A3YTnN3goTyf8MJ+v7vVkwyyd8ieccFKI0SzEuxMmfQh/p4yNyLZWcMVwpInA== +"@fastify/bearer-auth@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@fastify/bearer-auth/-/bearer-auth-10.0.1.tgz#893466052fa566c24eb4f44a3c6aacb50db96ecd" + integrity sha512-i2snRkAJsMmfFcsRS/fFIovcLL3WeZtxJP9pprx2NvB8N/l+fjMNmKeWWyX0hDS2Q0zEPqLz/G0DK92nqJYAJQ== dependencies: - fastify-plugin "^4.0.0" + "@fastify/error" "^4.0.0" + fastify-plugin "^5.0.0" "@fastify/busboy@^2.0.0": version "2.1.1" resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== -"@fastify/cors@^8.2.1": - version "8.2.1" - resolved "https://registry.yarnpkg.com/@fastify/cors/-/cors-8.2.1.tgz#dd348162bcbfb87dff4b492e2bef32d41244006a" - integrity sha512-2H2MrDD3ea7g707g1CNNLWb9/tYbmw7HS+MK2SDcgjxwzbOFR93JortelTIO8DBFsZqFtEpKNxiZfSyrGgYcbw== +"@fastify/cors@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@fastify/cors/-/cors-10.0.1.tgz#c208fa5f672db31a8383400349e9852762903d64" + integrity sha512-O8JIf6448uQbOgzSkCqhClw6gFTAqrdfeA6R3fc/3gwTJGUp7gl8/3tbNB+6INuu4RmgVOq99BmvdGbtu5pgOA== dependencies: - fastify-plugin "^4.0.0" - mnemonist "0.39.5" + fastify-plugin "^5.0.0" + mnemonist "0.39.8" -"@fastify/deepmerge@^1.0.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@fastify/deepmerge/-/deepmerge-1.3.0.tgz#8116858108f0c7d9fd460d05a7d637a13fe3239a" - integrity sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A== - -"@fastify/error@^3.3.0", "@fastify/error@^3.4.0": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@fastify/error/-/error-3.4.1.tgz#b14bb4cac3dd4ec614becbc643d1511331a6425c" - integrity sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ== +"@fastify/error@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@fastify/error/-/error-4.0.0.tgz#7842d6161fbce78953638318be99033a0c2d5070" + integrity sha512-OO/SA8As24JtT1usTUTKgGH7uLvhfwZPwlptRi2Dp5P4KKmJI3gvsZ8MIHnNwDs4sLf/aai5LzTyl66xr7qMxA== -"@fastify/fast-json-stringify-compiler@^4.3.0": - version "4.3.0" - resolved "https://registry.yarnpkg.com/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz#5df89fa4d1592cbb8780f78998355feb471646d5" - integrity sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA== +"@fastify/fast-json-stringify-compiler@^5.0.0": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-5.0.1.tgz#659c74f3181fb4f984fe27dcc95d14366ae85ca0" + integrity sha512-f2d3JExJgFE3UbdFcpPwqNUEoHWmt8pAKf8f+9YuLESdefA0WgqxeT6DrGL4Yrf/9ihXNSKOqpjEmurV405meA== dependencies: - fast-json-stringify "^5.7.0" + fast-json-stringify "^6.0.0" -"@fastify/merge-json-schemas@^0.1.0": +"@fastify/merge-json-schemas@^0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz#3551857b8a17a24e8c799e9f51795edb07baa0bc" integrity sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA== dependencies: fast-deep-equal "^3.1.3" -"@fastify/send@^2.0.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@fastify/send/-/send-2.1.0.tgz#1aa269ccb4b0940a2dadd1f844443b15d8224ea0" - integrity sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA== +"@fastify/send@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@fastify/send/-/send-3.1.1.tgz#455a8fa56ae005c4c387ddf111364f346b848117" + integrity sha512-LdiV2mle/2tH8vh6GwGl0ubfUAgvY+9yF9oGI1iiwVyNUVOQamvw5n+OFu6iCNNoyuCY80FFURBn4TZCbTe8LA== dependencies: - "@lukeed/ms" "^2.0.1" + "@lukeed/ms" "^2.0.2" escape-html "~1.0.3" fast-decode-uri-component "^1.0.1" - http-errors "2.0.0" - mime "^3.0.0" - -"@fastify/static@^6.0.0": - version "6.11.2" - resolved "https://registry.yarnpkg.com/@fastify/static/-/static-6.11.2.tgz#1fe40c40daf055a28d29db807b459fcff431d9b6" - integrity sha512-EH7mh7q4MfNdT7N07ZVlwsX/ObngMvQ7KBP0FXAuPov99Fjn80KSJMdxQhhYKAKWW1jXiFdrk8X7d6uGWdZFxg== - dependencies: - "@fastify/accept-negotiator" "^1.0.0" - "@fastify/send" "^2.0.0" - content-disposition "^0.5.3" - fastify-plugin "^4.0.0" - glob "^8.0.1" - p-limit "^3.1.0" + http-errors "^2.0.0" + mime "^3" -"@fastify/swagger-ui@^1.9.3": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@fastify/swagger-ui/-/swagger-ui-1.9.3.tgz#1ec03ea2595cb2e7d6de6ae7c949bebcff8370a5" - integrity sha512-YYqce4CydjDIEry6Zo4JLjVPe5rjS8iGnk3fHiIQnth9sFSLeyG0U1DCH+IyYmLddNDg1uWJOuErlVqnu/jI3w== +"@fastify/static@^8.0.0": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@fastify/static/-/static-8.0.1.tgz#137059a4625c64cce8ee7eb513961c5e23018805" + integrity sha512-7idyhbcgf14v4bjWzUeHEFvnVxvNJ1n5cyGPgFtwTZjnjUQ1wgC7a2FQai7OGKqCKywDEjzbPhAZRW+uEK1LMg== dependencies: - "@fastify/static" "^6.0.0" - fastify-plugin "^4.0.0" - openapi-types "^12.0.2" - rfdc "^1.3.0" - yaml "^2.2.2" + "@fastify/accept-negotiator" "^2.0.0" + "@fastify/send" "^3.1.0" + content-disposition "^0.5.4" + fastify-plugin "^5.0.0" + fastq "^1.17.1" + glob "^11.0.0" -"@fastify/swagger@^8.10.0": - version "8.10.0" - resolved "https://registry.yarnpkg.com/@fastify/swagger/-/swagger-8.10.0.tgz#d978ae9f2d802ab652955d02be7a125f7f6d9f05" - integrity sha512-0o6nd0qWpJbVSv/vbK4bzHSYe7l+PTGPqrQVwWIXVGd7CvXr585SBx+h8EgrMOY80bcOnGreqnjYFOV0osGP5A== +"@fastify/swagger-ui@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@fastify/swagger-ui/-/swagger-ui-5.0.1.tgz#76c348bbaf7e49e3cfb62ebe3cc3fb15ef0eefb3" + integrity sha512-nCDV5l0OTziK8nIeHaLZ30ENFFftZ4Pcs7GHDcqOO6Jp3qSnyOsqBg1/EosM+d1mrCvH4vSlM09xolkjrbuJQQ== dependencies: - fastify-plugin "^4.0.0" + "@fastify/static" "^8.0.0" + fastify-plugin "^5.0.0" + openapi-types "^12.1.3" + rfdc "^1.3.1" + yaml "^2.4.1" + +"@fastify/swagger@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@fastify/swagger/-/swagger-9.0.0.tgz#a6013ee3cf4ec0f2562e1455face9eb6ef787d89" + integrity sha512-E7TQbBCbhvS2djGLxJ7t2OFbhc2F+KCsOZCNhh6xQIlJxq9H4ZR5KuLKG+vn6COVqkLxRVUOZ9qtbbzdf5Jfqw== + dependencies: + fastify-plugin "^5.0.0" json-schema-resolver "^2.0.0" - openapi-types "^12.0.0" - rfdc "^1.3.0" - yaml "^2.2.2" + openapi-types "^12.1.3" + rfdc "^1.3.1" + yaml "^2.4.2" "@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3": version "1.1.3" @@ -1857,10 +1853,10 @@ race-signal "^1.0.2" 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== +"@lukeed/ms@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@lukeed/ms/-/ms-2.0.2.tgz#07f09e59a74c52f4d88c6db5c1054e819538e2a8" + integrity sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA== "@microsoft/api-extractor-model@7.28.13": version "7.28.13" @@ -3887,10 +3883,10 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv-formats@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" - integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== +ajv-formats@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-3.0.1.tgz#3d5dc762bca17679c3c2ea7e90ad6b7532309578" + integrity sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ== dependencies: ajv "^8.0.0" @@ -3904,7 +3900,7 @@ ajv@^6.12.4, ajv@~6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.10.0, ajv@^8.11.0, ajv@^8.12.0: +ajv@^8.0.0, ajv@^8.12.0: version "8.12.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== @@ -4060,11 +4056,6 @@ archiver@^7.0.0: tar-stream "^3.0.0" zip-stream "^6.0.1" -archy@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz" - integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= - are-we-there-yet@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz" @@ -4287,14 +4278,12 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -avvio@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/avvio/-/avvio-8.3.0.tgz#1e019433d935730b814978a583eefac41a65082f" - integrity sha512-VBVH0jubFr9LdFASy/vNtm5giTrnbVquWBhT0fyizuNK2rQ7e7ONU2plZQWUNqtE1EmxFEb+kbSkFRkstiaS9Q== +avvio@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/avvio/-/avvio-9.0.0.tgz#3ae02fb318377006e0e06a3f47842c98d8668607" + integrity sha512-UbYrOXgE/I+knFG+3kJr9AgC7uNo8DG+FGGODpH9Bj1O1kL/QDjBXnTem9leD3VdQKtaHjV3O85DQ7hHh4IIHw== dependencies: - "@fastify/error" "^3.3.0" - archy "^1.0.0" - debug "^4.0.0" + "@fastify/error" "^4.0.0" fastq "^1.17.1" aws-sdk@^2.932.0: @@ -5236,7 +5225,7 @@ constants-browserify@^1.0.0: resolved "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz" integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= -content-disposition@^0.5.3: +content-disposition@^0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== @@ -5558,7 +5547,7 @@ de-indent@^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: +debug@4, debug@4.3.4, 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" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -6568,11 +6557,6 @@ extract-zip@^2.0.1: optionalDependencies: "@types/yauzl" "^2.9.1" -fast-content-type-parse@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz#4087162bf5af3294d4726ff29b334f72e3a1092c" - integrity sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ== - fast-decode-uri-component@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz" @@ -6614,28 +6598,16 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-json-stringify@^5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-5.7.0.tgz#b0a04c848fdeb6ecd83440c71a4db35067023bed" - integrity sha512-sBVPTgnAZseLu1Qgj6lUbQ0HfjFhZWXAmpZ5AaSGkyLh5gAXBga/uPJjQPHpDFjC9adWIpdOcCLSDTgrZ7snoQ== - dependencies: - "@fastify/deepmerge" "^1.0.0" - ajv "^8.10.0" - ajv-formats "^2.1.1" - fast-deep-equal "^3.1.3" - fast-uri "^2.1.0" - rfdc "^1.2.0" - -fast-json-stringify@^5.8.0: - version "5.13.0" - resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-5.13.0.tgz#3eafc02168713ef934d75000a8cf749492729fe8" - integrity sha512-XjTDWKHP3GoMQUOfnjYUbqeHeEt+PvYgvBdG2fRSmYaORILbSr8xTJvZX+w1YSAP5pw2NwKrGRmQleYueZEoxw== +fast-json-stringify@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-6.0.0.tgz#15c5e85b567ead695773bf55938b56aaaa57d805" + integrity sha512-FGMKZwniMTgZh7zQp9b6XnBVxUmKVahQLQeRQHqwYmPDqDhcEKZ3BaQsxelFFI5PY7nN71OEeiL47/zUWcYe1A== dependencies: - "@fastify/merge-json-schemas" "^0.1.0" - ajv "^8.10.0" - ajv-formats "^2.1.1" + "@fastify/merge-json-schemas" "^0.1.1" + ajv "^8.12.0" + ajv-formats "^3.0.1" fast-deep-equal "^3.1.3" - fast-uri "^2.1.0" + fast-uri "^2.3.0" json-schema-ref-resolver "^1.0.1" rfdc "^1.2.0" @@ -6661,37 +6633,41 @@ fast-safe-stringify@^2.1.1: resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== -fast-uri@^2.0.0, fast-uri@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-2.2.0.tgz#519a0f849bef714aad10e9753d69d8f758f7445a" - integrity sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg== +fast-uri@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-2.4.0.tgz#67eae6fbbe9f25339d5d3f4c4234787b65d7d55e" + integrity sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA== -fastify-plugin@^4.0.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-4.5.0.tgz#8b853923a0bba6ab6921bb8f35b81224e6988d91" - integrity sha512-79ak0JxddO0utAXAQ5ccKhvs6vX2MGyHHMMsmZkBANrq3hXc1CHzvNPHOcvTsVMEPl5I+NT+RO4YKMGehOfSIg== +fast-uri@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== -fastify@^4.27.0: - version "4.27.0" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-4.27.0.tgz#e4a9b2a0a7b9efaeaf1140d47fdd4f91b5fcacb1" - integrity sha512-ci9IXzbigB8dyi0mSy3faa3Bsj0xWAPb9JeT4KRzubdSb6pNhcADRUaXCBml6V1Ss/a05kbtQls5LBmhHydoTA== +fastify-plugin@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-5.0.1.tgz#82d44e6fe34d1420bb5a4f7bee434d501e41939f" + integrity sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ== + +fastify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-5.0.0.tgz#f8f80bd741bde2de1997c25dbe31e61c91978111" + integrity sha512-Qe4dU+zGOzg7vXjw4EvcuyIbNnMwTmcuOhlOrOJsgwzvjEZmsM/IeHulgJk+r46STjdJS/ZJbxO8N70ODXDMEQ== dependencies: - "@fastify/ajv-compiler" "^3.5.0" - "@fastify/error" "^3.4.0" - "@fastify/fast-json-stringify-compiler" "^4.3.0" + "@fastify/ajv-compiler" "^4.0.0" + "@fastify/error" "^4.0.0" + "@fastify/fast-json-stringify-compiler" "^5.0.0" abstract-logging "^2.0.1" - avvio "^8.3.0" - fast-content-type-parse "^1.1.0" - fast-json-stringify "^5.8.0" - find-my-way "^8.0.0" - light-my-request "^5.11.0" + avvio "^9.0.0" + fast-json-stringify "^6.0.0" + find-my-way "^9.0.0" + light-my-request "^6.0.0" pino "^9.0.0" - process-warning "^3.0.0" + process-warning "^4.0.0" proxy-addr "^2.0.7" - rfdc "^1.3.0" + rfdc "^1.3.1" secure-json-parse "^2.7.0" - semver "^7.5.4" - toad-cache "^3.3.0" + semver "^7.6.0" + toad-cache "^3.7.0" fastq@^1.17.1: version "1.17.1" @@ -6782,14 +6758,14 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" -find-my-way@^8.0.0: - version "8.2.2" - resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-8.2.2.tgz#f3e78bc6ead2da4fdaa201335da3228600ed0285" - integrity sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA== +find-my-way@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-9.0.1.tgz#991c3a7af36734480d48cd4ad0889ed168ed6c40" + integrity sha512-/5NN/R0pFWuff16TMajeKt2JyiW+/OE8nOO8vo1DwZTxLaIURb7lcBYPIgRPh61yCNh9l8voeKwcrkUzmB00vw== dependencies: fast-deep-equal "^3.1.3" fast-querystring "^1.0.0" - safe-regex2 "^3.1.0" + safe-regex2 "^4.0.0" find-up@5.0.0, find-up@^5.0.0: version "5.0.0" @@ -7277,6 +7253,18 @@ glob@^10.4.1: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" +glob@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.0.tgz#6031df0d7b65eaa1ccb9b29b5ced16cea658e77e" + integrity sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^4.0.1" + minimatch "^10.0.0" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^2.0.0" + glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -7573,7 +7561,7 @@ http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^ resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -http-errors@2.0.0: +http-errors@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== @@ -8440,6 +8428,15 @@ jackspeak@^3.1.2: optionalDependencies: "@pkgjs/parseargs" "^0.11.0" +jackspeak@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.0.1.tgz#9fca4ce961af6083e259c376e9e3541431f5287b" + integrity sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jake@^10.8.5: version "10.8.5" resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.5.tgz#f2183d2c59382cb274226034543b9c03b8164c46" @@ -8829,14 +8826,14 @@ libp2p@1.4.3: multiformats "^13.1.0" uint8arrays "^5.0.3" -light-my-request@^5.11.0: - version "5.12.0" - resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-5.12.0.tgz#e42ed02ddbfa587f82031b21459c6841a6948dfa" - integrity sha512-P526OX6E7aeCIfw/9UyJNsAISfcFETghysaWHQAlQYayynShT08MOj4c6fBCvTWBrHXSvqBAKDp3amUPSCQI4w== +light-my-request@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-6.0.0.tgz#97c6d0d5448ea2fc37836f0aefe94298f5a87dde" + integrity sha512-kFkFXrmKCL0EEeOmJybMH5amWFd+AFvlvMlvFTRxCUwbhfapZqDmeLMPoWihntnYY6JpoQDE9k+vOzObF1fDqg== dependencies: cookie "^0.6.0" - process-warning "^3.0.0" - set-cookie-parser "^2.4.1" + process-warning "^4.0.0" + set-cookie-parser "^2.6.0" lines-and-columns@^1.1.6: version "1.2.4" @@ -9066,6 +9063,11 @@ lru-cache@^10.2.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== +lru-cache@^11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.0.1.tgz#3a732fbfedb82c5ba7bca6564ad3f42afcb6e147" + integrity sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -9320,7 +9322,7 @@ mime@2.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== -mime@^3.0.0: +mime@^3: version "3.0.0" resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== @@ -9386,6 +9388,13 @@ minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1: dependencies: brace-expansion "^2.0.1" +minimatch@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" + integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -9568,10 +9577,10 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mnemonist@0.39.5: - version "0.39.5" - resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.39.5.tgz#5850d9b30d1b2bc57cc8787e5caa40f6c3420477" - integrity sha512-FPUtkhtJ0efmEFGpU14x7jGbTB+s18LrzRL2KgoWz9YvcY3cPomz8tih01GbHwnGk/OmkOKfqd/RAQoc8Lm7DQ== +mnemonist@0.39.8: + version "0.39.8" + resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.39.8.tgz#9078cd8386081afd986cca34b52b5d84ea7a4d38" + integrity sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ== dependencies: obliterator "^2.0.1" @@ -10276,7 +10285,7 @@ open@^8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" -openapi-types@^12.0.0, openapi-types@^12.0.2: +openapi-types@^12.1.3: version "12.1.3" resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-12.1.3.tgz#471995eb26c4b97b7bd356aacf7b91b73e777dd3" integrity sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw== @@ -10372,7 +10381,7 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2, p-limit@^3.1.0: +p-limit@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -10660,6 +10669,14 @@ path-scurry@^1.11.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" +path-scurry@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.0.tgz#9f052289f23ad8bf9397a2a0425e7b8615c58580" + integrity sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg== + dependencies: + lru-cache "^11.0.0" + minipass "^7.1.2" + path-to-regexp@^6.2.0: version "6.3.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.3.0.tgz#2b6a26a337737a8e1416f9272ed0766b1c0389f4" @@ -10846,6 +10863,11 @@ process-warning@^3.0.0: resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-3.0.0.tgz#96e5b88884187a1dce6f5c3166d611132058710b" integrity sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ== +process-warning@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-4.0.0.tgz#581e3a7a1fb456c5f4fd239f76bce75897682d5a" + integrity sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw== + process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" @@ -11358,10 +11380,10 @@ restore-cursor@^4.0.0: onetime "^5.1.0" signal-exit "^3.0.2" -ret@~0.4.0: - version "0.4.3" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.4.3.tgz#5243fa30e704a2e78a9b9b1e86079e15891aa85c" - integrity sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ== +ret@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.5.0.tgz#30a4d38a7e704bd96dc5ffcbe7ce2a9274c41c95" + integrity sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw== retry@^0.12.0: version "0.12.0" @@ -11387,10 +11409,10 @@ rewiremock@^3.14.5: wipe-node-cache "^2.1.2" wipe-webpack-cache "^2.1.0" -rfdc@^1.1.4, rfdc@^1.2.0, rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== +rfdc@^1.1.4, rfdc@^1.2.0, rfdc@^1.3.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== rgb2hex@0.2.5: version "0.2.5" @@ -11550,12 +11572,12 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -safe-regex2@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-3.1.0.tgz#fd7ec23908e2c730e1ce7359a5b72883a87d2763" - integrity sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug== +safe-regex2@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-4.0.0.tgz#5e04d8362cd4884753c8bce9715d4759a5239c0a" + integrity sha512-Hvjfv25jPDVr3U+4LDzBuZPPOymELG3PYcSk5hcevooo1yxxamQL/bHs/GrEPGmMoMEwRrHVGiCA1pXi97B8Ew== dependencies: - ret "~0.4.0" + ret "~0.5.0" safe-stable-stringify@^2.3.1: version "2.4.2" @@ -11654,10 +11676,10 @@ set-blocking@^2.0.0: resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -set-cookie-parser@^2.4.1: - version "2.4.8" - resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz" - integrity sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg== +set-cookie-parser@^2.6.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz#ef5552b56dc01baae102acb5fc9fb8cd060c30f9" + integrity sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ== set-function-length@^1.1.1: version "1.2.0" @@ -12529,7 +12551,7 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -toad-cache@^3.3.0: +toad-cache@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/toad-cache/-/toad-cache-3.7.0.tgz#b9b63304ea7c45ec34d91f1d2fa513517025c441" integrity sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw== @@ -13843,10 +13865,10 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^2.2.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144" - integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg== +yaml@^2.2.2, yaml@^2.4.1, yaml@^2.4.2: + version "2.5.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130" + integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q== yargs-parser@20.2.4: version "20.2.4" From ad4ec7713d0ab39c54ea1ffa28d6f6f997769fa0 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:33:43 -0700 Subject: [PATCH 114/259] feat: move requests from execution payload to beacon block body (#7094) * Move requests from payload to block body * Lint * Add execution requests to engine api * Remove engine_getPayloadBodies*V2 * Update spec test version * Lint * Fix unit test and polish * Remove todo --- .../blocks/verifyBlocksExecutionPayloads.ts | 7 +- .../chain/produceBlock/produceBlockBody.ts | 10 +- .../beacon-node/src/execution/engine/http.ts | 41 ++++-- .../src/execution/engine/interface.ts | 10 +- .../beacon-node/src/execution/engine/mock.ts | 2 - .../src/execution/engine/payloadIdCache.ts | 20 --- .../beacon-node/src/execution/engine/types.ts | 135 ++++++++---------- .../test/sim/electra-interop.test.ts | 8 +- .../test/spec/specTestVersioning.ts | 2 +- .../test/spec/utils/specTestIterator.ts | 2 + .../upgradeLightClientHeader.test.ts | 2 +- .../test/unit/executionEngine/http.test.ts | 12 -- packages/light-client/src/spec/utils.ts | 17 +-- .../src/block/processOperations.ts | 6 +- .../src/slot/upgradeStateToElectra.ts | 9 +- .../state-transition/src/util/execution.ts | 10 +- packages/types/src/electra/sszTypes.ts | 66 +++------ packages/types/src/electra/types.ts | 6 +- packages/types/src/types.ts | 18 ++- packages/types/src/utils/typeguards.ts | 6 +- 20 files changed, 160 insertions(+), 229 deletions(-) diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts index 284d4c0976ee..e641ff9ae6d9 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts @@ -5,7 +5,7 @@ import { isMergeTransitionBlock as isMergeTransitionBlockFn, isExecutionEnabled, } from "@lodestar/state-transition"; -import {bellatrix, Slot, deneb, SignedBeaconBlock} from "@lodestar/types"; +import {bellatrix, Slot, deneb, SignedBeaconBlock, electra} from "@lodestar/types"; import { IForkChoice, assertValidTerminalPowBlock, @@ -302,6 +302,8 @@ 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 executionRequests = + ForkSeq[fork] >= ForkSeq.electra ? (block.message.body as electra.BeaconBlockBody).executionRequests : undefined; const logCtx = {slot: block.message.slot, executionBlock: executionPayloadEnabled.blockNumber}; chain.logger.debug("Call engine api newPayload", logCtx); @@ -309,7 +311,8 @@ export async function verifyBlockExecutionPayload( fork, executionPayloadEnabled, versionedHashes, - parentBlockRoot + parentBlockRoot, + executionRequests ); chain.logger.debug("Receive engine api newPayload result", {...logCtx, status: execResult.status}); diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index ba560d5a7ff0..ff8221a326e9 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -17,6 +17,7 @@ import { BlindedBeaconBlockBody, BlindedBeaconBlock, sszTypesFor, + electra, } from "@lodestar/types"; import { CachedBeaconStateAllForks, @@ -258,7 +259,7 @@ export async function produceBlockBody( } const engineRes = await this.executionEngine.getPayload(fork, payloadId); - const {executionPayload, blobsBundle} = engineRes; + const {executionPayload, blobsBundle, executionRequests} = engineRes; shouldOverrideBuilder = engineRes.shouldOverrideBuilder; (blockBody as BeaconBlockBody).executionPayload = executionPayload; @@ -298,6 +299,13 @@ export async function produceBlockBody( } else { blobsResult = {type: BlobsResultType.preDeneb}; } + + if (ForkSeq[fork] >= ForkSeq.electra) { + if (executionRequests === undefined) { + throw Error(`Missing executionRequests response from getPayload at fork=${fork}`); + } + (blockBody as electra.BeaconBlockBody).executionRequests = executionRequests; + } } } catch (e) { this.metrics?.blockPayload.payloadFetchErrors.inc(); diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index a69a5b94bd65..b42424b28998 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -1,4 +1,4 @@ -import {ExecutionPayload, Root, RootHex, Wei} from "@lodestar/types"; +import {ExecutionPayload, ExecutionRequests, Root, RootHex, Wei} from "@lodestar/types"; import {SLOTS_PER_EPOCH, ForkName, ForkSeq} from "@lodestar/params"; import {Logger} from "@lodestar/logger"; import { @@ -37,6 +37,7 @@ import { ExecutionPayloadBody, assertReqSizeLimit, deserializeExecutionPayloadBody, + serializeExecutionRequests, } from "./types.js"; import {getExecutionEngineState} from "./utils.js"; @@ -195,7 +196,8 @@ export class ExecutionEngineHttp implements IExecutionEngine { fork: ForkName, executionPayload: ExecutionPayload, versionedHashes?: VersionedHashes, - parentBlockRoot?: Root + parentBlockRoot?: Root, + executionRequests?: ExecutionRequests ): Promise { const method = ForkSeq[fork] >= ForkSeq.electra @@ -220,12 +222,28 @@ export class ExecutionEngineHttp implements IExecutionEngine { const serializedVersionedHashes = serializeVersionedHashes(versionedHashes); const parentBeaconBlockRoot = serializeBeaconBlockRoot(parentBlockRoot); - const method = ForkSeq[fork] >= ForkSeq.electra ? "engine_newPayloadV4" : "engine_newPayloadV3"; - engineRequest = { - method, - params: [serializedExecutionPayload, serializedVersionedHashes, parentBeaconBlockRoot], - methodOpts: notifyNewPayloadOpts, - }; + if (ForkSeq[fork] >= ForkSeq.electra) { + if (executionRequests === undefined) { + throw Error(`executionRequests required in notifyNewPayload for fork=${fork}`); + } + const serializedExecutionRequests = serializeExecutionRequests(executionRequests); + engineRequest = { + method: "engine_newPayloadV4", + params: [ + serializedExecutionPayload, + serializedVersionedHashes, + parentBeaconBlockRoot, + serializedExecutionRequests, + ], + methodOpts: notifyNewPayloadOpts, + }; + } else { + engineRequest = { + method: "engine_newPayloadV3", + params: [serializedExecutionPayload, serializedVersionedHashes, parentBeaconBlockRoot], + methodOpts: notifyNewPayloadOpts, + }; + } } else { const method = ForkSeq[fork] >= ForkSeq.capella ? "engine_newPayloadV2" : "engine_newPayloadV1"; engineRequest = { @@ -391,6 +409,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { executionPayload: ExecutionPayload; executionPayloadValue: Wei; blobsBundle?: BlobsBundle; + executionRequests?: ExecutionRequests; shouldOverrideBuilder?: boolean; }> { const method = @@ -419,8 +438,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { } async getPayloadBodiesByHash(fork: ForkName, blockHashes: RootHex[]): Promise<(ExecutionPayloadBody | null)[]> { - const method = - ForkSeq[fork] >= ForkSeq.electra ? "engine_getPayloadBodiesByHashV2" : "engine_getPayloadBodiesByHashV1"; + const method = "engine_getPayloadBodiesByHashV1"; assertReqSizeLimit(blockHashes.length, 32); const response = await this.rpc.fetchWithRetries< EngineApiRpcReturnTypes[typeof method], @@ -434,8 +452,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { startBlockNumber: number, blockCount: number ): Promise<(ExecutionPayloadBody | null)[]> { - const method = - ForkSeq[fork] >= ForkSeq.electra ? "engine_getPayloadBodiesByRangeV2" : "engine_getPayloadBodiesByRangeV1"; + const method = "engine_getPayloadBodiesByRangeV1"; assertReqSizeLimit(blockCount, 32); const start = numToQuantity(startBlockNumber); const count = numToQuantity(blockCount); diff --git a/packages/beacon-node/src/execution/engine/interface.ts b/packages/beacon-node/src/execution/engine/interface.ts index 5226a46ac720..e6f9cfee526b 100644 --- a/packages/beacon-node/src/execution/engine/interface.ts +++ b/packages/beacon-node/src/execution/engine/interface.ts @@ -1,12 +1,12 @@ import {ForkName} from "@lodestar/params"; import {KZGCommitment, Blob, KZGProof} from "@lodestar/types/deneb"; -import {Root, RootHex, capella, Wei, ExecutionPayload} from "@lodestar/types"; +import {Root, RootHex, capella, Wei, ExecutionPayload, ExecutionRequests} from "@lodestar/types"; import {DATA} from "../../eth1/provider/utils.js"; -import {PayloadIdCache, PayloadId, WithdrawalV1, DepositRequestV1} from "./payloadIdCache.js"; +import {PayloadIdCache, PayloadId, WithdrawalV1} from "./payloadIdCache.js"; import {ExecutionPayloadBody} from "./types.js"; -export {PayloadIdCache, type PayloadId, type WithdrawalV1, type DepositRequestV1}; +export {PayloadIdCache, type PayloadId, type WithdrawalV1}; export enum ExecutionPayloadStatus { /** given payload is valid */ @@ -134,7 +134,8 @@ export interface IExecutionEngine { fork: ForkName, executionPayload: ExecutionPayload, versionedHashes?: VersionedHashes, - parentBeaconBlockRoot?: Root + parentBeaconBlockRoot?: Root, + executionRequests?: ExecutionRequests ): Promise; /** @@ -171,6 +172,7 @@ export interface IExecutionEngine { executionPayload: ExecutionPayload; executionPayloadValue: Wei; blobsBundle?: BlobsBundle; + executionRequests?: ExecutionRequests; shouldOverrideBuilder?: boolean; }>; diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index 9fed781fa523..4cff2a8d00f4 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -98,10 +98,8 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { engine_getPayloadV3: this.getPayload.bind(this), engine_getPayloadV4: this.getPayload.bind(this), engine_getPayloadBodiesByHashV1: this.getPayloadBodiesByHash.bind(this), - engine_getPayloadBodiesByHashV2: this.getPayloadBodiesByHash.bind(this), engine_getPayloadBodiesByRangeV1: this.getPayloadBodiesByRange.bind(this), engine_getClientVersionV1: this.getClientVersionV1.bind(this), - engine_getPayloadBodiesByRangeV2: this.getPayloadBodiesByRange.bind(this), }; } diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index 005a1ef14322..ea37e0922e9c 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -18,26 +18,6 @@ export type WithdrawalV1 = { amount: QUANTITY; }; -export type DepositRequestV1 = { - pubkey: DATA; - withdrawalCredentials: DATA; - amount: QUANTITY; - signature: DATA; - index: QUANTITY; -}; - -export type WithdrawalRequestV1 = { - sourceAddress: DATA; - validatorPubkey: DATA; - amount: QUANTITY; -}; - -export type ConsolidationRequestV1 = { - sourceAddress: DATA; - sourcePubkey: DATA; - targetPubkey: DATA; -}; - type FcuAttributes = {headBlockHash: DATA; finalizedBlockHash: DATA} & Omit; export class PayloadIdCache { diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 139fc6822780..32fe4cb79d3d 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -1,4 +1,4 @@ -import {capella, deneb, electra, Wei, bellatrix, Root, ExecutionPayload} from "@lodestar/types"; +import {capella, deneb, electra, Wei, bellatrix, Root, ExecutionPayload, ExecutionRequests} from "@lodestar/types"; import { BYTES_PER_LOGS_BLOOM, FIELD_ELEMENTS_PER_BLOB, @@ -17,7 +17,7 @@ import { quantityToBigint, } from "../../eth1/provider/utils.js"; import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js"; -import {WithdrawalV1, DepositRequestV1, WithdrawalRequestV1, ConsolidationRequestV1} from "./payloadIdCache.js"; +import {WithdrawalV1} from "./payloadIdCache.js"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -28,7 +28,7 @@ export type EngineApiRpcParamTypes = { engine_newPayloadV1: [ExecutionPayloadRpc]; engine_newPayloadV2: [ExecutionPayloadRpc]; engine_newPayloadV3: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; - engine_newPayloadV4: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; + engine_newPayloadV4: [ExecutionPayloadRpc, VersionedHashesRpc, DATA, ExecutionRequestsRpc]; /** * 1. Object - Payload validity status with respect to the consensus rules: * - blockHash: DATA, 32 Bytes - block hash value of the payload @@ -58,7 +58,6 @@ export type EngineApiRpcParamTypes = { * 1. Array of DATA - Array of block_hash field values of the ExecutionPayload structure * */ engine_getPayloadBodiesByHashV1: DATA[][]; - engine_getPayloadBodiesByHashV2: DATA[][]; /** * 1. start: QUANTITY, 64 bits - Starting block number @@ -70,7 +69,6 @@ export type EngineApiRpcParamTypes = { * Object - Instance of ClientVersion */ engine_getClientVersionV1: [ClientVersionRpc]; - engine_getPayloadBodiesByRangeV2: [start: QUANTITY, count: QUANTITY]; }; export type PayloadStatus = { @@ -109,12 +107,10 @@ export type EngineApiRpcReturnTypes = { engine_getPayloadV4: ExecutionPayloadResponse; engine_getPayloadBodiesByHashV1: (ExecutionPayloadBodyRpc | null)[]; - engine_getPayloadBodiesByHashV2: (ExecutionPayloadBodyRpc | null)[]; engine_getPayloadBodiesByRangeV1: (ExecutionPayloadBodyRpc | null)[]; engine_getClientVersionV1: ClientVersionRpc[]; - engine_getPayloadBodiesByRangeV2: (ExecutionPayloadBodyRpc | null)[]; }; type ExecutionPayloadRpcWithValue = { @@ -122,6 +118,7 @@ type ExecutionPayloadRpcWithValue = { // even though CL tracks this as executionPayloadValue, EL returns this as blockValue blockValue: QUANTITY; blobsBundle?: BlobsBundleRpc; + requests?: ExecutionRequestsRpc; shouldOverrideBuilder?: boolean; }; type ExecutionPayloadResponse = ExecutionPayloadRpc | ExecutionPayloadRpcWithValue; @@ -129,19 +126,11 @@ type ExecutionPayloadResponse = ExecutionPayloadRpc | ExecutionPayloadRpcWithVal export type ExecutionPayloadBodyRpc = { transactions: DATA[]; withdrawals: WithdrawalV1[] | null | undefined; - // currently there is a discepancy between EL and CL field name references for deposit requests - // its likely CL receipt will be renamed to requests - depositRequests: DepositRequestV1[] | null | undefined; - withdrawalRequests: WithdrawalRequestV1[] | null | undefined; - consolidationRequests: ConsolidationRequestV1[] | null | undefined; }; export type ExecutionPayloadBody = { transactions: bellatrix.Transaction[]; withdrawals: capella.Withdrawals | null; - depositRequests: electra.DepositRequests | null; - withdrawalRequests: electra.WithdrawalRequests | null; - consolidationRequests: electra.ConsolidationRequests | null; }; export type ExecutionPayloadRpc = { @@ -163,9 +152,6 @@ export type ExecutionPayloadRpc = { blobGasUsed?: QUANTITY; // DENEB excessBlobGas?: QUANTITY; // DENEB parentBeaconBlockRoot?: QUANTITY; // DENEB - depositRequests?: DepositRequestRpc[]; // ELECTRA - withdrawalRequests?: WithdrawalRequestRpc[]; // ELECTRA - consolidationRequests?: ConsolidationRequestRpc[]; // ELECTRA }; export type WithdrawalRpc = { @@ -175,9 +161,29 @@ export type WithdrawalRpc = { amount: QUANTITY; }; -export type DepositRequestRpc = DepositRequestV1; -export type WithdrawalRequestRpc = WithdrawalRequestV1; -export type ConsolidationRequestRpc = ConsolidationRequestV1; +export type ExecutionRequestsRpc = { + deposits: DepositRequestRpc[]; + withdrawals: WithdrawalRequestRpc[]; + consolidations: ConsolidationRequestRpc[]; +}; + +export type DepositRequestRpc = { + pubkey: DATA; + withdrawalCredentials: DATA; + amount: QUANTITY; + signature: DATA; + index: QUANTITY; +}; +export type WithdrawalRequestRpc = { + sourceAddress: DATA; + validatorPubkey: DATA; + amount: QUANTITY; +}; +export type ConsolidationRequestRpc = { + sourceAddress: DATA; + sourcePubkey: DATA; + targetPubkey: DATA; +}; export type VersionedHashesRpc = DATA[]; @@ -241,13 +247,7 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload payload.excessBlobGas = numToQuantity(excessBlobGas); } - // ELECTRA adds depositRequests/depositRequests to the ExecutionPayload - if (ForkSeq[fork] >= ForkSeq.electra) { - const {depositRequests, withdrawalRequests, consolidationRequests} = data as electra.ExecutionPayload; - payload.depositRequests = depositRequests.map(serializeDepositRequest); - payload.withdrawalRequests = withdrawalRequests.map(serializeWithdrawalRequest); - payload.consolidationRequests = consolidationRequests.map(serializeConsolidationRequest); - } + // No changes in Electra return payload; } @@ -267,23 +267,27 @@ export function parseExecutionPayload( executionPayload: ExecutionPayload; executionPayloadValue: Wei; blobsBundle?: BlobsBundle; + executionRequests?: ExecutionRequests; shouldOverrideBuilder?: boolean; } { let data: ExecutionPayloadRpc; let executionPayloadValue: Wei; let blobsBundle: BlobsBundle | undefined; + let executionRequests: ExecutionRequests | undefined; let shouldOverrideBuilder: boolean; if (hasPayloadValue(response)) { executionPayloadValue = quantityToBigint(response.blockValue); data = response.executionPayload; blobsBundle = response.blobsBundle ? parseBlobsBundle(response.blobsBundle) : undefined; + executionRequests = response.requests ? deserializeExecutionRequests(response.requests) : undefined; shouldOverrideBuilder = response.shouldOverrideBuilder ?? false; } else { data = response; // Just set it to zero as default executionPayloadValue = BigInt(0); blobsBundle = undefined; + executionRequests = undefined; shouldOverrideBuilder = false; } @@ -334,36 +338,9 @@ export function parseExecutionPayload( (executionPayload as deneb.ExecutionPayload).excessBlobGas = quantityToBigint(excessBlobGas); } - if (ForkSeq[fork] >= ForkSeq.electra) { - // electra adds depositRequests/depositRequests - const {depositRequests, withdrawalRequests, consolidationRequests} = data; - // Geth can also reply with null - if (depositRequests == null) { - throw Error( - `depositRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` - ); - } - (executionPayload as electra.ExecutionPayload).depositRequests = depositRequests.map(deserializeDepositRequest); - - if (withdrawalRequests == null) { - throw Error( - `withdrawalRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` - ); - } - (executionPayload as electra.ExecutionPayload).withdrawalRequests = - withdrawalRequests.map(deserializeWithdrawalRequest); - - if (consolidationRequests == null) { - throw Error( - `consolidationRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` - ); - } - (executionPayload as electra.ExecutionPayload).consolidationRequests = consolidationRequests.map( - deserializeConsolidationRequest - ); - } + // No changes in Electra - return {executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder}; + return {executionPayload, executionPayloadValue, blobsBundle, executionRequests, shouldOverrideBuilder}; } export function serializePayloadAttributes(data: PayloadAttributes): PayloadAttributesRpc { @@ -429,7 +406,7 @@ export function deserializeWithdrawal(serialized: WithdrawalRpc): capella.Withdr } as capella.Withdrawal; } -export function serializeDepositRequest(depositRequest: electra.DepositRequest): DepositRequestRpc { +function serializeDepositRequest(depositRequest: electra.DepositRequest): DepositRequestRpc { return { pubkey: bytesToData(depositRequest.pubkey), withdrawalCredentials: bytesToData(depositRequest.withdrawalCredentials), @@ -439,7 +416,7 @@ export function serializeDepositRequest(depositRequest: electra.DepositRequest): }; } -export function deserializeDepositRequest(serialized: DepositRequestRpc): electra.DepositRequest { +function deserializeDepositRequest(serialized: DepositRequestRpc): electra.DepositRequest { return { pubkey: dataToBytes(serialized.pubkey, 48), withdrawalCredentials: dataToBytes(serialized.withdrawalCredentials, 32), @@ -449,7 +426,7 @@ export function deserializeDepositRequest(serialized: DepositRequestRpc): electr } as electra.DepositRequest; } -export function serializeWithdrawalRequest(withdrawalRequest: electra.WithdrawalRequest): WithdrawalRequestRpc { +function serializeWithdrawalRequest(withdrawalRequest: electra.WithdrawalRequest): WithdrawalRequestRpc { return { sourceAddress: bytesToData(withdrawalRequest.sourceAddress), validatorPubkey: bytesToData(withdrawalRequest.validatorPubkey), @@ -457,7 +434,7 @@ export function serializeWithdrawalRequest(withdrawalRequest: electra.Withdrawal }; } -export function deserializeWithdrawalRequest(withdrawalRequest: WithdrawalRequestRpc): electra.WithdrawalRequest { +function deserializeWithdrawalRequest(withdrawalRequest: WithdrawalRequestRpc): electra.WithdrawalRequest { return { sourceAddress: dataToBytes(withdrawalRequest.sourceAddress, 20), validatorPubkey: dataToBytes(withdrawalRequest.validatorPubkey, 48), @@ -465,9 +442,7 @@ export function deserializeWithdrawalRequest(withdrawalRequest: WithdrawalReques }; } -export function serializeConsolidationRequest( - consolidationRequest: electra.ConsolidationRequest -): ConsolidationRequestRpc { +function serializeConsolidationRequest(consolidationRequest: electra.ConsolidationRequest): ConsolidationRequestRpc { return { sourceAddress: bytesToData(consolidationRequest.sourceAddress), sourcePubkey: bytesToData(consolidationRequest.sourcePubkey), @@ -475,9 +450,7 @@ export function serializeConsolidationRequest( }; } -export function deserializeConsolidationRequest( - consolidationRequest: ConsolidationRequestRpc -): electra.ConsolidationRequest { +function deserializeConsolidationRequest(consolidationRequest: ConsolidationRequestRpc): electra.ConsolidationRequest { return { sourceAddress: dataToBytes(consolidationRequest.sourceAddress, 20), sourcePubkey: dataToBytes(consolidationRequest.sourcePubkey, 48), @@ -485,16 +458,29 @@ export function deserializeConsolidationRequest( }; } +export function serializeExecutionRequests(executionRequests: ExecutionRequests): ExecutionRequestsRpc { + const {deposits, withdrawals, consolidations} = executionRequests; + return { + deposits: deposits.map(serializeDepositRequest), + withdrawals: withdrawals.map(serializeWithdrawalRequest), + consolidations: consolidations.map(serializeConsolidationRequest), + }; +} + +export function deserializeExecutionRequests(executionRequests: ExecutionRequestsRpc): ExecutionRequests { + const {deposits, withdrawals, consolidations} = executionRequests; + return { + deposits: deposits.map(deserializeDepositRequest), + withdrawals: withdrawals.map(deserializeWithdrawalRequest), + consolidations: consolidations.map(deserializeConsolidationRequest), + }; +} + export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | null): ExecutionPayloadBody | null { return data ? { transactions: data.transactions.map((tran) => dataToBytes(tran, null)), withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null, - depositRequests: data.depositRequests ? data.depositRequests.map(deserializeDepositRequest) : null, - withdrawalRequests: data.withdrawalRequests ? data.withdrawalRequests.map(deserializeWithdrawalRequest) : null, - consolidationRequests: data.consolidationRequests - ? data.consolidationRequests.map(deserializeConsolidationRequest) - : null, } : null; } @@ -504,11 +490,6 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null) ? { transactions: data.transactions.map((tran) => bytesToData(tran)), withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null, - depositRequests: data.depositRequests ? data.depositRequests.map(serializeDepositRequest) : null, - withdrawalRequests: data.withdrawalRequests ? data.withdrawalRequests.map(serializeWithdrawalRequest) : null, - consolidationRequests: data.consolidationRequests - ? data.consolidationRequests.map(serializeConsolidationRequest) - : null, } : null; } diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index d0c00e75fd59..2d08428df558 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -171,7 +171,6 @@ describe("executionEngine / ExecutionEngineHttp", function () { blockHash: dataToBytes(newPayloadBlockHash, 32), receiptsRoot: dataToBytes("0x0b67bea29f17eeb290685e01e9a2e4cd77a83471d9985a8ce27997a7ed3ee3f8", 32), blobGasUsed: 0n, - withdrawalRequests: [], }; const parentBeaconBlockRoot = dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32); const payloadResult = await executionEngine.notifyNewPayload( @@ -208,6 +207,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { await sleep(1000); const payloadAndBlockValue = await executionEngine.getPayload(ForkName.electra, payloadId2); const payload = payloadAndBlockValue.executionPayload as electra.ExecutionPayload; + const depositRequests = payloadAndBlockValue.executionRequests?.deposits; if (payload.transactions.length !== 1) { throw Error(`Number of transactions mismatched. Expected: 1, actual: ${payload.transactions.length}`); @@ -219,11 +219,11 @@ describe("executionEngine / ExecutionEngineHttp", function () { } } - if (payload.depositRequests.length !== 1) { - throw Error(`Number of depositRequests mismatched. Expected: 1, actual: ${payload.depositRequests.length}`); + if (depositRequests === undefined || depositRequests.length !== 1) { + throw Error(`Number of depositRequests mismatched. Expected: 1, actual: ${depositRequests?.length}`); } - const actualDepositRequest = payload.depositRequests[0]; + const actualDepositRequest = depositRequests[0]; assert.deepStrictEqual( actualDepositRequest, depositRequestB, diff --git a/packages/beacon-node/test/spec/specTestVersioning.ts b/packages/beacon-node/test/spec/specTestVersioning.ts index 7229a0236d84..d4bc192f6cad 100644 --- a/packages/beacon-node/test/spec/specTestVersioning.ts +++ b/packages/beacon-node/test/spec/specTestVersioning.ts @@ -15,7 +15,7 @@ import {DownloadTestsOptions} from "@lodestar/spec-test-util/downloadTests"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const ethereumConsensusSpecsTests: DownloadTestsOptions = { - specVersion: "v1.5.0-alpha.5", + specVersion: "v1.5.0-alpha.6", // Target directory is the host package root: 'packages/*/spec-tests' outputDir: path.join(__dirname, "../../spec-tests"), specTestsRepoUrl: "https://github.com/ethereum/consensus-spec-tests", diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index d8b4f9c0574c..bd5142627e3f 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -66,6 +66,8 @@ export const defaultSkipOpts: SkipOpts = { /^capella\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, /^deneb\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, /^electra\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, + // TODO Electra: slashings tests to be enabled in PR#7071 + /^electra\/epoch_processing\/slashings.*/, ], skippedTests: [], skippedRunners: ["merkle_proof", "networking"], diff --git a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts index abb520bddafb..6da728be46e9 100644 --- a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts +++ b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts @@ -28,7 +28,7 @@ describe("UpgradeLightClientHeader", function () { capella: ssz.capella.LightClientHeader.defaultValue(), bellatrix: ssz.altair.LightClientHeader.defaultValue(), deneb: ssz.deneb.LightClientHeader.defaultValue(), - electra: ssz.electra.LightClientHeader.defaultValue(), + electra: ssz.deneb.LightClientHeader.defaultValue(), }; testSlots = { diff --git a/packages/beacon-node/test/unit/executionEngine/http.test.ts b/packages/beacon-node/test/unit/executionEngine/http.test.ts index 5ac4fd4ca670..c9f4ae671e53 100644 --- a/packages/beacon-node/test/unit/executionEngine/http.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/http.test.ts @@ -193,9 +193,6 @@ describe("ExecutionEngine / http", () => { amount: "0x7b", }, ], - depositRequests: null, // depositRequests is null pre-electra - withdrawalRequests: null, - consolidationRequests: null, }, null, // null returned for missing blocks { @@ -204,9 +201,6 @@ describe("ExecutionEngine / http", () => { "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", ], withdrawals: null, // withdrawals is null pre-capella - depositRequests: null, // depositRequests is null pre-electra - withdrawalRequests: null, - consolidationRequests: null, }, ], }; @@ -254,9 +248,6 @@ describe("ExecutionEngine / http", () => { amount: "0x7b", }, ], - depositRequests: null, // depositRequests is null pre-electra - withdrawalRequests: null, - consolidationRequests: null, }, null, // null returned for missing blocks { @@ -265,9 +256,6 @@ describe("ExecutionEngine / http", () => { "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", ], withdrawals: null, // withdrawals is null pre-capella - depositRequests: null, // depositRequests is null pre-electra - withdrawalRequests: null, - consolidationRequests: null, }, ], }; diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 872aa5d9f910..408412464606 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -128,12 +128,7 @@ export function upgradeLightClientHeader( // eslint-disable-next-line no-fallthrough case ForkName.electra: - (upgradedHeader as LightClientHeader).execution.depositRequestsRoot = - ssz.electra.LightClientHeader.fields.execution.fields.depositRequestsRoot.defaultValue(); - (upgradedHeader as LightClientHeader).execution.withdrawalRequestsRoot = - ssz.electra.LightClientHeader.fields.execution.fields.withdrawalRequestsRoot.defaultValue(); - (upgradedHeader as LightClientHeader).execution.consolidationRequestsRoot = - ssz.electra.LightClientHeader.fields.execution.fields.consolidationRequestsRoot.defaultValue(); + // No changes to LightClientHeader in Electra // Break if no further upgrades is required else fall through if (ForkSeq[targetFork] <= ForkSeq.electra) break; @@ -170,16 +165,6 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: LightC } } - if (epoch < config.ELECTRA_FORK_EPOCH) { - if ( - (header as LightClientHeader).execution.depositRequestsRoot !== undefined || - (header as LightClientHeader).execution.withdrawalRequestsRoot !== undefined || - (header as LightClientHeader).execution.consolidationRequestsRoot !== undefined - ) { - return false; - } - } - return isValidMerkleBranch( config .getExecutionForkTypes(header.beacon.slot) diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index 6f61e7c242fb..bb52af14ba32 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -67,15 +67,15 @@ export function processOperations( const stateElectra = state as CachedBeaconStateElectra; const bodyElectra = body as electra.BeaconBlockBody; - for (const depositRequest of bodyElectra.executionPayload.depositRequests) { + for (const depositRequest of bodyElectra.executionRequests.deposits) { processDepositRequest(fork, stateElectra, depositRequest); } - for (const elWithdrawalRequest of bodyElectra.executionPayload.withdrawalRequests) { + for (const elWithdrawalRequest of bodyElectra.executionRequests.withdrawals) { processWithdrawalRequest(fork, stateElectra, elWithdrawalRequest); } - for (const elConsolidationRequest of bodyElectra.executionPayload.consolidationRequests) { + for (const elConsolidationRequest of bodyElectra.executionRequests.consolidations) { processConsolidationRequest(stateElectra, elConsolidationRequest); } } diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 6600ad98e80a..0bd36a909b46 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -48,17 +48,11 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache stateElectraView.inactivityScores = stateElectraCloned.inactivityScores; stateElectraView.currentSyncCommittee = stateElectraCloned.currentSyncCommittee; stateElectraView.nextSyncCommittee = stateElectraCloned.nextSyncCommittee; - stateElectraView.latestExecutionPayloadHeader = ssz.electra.BeaconState.fields.latestExecutionPayloadHeader.toViewDU({ - ...stateElectraCloned.latestExecutionPayloadHeader.toValue(), - depositRequestsRoot: ssz.Root.defaultValue(), - withdrawalRequestsRoot: ssz.Root.defaultValue(), - consolidationRequestsRoot: ssz.Root.defaultValue(), - }); + stateElectraView.latestExecutionPayloadHeader = stateElectraCloned.latestExecutionPayloadHeader; stateElectraView.nextWithdrawalIndex = stateDeneb.nextWithdrawalIndex; stateElectraView.nextWithdrawalValidatorIndex = stateDeneb.nextWithdrawalValidatorIndex; stateElectraView.historicalSummaries = stateElectraCloned.historicalSummaries; - // latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default // default value of depositRequestsStartIndex is UNSET_DEPOSIT_REQUESTS_START_INDEX stateElectraView.depositRequestsStartIndex = UNSET_DEPOSIT_REQUESTS_START_INDEX; stateElectraView.depositBalanceToConsume = BigInt(0); @@ -137,7 +131,6 @@ export function upgradeStateToElectraOriginal(stateDeneb: CachedBeaconStateDeneb epoch: stateDeneb.epochCtx.epoch, }); - // latestExecutionPayloadHeader's depositRequestsRoot and withdrawalRequestsRoot set to zeros by default // default value of depositRequestsStartIndex is UNSET_DEPOSIT_REQUESTS_START_INDEX stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_REQUESTS_START_INDEX; diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index 06e654f9f1d2..b9243ebe7874 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -2,7 +2,6 @@ import { bellatrix, capella, deneb, - electra, isBlindedBeaconBlockBody, ssz, BeaconBlock, @@ -171,14 +170,7 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio ).excessBlobGas; } - if (fork >= ForkSeq.electra) { - (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositRequestsRoot = - ssz.electra.DepositRequests.hashTreeRoot((payload as electra.ExecutionPayload).depositRequests); - (bellatrixPayloadFields as electra.ExecutionPayloadHeader).withdrawalRequestsRoot = - ssz.electra.WithdrawalRequests.hashTreeRoot((payload as electra.ExecutionPayload).withdrawalRequests); - (bellatrixPayloadFields as electra.ExecutionPayloadHeader).consolidationRequestsRoot = - ssz.electra.ConsolidationRequests.hashTreeRoot((payload as electra.ExecutionPayload).consolidationRequests); - } + // No change in Electra return bellatrixPayloadFields; } diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 522f7245cc1b..9d995c38efd5 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -8,7 +8,6 @@ import { } from "@chainsafe/ssz"; import { HISTORICAL_ROOTS_LIMIT, - BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD, @@ -149,25 +148,18 @@ export const ConsolidationRequests = new ListCompositeType( MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD ); -export const ExecutionPayload = new ContainerType( +export const ExecutionRequests = new ContainerType( { - ...denebSsz.ExecutionPayload.fields, - depositRequests: DepositRequests, // New in ELECTRA - withdrawalRequests: WithdrawalRequests, // New in ELECTRA - consolidationRequests: ConsolidationRequests, // New in ELECTRA + deposits: DepositRequests, + withdrawals: WithdrawalRequests, + consolidations: ConsolidationRequests, }, - {typeName: "ExecutionPayload", jsonCase: "eth2"} + {typeName: "ExecutionRequests", jsonCase: "eth2"} ); -export const ExecutionPayloadHeader = new ContainerType( - { - ...denebSsz.ExecutionPayloadHeader.fields, - depositRequestsRoot: Root, // New in ELECTRA - withdrawalRequestsRoot: Root, // New in ELECTRA - consolidationRequestsRoot: Root, // New in ELECTRA - }, - {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} -); +// Explicitly defining electra containers for consistency's sake +export const ExecutionPayloadHeader = denebSsz.ExecutionPayloadHeader; +export const ExecutionPayload = denebSsz.ExecutionPayload; // We have to preserve Fields ordering while changing the type of ExecutionPayload export const BeaconBlockBody = new ContainerType( @@ -181,9 +173,10 @@ export const BeaconBlockBody = new ContainerType( deposits: phase0Ssz.BeaconBlockBody.fields.deposits, voluntaryExits: phase0Ssz.BeaconBlockBody.fields.voluntaryExits, syncAggregate: altairSsz.BeaconBlockBody.fields.syncAggregate, - executionPayload: ExecutionPayload, // Modified in ELECTRA + executionPayload: ExecutionPayload, blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, + executionRequests: ExecutionRequests, // New in ELECTRA:EIP7251 }, {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); @@ -215,7 +208,7 @@ export const BlindedBeaconBlockBody = new ContainerType( deposits: phase0Ssz.BeaconBlockBody.fields.deposits, voluntaryExits: phase0Ssz.BeaconBlockBody.fields.voluntaryExits, syncAggregate: altairSsz.SyncAggregate, - executionPayloadHeader: ExecutionPayloadHeader, // Modified in ELECTRA + executionPayloadHeader: ExecutionPayloadHeader, blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, }, @@ -256,14 +249,6 @@ export const SignedBuilderBid = new ContainerType( {typeName: "SignedBuilderBid", jsonCase: "eth2"} ); -export const ExecutionPayloadAndBlobsBundle = new ContainerType( - { - executionPayload: ExecutionPayload, // Modified in ELECTRA - blobsBundle: denebSsz.BlobsBundle, - }, - {typeName: "ExecutionPayloadAndBlobsBundle", jsonCase: "eth2"} -); - export const PendingBalanceDeposit = new ContainerType( { index: ValidatorIndex, @@ -328,7 +313,7 @@ export const BeaconState = new ContainerType( currentSyncCommittee: altairSsz.SyncCommittee, nextSyncCommittee: altairSsz.SyncCommittee, // Execution - latestExecutionPayloadHeader: ExecutionPayloadHeader, // Modified in ELECTRA + latestExecutionPayloadHeader: ExecutionPayloadHeader, // Withdrawals nextWithdrawalIndex: capellaSsz.BeaconState.fields.nextWithdrawalIndex, nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex, @@ -347,30 +332,21 @@ export const BeaconState = new ContainerType( {typeName: "BeaconState", jsonCase: "eth2"} ); -export const LightClientHeader = new ContainerType( - { - beacon: phase0Ssz.BeaconBlockHeader, - execution: ExecutionPayloadHeader, // Modified in ELECTRA - executionBranch: new VectorCompositeType(Bytes32, EXECUTION_PAYLOAD_DEPTH), - }, - {typeName: "LightClientHeader", jsonCase: "eth2"} -); - export const LightClientBootstrap = new ContainerType( { - header: LightClientHeader, // Modified in ELECTRA + header: denebSsz.LightClientHeader, currentSyncCommittee: altairSsz.SyncCommittee, - currentSyncCommitteeBranch: new VectorCompositeType(Bytes32, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA), // Modified in ELECTRA + currentSyncCommitteeBranch: new VectorCompositeType(Bytes32, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA), }, {typeName: "LightClientBootstrap", jsonCase: "eth2"} ); export const LightClientUpdate = new ContainerType( { - attestedHeader: LightClientHeader, // Modified in ELECTRA + attestedHeader: denebSsz.LightClientHeader, nextSyncCommittee: altairSsz.SyncCommittee, nextSyncCommitteeBranch: new VectorCompositeType(Bytes32, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA), // Modified in ELECTRA - finalizedHeader: LightClientHeader, // Modified in ELECTRA + finalizedHeader: denebSsz.LightClientHeader, finalityBranch: new VectorCompositeType(Bytes32, FINALIZED_ROOT_DEPTH_ELECTRA), // Modified in ELECTRA syncAggregate: altairSsz.SyncAggregate, signatureSlot: Slot, @@ -380,8 +356,8 @@ export const LightClientUpdate = new ContainerType( export const LightClientFinalityUpdate = new ContainerType( { - attestedHeader: LightClientHeader, - finalizedHeader: LightClientHeader, + attestedHeader: denebSsz.LightClientHeader, + finalizedHeader: denebSsz.LightClientHeader, finalityBranch: new VectorCompositeType(Bytes32, FINALIZED_ROOT_DEPTH_ELECTRA), // Modified in ELECTRA syncAggregate: altairSsz.SyncAggregate, signatureSlot: Slot, @@ -391,7 +367,7 @@ export const LightClientFinalityUpdate = new ContainerType( export const LightClientOptimisticUpdate = new ContainerType( { - attestedHeader: LightClientHeader, // Modified in ELECTRA + attestedHeader: denebSsz.LightClientHeader, syncAggregate: altairSsz.SyncAggregate, signatureSlot: Slot, }, @@ -400,8 +376,8 @@ export const LightClientOptimisticUpdate = new ContainerType( export const LightClientStore = new ContainerType( { - snapshot: LightClientBootstrap, // Modified in ELECTRA - validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), // Modified in ELECTRA + snapshot: LightClientBootstrap, + validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), }, {typeName: "LightClientStore", jsonCase: "eth2"} ); diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index 9a81aec43b53..f7996cf336f9 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -20,8 +20,7 @@ export type ConsolidationRequests = ValueOf; export type ExecutionPayload = ValueOf; export type ExecutionPayloadHeader = ValueOf; - -export type ExecutionPayloadAndBlobsBundle = ValueOf; +export type ExecutionRequests = ValueOf; export type BeaconBlockBody = ValueOf; export type BeaconBlock = ValueOf; @@ -33,13 +32,10 @@ export type BlindedBeaconBlockBody = ValueOf; export type BlindedBeaconBlock = ValueOf; export type SignedBlindedBeaconBlock = ValueOf; -export type FullOrBlindedExecutionPayload = ExecutionPayload | ExecutionPayloadHeader; - export type BuilderBid = ValueOf; export type SignedBuilderBid = ValueOf; export type SSEPayloadAttributes = ValueOf; -export type LightClientHeader = ValueOf; export type LightClientBootstrap = ValueOf; export type LightClientUpdate = ValueOf; export type LightClientFinalityUpdate = ValueOf; diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 1071eed79a10..08fc06ac6cb9 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -1,4 +1,12 @@ -import {ForkAll, ForkBlobs, ForkExecution, ForkLightClient, ForkName, ForkPreBlobs} from "@lodestar/params"; +import { + ForkAll, + ForkBlobs, + ForkExecution, + ForkLightClient, + ForkName, + ForkPostElectra, + ForkPreBlobs, +} from "@lodestar/params"; import {ts as phase0} from "./phase0/index.js"; import {ts as altair} from "./altair/index.js"; import {ts as bellatrix} from "./bellatrix/index.js"; @@ -172,7 +180,7 @@ type TypesByFork = { BeaconState: electra.BeaconState; SignedBeaconBlock: electra.SignedBeaconBlock; Metadata: altair.Metadata; - LightClientHeader: electra.LightClientHeader; + LightClientHeader: deneb.LightClientHeader; LightClientBootstrap: electra.LightClientBootstrap; LightClientUpdate: electra.LightClientUpdate; LightClientFinalityUpdate: electra.LightClientFinalityUpdate; @@ -181,8 +189,8 @@ type TypesByFork = { BlindedBeaconBlock: electra.BlindedBeaconBlock; BlindedBeaconBlockBody: electra.BlindedBeaconBlockBody; SignedBlindedBeaconBlock: electra.SignedBlindedBeaconBlock; - ExecutionPayload: electra.ExecutionPayload; - ExecutionPayloadHeader: electra.ExecutionPayloadHeader; + ExecutionPayload: deneb.ExecutionPayload; + ExecutionPayloadHeader: deneb.ExecutionPayloadHeader; BuilderBid: electra.BuilderBid; SignedBuilderBid: electra.SignedBuilderBid; SSEPayloadAttributes: electra.SSEPayloadAttributes; @@ -199,6 +207,7 @@ type TypesByFork = { AttesterSlashing: electra.AttesterSlashing; AggregateAndProof: electra.AggregateAndProof; SignedAggregateAndProof: electra.SignedAggregateAndProof; + ExecutionRequests: electra.ExecutionRequests; }; }; @@ -233,6 +242,7 @@ export type SignedBeaconBlockOrContents = TypesByFork[F]["ExecutionPayload"]; export type ExecutionPayloadHeader = TypesByFork[F]["ExecutionPayloadHeader"]; +export type ExecutionRequests = TypesByFork[F]["ExecutionRequests"]; export type BlobsBundle = TypesByFork[F]["BlobsBundle"]; export type Contents = TypesByFork[F]["Contents"]; diff --git a/packages/types/src/utils/typeguards.ts b/packages/types/src/utils/typeguards.ts index a5f5b7808ae5..a892c3a0c9c0 100644 --- a/packages/types/src/utils/typeguards.ts +++ b/packages/types/src/utils/typeguards.ts @@ -1,4 +1,4 @@ -import {ForkBlobs, ForkExecution, ForkPostElectra} from "@lodestar/params"; +import {FINALIZED_ROOT_DEPTH_ELECTRA, ForkBlobs, ForkExecution, ForkPostElectra} from "@lodestar/params"; import { BlockContents, SignedBeaconBlock, @@ -76,7 +76,7 @@ export function isElectraAttestation(attestation: Attestation): attestation is A export function isElectraLightClientUpdate(update: LightClientUpdate): update is LightClientUpdate { const updatePostElectra = update as LightClientUpdate; return ( - updatePostElectra.attestedHeader.execution !== undefined && - updatePostElectra.attestedHeader.execution.depositRequestsRoot !== undefined + updatePostElectra.finalityBranch !== undefined && + updatePostElectra.finalityBranch.length === FINALIZED_ROOT_DEPTH_ELECTRA ); } From f1a77eadb7b00218bd8b4eecbbf6ca638ffe3552 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 25 Sep 2024 13:19:34 +0100 Subject: [PATCH 115/259] feat: set proper user-agent in validator client http requests (#7106) --- packages/cli/src/cmds/validator/handler.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/src/cmds/validator/handler.ts b/packages/cli/src/cmds/validator/handler.ts index 01c15126b796..53250c2c9a86 100644 --- a/packages/cli/src/cmds/validator/handler.ts +++ b/packages/cli/src/cmds/validator/handler.ts @@ -157,6 +157,7 @@ export async function validatorHandler(args: IValidatorCliArgs & GlobalArgs): Pr globalInit: { requestWireFormat: parseWireFormat(args, "http.requestWireFormat"), responseWireFormat: parseWireFormat(args, "http.responseWireFormat"), + headers: {"User-Agent": `Lodestar/${version}`}, }, }, logger, From bf607863e11dd96a255e1ab61792d764a6d0dd2a Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 25 Sep 2024 21:39:48 +0100 Subject: [PATCH 116/259] chore: remove signing domain for consolidations (#7092) --- packages/beacon-node/src/api/impl/config/constants.ts | 2 -- packages/params/src/index.ts | 1 - 2 files changed, 3 deletions(-) diff --git a/packages/beacon-node/src/api/impl/config/constants.ts b/packages/beacon-node/src/api/impl/config/constants.ts index 4b239ee4cac6..14ecade15b2e 100644 --- a/packages/beacon-node/src/api/impl/config/constants.ts +++ b/packages/beacon-node/src/api/impl/config/constants.ts @@ -37,7 +37,6 @@ import { BLOB_TX_TYPE, VERSIONED_HASH_VERSION_KZG, COMPOUNDING_WITHDRAWAL_PREFIX, - DOMAIN_CONSOLIDATION, UNSET_DEPOSIT_REQUESTS_START_INDEX, FULL_EXIT_REQUEST_AMOUNT, } from "@lodestar/params"; @@ -71,7 +70,6 @@ export const specConstants = { DOMAIN_SELECTION_PROOF, DOMAIN_AGGREGATE_AND_PROOF, DOMAIN_APPLICATION_BUILDER, - DOMAIN_CONSOLIDATION, // phase0/validator.md TARGET_AGGREGATORS_PER_COMMITTEE, diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index dd5c24ac3a54..aa6e97641526 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -146,7 +146,6 @@ export const DOMAIN_SYNC_COMMITTEE = Uint8Array.from([7, 0, 0, 0]); export const DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF = Uint8Array.from([8, 0, 0, 0]); export const DOMAIN_CONTRIBUTION_AND_PROOF = Uint8Array.from([9, 0, 0, 0]); export const DOMAIN_BLS_TO_EXECUTION_CHANGE = Uint8Array.from([10, 0, 0, 0]); -export const DOMAIN_CONSOLIDATION = Uint8Array.from([11, 0, 0, 0]); // Application specific domains From bb8204606762282036aebb15c216617a4c7df41f Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 26 Sep 2024 21:01:37 +0100 Subject: [PATCH 117/259] feat: add electra support for remote signer (#7100) --- .../validator/src/services/validatorStore.ts | 10 +++--- .../src/util/externalSignerClient.ts | 33 +++++++++++++++--- .../validator/test/e2e/web3signer.test.ts | 34 ++++++++++++------- 3 files changed, 56 insertions(+), 21 deletions(-) diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index 6da4f597d87c..ce507349689f 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -562,13 +562,13 @@ export class ValidatorStore { const signingSlot = aggregate.data.slot; const domain = this.config.getDomain(signingSlot, DOMAIN_AGGREGATE_AND_PROOF); - const signingRoot = - this.config.getForkSeq(duty.slot) >= ForkSeq.electra - ? computeSigningRoot(ssz.electra.AggregateAndProof, aggregateAndProof, domain) - : computeSigningRoot(ssz.phase0.AggregateAndProof, aggregateAndProof, domain); + const isPostElectra = this.config.getForkSeq(duty.slot) >= ForkSeq.electra; + const signingRoot = isPostElectra + ? computeSigningRoot(ssz.electra.AggregateAndProof, aggregateAndProof, domain) + : computeSigningRoot(ssz.phase0.AggregateAndProof, aggregateAndProof, domain); const signableMessage: SignableMessage = { - type: SignableMessageType.AGGREGATE_AND_PROOF, + type: isPostElectra ? SignableMessageType.AGGREGATE_AND_PROOF_V2 : SignableMessageType.AGGREGATE_AND_PROOF, data: aggregateAndProof, }; diff --git a/packages/validator/src/util/externalSignerClient.ts b/packages/validator/src/util/externalSignerClient.ts index 4fd615ce5280..1d9778375b88 100644 --- a/packages/validator/src/util/externalSignerClient.ts +++ b/packages/validator/src/util/externalSignerClient.ts @@ -1,11 +1,23 @@ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {fetch} from "@lodestar/api"; -import {phase0, altair, capella, BeaconBlock, BlindedBeaconBlock} from "@lodestar/types"; -import {ForkSeq} from "@lodestar/params"; +import { + phase0, + altair, + capella, + BeaconBlock, + BlindedBeaconBlock, + AggregateAndProof, + sszTypesFor, + ssz, + Slot, + Epoch, + RootHex, + Root, +} from "@lodestar/types"; +import {ForkPreExecution, ForkSeq} from "@lodestar/params"; import {ValidatorRegistrationV1} from "@lodestar/types/bellatrix"; import {BeaconConfig} from "@lodestar/config"; import {computeEpochAtSlot, blindedOrFullBlockToHeader} from "@lodestar/state-transition"; -import {Epoch, Root, RootHex, Slot, ssz} from "@lodestar/types"; import {toHex, toRootHex} from "@lodestar/utils"; import {PubkeyHex} from "../types.js"; @@ -14,6 +26,7 @@ import {PubkeyHex} from "../types.js"; export enum SignableMessageType { AGGREGATION_SLOT = "AGGREGATION_SLOT", AGGREGATE_AND_PROOF = "AGGREGATE_AND_PROOF", + AGGREGATE_AND_PROOF_V2 = "AGGREGATE_AND_PROOF_V2", ATTESTATION = "ATTESTATION", BLOCK_V2 = "BLOCK_V2", DEPOSIT = "DEPOSIT", @@ -63,8 +76,9 @@ const SyncAggregatorSelectionDataType = new ContainerType( export type SignableMessage = | {type: SignableMessageType.AGGREGATION_SLOT; data: {slot: Slot}} | {type: SignableMessageType.AGGREGATE_AND_PROOF; data: phase0.AggregateAndProof} + | {type: SignableMessageType.AGGREGATE_AND_PROOF_V2; data: AggregateAndProof} | {type: SignableMessageType.ATTESTATION; data: phase0.AttestationData} - | {type: SignableMessageType.BLOCK_V2; data: BeaconBlock | BlindedBeaconBlock} + | {type: SignableMessageType.BLOCK_V2; data: BeaconBlock | BlindedBeaconBlock} | {type: SignableMessageType.DEPOSIT; data: ValueOf} | {type: SignableMessageType.RANDAO_REVEAL; data: {epoch: Epoch}} | {type: SignableMessageType.VOLUNTARY_EXIT; data: phase0.VoluntaryExit} @@ -77,6 +91,7 @@ export type SignableMessage = const requiresForkInfo: Record = { [SignableMessageType.AGGREGATION_SLOT]: true, [SignableMessageType.AGGREGATE_AND_PROOF]: true, + [SignableMessageType.AGGREGATE_AND_PROOF_V2]: true, [SignableMessageType.ATTESTATION]: true, [SignableMessageType.BLOCK_V2]: true, [SignableMessageType.DEPOSIT]: false, @@ -203,6 +218,16 @@ function serializerSignableMessagePayload(config: BeaconConfig, payload: Signabl case SignableMessageType.AGGREGATE_AND_PROOF: return {aggregate_and_proof: ssz.phase0.AggregateAndProof.toJson(payload.data)}; + case SignableMessageType.AGGREGATE_AND_PROOF_V2: { + const fork = config.getForkName(payload.data.aggregate.data.slot); + return { + aggregate_and_proof: { + version: fork.toUpperCase(), + data: sszTypesFor(fork).AggregateAndProof.toJson(payload.data), + }, + }; + } + case SignableMessageType.ATTESTATION: return {attestation: ssz.phase0.AttestationData.toJson(payload.data)}; diff --git a/packages/validator/test/e2e/web3signer.test.ts b/packages/validator/test/e2e/web3signer.test.ts index 326dbae8c4f7..ae22bc31446b 100644 --- a/packages/validator/test/e2e/web3signer.test.ts +++ b/packages/validator/test/e2e/web3signer.test.ts @@ -5,7 +5,7 @@ import {computeStartSlotAtEpoch, interopSecretKey, interopSecretKeys} from "@lod import {createBeaconConfig} from "@lodestar/config"; import {genesisData} from "@lodestar/config/networks"; import {getClient, routes} from "@lodestar/api"; -import {ssz} from "@lodestar/types"; +import {ssz, sszTypesFor} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import {getKeystoresStr, StartedExternalSigner, startExternalSigner} from "@lodestar/test-utils"; import {Interchange, ISlashingProtection, Signer, SignerType, ValidatorStore} from "../../src/index.js"; @@ -93,17 +93,27 @@ describe("web3signer signature test", function () { await assertSameSignature("signAttestation", duty, attestationData, epoch); }); - it("signAggregateAndProof", async () => { - const aggregateAndProof = ssz.phase0.AggregateAndProof.defaultValue(); - aggregateAndProof.aggregate.data.slot = duty.slot; - aggregateAndProof.aggregate.data.index = duty.committeeIndex; - await assertSameSignature( - "signAggregateAndProof", - duty, - aggregateAndProof.selectionProof, - aggregateAndProof.aggregate - ); - }); + for (const fork of config.forksAscendingEpochOrder) { + it(`signAggregateAndProof ${fork.name}`, async ({skip}) => { + // Only test till the fork the signer version supports + if (ForkSeq[fork.name] > externalSigner.supportedForkSeq) { + skip(); + return; + } + + const aggregateAndProof = sszTypesFor(fork.name).AggregateAndProof.defaultValue(); + const slot = computeStartSlotAtEpoch(fork.epoch); + aggregateAndProof.aggregate.data.slot = slot; + aggregateAndProof.aggregate.data.index = duty.committeeIndex; + + await assertSameSignature( + "signAggregateAndProof", + {...duty, slot}, + aggregateAndProof.selectionProof, + aggregateAndProof.aggregate + ); + }); + } it("signSyncCommitteeSignature", async () => { const beaconBlockRoot = ssz.phase0.BeaconBlockHeader.defaultValue().bodyRoot; From 58dea7543c846e912a0d7422aee0b836f57a3b7a Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 26 Sep 2024 21:59:20 +0100 Subject: [PATCH 118/259] feat: use POST variant to get validators from state (#6897) * feat: use POST variant to get validators from state * Fix api handler used during testing * Update more calls to use POST variant --- .../test/e2e/api/impl/lightclient/endpoint.test.ts | 2 +- .../cli/src/cmds/validator/blsToExecutionChange.ts | 2 +- packages/cli/src/cmds/validator/voluntaryExit.ts | 2 +- packages/cli/test/sim/endpoints.test.ts | 10 +++++----- packages/flare/src/cmds/selfSlashAttester.ts | 4 ++-- packages/flare/src/cmds/selfSlashProposer.ts | 4 ++-- packages/validator/src/services/indices.ts | 12 +++++++----- packages/validator/src/validator.ts | 4 +++- .../validator/test/unit/services/attestation.test.ts | 2 +- .../test/unit/services/attestationDuties.test.ts | 2 +- .../test/unit/services/syncCommitteDuties.test.ts | 2 +- .../test/unit/services/syncCommittee.test.ts | 2 +- packages/validator/test/utils/apiStub.ts | 1 + 13 files changed, 27 insertions(+), 22 deletions(-) diff --git a/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts b/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts index 81154005af68..c746746741cf 100644 --- a/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts @@ -122,7 +122,7 @@ describe("lightclient api", function () { const committeeRes = await lightclient.getLightClientCommitteeRoot({startPeriod: 0, count: 1}); committeeRes.assertOk(); const client = getClient({baseUrl: `http://127.0.0.1:${restPort}`}, {config}).beacon; - const validators = (await client.getStateValidators({stateId: "head"})).value(); + const validators = (await client.postStateValidators({stateId: "head"})).value(); const pubkeys = validators.map((v) => v.validator.pubkey); expect(pubkeys.length).toBe(validatorCount); // only 2 validators spreading to 512 committee slots diff --git a/packages/cli/src/cmds/validator/blsToExecutionChange.ts b/packages/cli/src/cmds/validator/blsToExecutionChange.ts index dc55647fda80..7fbdbb029bf5 100644 --- a/packages/cli/src/cmds/validator/blsToExecutionChange.ts +++ b/packages/cli/src/cmds/validator/blsToExecutionChange.ts @@ -60,7 +60,7 @@ like to choose for BLS To Execution Change.", const {genesisValidatorsRoot} = (await client.beacon.getGenesis()).value(); const config = createBeaconConfig(chainForkConfig, genesisValidatorsRoot); - const validators = (await client.beacon.getStateValidators({stateId: "head", validatorIds: [publicKey]})).value(); + const validators = (await client.beacon.postStateValidators({stateId: "head", validatorIds: [publicKey]})).value(); const validator = validators[0]; if (validator === undefined) { throw new Error(`Validator pubkey ${publicKey} not found in state`); diff --git a/packages/cli/src/cmds/validator/voluntaryExit.ts b/packages/cli/src/cmds/validator/voluntaryExit.ts index a399a763662d..02f1591b59ed 100644 --- a/packages/cli/src/cmds/validator/voluntaryExit.ts +++ b/packages/cli/src/cmds/validator/voluntaryExit.ts @@ -207,7 +207,7 @@ function selectSignersToExit(args: VoluntaryExitArgs, signers: Signer[]): Signer async function resolveValidatorIndexes(client: ApiClient, signersToExit: SignerPubkey[]) { const pubkeys = signersToExit.map(({pubkey}) => pubkey); - const validators = (await client.beacon.getStateValidators({stateId: "head", validatorIds: pubkeys})).value(); + const validators = (await client.beacon.postStateValidators({stateId: "head", validatorIds: pubkeys})).value(); const dataByPubkey = new Map(validators.map((item) => [toPubkeyHex(item.validator.pubkey), item])); diff --git a/packages/cli/test/sim/endpoints.test.ts b/packages/cli/test/sim/endpoints.test.ts index 07cd5fec0cc4..a42b9568f9a3 100644 --- a/packages/cli/test/sim/endpoints.test.ts +++ b/packages/cli/test/sim/endpoints.test.ts @@ -40,7 +40,7 @@ await env.start({runTimeoutMs: estimatedTimeoutMs}); const node = env.nodes[0].beacon; await waitForSlot("Wait for 2 slots before checking endpoints", {env, slot: 2}); -const validators = (await node.api.beacon.getStateValidators({stateId: "head"})).value(); +const validators = (await node.api.beacon.postStateValidators({stateId: "head"})).value(); await env.tracker.assert("should have correct validators count called without filters", async () => { assert.equal(validators.length, validatorCount); @@ -55,12 +55,12 @@ await env.tracker.assert("should have correct validator index for second validat }); await env.tracker.assert( - "should return correct number of filtered validators when getStateValidators called with filters", + "should return correct number of filtered validators when postStateValidators called with filters", async () => { const filterPubKey = "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c"; - const res = await node.api.beacon.getStateValidators({stateId: "head", validatorIds: [filterPubKey]}); + const res = await node.api.beacon.postStateValidators({stateId: "head", validatorIds: [filterPubKey]}); assert.equal(res.value().length, 1); @@ -71,12 +71,12 @@ await env.tracker.assert( ); await env.tracker.assert( - "should return correct filtered validators when getStateValidators called with filters", + "should return correct filtered validators when postStateValidators called with filters", async () => { const filterPubKey = "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c"; - const res = await node.api.beacon.getStateValidators({stateId: "head", validatorIds: [filterPubKey]}); + const res = await node.api.beacon.postStateValidators({stateId: "head", validatorIds: [filterPubKey]}); assert.equal(toHexString(res.value()[0].validator.pubkey), filterPubKey); } diff --git a/packages/flare/src/cmds/selfSlashAttester.ts b/packages/flare/src/cmds/selfSlashAttester.ts index a37c6c765bd3..6ccc9d80a98f 100644 --- a/packages/flare/src/cmds/selfSlashAttester.ts +++ b/packages/flare/src/cmds/selfSlashAttester.ts @@ -79,7 +79,7 @@ export async function selfSlashAttesterHandler(args: SelfSlashArgs): Promise sk.toPublicKey().toHex()); - const validators = (await client.beacon.getStateValidators({stateId: "head", validatorIds: pksHex})).value(); + const validators = (await client.beacon.postStateValidators({stateId: "head", validatorIds: pksHex})).value(); // All validators in the batch will be part of the same AttesterSlashing const attestingIndices = validators.map((v) => v.index); @@ -92,7 +92,7 @@ export async function selfSlashAttesterHandler(args: SelfSlashArgs): Promise sk.toPublicKey().toHex()); - const validators = (await client.beacon.getStateValidators({stateId: "head", validatorIds: pksHex})).value(); + const validators = (await client.beacon.postStateValidators({stateId: "head", validatorIds: pksHex})).value(); // Submit all ProposerSlashing for range at once await Promise.all( @@ -88,7 +88,7 @@ export async function selfSlashProposerHandler(args: SelfSlashArgs): Promise { - const validators = (await this.api.beacon.getStateValidators({stateId: "head", validatorIds: pubkeysHex})).value(); + const validators = (await this.api.beacon.postStateValidators({stateId: "head", validatorIds: pubkeysHex})).value(); const newIndices = []; diff --git a/packages/validator/src/validator.ts b/packages/validator/src/validator.ts index 980e64f7eac2..6ffebff2b3bd 100644 --- a/packages/validator/src/validator.ts +++ b/packages/validator/src/validator.ts @@ -372,7 +372,9 @@ export class Validator { * Create a signed voluntary exit message for the given validator by its key. */ async signVoluntaryExit(publicKey: string, exitEpoch?: number): Promise { - const validators = (await this.api.beacon.getStateValidators({stateId: "head", validatorIds: [publicKey]})).value(); + const validators = ( + await this.api.beacon.postStateValidators({stateId: "head", validatorIds: [publicKey]}) + ).value(); const validator = validators[0]; if (validator === undefined) { diff --git a/packages/validator/test/unit/services/attestation.test.ts b/packages/validator/test/unit/services/attestation.test.ts index 356503cbdd09..66b722273102 100644 --- a/packages/validator/test/unit/services/attestation.test.ts +++ b/packages/validator/test/unit/services/attestation.test.ts @@ -105,7 +105,7 @@ describe("AttestationService", function () { ]; // Return empty replies to duties service - api.beacon.getStateValidators.mockResolvedValue( + api.beacon.postStateValidators.mockResolvedValue( mockApiResponse({data: [], meta: {executionOptimistic: false, finalized: false}}) ); api.validator.getAttesterDuties.mockResolvedValue( diff --git a/packages/validator/test/unit/services/attestationDuties.test.ts b/packages/validator/test/unit/services/attestationDuties.test.ts index 751ebcf11205..a9d50eaf42c6 100644 --- a/packages/validator/test/unit/services/attestationDuties.test.ts +++ b/packages/validator/test/unit/services/attestationDuties.test.ts @@ -52,7 +52,7 @@ describe("AttestationDutiesService", function () { index, validator: {...defaultValidator.validator, pubkey: pubkeys[0]}, }; - api.beacon.getStateValidators.mockResolvedValue( + api.beacon.postStateValidators.mockResolvedValue( mockApiResponse({data: [validatorResponse], meta: {executionOptimistic: false, finalized: false}}) ); }); diff --git a/packages/validator/test/unit/services/syncCommitteDuties.test.ts b/packages/validator/test/unit/services/syncCommitteDuties.test.ts index 10bac3ab2fe9..dc43502d5b57 100644 --- a/packages/validator/test/unit/services/syncCommitteDuties.test.ts +++ b/packages/validator/test/unit/services/syncCommitteDuties.test.ts @@ -60,7 +60,7 @@ describe("SyncCommitteeDutiesService", function () { index: indices[i], validator: {...defaultValidator.validator, pubkey: pubkeys[i]}, })); - api.beacon.getStateValidators.mockResolvedValue( + api.beacon.postStateValidators.mockResolvedValue( mockApiResponse({data: validatorResponses, meta: {executionOptimistic: false, finalized: false}}) ); }); diff --git a/packages/validator/test/unit/services/syncCommittee.test.ts b/packages/validator/test/unit/services/syncCommittee.test.ts index 66e63ab72a6c..449f826c3806 100644 --- a/packages/validator/test/unit/services/syncCommittee.test.ts +++ b/packages/validator/test/unit/services/syncCommittee.test.ts @@ -102,7 +102,7 @@ describe("SyncCommitteeService", function () { ]; // Return empty replies to duties service - api.beacon.getStateValidators.mockResolvedValue( + api.beacon.postStateValidators.mockResolvedValue( mockApiResponse({data: [], meta: {executionOptimistic: false, finalized: false}}) ); api.validator.getSyncCommitteeDuties.mockResolvedValue( diff --git a/packages/validator/test/utils/apiStub.ts b/packages/validator/test/utils/apiStub.ts index ef615af03369..4443dab5c4ac 100644 --- a/packages/validator/test/utils/apiStub.ts +++ b/packages/validator/test/utils/apiStub.ts @@ -16,6 +16,7 @@ export function getApiClientStub(): ApiClientStub { return { beacon: { getStateValidators: vi.fn(), + postStateValidators: vi.fn(), publishBlindedBlockV2: vi.fn(), publishBlockV2: vi.fn(), submitPoolSyncCommitteeSignatures: vi.fn(), From 77006ea0ce9ac043b71b7aaa07b9fae6f38f5250 Mon Sep 17 00:00:00 2001 From: twoeths Date: Fri, 27 Sep 2024 08:15:21 +0700 Subject: [PATCH 119/259] fix: state serialization time (#7109) * fix: release memory to BufferPool * fix: correct the serializeState metric * fix: check types * chore: fix lint --- .../src/chain/archiver/archiveStates.ts | 13 ++++-- .../beacon-node/src/chain/archiver/index.ts | 6 ++- packages/beacon-node/src/chain/chain.ts | 2 +- .../beacon-node/src/chain/serializeState.ts | 11 +++-- .../stateCache/persistentCheckpointsCache.ts | 45 +++++++++++-------- .../src/metrics/metrics/lodestar.ts | 11 ++--- .../stateCache/nHistoricalStates.test.ts | 7 ++- 7 files changed, 55 insertions(+), 40 deletions(-) diff --git a/packages/beacon-node/src/chain/archiver/archiveStates.ts b/packages/beacon-node/src/chain/archiver/archiveStates.ts index 53f2033d80e8..8fd9081ab243 100644 --- a/packages/beacon-node/src/chain/archiver/archiveStates.ts +++ b/packages/beacon-node/src/chain/archiver/archiveStates.ts @@ -8,6 +8,7 @@ import {IStateRegenerator} from "../regen/interface.js"; import {getStateSlotFromBytes} from "../../util/multifork.js"; import {serializeState} from "../serializeState.js"; import {AllocSource, BufferPool} from "../../util/bufferPool.js"; +import {Metrics} from "../../metrics/metrics.js"; /** * Minimum number of epochs between single temp archived states @@ -48,13 +49,13 @@ export class StatesArchiver { * epoch - 1024*2 epoch - 1024 epoch - 32 epoch * ``` */ - async maybeArchiveState(finalized: CheckpointWithHex): Promise { + async maybeArchiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise { const lastStoredSlot = await this.db.stateArchive.lastKey(); const lastStoredEpoch = computeEpochAtSlot(lastStoredSlot ?? 0); const {archiveStateEpochFrequency} = this.opts; if (finalized.epoch - lastStoredEpoch >= Math.min(PERSIST_TEMP_STATE_EVERY_EPOCHS, archiveStateEpochFrequency)) { - await this.archiveState(finalized); + await this.archiveState(finalized, metrics); // Only check the current and previous intervals const minEpoch = Math.max( @@ -86,7 +87,7 @@ export class StatesArchiver { * Archives finalized states from active bucket to archive bucket. * Only the new finalized state is stored to disk */ - async archiveState(finalized: CheckpointWithHex): Promise { + async archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise { // starting from Mar 2024, the finalized state could be from disk or in memory const finalizedStateOrBytes = await this.regen.getCheckpointStateOrBytes(finalized); const {rootHex} = finalized; @@ -99,10 +100,14 @@ export class StatesArchiver { this.logger.verbose("Archived finalized state bytes", {epoch: finalized.epoch, slot, root: rootHex}); } else { // serialize state using BufferPool if provided + const timer = metrics?.stateSerializeDuration.startTimer({source: AllocSource.ARCHIVE_STATE}); await serializeState( finalizedStateOrBytes, AllocSource.ARCHIVE_STATE, - (stateBytes) => this.db.stateArchive.putBinary(finalizedStateOrBytes.slot, stateBytes), + (stateBytes) => { + timer?.(); + return this.db.stateArchive.putBinary(finalizedStateOrBytes.slot, stateBytes); + }, this.bufferPool ); // don't delete states before the finalized state, auto-prune will take care of it diff --git a/packages/beacon-node/src/chain/archiver/index.ts b/packages/beacon-node/src/chain/archiver/index.ts index 294c2281e19b..45169b2fa802 100644 --- a/packages/beacon-node/src/chain/archiver/index.ts +++ b/packages/beacon-node/src/chain/archiver/index.ts @@ -4,6 +4,7 @@ import {IBeaconDb} from "../../db/index.js"; import {JobItemQueue} from "../../util/queue/index.js"; import {IBeaconChain} from "../interface.js"; import {ChainEvent} from "../emitter.js"; +import {Metrics} from "../../metrics/metrics.js"; import {StatesArchiver, StatesArchiverOpts} from "./archiveStates.js"; import {archiveBlocks} from "./archiveBlocks.js"; @@ -45,7 +46,8 @@ export class Archiver { private readonly chain: IBeaconChain, private readonly logger: Logger, signal: AbortSignal, - opts: ArchiverOpts + opts: ArchiverOpts, + private readonly metrics?: Metrics | null ) { this.archiveBlobEpochs = opts.archiveBlobEpochs; this.statesArchiver = new StatesArchiver(chain.regen, db, logger, opts, chain.bufferPool); @@ -105,7 +107,7 @@ export class Archiver { this.prevFinalized = finalized; // should be after ArchiveBlocksTask to handle restart cleanly - await this.statesArchiver.maybeArchiveState(finalized); + await this.statesArchiver.maybeArchiveState(finalized, this.metrics); this.chain.regen.pruneOnFinalized(finalizedEpoch); diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 0b0ac30edf40..696f4bd51dc3 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -345,7 +345,7 @@ export class BeaconChain implements IBeaconChain { this.bls = bls; this.emitter = emitter; - this.archiver = new Archiver(db, this, logger, signal, opts); + this.archiver = new Archiver(db, this, logger, signal, opts, metrics); // always run PrepareNextSlotScheduler except for fork_choice spec tests if (!opts?.disablePrepareNextSlot) { new PrepareNextSlotScheduler(this, this.config, metrics, this.logger, signal); diff --git a/packages/beacon-node/src/chain/serializeState.ts b/packages/beacon-node/src/chain/serializeState.ts index cbb2ecd18cff..c6e796cd614c 100644 --- a/packages/beacon-node/src/chain/serializeState.ts +++ b/packages/beacon-node/src/chain/serializeState.ts @@ -15,19 +15,18 @@ export async function serializeState( const size = state.type.tree_serializedSize(state.node); let stateBytes: Uint8Array | null = null; if (bufferPool) { - const bufferWithKey = bufferPool.alloc(size, source); + using bufferWithKey = bufferPool.alloc(size, source); if (bufferWithKey) { stateBytes = bufferWithKey.buffer; const dataView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength); state.serializeToBytes({uint8Array: stateBytes, dataView}, 0); + return processFn(stateBytes); } + // release the buffer back to the pool automatically } - if (!stateBytes) { - // we already have metrics in BufferPool so no need to do it here - stateBytes = state.serialize(); - } + // we already have metrics in BufferPool so no need to do it here + stateBytes = state.serialize(); return processFn(stateBytes); - // release the buffer back to the pool automatically } diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 74e85e6fa574..07c96f224bee 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -94,7 +94,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { private readonly cache: MapTracker; /** Epoch -> Set */ private readonly epochIndex = new MapDef>(() => new Set()); - private readonly metrics: Metrics["cpStateCache"] | null | undefined; + private readonly metrics: Metrics | null | undefined; private readonly logger: Logger; private readonly clock: IClock | null | undefined; private readonly signal: AbortSignal | undefined; @@ -123,7 +123,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { ) { this.cache = new MapTracker(metrics?.cpStateCache); if (metrics) { - this.metrics = metrics.cpStateCache; + this.metrics = metrics; metrics.cpStateCache.size.addCollect(() => { let persistCount = 0; let inMemoryCount = 0; @@ -194,24 +194,26 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { const {persistedKey, stateBytes} = stateOrStateBytesData; const logMeta = {persistedKey: toHex(persistedKey)}; this.logger.debug("Reload: read state successful", logMeta); - this.metrics?.stateReloadSecFromSlot.observe(this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0); + this.metrics?.cpStateCache.stateReloadSecFromSlot.observe( + this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0 + ); const seedState = this.findSeedStateToReload(cp); - this.metrics?.stateReloadEpochDiff.observe(Math.abs(seedState.epochCtx.epoch - cp.epoch)); + this.metrics?.cpStateCache.stateReloadEpochDiff.observe(Math.abs(seedState.epochCtx.epoch - cp.epoch)); this.logger.debug("Reload: found seed state", {...logMeta, seedSlot: seedState.slot}); try { // 80% of validators serialization time comes from memory allocation, this is to avoid it - const sszTimer = this.metrics?.stateReloadValidatorsSerializeDuration.startTimer(); + const sszTimer = this.metrics?.cpStateCache.stateReloadValidatorsSerializeDuration.startTimer(); // automatically free the buffer pool after this scope using validatorsBytesWithKey = this.serializeStateValidators(seedState); let validatorsBytes = validatorsBytesWithKey?.buffer; if (validatorsBytes == null) { // fallback logic in case we can't use the buffer pool - this.metrics?.stateReloadValidatorsSerializeAllocCount.inc(); + this.metrics?.cpStateCache.stateReloadValidatorsSerializeAllocCount.inc(); validatorsBytes = seedState.validators.serialize(); } sszTimer?.(); - const timer = this.metrics?.stateReloadDuration.startTimer(); + const timer = this.metrics?.cpStateCache.stateReloadDuration.startTimer(); const newCachedState = loadCachedBeaconState(seedState, stateBytes, {}, validatorsBytes); newCachedState.commit(); const stateRoot = toRootHex(newCachedState.hashTreeRoot()); @@ -275,7 +277,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { } const persistedKey = cacheItem.value; - const dbReadTimer = this.metrics?.stateReloadDbReadTime.startTimer(); + const dbReadTimer = this.metrics?.cpStateCache.stateReloadDbReadTime.startTimer(); const stateBytes = await this.datastore.read(persistedKey); dbReadTimer?.(); @@ -289,7 +291,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { * Similar to get() api without reloading from disk */ get(cpOrKey: CheckpointHex | string, opts?: StateCloneOpts): CachedBeaconStateAllForks | null { - this.metrics?.lookups.inc(); + this.metrics?.cpStateCache.lookups.inc(); const cpKey = typeof cpOrKey === "string" ? cpOrKey : toCacheKey(cpOrKey); const cacheItem = this.cache.get(cpKey); @@ -297,7 +299,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { return null; } - this.metrics?.hits.inc(); + this.metrics?.cpStateCache.hits.inc(); if (cpKey === this.preComputedCheckpoint) { this.preComputedCheckpointHits = (this.preComputedCheckpointHits ?? 0) + 1; @@ -305,7 +307,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { if (isInMemoryCacheItem(cacheItem)) { const {state} = cacheItem; - this.metrics?.stateClonedCount.observe(state.clonedCount); + this.metrics?.cpStateCache.stateClonedCount.observe(state.clonedCount); return state.clone(opts?.dontTransferCache); } @@ -319,7 +321,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { const cpHex = toCheckpointHex(cp); const key = toCacheKey(cpHex); const cacheItem = this.cache.get(key); - this.metrics?.adds.inc(); + this.metrics?.cpStateCache.adds.inc(); if (cacheItem !== undefined && isPersistedCacheItem(cacheItem)) { const persistedKey = cacheItem.value; // was persisted to disk, set back to memory @@ -683,7 +685,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { this.logger.verbose("Pruned checkpoint state from memory but no need to persist", logMeta); } else { // persist and do not update epochIndex - this.metrics?.statePersistSecFromSlot.observe(this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0); + this.metrics?.cpStateCache.statePersistSecFromSlot.observe( + this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0 + ); const cpPersist = {epoch: epoch, root: fromHex(rootHex)}; // It's not sustainable to allocate ~240MB for each state every epoch, so we use buffer pool to reuse the memory. // As monitored on holesky as of Jan 2024: @@ -691,14 +695,19 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { // - It helps stabilize persist time and save ~300ms in average (1.5s vs 1.2s) // - It also helps the state reload to save ~500ms in average (4.3s vs 3.8s) // - Also `serializeState.test.ts` perf test shows a lot of differences allocating ~240MB once vs per state serialization - const timer = this.metrics?.stateSerializeDuration.startTimer(); + const timer = this.metrics?.stateSerializeDuration.startTimer({ + source: AllocSource.PERSISTENT_CHECKPOINTS_CACHE_STATE, + }); persistedKey = await serializeState( state, AllocSource.PERSISTENT_CHECKPOINTS_CACHE_STATE, - (stateBytes) => this.datastore.write(cpPersist, stateBytes), + (stateBytes) => { + timer?.(); + return this.datastore.write(cpPersist, stateBytes); + }, this.bufferPool ); - timer?.(); + persistCount++; this.logger.verbose("Pruned checkpoint state from memory and persisted to disk", { ...logMeta, @@ -718,7 +727,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { this.cache.delete(cpKey); this.epochIndex.get(epoch)?.delete(rootHex); } - this.metrics?.statePruneFromMemoryCount.inc(); + this.metrics?.cpStateCache.statePruneFromMemoryCount.inc(); this.logger.verbose("Pruned checkpoint state from memory", logMeta); } } @@ -742,7 +751,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { if (persistedKey) { await this.datastore.remove(persistedKey); persistCount++; - this.metrics?.persistedStateRemoveCount.inc(); + this.metrics?.cpStateCache.persistedStateRemoveCount.inc(); } } this.cache.delete(key); diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index fb4ea61b6523..bac740b7ee04 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -1218,11 +1218,6 @@ export function createLodestarMetrics( help: "Histogram of cloned count per state every time state.clone() is called", buckets: [1, 2, 5, 10, 50, 250], }), - stateSerializeDuration: register.histogram({ - name: "lodestar_cp_state_cache_state_serialize_seconds", - help: "Histogram of time to serialize state to db", - buckets: [0.1, 0.5, 1, 2, 3, 4], - }), numStatesUpdated: register.histogram({ name: "lodestar_cp_state_cache_state_updated_count", help: "Histogram of number of state cache items updated every time removing and adding pubkeys to pubkey cache", @@ -1434,6 +1429,12 @@ export function createLodestarMetrics( name: "lodestar_unhandled_promise_rejections_total", help: "UnhandledPromiseRejection total count", }), + stateSerializeDuration: register.histogram<{source: AllocSource}>({ + name: "lodestar_state_serialize_seconds", + help: "Histogram of time to serialize state", + labelNames: ["source"], + buckets: [0.1, 0.5, 1, 2, 3, 4], + }), // regen.getState metrics regenGetState: { diff --git a/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts b/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts index 005b28baeefc..fd14b7b8b8c0 100644 --- a/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts +++ b/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts @@ -412,11 +412,10 @@ describe("regen/reload states with n-historical states configuration", function )?.value ).toEqual(reloadCount); - const stateSszMetricValues = await (followupBn.metrics?.cpStateCache.stateSerializeDuration as Histogram).get(); + const stateSszMetricValues = await (followupBn.metrics?.stateSerializeDuration as Histogram).get(); expect( - stateSszMetricValues?.values.find( - (value) => value.metricName === "lodestar_cp_state_cache_state_serialize_seconds_count" - )?.value + stateSszMetricValues?.values.find((value) => value.metricName === "lodestar_state_serialize_seconds_count") + ?.value ).toEqual(persistCount); // assert number of persisted/in-memory states From 94b6c5b0db4e60c7406309367f5b2d7253e8d3c5 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 27 Sep 2024 19:39:18 +0100 Subject: [PATCH 120/259] chore: use signing slot to determine fork (#7112) --- packages/validator/src/services/validatorStore.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index ce507349689f..c2b18bfd7e09 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -531,7 +531,7 @@ export class ValidatorStore { data: attestationData, }; - if (this.config.getForkSeq(duty.slot) >= ForkSeq.electra) { + if (this.config.getForkSeq(signingSlot) >= ForkSeq.electra) { return { aggregationBits: BitArray.fromSingleBit(duty.committeeLength, duty.validatorCommitteeIndex), data: attestationData, @@ -562,7 +562,7 @@ export class ValidatorStore { const signingSlot = aggregate.data.slot; const domain = this.config.getDomain(signingSlot, DOMAIN_AGGREGATE_AND_PROOF); - const isPostElectra = this.config.getForkSeq(duty.slot) >= ForkSeq.electra; + const isPostElectra = this.config.getForkSeq(signingSlot) >= ForkSeq.electra; const signingRoot = isPostElectra ? computeSigningRoot(ssz.electra.AggregateAndProof, aggregateAndProof, domain) : computeSigningRoot(ssz.phase0.AggregateAndProof, aggregateAndProof, domain); @@ -802,7 +802,7 @@ export class ValidatorStore { throw Error(`Inconsistent duties during signing: duty.slot ${duty.slot} != att.slot ${data.slot}`); } - const isPostElectra = this.config.getForkSeq(duty.slot) >= ForkSeq.electra; + const isPostElectra = this.config.getForkSeq(data.slot) >= ForkSeq.electra; if (!isPostElectra && duty.committeeIndex != data.index) { throw Error( `Inconsistent duties during signing: duty.committeeIndex ${duty.committeeIndex} != att.committeeIndex ${data.index}` From f87ee1ab5613409748bff29c11249eae28736c4a Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 27 Sep 2024 20:05:09 +0100 Subject: [PATCH 121/259] feat: add validator identities endpoint (#7107) * feat: add validator identities endpoint * Test against official spec release from beacon-apis repo * Prepopulate validatorIdentities in else clause * Log warning if validator index can't be resolved --- .../api/src/beacon/routes/beacon/index.ts | 1 + .../api/src/beacon/routes/beacon/state.ts | 52 +++++++++++++++++++ .../api/test/unit/beacon/oapiSpec.test.ts | 4 +- .../api/test/unit/beacon/testData/beacon.ts | 7 +++ .../src/api/impl/beacon/state/index.ts | 38 +++++++++++++- 5 files changed, 99 insertions(+), 3 deletions(-) diff --git a/packages/api/src/beacon/routes/beacon/index.ts b/packages/api/src/beacon/routes/beacon/index.ts index f70792f9d76f..39d7d995dfb1 100644 --- a/packages/api/src/beacon/routes/beacon/index.ts +++ b/packages/api/src/beacon/routes/beacon/index.ts @@ -25,6 +25,7 @@ export type { export type { StateId, ValidatorId, + ValidatorIdentities, ValidatorStatus, FinalityCheckpoints, ValidatorResponse, diff --git a/packages/api/src/beacon/routes/beacon/state.ts b/packages/api/src/beacon/routes/beacon/state.ts index 4f8d414f5b6c..e3cfe2e16edf 100644 --- a/packages/api/src/beacon/routes/beacon/state.ts +++ b/packages/api/src/beacon/routes/beacon/state.ts @@ -53,6 +53,14 @@ export const ValidatorResponseType = new ContainerType({ status: new StringType(), validator: ssz.phase0.Validator, }); +export const ValidatorIdentityType = new ContainerType( + { + index: ssz.ValidatorIndex, + pubkey: ssz.BLSPubkey, + activationEpoch: ssz.UintNum64, + }, + {jsonCase: "eth2"} +); export const EpochCommitteeResponseType = new ContainerType({ index: ssz.CommitteeIndex, slot: ssz.Slot, @@ -73,6 +81,7 @@ export const EpochSyncCommitteeResponseType = new ContainerType( {jsonCase: "eth2"} ); export const ValidatorResponseListType = ArrayOf(ValidatorResponseType); +export const ValidatorIdentitiesType = ArrayOf(ValidatorIdentityType); export const EpochCommitteeResponseListType = ArrayOf(EpochCommitteeResponseType); export const ValidatorBalanceListType = ArrayOf(ValidatorBalanceType); @@ -84,6 +93,7 @@ export type ValidatorBalance = ValueOf; export type EpochSyncCommitteeResponse = ValueOf; export type ValidatorResponseList = ValueOf; +export type ValidatorIdentities = ValueOf; export type EpochCommitteeResponseList = ValueOf; export type ValidatorBalanceList = ValueOf; @@ -191,6 +201,26 @@ export type Endpoints = { ExecutionOptimisticAndFinalizedMeta >; + /** + * Get validator identities from state + * + * Returns filterable list of validators identities. + * + * Identities will be returned for all indices or public keys that match known validators. If an index or public key does not + * match any known validator, no identity will be returned but this will not cause an error. There are no guarantees for the + * returned data in terms of ordering. + */ + postStateValidatorIdentities: Endpoint< + "POST", + StateArgs & { + /** An array of values, with each value either a hex encoded public key (any bytes48 with 0x prefix) or a validator index */ + validatorIds?: ValidatorId[]; + }, + {params: {state_id: string}; body: string[]}, + ValidatorIdentities, + ExecutionOptimisticAndFinalizedMeta + >; + /** * Get validator balances from state * Returns filterable list of validator balances. @@ -404,6 +434,28 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({ + params: {state_id: stateId.toString()}, + body: toValidatorIdsStr(validatorIds) || [], + }), + parseReqJson: ({params, body = []}) => ({ + stateId: params.state_id, + validatorIds: fromValidatorIdsStr(body), + }), + schema: { + params: {state_id: Schema.StringRequired}, + body: Schema.UintOrStringArray, + }, + }), + resp: { + data: ValidatorIdentitiesType, + meta: ExecutionOptimisticAndFinalizedCodec, + }, + }, getStateValidatorBalances: { url: "/eth/v1/beacon/states/{state_id}/validator_balances", method: "GET", diff --git a/packages/api/test/unit/beacon/oapiSpec.test.ts b/packages/api/test/unit/beacon/oapiSpec.test.ts index a84b2cc36767..89079cd0768c 100644 --- a/packages/api/test/unit/beacon/oapiSpec.test.ts +++ b/packages/api/test/unit/beacon/oapiSpec.test.ts @@ -21,9 +21,9 @@ import {testData as validatorTestData} from "./testData/validator.js"; // eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const version = "v2.6.0-alpha.1"; +const version = "v3.0.0-alpha.6"; const openApiFile: OpenApiFile = { - url: `https://raw.githubusercontent.com/nflaig/beacon-api-spec/main/${version}/beacon-node-oapi.json`, + url: `https://github.com/ethereum/beacon-APIs/releases/download/${version}/beacon-node-oapi.json`, filepath: path.join(__dirname, "../../../oapi-schemas/beacon-node-oapi.json"), version: RegExp(version), }; diff --git a/packages/api/test/unit/beacon/testData/beacon.ts b/packages/api/test/unit/beacon/testData/beacon.ts index b0e958f4bc58..23ab13147454 100644 --- a/packages/api/test/unit/beacon/testData/beacon.ts +++ b/packages/api/test/unit/beacon/testData/beacon.ts @@ -191,6 +191,13 @@ export const testData: GenericServerTestCases = { args: {stateId: "head", validatorIds: [pubkeyHex, 1300], statuses: ["active_ongoing"]}, res: {data: [validatorResponse], meta: {executionOptimistic: true, finalized: false}}, }, + postStateValidatorIdentities: { + args: {stateId: "head", validatorIds: [1300]}, + res: { + data: [{index: 1300, pubkey: ssz.BLSPubkey.defaultValue(), activationEpoch: 1}], + meta: {executionOptimistic: true, finalized: false}, + }, + }, getStateValidator: { args: {stateId: "head", validatorId: pubkeyHex}, res: {data: validatorResponse, meta: {executionOptimistic: true, finalized: false}}, diff --git a/packages/beacon-node/src/api/impl/beacon/state/index.ts b/packages/beacon-node/src/api/impl/beacon/state/index.ts index 77e2fd5aab46..a5e46a2da4c0 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/index.ts @@ -22,7 +22,8 @@ import { export function getBeaconStateApi({ chain, config, -}: Pick): ApplicationMethods { + logger, +}: Pick): ApplicationMethods { async function getState( stateId: routes.beacon.StateId ): Promise<{state: BeaconStateAllForks; executionOptimistic: boolean; finalized: boolean}> { @@ -98,6 +99,8 @@ export function getBeaconStateApi({ currentEpoch ); validatorResponses.push(validatorResponse); + } else { + logger.warn(resp.reason, {id}); } } return { @@ -130,6 +133,39 @@ export function getBeaconStateApi({ return this.getStateValidators(args, context); }, + async postStateValidatorIdentities({stateId, validatorIds = []}) { + const {state, executionOptimistic, finalized} = await getStateResponse(chain, stateId); + const {pubkey2index} = chain.getHeadState().epochCtx; + + let validatorIdentities: routes.beacon.ValidatorIdentities; + + if (validatorIds.length) { + validatorIdentities = []; + for (const id of validatorIds) { + const resp = getStateValidatorIndex(id, state, pubkey2index); + if (resp.valid) { + const index = resp.validatorIndex; + const {pubkey, activationEpoch} = state.validators.getReadonly(index); + validatorIdentities.push({index, pubkey, activationEpoch}); + } else { + logger.warn(resp.reason, {id}); + } + } + } else { + const validatorsArr = state.validators.getAllReadonlyValues(); + validatorIdentities = new Array(validatorsArr.length) as routes.beacon.ValidatorIdentities; + for (let i = 0; i < validatorsArr.length; i++) { + const {pubkey, activationEpoch} = validatorsArr[i]; + validatorIdentities[i] = {index: i, pubkey, activationEpoch}; + } + } + + return { + data: validatorIdentities, + meta: {executionOptimistic, finalized}, + }; + }, + async getStateValidator({stateId, validatorId}) { const {state, executionOptimistic, finalized} = await getStateResponse(chain, stateId); const {pubkey2index} = chain.getHeadState().epochCtx; From 13d1a378b831b9d0a3f3ced89e317aa45147023c Mon Sep 17 00:00:00 2001 From: twoeths Date: Mon, 30 Sep 2024 08:59:55 +0700 Subject: [PATCH 122/259] fix: n-historical-states state serialization panel (#7111) --- dashboards/lodestar_state_cache_regen.json | 79 ++++++++++++++-------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/dashboards/lodestar_state_cache_regen.json b/dashboards/lodestar_state_cache_regen.json index 426cde226022..1cca1d26c561 100644 --- a/dashboards/lodestar_state_cache_regen.json +++ b/dashboards/lodestar_state_cache_regen.json @@ -425,7 +425,32 @@ }, "mappings": [] }, - "overrides": [] + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "epochs_in-memory" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] }, "gridPos": { "h": 8, @@ -1325,30 +1350,6 @@ "value": "none" } ] - }, - { - "__systemRef": "hideSeriesFrom", - "matcher": { - "id": "byNames", - "options": { - "mode": "exclude", - "names": [ - "sec_from_slot" - ], - "prefix": "All except:", - "readOnly": true - } - }, - "properties": [ - { - "id": "custom.hideFrom", - "value": { - "legend": false, - "tooltip": false, - "viz": true - } - } - ] } ] }, @@ -1378,7 +1379,7 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "rate(lodestar_cp_state_cache_state_serialize_seconds_sum[$rate_interval])\n/\nrate(lodestar_cp_state_cache_state_serialize_seconds_count[$rate_interval])", + "expr": "rate(lodestar_state_serialize_seconds_sum{source=\"persistent_checkpoints_cache_state\"}[$rate_interval])\n/\nrate(lodestar_state_serialize_seconds_count{source=\"persistent_checkpoints_cache_state\"}[$rate_interval])", "hide": false, "instant": false, "legendFormat": "serialize_duration", @@ -1475,6 +1476,30 @@ "id": "unit" } ] + }, + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "reload_duration" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] } ] }, @@ -1618,7 +1643,7 @@ "options": { "mode": "exclude", "names": [ - "from_persistent" + "from_memory" ], "prefix": "All except:", "readOnly": true From d69d809e7ab5d5a2cf5030429e83b6af1d5af31a Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Sun, 29 Sep 2024 19:58:19 -0700 Subject: [PATCH 123/259] feat: update correlation penalty computation (#7071) * Update slashing calculation to be more aligned with spec style * Update calculation * Lint * Fix rounding issue * Update calculation * Enable slashing spec test * lint --- .../beacon-node/test/spec/utils/specTestIterator.ts | 2 -- .../state-transition/src/epoch/processSlashings.ts | 12 ++++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index bd5142627e3f..d8b4f9c0574c 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -66,8 +66,6 @@ export const defaultSkipOpts: SkipOpts = { /^capella\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, /^deneb\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, /^electra\/light_client\/single_merkle_proof\/BeaconBlockBody.*/, - // TODO Electra: slashings tests to be enabled in PR#7071 - /^electra\/epoch_processing\/slashings.*/, ], skippedTests: [], skippedRunners: ["merkle_proof", "networking"], diff --git a/packages/state-transition/src/epoch/processSlashings.ts b/packages/state-transition/src/epoch/processSlashings.ts index ba4b483dffc2..23ee815cabb3 100644 --- a/packages/state-transition/src/epoch/processSlashings.ts +++ b/packages/state-transition/src/epoch/processSlashings.ts @@ -50,6 +50,10 @@ export function processSlashings( totalBalanceByIncrement ); const increment = EFFECTIVE_BALANCE_INCREMENT; + + const penaltyPerEffectiveBalanceIncrement = Math.floor( + (adjustedTotalSlashingBalanceByIncrement * increment) / totalBalanceByIncrement + ); const penalties: number[] = []; const penaltiesByEffectiveBalanceIncrement = new Map(); @@ -57,8 +61,12 @@ export function processSlashings( const effectiveBalanceIncrement = effectiveBalanceIncrements[index]; let penalty = penaltiesByEffectiveBalanceIncrement.get(effectiveBalanceIncrement); if (penalty === undefined) { - const penaltyNumeratorByIncrement = effectiveBalanceIncrement * adjustedTotalSlashingBalanceByIncrement; - penalty = Math.floor(penaltyNumeratorByIncrement / totalBalanceByIncrement) * increment; + if (fork < ForkSeq.electra) { + const penaltyNumeratorByIncrement = effectiveBalanceIncrement * adjustedTotalSlashingBalanceByIncrement; + penalty = Math.floor(penaltyNumeratorByIncrement / totalBalanceByIncrement) * increment; + } else { + penalty = penaltyPerEffectiveBalanceIncrement * effectiveBalanceIncrement; + } penaltiesByEffectiveBalanceIncrement.set(effectiveBalanceIncrement, penalty); } From fe7e21be0459dfba49ebe04e5a3efc1b1ee836d4 Mon Sep 17 00:00:00 2001 From: twoeths Date: Mon, 30 Sep 2024 23:09:52 +0700 Subject: [PATCH 124/259] feat: use napi-rs pubkey-index-map (#7091) * feat: use napi-rs pubkey-index-map * fix: export toMemoryEfficientHexStr() * fix: state-transition CachedBeaconState unit test * chore: remove commented code --- packages/beacon-node/package.json | 1 + .../src/api/impl/beacon/state/index.ts | 3 +- .../src/api/impl/beacon/state/utils.ts | 5 +-- .../src/api/impl/validator/index.ts | 2 +- packages/beacon-node/src/chain/chain.ts | 2 +- .../historicalState/getHistoricalState.ts | 2 +- .../src/chain/historicalState/worker.ts | 8 ++--- packages/beacon-node/src/chain/interface.ts | 2 +- .../src/chain/rewards/attestationsRewards.ts | 3 +- .../updateUnfinalizedPubkeys.test.ts | 17 +++++---- .../unit/api/impl/beacon/state/utils.test.ts | 8 ++++- packages/beacon-node/test/utils/state.ts | 2 +- packages/state-transition/package.json | 1 + .../src/block/processConsolidationRequest.ts | 2 +- .../src/block/processDeposit.ts | 2 +- .../src/block/processWithdrawalRequest.ts | 2 +- .../state-transition/src/cache/epochCache.ts | 15 ++++---- .../state-transition/src/cache/pubkeyCache.ts | 21 +---------- .../src/cache/syncCommitteeCache.ts | 4 +-- packages/state-transition/src/index.ts | 2 +- packages/state-transition/test/perf/util.ts | 2 +- .../perf/util/loadState/loadState.test.ts | 3 +- .../test/unit/cachedBeaconState.test.ts | 4 +-- .../test/unit/upgradeState.test.ts | 2 +- .../test/unit/util/cachedBeaconState.test.ts | 3 +- packages/state-transition/test/utils/state.ts | 2 +- yarn.lock | 36 +++++++++++++++++++ 27 files changed, 94 insertions(+), 62 deletions(-) diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index f101206bfd9e..4deaf7c6ac16 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -105,6 +105,7 @@ "@chainsafe/prometheus-gc-stats": "^1.0.0", "@chainsafe/ssz": "^0.17.1", "@chainsafe/threads": "^1.11.1", + "@chainsafe/pubkey-index-map": "2.0.0", "@ethersproject/abi": "^5.7.0", "@fastify/bearer-auth": "^10.0.1", "@fastify/cors": "^10.0.1", diff --git a/packages/beacon-node/src/api/impl/beacon/state/index.ts b/packages/beacon-node/src/api/impl/beacon/state/index.ts index a5e46a2da4c0..669aaa9d1fb3 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/index.ts @@ -9,6 +9,7 @@ import { getRandaoMix, } from "@lodestar/state-transition"; import {EPOCHS_PER_HISTORICAL_VECTOR} from "@lodestar/params"; +import {fromHex} from "@lodestar/utils"; import {ApiError} from "../../errors.js"; import {ApiModules} from "../../types.js"; import { @@ -200,7 +201,7 @@ export function getBeaconStateApi({ } balances.push({index: id, balance: state.balances.get(id)}); } else { - const index = headState.epochCtx.pubkey2index.get(id); + const index = headState.epochCtx.pubkey2index.get(fromHex(id)); if (index != null && index <= state.validators.length) { balances.push({index, balance: state.balances.get(index)}); } diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index 40b1e2815263..de21c6a244ed 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -1,6 +1,7 @@ +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {routes} from "@lodestar/api"; import {FAR_FUTURE_EPOCH, GENESIS_SLOT} from "@lodestar/params"; -import {BeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; +import {BeaconStateAllForks} from "@lodestar/state-transition"; import {BLSPubkey, Epoch, phase0, RootHex, Slot, ValidatorIndex} from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; import {CheckpointWithHex, IForkChoice} from "@lodestar/fork-choice"; @@ -187,7 +188,7 @@ export function getStateValidatorIndex( // typeof id === Uint8Array const validatorIndex = pubkey2index.get(id); - if (validatorIndex === undefined) { + if (validatorIndex === null) { return {valid: false, code: 404, reason: "Validator pubkey not found in state"}; } if (validatorIndex >= state.validators.length) { diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 4876975c1bea..2347d7086d46 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -1359,7 +1359,7 @@ export function getValidatorApi( const filteredRegistrations = registrations.filter((registration) => { const {pubkey} = registration.message; const validatorIndex = headState.epochCtx.pubkey2index.get(pubkey); - if (validatorIndex === undefined) return false; + if (validatorIndex === null) return false; const validator = headState.validators.getReadonly(validatorIndex); const status = getValidatorStatus(validator, currentEpoch); diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 696f4bd51dc3..371f660abe2e 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -1,5 +1,6 @@ import path from "node:path"; import {CompositeTypeAny, TreeView, Type} from "@chainsafe/ssz"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import { BeaconStateAllForks, CachedBeaconStateAllForks, @@ -10,7 +11,6 @@ import { getEffectiveBalanceIncrementsZeroInactive, isCachedBeaconState, Index2PubkeyCache, - PubkeyIndexMap, EpochShuffling, computeEndSlotAtEpoch, computeAnchorCheckpoint, diff --git a/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts b/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts index ada4f3c284d7..1f352b3d683a 100644 --- a/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts +++ b/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts @@ -1,9 +1,9 @@ +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import { BeaconStateAllForks, CachedBeaconStateAllForks, DataAvailableStatus, ExecutionPayloadStatus, - PubkeyIndexMap, createCachedBeaconState, stateTransition, } from "@lodestar/state-transition"; diff --git a/packages/beacon-node/src/chain/historicalState/worker.ts b/packages/beacon-node/src/chain/historicalState/worker.ts index a07207cac5f5..2ea673d0faff 100644 --- a/packages/beacon-node/src/chain/historicalState/worker.ts +++ b/packages/beacon-node/src/chain/historicalState/worker.ts @@ -1,13 +1,9 @@ import worker from "node:worker_threads"; import {Transfer, expose} from "@chainsafe/threads/worker"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {createBeaconConfig, chainConfigFromJson} from "@lodestar/config"; import {getNodeLogger} from "@lodestar/logger/node"; -import { - EpochTransitionStep, - PubkeyIndexMap, - StateCloneSource, - StateHashTreeRootSource, -} from "@lodestar/state-transition"; +import {EpochTransitionStep, StateCloneSource, StateHashTreeRootSource} from "@lodestar/state-transition"; import {LevelDbController} from "@lodestar/db"; import {RegistryMetricCreator, collectNodeJSMetrics} from "../../metrics/index.js"; import {JobFnQueue} from "../../util/queue/fnQueue.js"; diff --git a/packages/beacon-node/src/chain/interface.ts b/packages/beacon-node/src/chain/interface.ts index 5185662eaa4f..531f60dc0e63 100644 --- a/packages/beacon-node/src/chain/interface.ts +++ b/packages/beacon-node/src/chain/interface.ts @@ -1,4 +1,5 @@ import {CompositeTypeAny, TreeView, Type} from "@chainsafe/ssz"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import { UintNum64, Root, @@ -21,7 +22,6 @@ import { CachedBeaconStateAllForks, EpochShuffling, Index2PubkeyCache, - PubkeyIndexMap, } from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; import {Logger} from "@lodestar/utils"; diff --git a/packages/beacon-node/src/chain/rewards/attestationsRewards.ts b/packages/beacon-node/src/chain/rewards/attestationsRewards.ts index e909e4b1b57e..70fb27de239a 100644 --- a/packages/beacon-node/src/chain/rewards/attestationsRewards.ts +++ b/packages/beacon-node/src/chain/rewards/attestationsRewards.ts @@ -24,6 +24,7 @@ import { isInInactivityLeak, } from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; +import {fromHex} from "@lodestar/utils"; export type AttestationsRewards = routes.beacon.AttestationsRewards; type IdealAttestationsReward = routes.beacon.IdealAttestationsReward; @@ -143,7 +144,7 @@ function computeTotalAttestationsRewardsAltair( const {flags} = transitionCache; const {epochCtx, config} = state; const validatorIndices = validatorIds - .map((id) => (typeof id === "number" ? id : epochCtx.pubkey2index.get(id))) + .map((id) => (typeof id === "number" ? id : epochCtx.pubkey2index.get(fromHex(id)))) .filter((index) => index !== undefined); // Validator indices to include in the result const inactivityPenaltyDenominator = config.INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT_ALTAIR; diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 46659ab3d287..eab66d2bee53 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -1,10 +1,11 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; -import {Map} from "immutable"; +import {Map as ImmutableMap} from "immutable"; import {toBufferBE} from "bigint-buffer"; import {digest} from "@chainsafe/as-sha256"; import {SecretKey} from "@chainsafe/blst"; -import {ssz} from "@lodestar/types"; -import {type CachedBeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; +import {ValidatorIndex, ssz} from "@lodestar/types"; +import {type CachedBeaconStateAllForks, toMemoryEfficientHexStr} from "@lodestar/state-transition"; import {bytesToBigInt, intToBytes} from "@lodestar/utils"; import {InMemoryCheckpointStateCache, BlockStateCacheImpl} from "../../../../src/chain/stateCache/index.js"; import {BlockStateCache} from "../../../../src/chain/stateCache/types.js"; @@ -31,7 +32,7 @@ describe("updateUnfinalizedPubkeys perf tests", function () { itBench({ id: `updateUnfinalizedPubkeys - updating ${numPubkeysToBeFinalized} pubkeys`, beforeEach: async () => { - baseState.epochCtx.unfinalizedPubkey2index = Map(unfinalizedPubkey2Index.map); + baseState.epochCtx.unfinalizedPubkey2index = ImmutableMap(unfinalizedPubkey2Index); baseState.epochCtx.pubkey2index = new PubkeyIndexMap(); baseState.epochCtx.index2pubkey = []; @@ -80,12 +81,14 @@ describe("updateUnfinalizedPubkeys perf tests", function () { }); } - function generatePubkey2Index(startIndex: number, endIndex: number): PubkeyIndexMap { - const pubkey2Index = new PubkeyIndexMap(); + type PubkeyHex = string; + + function generatePubkey2Index(startIndex: number, endIndex: number): Map { + const pubkey2Index = new Map(); const pubkeys = generatePubkeys(endIndex - startIndex); for (let i = startIndex; i < endIndex; i++) { - pubkey2Index.set(pubkeys[i], i); + pubkey2Index.set(toMemoryEfficientHexStr(pubkeys[i]), i); } return pubkey2Index; diff --git a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts index a6020c0a3c13..79a8f3383e5d 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts @@ -117,7 +117,13 @@ describe("beacon state api utils", function () { // "validator id not in state" expect(getStateValidatorIndex(String(state.validators.length), state, pubkey2index).valid).toBe(false); // "validator pubkey not in state" - expect(getStateValidatorIndex("0xabcd", state, pubkey2index).valid).toBe(false); + expect( + getStateValidatorIndex( + "0xa99af0913a2834ef4959637e8d7c4e17f0b63adc587d36ab43510452db3102d0771a4554ea4118a33913827d5ee80b76", + state, + pubkey2index + ).valid + ).toBe(false); }); it("should return valid: true on validator indices / pubkeys in the state", () => { diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index 49a27435bdd7..6ad85f3422f7 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -1,10 +1,10 @@ import {SecretKey} from "@chainsafe/blst"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {config as minimalConfig} from "@lodestar/config/default"; import { BeaconStateAllForks, CachedBeaconStateAllForks, createCachedBeaconState, - PubkeyIndexMap, CachedBeaconStateBellatrix, BeaconStateBellatrix, CachedBeaconStateElectra, diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 2df87a522a63..6816e5679cf5 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -66,6 +66,7 @@ "@lodestar/config": "^1.22.0", "@lodestar/params": "^1.22.0", "@lodestar/types": "^1.22.0", + "@chainsafe/pubkey-index-map": "2.0.0", "@lodestar/utils": "^1.22.0", "bigint-buffer": "^1.1.5", "immutable": "^4.3.2" diff --git a/packages/state-transition/src/block/processConsolidationRequest.ts b/packages/state-transition/src/block/processConsolidationRequest.ts index 71b85e927336..691ecd5eca0b 100644 --- a/packages/state-transition/src/block/processConsolidationRequest.ts +++ b/packages/state-transition/src/block/processConsolidationRequest.ts @@ -24,7 +24,7 @@ export function processConsolidationRequest( const sourceIndex = state.epochCtx.getValidatorIndex(sourcePubkey); const targetIndex = state.epochCtx.getValidatorIndex(targetPubkey); - if (sourceIndex === undefined || targetIndex === undefined) { + if (sourceIndex === null || targetIndex === null) { return; } diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 7e343d7fc33d..ee75dff0dfd1 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -65,7 +65,7 @@ export function applyDeposit( const {pubkey, withdrawalCredentials, amount} = deposit; const cachedIndex = epochCtx.getValidatorIndex(pubkey); - if (cachedIndex === undefined || !Number.isSafeInteger(cachedIndex) || cachedIndex >= validators.length) { + if (cachedIndex === null || !Number.isSafeInteger(cachedIndex) || cachedIndex >= validators.length) { if (isValidDepositSignature(config, pubkey, withdrawalCredentials, amount, deposit.signature)) { addValidatorToRegistry(fork, state, pubkey, withdrawalCredentials, amount); } diff --git a/packages/state-transition/src/block/processWithdrawalRequest.ts b/packages/state-transition/src/block/processWithdrawalRequest.ts index 0587a06ee179..e8a64ec63e41 100644 --- a/packages/state-transition/src/block/processWithdrawalRequest.ts +++ b/packages/state-transition/src/block/processWithdrawalRequest.ts @@ -33,7 +33,7 @@ export function processWithdrawalRequest( // bail out if validator is not in beacon state // note that we don't need to check for 6110 unfinalized vals as they won't be eligible for withdraw/exit anyway const validatorIndex = pubkey2index.get(withdrawalRequest.validatorPubkey); - if (validatorIndex === undefined) { + if (validatorIndex === null) { return; } diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 3783c7f91f0d..5e901e33d992 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -1,5 +1,6 @@ import {PublicKey} from "@chainsafe/blst"; import * as immutable from "immutable"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import { BLSSignature, CommitteeIndex, @@ -53,7 +54,6 @@ import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from " import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; import { Index2PubkeyCache, - PubkeyIndexMap, UnfinalizedPubkeyIndexMap, syncPubkeys, toMemoryEfficientHexStr, @@ -1023,9 +1023,9 @@ export class EpochCache { return this.index2pubkey[index]; } - getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { + getValidatorIndex(pubkey: Uint8Array): ValidatorIndex | null { if (this.isPostElectra()) { - return this.pubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); + return this.pubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)) ?? null; } else { return this.pubkey2index.get(pubkey); } @@ -1059,17 +1059,20 @@ export class EpochCache { * Add finalized validator index and pubkey into finalized cache. * Since addFinalizedPubkey() primarily takes pubkeys from unfinalized cache, it can take pubkey hex string directly */ - addFinalizedPubkey(index: ValidatorIndex, pubkey: PubkeyHex | Uint8Array, metrics?: EpochCacheMetrics): void { + addFinalizedPubkey(index: ValidatorIndex, pubkeyOrHex: PubkeyHex | Uint8Array, metrics?: EpochCacheMetrics): void { + const pubkey = typeof pubkeyOrHex === "string" ? fromHex(pubkeyOrHex) : pubkeyOrHex; const existingIndex = this.pubkey2index.get(pubkey); - if (existingIndex !== undefined) { + if (existingIndex !== null) { if (existingIndex === index) { // Repeated insert. metrics?.finalizedPubkeyDuplicateInsert.inc(); return; } else { // attempt to insert the same pubkey with different index, should never happen. - throw Error("inserted existing pubkey into finalizedPubkey2index cache with a different index"); + throw Error( + `inserted existing pubkey into finalizedPubkey2index cache with a different index, index=${index} priorIndex=${existingIndex}` + ); } } diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 44fe6df45592..f96436ec14f4 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -1,4 +1,5 @@ import {PublicKey} from "@chainsafe/blst"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import * as immutable from "immutable"; import {ValidatorIndex, phase0} from "@lodestar/types"; @@ -39,26 +40,6 @@ export function newUnfinalizedPubkeyIndexMap(): UnfinalizedPubkeyIndexMap { return immutable.Map(); } -export class PubkeyIndexMap { - // We don't really need the full pubkey. We could just use the first 20 bytes like an Ethereum address - readonly map = new Map(); - - get size(): number { - return this.map.size; - } - - /** - * Must support reading with string for API support where pubkeys are already strings - */ - get(key: Uint8Array | PubkeyHex): ValidatorIndex | undefined { - return this.map.get(toMemoryEfficientHexStr(key)); - } - - set(key: Uint8Array | PubkeyHex, value: ValidatorIndex): void { - this.map.set(toMemoryEfficientHexStr(key), value); - } -} - /** * Checks the pubkey indices against a state and adds missing pubkeys * diff --git a/packages/state-transition/src/cache/syncCommitteeCache.ts b/packages/state-transition/src/cache/syncCommitteeCache.ts index b0a93f121369..b9a65302c3e2 100644 --- a/packages/state-transition/src/cache/syncCommitteeCache.ts +++ b/packages/state-transition/src/cache/syncCommitteeCache.ts @@ -1,7 +1,7 @@ import {CompositeViewDU} from "@chainsafe/ssz"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {ssz, ValidatorIndex} from "@lodestar/types"; import {toPubkeyHex} from "@lodestar/utils"; -import {PubkeyIndexMap} from "./pubkeyCache.js"; type SyncComitteeValidatorIndexMap = Map; @@ -82,7 +82,7 @@ function computeSyncCommitteeIndices( const pubkeys = syncCommittee.pubkeys.getAllReadonly(); for (const pubkey of pubkeys) { const validatorIndex = pubkey2index.get(pubkey); - if (validatorIndex === undefined) { + if (validatorIndex === null) { throw Error(`SyncCommittee pubkey is unknown ${toPubkeyHex(pubkey)}`); } diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index 4ed801e3c490..600bbf173462 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -41,11 +41,11 @@ export { EpochCacheError, EpochCacheErrorCode, } from "./cache/epochCache.js"; +export {toMemoryEfficientHexStr} from "./cache/pubkeyCache.js"; export {type EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js"; // Aux data-structures export { - PubkeyIndexMap, type Index2PubkeyCache, type UnfinalizedPubkeyIndexMap, newUnfinalizedPubkeyIndexMap, diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index f3c2eaef91e5..c764e2d039f9 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -1,5 +1,6 @@ import {BitArray, fromHexString} from "@chainsafe/ssz"; import {PublicKey, SecretKey} from "@chainsafe/blst"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {phase0, ssz, Slot, BeaconState} from "@lodestar/types"; import {config} from "@lodestar/config/default"; import {createBeaconConfig, createChainForkConfig} from "@lodestar/config"; @@ -17,7 +18,6 @@ import { interopSecretKey, computeEpochAtSlot, getActiveValidatorIndices, - PubkeyIndexMap, newFilledArray, createCachedBeaconState, computeCommitteeCount, diff --git a/packages/state-transition/test/perf/util/loadState/loadState.test.ts b/packages/state-transition/test/perf/util/loadState/loadState.test.ts index 25b43e242d02..9f6175e95684 100644 --- a/packages/state-transition/test/perf/util/loadState/loadState.test.ts +++ b/packages/state-transition/test/perf/util/loadState/loadState.test.ts @@ -1,8 +1,9 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {PublicKey} from "@chainsafe/blst"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {loadState} from "../../../../src/util/loadState/loadState.js"; import {createCachedBeaconState} from "../../../../src/cache/stateCache.js"; -import {Index2PubkeyCache, PubkeyIndexMap} from "../../../../src/cache/pubkeyCache.js"; +import {Index2PubkeyCache} from "../../../../src/cache/pubkeyCache.js"; import {generatePerfTestCachedStateAltair} from "../../util.js"; /** diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index 092dda321610..96c026340143 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -1,11 +1,11 @@ import {fromHexString} from "@chainsafe/ssz"; import {describe, it, expect} from "vitest"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {ssz} from "@lodestar/types"; import {toHexString} from "@lodestar/utils"; import {config as defaultConfig} from "@lodestar/config/default"; import {createBeaconConfig, createChainForkConfig} from "@lodestar/config"; import {createCachedBeaconStateTest} from "../utils/state.js"; -import {PubkeyIndexMap} from "../../src/cache/pubkeyCache.js"; import {createCachedBeaconState, loadCachedBeaconState} from "../../src/cache/stateCache.js"; import {interopPubkeysCached} from "../utils/interop.js"; import {modifyStateSameValidator, newStateWithValidators} from "../utils/capella.js"; @@ -83,7 +83,7 @@ describe("CachedBeaconState", () => { expect(state1.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); expect(state2.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); - expect(state1.epochCtx.getValidatorIndex(pubkey2)).toBe(undefined); + expect(state1.epochCtx.getValidatorIndex(pubkey2)).toBe(null); expect(state2.epochCtx.getValidatorIndex(pubkey2)).toBe(index2); }); diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index df9b052542f9..301cb105dc98 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -1,4 +1,5 @@ import {expect, describe, it} from "vitest"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {ssz} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; import {createBeaconConfig, ChainForkConfig, createChainForkConfig} from "@lodestar/config"; @@ -7,7 +8,6 @@ import {config as chainConfig} from "@lodestar/config/default"; import {upgradeStateToDeneb} from "../../src/slot/upgradeStateToDeneb.js"; import {upgradeStateToElectra} from "../../src/slot/upgradeStateToElectra.js"; import {createCachedBeaconState} from "../../src/cache/stateCache.js"; -import {PubkeyIndexMap} from "../../src/cache/pubkeyCache.js"; describe("upgradeState", () => { it("upgradeStateToDeneb", () => { diff --git a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts index 654e0752adb8..c85a8c7a2ffd 100644 --- a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts @@ -1,8 +1,9 @@ import {describe, it} from "vitest"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; -import {createCachedBeaconState, PubkeyIndexMap} from "../../../src/index.js"; +import {createCachedBeaconState} from "../../../src/index.js"; describe("CachedBeaconState", () => { it("Create empty CachedBeaconState", () => { diff --git a/packages/state-transition/test/utils/state.ts b/packages/state-transition/test/utils/state.ts index 29a1f98b5562..9a79faf74480 100644 --- a/packages/state-transition/test/utils/state.ts +++ b/packages/state-transition/test/utils/state.ts @@ -1,3 +1,4 @@ +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {config as minimalConfig} from "@lodestar/config/default"; import { EPOCHS_PER_HISTORICAL_VECTOR, @@ -18,7 +19,6 @@ import { CachedBeaconStateAllForks, BeaconStateAllForks, createCachedBeaconState, - PubkeyIndexMap, } from "../../src/index.js"; import {BeaconStateCache} from "../../src/cache/stateCache.js"; import {EpochCacheOpts} from "../../src/cache/epochCache.js"; diff --git a/yarn.lock b/yarn.lock index f546d770acd8..a96092ec2fff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -586,6 +586,42 @@ resolved "https://registry.yarnpkg.com/@chainsafe/prometheus-gc-stats/-/prometheus-gc-stats-1.0.2.tgz#585f8f1555251db156d7e50ef8c86dd4f3e78f70" integrity sha512-h3mFKduSX85XMVbOdWOYvx9jNq99jGcRVNyW5goGOqju1CsI+ZJLhu5z4zBb/G+ksL0R4uLVulu/mIMe7Y0rNg== +"@chainsafe/pubkey-index-map-darwin-arm64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/pubkey-index-map-darwin-arm64/-/pubkey-index-map-darwin-arm64-2.0.0.tgz#e468e772787f2411ecab8e8316da6c801356b72d" + integrity sha512-7eROFdQvwN1b0zJy0YJd1wBSv8j+Sp8tc3HsyaLQvjX7w93LcPPe+2Y5QpMkECBFzD2BcvKFpYxIvkDzV2v8rw== + +"@chainsafe/pubkey-index-map-darwin-x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/pubkey-index-map-darwin-x64/-/pubkey-index-map-darwin-x64-2.0.0.tgz#995755f71bcb49e5393a6af122c11a850aef4ce4" + integrity sha512-HfKIV83Y+AOugw0jaeUIHqe4Ikfwo47baFg97fpdcpUwPfWnw4Blej5C1zAyEX2IuUo2S1D450neTBSUgSdNCA== + +"@chainsafe/pubkey-index-map-linux-arm64-gnu@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/pubkey-index-map-linux-arm64-gnu/-/pubkey-index-map-linux-arm64-gnu-2.0.0.tgz#0c25ffb451d9861515e26e68006aa08e18ebc42d" + integrity sha512-t7Tdy+m9lZF2gqs0LmxFTAztNe6tDuSxje0xS8LTYanBSWQ6ADbWjTxcp/63yBbIYGzncigePZG2iis9nxB95Q== + +"@chainsafe/pubkey-index-map-linux-x64-gnu@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/pubkey-index-map-linux-x64-gnu/-/pubkey-index-map-linux-x64-gnu-2.0.0.tgz#26c3628faaeb1ef9b47952cc03ae209d7e9656d8" + integrity sha512-1DKoITe7ZwjClhCBpIZq7SOIOJbUNLxgsFuV7e0ZcBq+tz5UqhKB8SSRzNn7THoo+XRg1mJiDyFPzDKGxHxRkg== + +"@chainsafe/pubkey-index-map-win32-x64-msvc@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/pubkey-index-map-win32-x64-msvc/-/pubkey-index-map-win32-x64-msvc-2.0.0.tgz#0e35c67ed9dcaaee6ff9e582ed6a733d852473e9" + integrity sha512-hnEZBtTFxTl52lytogexOtzqPQyUKKB28mLbLTZnl2OicsEfNcczJpgF6o1uQ0O0zktAn/m1Tc6/iHmQg2VuhQ== + +"@chainsafe/pubkey-index-map@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/pubkey-index-map/-/pubkey-index-map-2.0.0.tgz#a8262b353e8335e9acf5e750353a53c55e5cf9be" + integrity sha512-2mVvWrHGApF3mPS7ecp8k3dI/C3QF5824bpQNSRWDsmZEU9H3HzITIj256v14QiB+22MIitpWkBc6hl2bjhJ+Q== + optionalDependencies: + "@chainsafe/pubkey-index-map-darwin-arm64" "2.0.0" + "@chainsafe/pubkey-index-map-darwin-x64" "2.0.0" + "@chainsafe/pubkey-index-map-linux-arm64-gnu" "2.0.0" + "@chainsafe/pubkey-index-map-linux-x64-gnu" "2.0.0" + "@chainsafe/pubkey-index-map-win32-x64-msvc" "2.0.0" + "@chainsafe/ssz@^0.11.1": version "0.11.1" resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.11.1.tgz#d4aec883af2ec5196ae67b96242c467da20b2476" From c4952eef7ee2e362e08a313c128e22e394bc44e0 Mon Sep 17 00:00:00 2001 From: twoeths Date: Tue, 1 Oct 2024 21:29:22 +0700 Subject: [PATCH 125/259] fix: adjust n-historical-states param (#7104) * fix: default params of n-historical-states config * chore: improve log * feat: enable nHistoricalStates by default * chore: fix typo in log --- packages/beacon-node/src/chain/options.ts | 2 +- packages/beacon-node/src/chain/regen/regen.ts | 2 +- .../chain/stateCache/fifoBlockStateCache.ts | 9 +++++-- .../stateCache/persistentCheckpointsCache.ts | 7 +++--- .../src/network/processor/gossipHandlers.ts | 24 ++++++++++--------- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/packages/beacon-node/src/chain/options.ts b/packages/beacon-node/src/chain/options.ts index 7c7cfcdde75b..bc2b73256272 100644 --- a/packages/beacon-node/src/chain/options.ts +++ b/packages/beacon-node/src/chain/options.ts @@ -111,7 +111,7 @@ export const defaultChainOptions: IChainOptions = { // batching too much may block the I/O thread so if useWorker=false, suggest this value to be 32 // since this batch attestation work is designed to work with useWorker=true, make this the lowest value minSameMessageSignatureSetsToBatch: 2, - nHistoricalStates: false, + nHistoricalStates: true, nHistoricalStatesFileDataStore: false, maxBlockStates: DEFAULT_MAX_BLOCK_STATES, maxCPStateEpochsInMemory: DEFAULT_MAX_CP_STATE_EPOCHS_IN_MEMORY, diff --git a/packages/beacon-node/src/chain/regen/regen.ts b/packages/beacon-node/src/chain/regen/regen.ts index 08fda70d9184..7c663c6e0d3d 100644 --- a/packages/beacon-node/src/chain/regen/regen.ts +++ b/packages/beacon-node/src/chain/regen/regen.ts @@ -218,7 +218,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { blockPromises[i] = this.modules.db.block.get(fromHex(protoBlock.blockRoot)); } - const logCtx = {stateRoot, replaySlots: replaySlots.join(",")}; + const logCtx = {stateRoot, caller, replaySlots: replaySlots.join(",")}; this.modules.logger.debug("Replaying blocks to get state", logCtx); const loadBlocksTimer = this.modules.metrics?.regenGetState.loadBlocks.startTimer({caller}); diff --git a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts index d38fc323174c..7766daf3c5b3 100644 --- a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts +++ b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts @@ -13,9 +13,14 @@ export type FIFOBlockStateCacheOpts = { }; /** - * Regen state if there's a reorg distance > 32 slots. + * Given `maxSkipSlots` = 32 and `DEFAULT_EARLIEST_PERMISSIBLE_SLOT_DISTANCE` = 32, lodestar doesn't need to + * reload states in order to process a gossip block. + * + * |-----------------------------------------------|-----------------------------------------------| + * maxSkipSlots DEFAULT_EARLIEST_PERMISSIBLE_SLOT_DISTANCE ^ + * clock slot */ -export const DEFAULT_MAX_BLOCK_STATES = 32; +export const DEFAULT_MAX_BLOCK_STATES = 64; /** * New implementation of BlockStateCache that keeps the most recent n states consistently diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 07c96f224bee..0719efcfd309 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -53,10 +53,11 @@ type CacheItem = InMemoryCacheItem | PersistedCacheItem; type LoadedStateBytesData = {persistedKey: DatastoreKey; stateBytes: Uint8Array}; /** - * Before n-historical states, lodestar keeps mostly 3 states in memory with 1 finalized state - * Since Jan 2024, lodestar stores the finalized state in disk and keeps up to 2 epochs in memory + * Before n-historical states, lodestar keeps all checkpoint states since finalized + * Since Sep 2024, lodestar stores 3 most recent checkpoint states in memory and the rest on disk. The finalized state + * may not be available in memory, and stay on disk instead. */ -export const DEFAULT_MAX_CP_STATE_EPOCHS_IN_MEMORY = 2; +export const DEFAULT_MAX_CP_STATE_EPOCHS_IN_MEMORY = 3; /** * An implementation of CheckpointStateCache that keep up to n epoch checkpoint states in memory and persist the rest to disk diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index 9e6f08a803c1..8df9f7b78126 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -144,6 +144,18 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler const blockInputMeta = config.getForkSeq(signedBlock.message.slot) >= ForkSeq.deneb ? blockInputRes.blockInputMeta : {}; + const logCtx = { + slot: slot, + root: blockHex, + currentSlot: chain.clock.currentSlot, + peerId: peerIdStr, + delaySec, + ...blockInputMeta, + recvToValLatency, + }; + + logger.debug("Received gossip block", {...logCtx}); + try { await validateGossipBlock(config, chain, signedBlock, fork); @@ -153,17 +165,7 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler metrics?.gossipBlock.gossipValidation.recvToValidation.observe(recvToValidation); metrics?.gossipBlock.gossipValidation.validationTime.observe(validationTime); - logger.debug("Received gossip block", { - slot: slot, - root: blockHex, - curentSlot: chain.clock.currentSlot, - peerId: peerIdStr, - delaySec, - ...blockInputMeta, - recvToValLatency, - recvToValidation, - validationTime, - }); + logger.debug("Validated gossip block", {...logCtx, recvToValidation, validationTime}); return blockInput; } catch (e) { From b457778eefb31ed4286a9da9597d51a0818b0f79 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 2 Oct 2024 14:05:16 +0100 Subject: [PATCH 126/259] feat: allow to configure api client when initializing light client (#7121) --- packages/light-client/README.md | 6 +++--- packages/light-client/src/utils/api.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/light-client/README.md b/packages/light-client/README.md index cd3a0265008a..0323e8fc4326 100644 --- a/packages/light-client/README.md +++ b/packages/light-client/README.md @@ -62,7 +62,7 @@ import { const config = getChainForkConfigFromNetwork("sepolia"); const logger = getConsoleLogger({logDebug: Boolean(process.env.DEBUG)}); -const api = getApiFromUrl({urls: ["https://lodestar-sepolia.chainsafe.io"]}, {config}); +const api = getApiFromUrl("https://lodestar-sepolia.chainsafe.io", "sepolia"); const lightclient = await Lightclient.initializeFromCheckpointRoot({ config, @@ -82,11 +82,11 @@ await lightclient.start(); logger.info("Lightclient synced"); lightclient.emitter.on(LightclientEvent.lightClientFinalityHeader, async (finalityUpdate) => { - logger.info(finalityUpdate); + logger.info("Received finality update", {slot: finalityUpdate.beacon.slot}); }); lightclient.emitter.on(LightclientEvent.lightClientOptimisticHeader, async (optimisticUpdate) => { - logger.info(optimisticUpdate); + logger.info("Received optimistic update", {slot: optimisticUpdate.beacon.slot}); }); ``` diff --git a/packages/light-client/src/utils/api.ts b/packages/light-client/src/utils/api.ts index 7947aa96dd3e..6ccb187052e1 100644 --- a/packages/light-client/src/utils/api.ts +++ b/packages/light-client/src/utils/api.ts @@ -1,13 +1,13 @@ -import {getClient, ApiClient} from "@lodestar/api"; +import {getClient, ApiClient, ApiRequestInit} from "@lodestar/api"; import {ChainForkConfig, createChainForkConfig} from "@lodestar/config"; import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; -export function getApiFromUrl(url: string, network: NetworkName): ApiClient { +export function getApiFromUrl(url: string, network: NetworkName, init?: ApiRequestInit): ApiClient { 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])}); + return getClient({urls: [url], globalInit: init}, {config: createChainForkConfig(networksChainConfig[network])}); } export function getChainForkConfigFromNetwork(network: NetworkName): ChainForkConfig { From bf4a25f0219481d176996b81206b0ca66f971aba Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 2 Oct 2024 16:24:08 +0100 Subject: [PATCH 127/259] fix: update HTTP error response format to be spec compliant (#7110) * fix: update HTTP error response format to be spec compliant * Fix error assertions * Remove group tag from keymanager option * Fix body has already been read * Assert deepEqual --- packages/beacon-node/src/api/rest/base.ts | 38 +++++++++++++++++-- packages/beacon-node/src/api/rest/index.ts | 1 + packages/cli/src/cmds/dev/options.ts | 4 ++ packages/cli/src/cmds/validator/handler.ts | 1 + .../src/cmds/validator/keymanager/server.ts | 1 + packages/cli/src/cmds/validator/options.ts | 6 +++ .../cli/src/options/beaconNodeOptions/api.ts | 9 +++++ packages/cli/test/sim/endpoints.test.ts | 16 +++++++- .../unit/options/beaconNodeOptions.test.ts | 2 + 9 files changed, 74 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/src/api/rest/base.ts b/packages/beacon-node/src/api/rest/base.ts index 5f191bf76beb..e8ea85f67af5 100644 --- a/packages/beacon-node/src/api/rest/base.ts +++ b/packages/beacon-node/src/api/rest/base.ts @@ -15,6 +15,7 @@ export type RestApiServerOpts = { bearerToken?: string; headerLimit?: number; bodyLimit?: number; + stacktraces?: boolean; swaggerUI?: boolean; }; @@ -29,11 +30,27 @@ export type RestApiServerMetrics = SocketMetrics & { errors: Gauge<{operationId: string}>; }; +/** + * Error response body format as defined in beacon-api spec + * + * See https://github.com/ethereum/beacon-APIs/blob/v2.5.0/types/http.yaml + */ +type ErrorResponse = { + code: number; + message: string; + stacktraces?: 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; +/** + * Error code used by Fastify if JSON schema validation failed + */ +const SCHEMA_VALIDATION_ERROR_CODE = errorCodes.FST_ERR_VALIDATION().code; + /** * REST API powered by `fastify` server. */ @@ -71,15 +88,30 @@ export class RestApiServer { // To parse our ApiError -> statusCode server.setErrorHandler((err, _req, res) => { + const stacktraces = opts.stacktraces ? err.stack?.split("\n") : undefined; if (err.validation) { - void res.status(400).send(err.validation); + const {instancePath, message} = err.validation[0]; + const payload: ErrorResponse = { + code: err.statusCode ?? 400, + message: `${instancePath.substring(instancePath.lastIndexOf("/") + 1)} ${message}`, + stacktraces, + }; + void res.status(400).send(payload); } else { // Convert our custom ApiError into status code const statusCode = err instanceof ApiError ? err.statusCode : 500; - void res.status(statusCode).send(err); + const payload: ErrorResponse = {code: statusCode, message: err.message, stacktraces}; + void res.status(statusCode).send(payload); } }); + server.setNotFoundHandler((req, res) => { + const message = `Route ${req.raw.method}:${req.raw.url} not found`; + this.logger.warn(message); + const payload: ErrorResponse = {code: 404, message}; + void res.code(404).send(payload); + }); + if (opts.cors) { void server.register(fastifyCors, {origin: opts.cors}); } @@ -127,7 +159,7 @@ export class RestApiServer { const operationId = getOperationId(req); - if (err instanceof ApiError || err.code === INVALID_MEDIA_TYPE_CODE) { + if (err instanceof ApiError || [INVALID_MEDIA_TYPE_CODE, SCHEMA_VALIDATION_ERROR_CODE].includes(err.code)) { this.logger.warn(`Req ${req.id} ${operationId} failed`, {reason: err.message}); } else { this.logger.error(`Req ${req.id} ${operationId} error`, {}, err); diff --git a/packages/beacon-node/src/api/rest/index.ts b/packages/beacon-node/src/api/rest/index.ts index e27ed6bd9139..6beaf061588c 100644 --- a/packages/beacon-node/src/api/rest/index.ts +++ b/packages/beacon-node/src/api/rest/index.ts @@ -22,6 +22,7 @@ export const beaconRestApiServerOpts: BeaconRestApiServerOpts = { cors: "*", // beacon -> validator API is trusted, and for large amounts of keys the payload is multi-MB bodyLimit: 20 * 1024 * 1024, // 20MB for big block + blobs + stacktraces: false, }; export type BeaconRestApiServerModules = RestApiServerModules & { diff --git a/packages/cli/src/cmds/dev/options.ts b/packages/cli/src/cmds/dev/options.ts index c484150e58d7..5286b81729c6 100644 --- a/packages/cli/src/cmds/dev/options.ts +++ b/packages/cli/src/cmds/dev/options.ts @@ -90,6 +90,10 @@ const externalOptionsOverrides: Partial = { @@ -141,6 +142,11 @@ export const keymanagerOptions: CliCommandOptions = { type: "number", description: "Defines the maximum payload, in bytes, the server is allowed to accept", }, + "keymanager.stacktraces": { + hidden: true, + type: "boolean", + description: "Return stacktraces in HTTP error responses", + }, }; export const validatorOptions: CliCommandOptions = { diff --git a/packages/cli/src/options/beaconNodeOptions/api.ts b/packages/cli/src/options/beaconNodeOptions/api.ts index 996136f262ec..bed0105fd944 100644 --- a/packages/cli/src/options/beaconNodeOptions/api.ts +++ b/packages/cli/src/options/beaconNodeOptions/api.ts @@ -12,6 +12,7 @@ export type ApiArgs = { "rest.port": number; "rest.headerLimit"?: number; "rest.bodyLimit"?: number; + "rest.stacktraces"?: boolean; "rest.swaggerUI"?: boolean; }; @@ -26,6 +27,7 @@ export function parseArgs(args: ApiArgs): IBeaconNodeOptions["api"] { port: args["rest.port"], headerLimit: args["rest.headerLimit"], bodyLimit: args["rest.bodyLimit"], + stacktraces: args["rest.stacktraces"], swaggerUI: args["rest.swaggerUI"], }, }; @@ -92,6 +94,13 @@ export const options: CliCommandOptions = { description: "Defines the maximum payload, in bytes, the server is allowed to accept", }, + "rest.stacktraces": { + hidden: true, + type: "boolean", + description: "Return stacktraces in HTTP error responses", + group: "api", + }, + "rest.swaggerUI": { type: "boolean", description: "Enable Swagger UI for API exploration at http://{address}:{port}/documentation", diff --git a/packages/cli/test/sim/endpoints.test.ts b/packages/cli/test/sim/endpoints.test.ts index a42b9568f9a3..b276ad4787c6 100644 --- a/packages/cli/test/sim/endpoints.test.ts +++ b/packages/cli/test/sim/endpoints.test.ts @@ -2,7 +2,7 @@ import path from "node:path"; import assert from "node:assert"; import {toHexString} from "@chainsafe/ssz"; -import {routes} from "@lodestar/api"; +import {routes, fetch} from "@lodestar/api"; import {Simulation} from "../utils/crucible/simulation.js"; import {BeaconClient, ExecutionClient} from "../utils/crucible/interfaces.js"; import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js"; @@ -105,6 +105,20 @@ await env.tracker.assert( } ); +await env.tracker.assert("should return HTTP error responses in a spec compliant format", async () => { + // ApiError with status 400 is thrown by handler + const res1 = await node.api.beacon.getStateValidator({stateId: "current", validatorId: 1}); + assert.deepEqual(JSON.parse(await res1.errorBody()), {code: 400, message: "Invalid block id 'current'"}); + + // JSON schema validation failed + const res2 = await node.api.beacon.getPoolAttestationsV2({slot: "current" as unknown as number, committeeIndex: 123}); + assert.deepEqual(JSON.parse(await res2.errorBody()), {code: 400, message: "slot must be integer"}); + + // Route does not exist + const res3 = await fetch(`${node.restPublicUrl}/not/implemented/route`); + assert.deepEqual(JSON.parse(await res3.text()), {code: 404, message: "Route GET:/not/implemented/route not found"}); +}); + await env.tracker.assert("BN Not Synced", async () => { const expectedSyncStatus: routes.node.SyncingStatus = { headSlot: 2, diff --git a/packages/cli/test/unit/options/beaconNodeOptions.test.ts b/packages/cli/test/unit/options/beaconNodeOptions.test.ts index d74ae73b966f..f873102edf74 100644 --- a/packages/cli/test/unit/options/beaconNodeOptions.test.ts +++ b/packages/cli/test/unit/options/beaconNodeOptions.test.ts @@ -17,6 +17,7 @@ describe("options / beaconNodeOptions", () => { "rest.port": 7654, "rest.headerLimit": 16384, "rest.bodyLimit": 30e6, + "rest.stacktraces": true, "chain.blsVerifyAllMultiThread": true, "chain.blsVerifyAllMainThread": true, @@ -122,6 +123,7 @@ describe("options / beaconNodeOptions", () => { port: 7654, headerLimit: 16384, bodyLimit: 30e6, + stacktraces: true, }, }, chain: { From a19655d95b02861840430a676cebaa9e79ec023c Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 2 Oct 2024 17:11:06 +0100 Subject: [PATCH 128/259] fix: update multiple api errors to be spec compliant (#7113) * fix: update HTTP error response format to be spec compliant * Fix error assertions * Remove group tag from keymanager option * Fix body has already been read * Assert deepEqual * fix: update multiple api errors to be spec compliant * Reorder test cases * Update res numbering * Use strict deep equal --- packages/api/src/utils/client/response.ts | 5 ++- .../src/api/impl/beacon/pool/index.ts | 32 ++++++++----------- packages/beacon-node/src/api/impl/errors.ts | 13 ++++++++ packages/beacon-node/src/api/rest/base.ts | 14 +++++++- packages/cli/test/sim/endpoints.test.ts | 24 +++++++++++--- 5 files changed, 63 insertions(+), 25 deletions(-) diff --git a/packages/api/src/utils/client/response.ts b/packages/api/src/utils/client/response.ts index ed008273588a..fdcb2afda943 100644 --- a/packages/api/src/utils/client/response.ts +++ b/packages/api/src/utils/client/response.ts @@ -189,8 +189,11 @@ export class ApiResponse extends Response { private getErrorMessage(): string { const errBody = this.resolvedErrorBody(); try { - const errJson = JSON.parse(errBody) as {message?: string}; + const errJson = JSON.parse(errBody) as {message?: string; failures?: {message: string}[]}; if (errJson.message) { + if (errJson.failures) { + return `${errJson.message}\n` + errJson.failures.map((e) => e.message).join("\n"); + } return errJson.message; } else { return errBody; diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index 398238aa2508..e01b172f1e72 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -16,7 +16,7 @@ import { SyncCommitteeError, } from "../../../../chain/errors/index.js"; import {validateGossipFnRetryUnknownRoot} from "../../../../network/processor/gossipHandlers.js"; -import {ApiError} from "../../errors.js"; +import {ApiError, FailureList, IndexedError} from "../../errors.js"; export function getBeaconPoolApi({ chain, @@ -88,7 +88,7 @@ export function getBeaconPoolApi({ async submitPoolAttestationsV2({signedAttestations}) { const seenTimestampSec = Date.now() / 1000; - const errors: Error[] = []; + const failures: FailureList = []; await Promise.all( signedAttestations.map(async (attestation, i) => { @@ -127,7 +127,7 @@ export function getBeaconPoolApi({ return; } - errors.push(e as Error); + failures.push({index: i, message: (e as Error).message}); logger.error(`Error on submitPoolAttestations [${i}]`, logCtx, e as Error); if (e instanceof AttestationError && e.action === GossipAction.REJECT) { chain.persistInvalidSszValue(ssz.phase0.Attestation, attestation, "api_reject"); @@ -136,10 +136,8 @@ export function getBeaconPoolApi({ }) ); - if (errors.length > 1) { - throw Error("Multiple errors on submitPoolAttestations\n" + errors.map((e) => e.message).join("\n")); - } else if (errors.length === 1) { - throw errors[0]; + if (failures.length > 0) { + throw new IndexedError("Error processing attestations", failures); } }, @@ -168,7 +166,7 @@ export function getBeaconPoolApi({ }, async submitPoolBLSToExecutionChange({blsToExecutionChanges}) { - const errors: Error[] = []; + const failures: FailureList = []; await Promise.all( blsToExecutionChanges.map(async (blsToExecutionChange, i) => { @@ -184,7 +182,7 @@ export function getBeaconPoolApi({ await network.publishBlsToExecutionChange(blsToExecutionChange); } } catch (e) { - errors.push(e as Error); + failures.push({index: i, message: (e as Error).message}); logger.error( `Error on submitPoolBLSToExecutionChange [${i}]`, {validatorIndex: blsToExecutionChange.message.validatorIndex}, @@ -194,10 +192,8 @@ export function getBeaconPoolApi({ }) ); - if (errors.length > 1) { - throw Error("Multiple errors on submitPoolBLSToExecutionChange\n" + errors.map((e) => e.message).join("\n")); - } else if (errors.length === 1) { - throw errors[0]; + if (failures.length > 0) { + throw new IndexedError("Error processing BLS to execution changes", failures); } }, @@ -221,7 +217,7 @@ export function getBeaconPoolApi({ // TODO: Fetch states at signature slots const state = chain.getHeadState(); - const errors: Error[] = []; + const failures: FailureList = []; await Promise.all( signatures.map(async (signature, i) => { @@ -261,7 +257,7 @@ export function getBeaconPoolApi({ return; } - errors.push(e as Error); + failures.push({index: i, message: (e as Error).message}); logger.debug( `Error on submitPoolSyncCommitteeSignatures [${i}]`, {slot: signature.slot, validatorIndex: signature.validatorIndex}, @@ -274,10 +270,8 @@ export function getBeaconPoolApi({ }) ); - if (errors.length > 1) { - throw Error("Multiple errors on submitPoolSyncCommitteeSignatures\n" + errors.map((e) => e.message).join("\n")); - } else if (errors.length === 1) { - throw errors[0]; + if (failures.length > 0) { + throw new IndexedError("Error processing sync committee signatures", failures); } }, }; diff --git a/packages/beacon-node/src/api/impl/errors.ts b/packages/beacon-node/src/api/impl/errors.ts index 848691f7cf6d..609f40f83a12 100644 --- a/packages/beacon-node/src/api/impl/errors.ts +++ b/packages/beacon-node/src/api/impl/errors.ts @@ -35,3 +35,16 @@ export class OnlySupportedByDVT extends ApiError { super(501, "Only supported by distributed validator middleware clients"); } } + +// Error thrown when processing multiple items failed - https://github.com/ethereum/beacon-APIs/blob/e7f7d70423b0abfe9d9f33b701be2ec03e44eb02/types/http.yaml#L175 +export class IndexedError extends ApiError { + failures: FailureList; + + constructor(message: string, failures: FailureList) { + super(400, message); + + this.failures = failures.sort((a, b) => a.index - b.index); + } +} + +export type FailureList = {index: number; message: string}[]; diff --git a/packages/beacon-node/src/api/rest/base.ts b/packages/beacon-node/src/api/rest/base.ts index e8ea85f67af5..10318b1b3ba7 100644 --- a/packages/beacon-node/src/api/rest/base.ts +++ b/packages/beacon-node/src/api/rest/base.ts @@ -5,7 +5,7 @@ import bearerAuthPlugin from "@fastify/bearer-auth"; import {addSszContentTypeParser} from "@lodestar/api/server"; import {ErrorAborted, Gauge, Histogram, Logger} from "@lodestar/utils"; import {isLocalhostIP} from "../../util/ip.js"; -import {ApiError, NodeIsSyncing} from "../impl/errors.js"; +import {ApiError, FailureList, IndexedError, NodeIsSyncing} from "../impl/errors.js"; import {HttpActiveSocketsTracker, SocketMetrics} from "./activeSockets.js"; export type RestApiServerOpts = { @@ -41,6 +41,10 @@ type ErrorResponse = { stacktraces?: string[]; }; +type IndexedErrorResponse = ErrorResponse & { + failures?: FailureList; +}; + /** * Error code used by Fastify if media type is not supported (415) */ @@ -97,6 +101,14 @@ export class RestApiServer { stacktraces, }; void res.status(400).send(payload); + } else if (err instanceof IndexedError) { + const payload: IndexedErrorResponse = { + code: err.statusCode, + message: err.message, + failures: err.failures, + stacktraces, + }; + void res.status(err.statusCode).send(payload); } else { // Convert our custom ApiError into status code const statusCode = err instanceof ApiError ? err.statusCode : 500; diff --git a/packages/cli/test/sim/endpoints.test.ts b/packages/cli/test/sim/endpoints.test.ts index b276ad4787c6..6a119fc219d7 100644 --- a/packages/cli/test/sim/endpoints.test.ts +++ b/packages/cli/test/sim/endpoints.test.ts @@ -3,6 +3,7 @@ import path from "node:path"; import assert from "node:assert"; import {toHexString} from "@chainsafe/ssz"; import {routes, fetch} from "@lodestar/api"; +import {ssz} from "@lodestar/types"; import {Simulation} from "../utils/crucible/simulation.js"; import {BeaconClient, ExecutionClient} from "../utils/crucible/interfaces.js"; import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js"; @@ -108,15 +109,30 @@ await env.tracker.assert( await env.tracker.assert("should return HTTP error responses in a spec compliant format", async () => { // ApiError with status 400 is thrown by handler const res1 = await node.api.beacon.getStateValidator({stateId: "current", validatorId: 1}); - assert.deepEqual(JSON.parse(await res1.errorBody()), {code: 400, message: "Invalid block id 'current'"}); + assert.deepStrictEqual(JSON.parse(await res1.errorBody()), {code: 400, message: "Invalid block id 'current'"}); // JSON schema validation failed const res2 = await node.api.beacon.getPoolAttestationsV2({slot: "current" as unknown as number, committeeIndex: 123}); - assert.deepEqual(JSON.parse(await res2.errorBody()), {code: 400, message: "slot must be integer"}); + assert.deepStrictEqual(JSON.parse(await res2.errorBody()), {code: 400, message: "slot must be integer"}); + + // Error processing multiple items + const signedAttestations = Array.from({length: 3}, () => ssz.phase0.Attestation.defaultValue()); + const res3 = await node.api.beacon.submitPoolAttestationsV2({signedAttestations}); + const errBody = JSON.parse(await res3.errorBody()) as {code: number; message: string; failures: unknown[]}; + assert.equal(errBody.code, 400); + assert.equal(errBody.message, "Error processing attestations"); + assert.equal(errBody.failures.length, signedAttestations.length); + assert.deepStrictEqual(errBody.failures[0], { + index: 0, + message: "ATTESTATION_ERROR_NOT_EXACTLY_ONE_AGGREGATION_BIT_SET", + }); // Route does not exist - const res3 = await fetch(`${node.restPublicUrl}/not/implemented/route`); - assert.deepEqual(JSON.parse(await res3.text()), {code: 404, message: "Route GET:/not/implemented/route not found"}); + const res4 = await fetch(`${node.restPublicUrl}/not/implemented/route`); + assert.deepStrictEqual(JSON.parse(await res4.text()), { + code: 404, + message: "Route GET:/not/implemented/route not found", + }); }); await env.tracker.assert("BN Not Synced", async () => { From 0d1fd9c839a84cfe91e0b9e6af95c27261bb5ef0 Mon Sep 17 00:00:00 2001 From: twoeths Date: Fri, 4 Oct 2024 19:29:20 +0700 Subject: [PATCH 129/259] chore: remove IndexedGossipQueueAvgTime (#7125) --- .../network/processor/gossipQueues/index.ts | 12 +- .../processor/gossipQueues/indexedAvgTime.ts | 129 ------------------ .../network/processor/gossipQueues/types.ts | 11 +- 3 files changed, 2 insertions(+), 150 deletions(-) delete mode 100644 packages/beacon-node/src/network/processor/gossipQueues/indexedAvgTime.ts diff --git a/packages/beacon-node/src/network/processor/gossipQueues/index.ts b/packages/beacon-node/src/network/processor/gossipQueues/index.ts index 347458c91445..968c11501426 100644 --- a/packages/beacon-node/src/network/processor/gossipQueues/index.ts +++ b/packages/beacon-node/src/network/processor/gossipQueues/index.ts @@ -3,16 +3,8 @@ import {GossipType} from "../../gossip/interface.js"; import {PendingGossipsubMessage} from "../types.js"; import {getGossipAttestationIndex} from "../../../util/sszBytes.js"; import {LinearGossipQueue} from "./linear.js"; -import { - DropType, - GossipQueue, - GossipQueueOpts, - QueueType, - isIndexedGossipQueueAvgTimeOpts, - isIndexedGossipQueueMinSizeOpts, -} from "./types.js"; +import {DropType, GossipQueue, GossipQueueOpts, QueueType, isIndexedGossipQueueMinSizeOpts} from "./types.js"; import {IndexedGossipQueueMinSize} from "./indexed.js"; -import {IndexedGossipQueueAvgTime} from "./indexedAvgTime.js"; /** * In normal condition, the higher this value the more efficient the signature verification. @@ -120,8 +112,6 @@ export function createGossipQueues(beaconAttestationBatchValidation = false): { return mapValues(gossipQueueOpts, (opts) => { if (isIndexedGossipQueueMinSizeOpts(opts)) { return new IndexedGossipQueueMinSize(opts); - } else if (isIndexedGossipQueueAvgTimeOpts(opts)) { - return new IndexedGossipQueueAvgTime(opts); } else { return new LinearGossipQueue(opts); } diff --git a/packages/beacon-node/src/network/processor/gossipQueues/indexedAvgTime.ts b/packages/beacon-node/src/network/processor/gossipQueues/indexedAvgTime.ts deleted file mode 100644 index b7bba4c132bb..000000000000 --- a/packages/beacon-node/src/network/processor/gossipQueues/indexedAvgTime.ts +++ /dev/null @@ -1,129 +0,0 @@ -import {GossipQueue, IndexedGossipQueueOpts} from "./types.js"; - -type ItemList = { - items: T[]; - avgRecvTimestampMs: number; -}; - -function listScore(list: ItemList): number { - return list.items.length / Math.max(1000, Date.now() - list.avgRecvTimestampMs); -} - -/** - * An implementation of GossipQueue that tries to run the batch with highest score first. - * TODO: add unit tests - * - index items by indexFn using a map - * - compute avgRecvTimestampMs for each key every time we add new item - * - on next, pick the key with the highest score (check the score function above) - */ -export class IndexedGossipQueueAvgTime implements GossipQueue { - private _length = 0; - private indexedItems: Map> = new Map(); - - constructor(private readonly opts: IndexedGossipQueueOpts) {} - - get length(): number { - return this._length; - } - - get keySize(): number { - return this.indexedItems.size; - } - - clear(): void { - this.indexedItems = new Map(); - this._length = 0; - } - - // not implemented for this gossip queue - getDataAgeMs(): number[] { - return []; - } - - /** - * Add item to gossip queue. If queue is full, drop first item of first key. - * Return number of items dropped - */ - add(item: T): number { - const key = this.opts.indexFn(item); - if (key == null) { - // this comes from getAttDataBase64FromAttestationSerialized() return type - // should not happen - return 0; - } - item.indexed = key; - let list = this.indexedItems.get(key); - if (list == null) { - list = { - items: [], - avgRecvTimestampMs: Date.now(), - }; - this.indexedItems.set(key, list); - } else { - list.avgRecvTimestampMs = (list.avgRecvTimestampMs * list.items.length + Date.now()) / (list.items.length + 1); - list.items.push(item); - } - this._length++; - if (this._length <= this.opts.maxLength) { - return 0; - } - - // overload, need to drop more items - const firstKey = this.indexedItems.keys().next().value as string; - // there should be at least 1 key - if (firstKey == null) { - return 0; - } - const firstList = this.indexedItems.get(firstKey); - // should not happen - if (firstList == null) { - return 0; - } - - const deletedItem = firstList.items.shift(); - if (deletedItem != null) { - this._length--; - if (firstList.items.length === 0) { - this.indexedItems.delete(firstKey); - } - return 1; - } else { - return 0; - } - } - - /** - * Try to get list of items of the same key with highest score - */ - next(): T[] | null { - let maxScore = 0; - let maxScoreKey: string | undefined; - for (const [key, list] of this.indexedItems) { - const score = listScore(list); - if (score > maxScore) { - maxScore = score; - maxScoreKey = key; - } - } - - if (maxScoreKey == null) { - return null; - } - const items = this.indexedItems.get(maxScoreKey)?.items; - if (items == null) { - // should not happen - return null; - } - this.indexedItems.delete(maxScoreKey); - this._length = Math.max(0, this._length - items.length); - return items; - } - - getAll(): T[] { - const items: T[] = []; - for (const list of this.indexedItems.values()) { - items.push(...list.items); - } - return items; - } -} diff --git a/packages/beacon-node/src/network/processor/gossipQueues/types.ts b/packages/beacon-node/src/network/processor/gossipQueues/types.ts index 448f44c3f5d7..58034e82ed06 100644 --- a/packages/beacon-node/src/network/processor/gossipQueues/types.ts +++ b/packages/beacon-node/src/network/processor/gossipQueues/types.ts @@ -1,4 +1,4 @@ -export type GossipQueueOpts = LinearGossipQueueOpts | IndexedGossipQueueOpts | IndexedGossipQueueMinSizeOpts; +export type GossipQueueOpts = LinearGossipQueueOpts | IndexedGossipQueueMinSizeOpts; export type LinearGossipQueueOpts = { type: QueueType; @@ -25,15 +25,6 @@ export function isIndexedGossipQueueMinSizeOpts(opts: GossipQueueOpts): op ); } -export function isIndexedGossipQueueAvgTimeOpts(opts: GossipQueueOpts): opts is IndexedGossipQueueOpts { - const avgTimeOpts = opts as IndexedGossipQueueMinSizeOpts; - return ( - avgTimeOpts.indexFn !== undefined && - avgTimeOpts.minChunkSize === undefined && - avgTimeOpts.maxChunkSize === undefined - ); -} - export interface GossipQueue { length: number; keySize: number; From 5f7b611eeb4adab186919b042bc6422a9ba5aa75 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 7 Oct 2024 20:26:37 +0100 Subject: [PATCH 130/259] feat: add standard endpoint to retrieve fork choice context (#7127) --- packages/api/src/beacon/routes/debug.ts | 53 +++++++++++++++++++ .../api/test/unit/beacon/oapiSpec.test.ts | 1 - .../api/test/unit/beacon/testData/debug.ts | 30 ++++++++++- .../beacon-node/src/api/impl/debug/index.ts | 31 +++++++++++ packages/beacon-node/src/api/rest/base.ts | 2 +- 5 files changed, 114 insertions(+), 3 deletions(-) diff --git a/packages/api/src/beacon/routes/debug.ts b/packages/api/src/beacon/routes/debug.ts index 8099fcac020e..590ecf71dd9c 100644 --- a/packages/api/src/beacon/routes/debug.ts +++ b/packages/api/src/beacon/routes/debug.ts @@ -58,11 +58,34 @@ const DebugChainHeadType = new ContainerType( {jsonCase: "eth2"} ); +const ForkChoiceNodeType = new ContainerType( + { + slot: ssz.Slot, + blockRoot: stringType, + parentRoot: stringType, + justifiedEpoch: ssz.Epoch, + finalizedEpoch: ssz.Epoch, + weight: ssz.UintNum64, + validity: new StringType<"valid" | "invalid" | "optimistic">(), + executionBlockHash: stringType, + }, + {jsonCase: "eth2"} +); +const ForkChoiceResponseType = new ContainerType( + { + justifiedCheckpoint: ssz.phase0.Checkpoint, + finalizedCheckpoint: ssz.phase0.Checkpoint, + forkChoiceNodes: ArrayOf(ForkChoiceNodeType), + }, + {jsonCase: "eth2"} +); + const ProtoNodeListType = ArrayOf(ProtoNodeType); const DebugChainHeadListType = ArrayOf(DebugChainHeadType); type ProtoNodeList = ValueOf; type DebugChainHeadList = ValueOf; +type ForkChoiceResponse = ValueOf; export type Endpoints = { /** @@ -77,6 +100,18 @@ export type Endpoints = { EmptyMeta >; + /** + * Retrieves all current fork choice context + */ + getDebugForkChoice: Endpoint< + // ⏎ + "GET", + EmptyArgs, + EmptyRequest, + ForkChoiceResponse, + EmptyMeta + >; + /** * Dump all ProtoArray's nodes to debug */ @@ -115,6 +150,24 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({ + ...(data as ForkChoiceResponse), + }), + fromResponse: (resp) => ({ + data: resp as ForkChoiceResponse, + }), + }, + }, + }, getProtoArrayNodes: { url: "/eth/v0/debug/forkchoice", method: "GET", diff --git a/packages/api/test/unit/beacon/oapiSpec.test.ts b/packages/api/test/unit/beacon/oapiSpec.test.ts index 89079cd0768c..2b8a8254dd6b 100644 --- a/packages/api/test/unit/beacon/oapiSpec.test.ts +++ b/packages/api/test/unit/beacon/oapiSpec.test.ts @@ -57,7 +57,6 @@ const ignoredOperations = [ /* missing route */ "getDepositSnapshot", // Won't fix for now, see https://github.com/ChainSafe/lodestar/issues/5697 "getNextWithdrawals", // https://github.com/ChainSafe/lodestar/issues/5696 - "getDebugForkChoice", // https://github.com/ChainSafe/lodestar/issues/5700 /* Must support ssz response body */ "getLightClientUpdatesByRange", // https://github.com/ChainSafe/lodestar/issues/6841 ]; diff --git a/packages/api/test/unit/beacon/testData/debug.ts b/packages/api/test/unit/beacon/testData/debug.ts index aac3b379ff4d..cb2799939ae3 100644 --- a/packages/api/test/unit/beacon/testData/debug.ts +++ b/packages/api/test/unit/beacon/testData/debug.ts @@ -4,13 +4,41 @@ import {ssz} from "@lodestar/types"; import {Endpoints} from "../../../../src/beacon/routes/debug.js"; import {GenericServerTestCases} from "../../../utils/genericServerTest.js"; -const rootHex = toHexString(Buffer.alloc(32, 1)); +const root = new Uint8Array(32).fill(1); +const rootHex = toHexString(root); export const testData: GenericServerTestCases = { getDebugChainHeadsV2: { args: undefined, res: {data: [{slot: 1, root: rootHex, executionOptimistic: true}]}, }, + getDebugForkChoice: { + args: undefined, + res: { + data: { + justifiedCheckpoint: { + epoch: 2, + root, + }, + finalizedCheckpoint: { + epoch: 1, + root, + }, + forkChoiceNodes: [ + { + slot: 1, + blockRoot: rootHex, + parentRoot: rootHex, + justifiedEpoch: 1, + finalizedEpoch: 1, + weight: 1, + validity: "valid", + executionBlockHash: rootHex, + }, + ], + }, + }, + }, getProtoArrayNodes: { args: undefined, res: { diff --git a/packages/beacon-node/src/api/impl/debug/index.ts b/packages/beacon-node/src/api/impl/debug/index.ts index 4edb8ba9b2dd..e5b6450b206f 100644 --- a/packages/beacon-node/src/api/impl/debug/index.ts +++ b/packages/beacon-node/src/api/impl/debug/index.ts @@ -1,6 +1,8 @@ import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; +import {ExecutionStatus} from "@lodestar/fork-choice"; import {BeaconState} from "@lodestar/types"; +import {ZERO_HASH_HEX} from "@lodestar/params"; import {getStateResponseWithRegen} from "../beacon/state/utils.js"; import {ApiModules} from "../types.js"; import {isOptimisticBlock} from "../../../util/forkChoice.js"; @@ -22,6 +24,35 @@ export function getDebugApi({ }; }, + async getDebugForkChoice() { + return { + data: { + justifiedCheckpoint: chain.forkChoice.getJustifiedCheckpoint(), + finalizedCheckpoint: chain.forkChoice.getFinalizedCheckpoint(), + forkChoiceNodes: chain.forkChoice.getAllNodes().map((node) => ({ + slot: node.slot, + blockRoot: node.blockRoot, + parentRoot: node.parentRoot, + justifiedEpoch: node.justifiedEpoch, + finalizedEpoch: node.finalizedEpoch, + weight: node.weight, + validity: (() => { + switch (node.executionStatus) { + case ExecutionStatus.Valid: + return "valid"; + case ExecutionStatus.Invalid: + return "invalid"; + case ExecutionStatus.Syncing: + case ExecutionStatus.PreMerge: + return "optimistic"; + } + })(), + executionBlockHash: node.executionPayloadBlockHash ?? ZERO_HASH_HEX, + })), + }, + }; + }, + async getProtoArrayNodes() { const nodes = chain.forkChoice.getAllNodes().map((node) => ({ // if node has executionPayloadNumber, it will overwrite the below default diff --git a/packages/beacon-node/src/api/rest/base.ts b/packages/beacon-node/src/api/rest/base.ts index 10318b1b3ba7..276583dc7281 100644 --- a/packages/beacon-node/src/api/rest/base.ts +++ b/packages/beacon-node/src/api/rest/base.ts @@ -96,7 +96,7 @@ export class RestApiServer { if (err.validation) { const {instancePath, message} = err.validation[0]; const payload: ErrorResponse = { - code: err.statusCode ?? 400, + code: 400, message: `${instancePath.substring(instancePath.lastIndexOf("/") + 1)} ${message}`, stacktraces, }; From 1fa3f37ab7a6ea53888650cb23da43456886c935 Mon Sep 17 00:00:00 2001 From: twoeths Date: Tue, 8 Oct 2024 02:31:39 +0700 Subject: [PATCH 131/259] refactor: remove beaconAttestationBatchValidation flag (#7129) * chore: remove beaconAttestationBatchValidation flag * chore: refactor SequentialGossipHandlers vs BatchGossipHandlers * chore: remove unused validateGossipAttestation() function * chore: lint * chore: fix lint * chore: SequentialGossipType vs BatchGossipType * chore: simplify getGossipHandlers() --- .../src/chain/validation/attestation.ts | 46 ++---------- .../src/network/gossip/interface.ts | 19 ++--- packages/beacon-node/src/network/options.ts | 2 - .../src/network/processor/gossipHandlers.ts | 71 ++----------------- .../network/processor/gossipQueues/index.ts | 26 +++---- .../src/network/processor/index.ts | 2 +- .../perf/chain/validation/attestation.test.ts | 22 +----- .../attestation/validateAttestation.test.ts | 29 ++++---- .../src/options/beaconNodeOptions/network.ts | 9 --- .../unit/options/beaconNodeOptions.test.ts | 2 - 10 files changed, 51 insertions(+), 177 deletions(-) diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index 4ceaf64d658d..119a8ee1a899 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -38,7 +38,6 @@ import {MAXIMUM_GOSSIP_CLOCK_DISPARITY_SEC} from "../../constants/index.js"; import {RegenCaller} from "../regen/index.js"; import { getAggregationBitsFromAttestationSerialized, - getAttDataFromAttestationSerialized, getAttDataFromSignedAggregateAndProofElectra, getCommitteeBitsFromAttestationSerialized, getCommitteeBitsFromSignedAggregateAndProofElectra, @@ -75,9 +74,8 @@ export type GossipAttestation = { serializedData: Uint8Array; // available in NetworkProcessor since we check for unknown block root attestations attSlot: Slot; - // for old LIFO linear gossip queue we don't have attDataBase64 // for indexed gossip queue we have attDataBase64 - attDataBase64?: SeenAttDataKey | null; + attDataBase64: SeenAttDataKey; }; export type Step0Result = AttestationValidationResult & { @@ -85,20 +83,6 @@ export type Step0Result = AttestationValidationResult & { validatorIndex: number; }; -/** - * Validate a single gossip attestation, do not prioritize bls signature set - */ -export async function validateGossipAttestation( - fork: ForkName, - chain: IBeaconChain, - attestationOrBytes: GossipAttestation, - /** Optional, to allow verifying attestations through API with unknown subnet */ - subnet: number -): Promise { - const prioritizeBls = false; - return validateAttestation(fork, chain, attestationOrBytes, subnet, prioritizeBls); -} - /** * Verify gossip attestations of the same attestation data. The main advantage is we can batch verify bls signatures * through verifySignatureSetsSameMessage bls api to improve performance. @@ -111,7 +95,7 @@ export async function validateGossipAttestationsSameAttData( attestationOrBytesArr: GossipAttestation[], subnet: number, // for unit test, consumers do not need to pass this - step0ValidationFn = validateGossipAttestationNoSignatureCheck + step0ValidationFn = validateAttestationNoSignatureCheck ): Promise { if (attestationOrBytesArr.length === 0) { return {results: [], batchableBls: false}; @@ -213,22 +197,10 @@ export async function validateApiAttestation( attestationOrBytes: ApiAttestation ): Promise { const prioritizeBls = true; - return validateAttestation(fork, chain, attestationOrBytes, null, prioritizeBls); -} + const subnet = null; -/** - * Validate a single unaggregated attestation - * subnet is null for api attestations - */ -export async function validateAttestation( - fork: ForkName, - chain: IBeaconChain, - attestationOrBytes: AttestationOrBytes, - subnet: number | null, - prioritizeBls = false -): Promise { try { - const step0Result = await validateGossipAttestationNoSignatureCheck(fork, chain, attestationOrBytes, subnet); + const step0Result = await validateAttestationNoSignatureCheck(fork, chain, attestationOrBytes, subnet); const {attestation, signatureSet, validatorIndex} = step0Result; const isValid = await chain.bls.verifySignatureSets([signatureSet], {batchable: true, priority: prioritizeBls}); @@ -256,7 +228,7 @@ export async function validateAttestation( * Only deserialize the attestation if needed, use the cached AttestationData instead * This is to avoid deserializing similar attestation multiple times which could help the gc */ -async function validateGossipAttestationNoSignatureCheck( +async function validateAttestationNoSignatureCheck( fork: ForkName, chain: IBeaconChain, attestationOrBytes: AttestationOrBytes, @@ -801,9 +773,6 @@ export function computeSubnetForSlot(shuffling: EpochShuffling, slot: number, co * Return fork-dependent seen attestation key * - for pre-electra, it's the AttestationData base64 * - for electra and later, it's the AttestationData base64 + committeeBits base64 - * - * we always have attDataBase64 from the IndexedGossipQueue, getAttDataFromAttestationSerialized() just for backward compatible when beaconAttestationBatchValidation is false - * TODO: remove beaconAttestationBatchValidation flag since the batch attestation is stable */ export function getSeenAttDataKeyFromGossipAttestation( fork: ForkName, @@ -811,13 +780,12 @@ export function getSeenAttDataKeyFromGossipAttestation( ): SeenAttDataKey | null { const {attDataBase64, serializedData} = attestation; if (isForkPostElectra(fork)) { - const attData = attDataBase64 ?? getAttDataFromAttestationSerialized(serializedData); const committeeBits = getCommitteeBitsFromAttestationSerialized(serializedData); - return attData && committeeBits ? attDataBase64 + committeeBits : null; + return attDataBase64 && committeeBits ? attDataBase64 + committeeBits : null; } // pre-electra - return attDataBase64 ?? getAttDataFromAttestationSerialized(serializedData); + return attDataBase64; } /** diff --git a/packages/beacon-node/src/network/gossip/interface.ts b/packages/beacon-node/src/network/gossip/interface.ts index ab9b8a65978d..af5e3888d04f 100644 --- a/packages/beacon-node/src/network/gossip/interface.ts +++ b/packages/beacon-node/src/network/gossip/interface.ts @@ -36,6 +36,9 @@ export enum GossipType { bls_to_execution_change = "bls_to_execution_change", } +export type SequentialGossipType = Exclude; +export type BatchGossipType = GossipType.beacon_attestation; + export enum GossipEncoding { ssz_snappy = "ssz_snappy", } @@ -181,25 +184,25 @@ export type GossipHandlerParamGeneric = { }; export type GossipHandlers = { - [K in GossipType]: DefaultGossipHandler | BatchGossipHandler; + [K in GossipType]: SequentialGossipHandler | BatchGossipHandler; }; -export type DefaultGossipHandler = ( +export type SequentialGossipHandler = ( gossipHandlerParam: GossipHandlerParamGeneric ) => Promise; -export type DefaultGossipHandlers = { - [K in GossipType]: DefaultGossipHandler; +export type SequentialGossipHandlers = { + [K in SequentialGossipType]: SequentialGossipHandler; +}; + +export type BatchGossipHandlers = { + [K in BatchGossipType]: BatchGossipHandler; }; export type BatchGossipHandler = ( gossipHandlerParams: GossipHandlerParamGeneric[] ) => Promise<(null | GossipActionError)[]>; -export type BatchGossipHandlers = { - [K in GossipType]?: BatchGossipHandler; -}; - // eslint-disable-next-line @typescript-eslint/no-explicit-any export type ResolvedType Promise> = F extends (...args: any) => Promise ? T diff --git a/packages/beacon-node/src/network/options.ts b/packages/beacon-node/src/network/options.ts index d2070873261b..ebb321584d12 100644 --- a/packages/beacon-node/src/network/options.ts +++ b/packages/beacon-node/src/network/options.ts @@ -40,8 +40,6 @@ export const defaultNetworkOptions: NetworkOptions = { maxYoungGenerationSizeMb: 152, // subscribe 2 slots before aggregator dutied slot to get stable mesh peers as monitored on goerli slotsToSubscribeBeforeAggregatorDuty: 2, - // this should only be set to true if useWorker is true - beaconAttestationBatchValidation: true, // This will enable the light client server by default disableLightClientServer: false, }; diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index 8df9f7b78126..90c131a943ed 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -20,7 +20,7 @@ import { } from "../../chain/errors/index.js"; import { BatchGossipHandlers, - DefaultGossipHandlers, + SequentialGossipHandlers, GossipHandlerParamGeneric, GossipHandlers, GossipType, @@ -36,8 +36,6 @@ import { validateGossipBlsToExecutionChange, AggregateAndProofValidationResult, validateGossipAttestationsSameAttData, - validateGossipAttestation, - AttestationValidationResult, GossipAttestation, } from "../../chain/validation/index.js"; import {NetworkEvent, NetworkEventBus} from "../events.js"; @@ -64,8 +62,6 @@ import {AggregatorTracker} from "./aggregatorTracker.js"; export type GossipHandlerOpts = { /** By default pass gossip attestations to forkchoice */ dontSendGossipAttestationsToForkchoice?: boolean; - /** By default don't validate gossip attestations in batch */ - beaconAttestationBatchValidation?: boolean; }; export type ValidatorFnsModules = { @@ -96,20 +92,15 @@ const BLOCK_AVAILABILITY_CUTOFF_MS = 3_000; * - Ethereum Consensus gossipsub protocol strictly defined a single topic for message */ export function getGossipHandlers(modules: ValidatorFnsModules, options: GossipHandlerOpts): GossipHandlers { - const defaultHandlers = getDefaultHandlers(modules, options); - if (options.beaconAttestationBatchValidation) { - const batchHandlers = getBatchHandlers(modules, options); - return {...defaultHandlers, ...batchHandlers}; - } - return defaultHandlers; + return {...getSequentialHandlers(modules, options), ...getBatchHandlers(modules, options)}; } /** * Default handlers validate gossip messages one by one. * We only have a choice to do batch validation for beacon_attestation topic. */ -function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandlerOpts): DefaultGossipHandlers { - const {chain, config, metrics, events, logger, core, aggregatorTracker} = modules; +function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHandlerOpts): SequentialGossipHandlers { + const {chain, config, metrics, events, logger, core} = modules; async function validateBeaconBlock( signedBlock: SignedBeaconBlock, @@ -458,58 +449,6 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler chain.emitter.emit(routes.events.EventType.attestation, signedAggregateAndProof.message.aggregate); }, - [GossipType.beacon_attestation]: async ({ - gossipData, - topic, - seenTimestampSec, - }: GossipHandlerParamGeneric): Promise => { - const {serializedData, msgSlot} = gossipData; - if (msgSlot == undefined) { - throw Error("msgSlot is undefined for beacon_attestation topic"); - } - const {subnet, fork} = topic; - - // do not deserialize gossipSerializedData here, it's done in validateGossipAttestation only if needed - let validationResult: AttestationValidationResult; - try { - validationResult = await validateGossipAttestation( - fork, - chain, - {attestation: null, serializedData, attSlot: msgSlot}, - subnet - ); - } catch (e) { - if (e instanceof AttestationError && e.action === GossipAction.REJECT) { - chain.persistInvalidSszBytes(ssz.phase0.Attestation.typeName, serializedData, "gossip_reject"); - } - throw e; - } - - // Handler - const {indexedAttestation, attDataRootHex, attestation, committeeIndex} = validationResult; - metrics?.registerGossipUnaggregatedAttestation(seenTimestampSec, indexedAttestation); - - try { - // Node may be subscribe to extra subnets (long-lived random subnets). For those, validate the messages - // but don't add to attestation pool, to save CPU and RAM - if (aggregatorTracker.shouldAggregate(subnet, indexedAttestation.data.slot)) { - const insertOutcome = chain.attestationPool.add(committeeIndex, attestation, attDataRootHex); - metrics?.opPool.attestationPoolInsertOutcome.inc({insertOutcome}); - } - } catch (e) { - logger.error("Error adding unaggregated attestation to pool", {subnet}, e as Error); - } - - if (!options.dontSendGossipAttestationsToForkchoice) { - try { - chain.forkChoice.onAttestation(indexedAttestation, attDataRootHex); - } catch (e) { - logger.debug("Error adding gossip unaggregated attestation to forkchoice", {subnet}, e as Error); - } - } - - chain.emitter.emit(routes.events.EventType.attestation, attestation); - }, [GossipType.attester_slashing]: async ({ gossipData, @@ -660,7 +599,7 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler /** * For now, only beacon_attestation topic is batched. */ -function getBatchHandlers(modules: ValidatorFnsModules, options: GossipHandlerOpts): Partial { +function getBatchHandlers(modules: ValidatorFnsModules, options: GossipHandlerOpts): BatchGossipHandlers { const {chain, metrics, logger, aggregatorTracker} = modules; return { [GossipType.beacon_attestation]: async ( diff --git a/packages/beacon-node/src/network/processor/gossipQueues/index.ts b/packages/beacon-node/src/network/processor/gossipQueues/index.ts index 968c11501426..12596a42b7a1 100644 --- a/packages/beacon-node/src/network/processor/gossipQueues/index.ts +++ b/packages/beacon-node/src/network/processor/gossipQueues/index.ts @@ -1,5 +1,5 @@ import {mapValues} from "@lodestar/utils"; -import {GossipType} from "../../gossip/interface.js"; +import {BatchGossipType, GossipType, SequentialGossipType} from "../../gossip/interface.js"; import {PendingGossipsubMessage} from "../types.js"; import {getGossipAttestationIndex} from "../../../util/sszBytes.js"; import {LinearGossipQueue} from "./linear.js"; @@ -20,8 +20,8 @@ export const MIN_SIGNATURE_SETS_TO_BATCH_VERIFY = 32; /** * Numbers from https://github.com/sigp/lighthouse/blob/b34a79dc0b02e04441ba01fd0f304d1e203d877d/beacon_node/network/src/beacon_processor/mod.rs#L69 */ -const defaultGossipQueueOpts: { - [K in GossipType]: GossipQueueOpts; +const linearGossipQueueOpts: { + [K in SequentialGossipType]: GossipQueueOpts; } = { // validation gossip block asap [GossipType.beacon_block]: {maxLength: 1024, type: QueueType.FIFO, dropOpts: {type: DropType.count, count: 1}}, @@ -37,15 +37,6 @@ const defaultGossipQueueOpts: { type: QueueType.LIFO, dropOpts: {type: DropType.count, count: 1}, }, - // lighthouse has attestation_queue 16384 and unknown_block_attestation_queue 8192, we use single queue - // this topic may cause node to be overload and drop 100% of lower priority queues - // so we want to drop it by ratio until node is stable enough (queue is empty) - // start with dropping 1% of the queue, then increase 1% more each time. Reset when queue is empty - [GossipType.beacon_attestation]: { - maxLength: 24576, - type: QueueType.LIFO, - dropOpts: {type: DropType.ratio, start: 0.01, step: 0.01}, - }, [GossipType.voluntary_exit]: {maxLength: 4096, type: QueueType.FIFO, dropOpts: {type: DropType.count, count: 1}}, [GossipType.proposer_slashing]: {maxLength: 4096, type: QueueType.FIFO, dropOpts: {type: DropType.count, count: 1}}, [GossipType.attester_slashing]: {maxLength: 4096, type: QueueType.FIFO, dropOpts: {type: DropType.count, count: 1}}, @@ -74,9 +65,11 @@ const defaultGossipQueueOpts: { }; const indexedGossipQueueOpts: { - [K in GossipType]?: GossipQueueOpts; + [K in BatchGossipType]: GossipQueueOpts; } = { [GossipType.beacon_attestation]: { + // lighthouse has attestation_queue 16384 and unknown_block_attestation_queue 8192, we use single queue + // this topic may cause node to be overload and drop 100% of lower priority queues maxLength: 24576, indexFn: (item: PendingGossipsubMessage) => { // Note indexFn is fork agnostic despite changes introduced in Electra @@ -103,12 +96,11 @@ const indexedGossipQueueOpts: { * By topic is too specific, so by type groups all similar objects in the same queue. All in the same won't allow * to customize different queue behaviours per object type (see `gossipQueueOpts`). */ -export function createGossipQueues(beaconAttestationBatchValidation = false): { +export function createGossipQueues(): { [K in GossipType]: GossipQueue; } { - const gossipQueueOpts = beaconAttestationBatchValidation - ? {...defaultGossipQueueOpts, ...indexedGossipQueueOpts} - : defaultGossipQueueOpts; + const gossipQueueOpts = {...linearGossipQueueOpts, ...indexedGossipQueueOpts}; + return mapValues(gossipQueueOpts, (opts) => { if (isIndexedGossipQueueMinSizeOpts(opts)) { return new IndexedGossipQueueMinSize(opts); diff --git a/packages/beacon-node/src/network/processor/index.ts b/packages/beacon-node/src/network/processor/index.ts index 9a1dcfb32fa0..5cfed6c20346 100644 --- a/packages/beacon-node/src/network/processor/index.ts +++ b/packages/beacon-node/src/network/processor/index.ts @@ -172,7 +172,7 @@ export class NetworkProcessor { this.metrics = metrics; this.logger = logger; this.events = events; - this.gossipQueues = createGossipQueues(this.opts.beaconAttestationBatchValidation); + this.gossipQueues = createGossipQueues(); this.gossipTopicConcurrency = mapValues(this.gossipQueues, () => 0); this.gossipValidatorFn = getGossipValidatorFn(modules.gossipHandlers ?? getGossipHandlers(modules, opts), modules); this.gossipValidatorBatchFn = getGossipValidatorBatchFn( diff --git a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts index f285317474d6..e942e1ea17d0 100644 --- a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts +++ b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts @@ -3,7 +3,7 @@ import {expect} from "chai"; import {ssz} from "@lodestar/types"; // eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../state-transition/test/perf/util.js"; -import {validateAttestation, validateGossipAttestationsSameAttData} from "../../../../src/chain/validation/index.js"; +import {validateGossipAttestationsSameAttData} from "../../../../src/chain/validation/index.js"; import {getAttestationValidData} from "../../../utils/validationData/attestation.js"; import {getAttDataFromAttestationSerialized} from "../../../../src/util/sszBytes.js"; @@ -29,25 +29,7 @@ describe("validate gossip attestation", () => { }); const attSlot = attestation0.data.slot; - const serializedData = ssz.phase0.Attestation.serialize(attestation0); const fork = chain.config.getForkName(stateSlot); - itBench({ - id: `validate gossip attestation - vc ${vc}`, - beforeEach: () => chain.seenAttesters["validatorIndexesByEpoch"].clear(), - fn: async () => { - await validateAttestation( - fork, - chain, - { - attestation: null, - serializedData, - attSlot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), - }, - subnet0 - ); - }, - }); for (const chunkSize of [32, 64, 128, 256]) { const attestations = [attestation0]; @@ -67,7 +49,7 @@ describe("validate gossip attestation", () => { attestation: null, serializedData, attSlot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }; }); diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts index 45d293ffbb33..90d37a74289d 100644 --- a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts @@ -2,6 +2,7 @@ import {BitArray} from "@chainsafe/ssz"; import {describe, expect, it} from "vitest"; import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ssz} from "@lodestar/types"; +import {LodestarError} from "@lodestar/utils"; // eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../../state-transition/test/perf/util.js"; import {AttestationErrorCode, GossipErrorCode} from "../../../../../src/chain/errors/index.js"; @@ -12,7 +13,7 @@ import { getSeenAttDataKeyFromGossipAttestation, getSeenAttDataKeyFromSignedAggregateAndProof, validateApiAttestation, - validateAttestation, + validateGossipAttestationsSameAttData, } from "../../../../../src/chain/validation/index.js"; import {getAttDataFromAttestationSerialized} from "../../../../../src/util/sszBytes.js"; import {memoOnce} from "../../../../utils/cache.js"; @@ -75,7 +76,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }, subnet, AttestationErrorCode.BAD_TARGET_EPOCH @@ -94,7 +95,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }, subnet, AttestationErrorCode.PAST_SLOT @@ -113,7 +114,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }, subnet, AttestationErrorCode.FUTURE_SLOT @@ -138,7 +139,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }, subnet, AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET @@ -158,7 +159,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }, subnet, AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET @@ -182,7 +183,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }, subnet, AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT @@ -202,7 +203,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }, subnet, AttestationErrorCode.INVALID_TARGET_ROOT @@ -229,7 +230,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }, subnet, AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS @@ -248,7 +249,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }, invalidSubnet, AttestationErrorCode.INVALID_SUBNET_ID @@ -268,7 +269,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }, subnet, AttestationErrorCode.ATTESTATION_ALREADY_KNOWN @@ -290,7 +291,7 @@ describe("validateAttestation", () => { attestation: null, serializedData, attSlot: attestation.data.slot, - attDataBase64: getAttDataFromAttestationSerialized(serializedData), + attDataBase64: getAttDataFromAttestationSerialized(serializedData) as string, }, subnet, AttestationErrorCode.INVALID_SIGNATURE @@ -314,7 +315,9 @@ describe("validateAttestation", () => { errorCode: string ): Promise { const fork = chain.config.getForkName(stateSlot); - await expectRejectedWithLodestarError(validateAttestation(fork, chain, attestationOrBytes, subnet), errorCode); + const {results} = await validateGossipAttestationsSameAttData(fork, chain, [attestationOrBytes], subnet); + expect(results.length).toEqual(1); + expect((results[0].err as LodestarError<{code: string}>).type.code).toEqual(errorCode); } }); diff --git a/packages/cli/src/options/beaconNodeOptions/network.ts b/packages/cli/src/options/beaconNodeOptions/network.ts index 25ba036a5dbf..bfe9c7710e86 100644 --- a/packages/cli/src/options/beaconNodeOptions/network.ts +++ b/packages/cli/src/options/beaconNodeOptions/network.ts @@ -26,7 +26,6 @@ export type NetworkArgs = { "network.connectToDiscv5Bootnodes"?: boolean; "network.discv5FirstQueryDelayMs"?: number; "network.dontSendGossipAttestationsToForkchoice"?: boolean; - "network.beaconAttestationBatchValidation"?: boolean; "network.allowPublishToZeroPeers"?: boolean; "network.gossipsubD"?: number; "network.gossipsubDLow"?: number; @@ -144,7 +143,6 @@ export function parseArgs(args: NetworkArgs): IBeaconNodeOptions["network"] { connectToDiscv5Bootnodes: args["network.connectToDiscv5Bootnodes"], discv5FirstQueryDelayMs: args["network.discv5FirstQueryDelayMs"], dontSendGossipAttestationsToForkchoice: args["network.dontSendGossipAttestationsToForkchoice"], - beaconAttestationBatchValidation: args["network.beaconAttestationBatchValidation"], allowPublishToZeroPeers: args["network.allowPublishToZeroPeers"], gossipsubD: args["network.gossipsubD"], gossipsubDLow: args["network.gossipsubDLow"], @@ -321,13 +319,6 @@ export const options: CliCommandOptions = { group: "network", }, - "network.beaconAttestationBatchValidation": { - hidden: true, - type: "boolean", - description: "Validate gossip attestations in batches", - group: "network", - }, - "network.allowPublishToZeroPeers": { hidden: true, type: "boolean", diff --git a/packages/cli/test/unit/options/beaconNodeOptions.test.ts b/packages/cli/test/unit/options/beaconNodeOptions.test.ts index f873102edf74..879b5bfa2fc9 100644 --- a/packages/cli/test/unit/options/beaconNodeOptions.test.ts +++ b/packages/cli/test/unit/options/beaconNodeOptions.test.ts @@ -95,7 +95,6 @@ describe("options / beaconNodeOptions", () => { "network.blockCountPeerLimit": 500, "network.rateTrackerTimeoutMs": 60000, "network.dontSendGossipAttestationsToForkchoice": true, - "network.beaconAttestationBatchValidation": true, "network.allowPublishToZeroPeers": true, "network.gossipsubD": 4, "network.gossipsubDLow": 2, @@ -206,7 +205,6 @@ describe("options / beaconNodeOptions", () => { connectToDiscv5Bootnodes: true, discv5FirstQueryDelayMs: 1000, dontSendGossipAttestationsToForkchoice: true, - beaconAttestationBatchValidation: true, allowPublishToZeroPeers: true, gossipsubD: 4, gossipsubDLow: 2, From c04157c9696ce7b9b12518f61ec638b872927c4b Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 8 Oct 2024 16:01:47 +0100 Subject: [PATCH 132/259] fix: ensure generated historical state slot matches requested slot (#7135) --- .../src/chain/historicalState/getHistoricalState.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts b/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts index 1f352b3d683a..a9f254dea3f2 100644 --- a/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts +++ b/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts @@ -102,6 +102,10 @@ export async function getHistoricalState( metrics?.stateTransitionBlocks.observe(blockCount); transitionTimer?.(); + if (state.slot !== slot) { + throw Error(`Failed to generate historical state for slot ${slot}`); + } + const serializeTimer = metrics?.stateSerializationTime.startTimer(); const stateBytes = state.serialize(); serializeTimer?.(); From 955f4569289d66e0a2ee171dfa7bd9984ce57ba7 Mon Sep 17 00:00:00 2001 From: Phil Ngo <58080811+philknows@users.noreply.github.com> Date: Tue, 8 Oct 2024 11:04:02 -0400 Subject: [PATCH 133/259] chore: add drips network ownership address (#7128) add drips network ownership address --- funding.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/funding.json b/funding.json index 872321cdca5b..3ff79f54b693 100644 --- a/funding.json +++ b/funding.json @@ -1,5 +1,10 @@ { "opRetro": { "projectId": "0x8ec88058175ef4c1c9b1f26910c4d4f2cfa733d6fcd1dbd9385476a313d9e12d" + }, + "drips": { + "ethereum": { + "ownedBy": "0x94107e24Ba695aeb884fe9e896BA0Bbc14D3B509" + } } } From f2b96ff008bf201b0109bd5bac868b631f9a241b Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Tue, 8 Oct 2024 15:08:26 -0700 Subject: [PATCH 134/259] fix: include skipped partial withdrawal to `partialWithdrawalsCount` (#7118) Include skipped partial withdrawal to count --- packages/params/src/presets/minimal.ts | 2 +- packages/state-transition/src/block/processWithdrawals.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 5dc8fc10d803..f93e3b1ca2c4 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -125,7 +125,7 @@ export const minimalPreset: BeaconPreset = { MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 2, MAX_ATTESTER_SLASHINGS_ELECTRA: 1, MAX_ATTESTATIONS_ELECTRA: 8, - MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 1, + MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 2, // 2**11 * 10**9 (= 2,048,000,000,000) Gwei MAX_EFFECTIVE_BALANCE_ELECTRA: 2048000000000, MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: 4096, diff --git a/packages/state-transition/src/block/processWithdrawals.ts b/packages/state-transition/src/block/processWithdrawals.ts index d4dfd47b4d94..610a2ed62b41 100644 --- a/packages/state-transition/src/block/processWithdrawals.ts +++ b/packages/state-transition/src/block/processWithdrawals.ts @@ -99,6 +99,8 @@ export function getExpectedWithdrawals( const withdrawals: capella.Withdrawal[] = []; const isPostElectra = fork >= ForkSeq.electra; + // partialWithdrawalsCount is withdrawals coming from EL since electra (EIP-7002) + let partialWithdrawalsCount = 0; if (isPostElectra) { const stateElectra = state as CachedBeaconStateElectra; @@ -138,11 +140,10 @@ export function getExpectedWithdrawals( }); withdrawalIndex++; } + partialWithdrawalsCount++; } } - // partialWithdrawalsCount is withdrawals coming from EL since electra (EIP-7002) - const partialWithdrawalsCount = withdrawals.length; const bound = Math.min(validators.length, MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP); let n = 0; // Just run a bounded loop max iterating over all withdrawals From 068fbae928989295706443887c645d476bb95695 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 9 Oct 2024 09:43:09 +0100 Subject: [PATCH 135/259] refactor: move validator status type and util to @lodestar/types (#7140) --- .../api/src/beacon/routes/beacon/state.ts | 14 +-- .../src/api/impl/beacon/state/index.ts | 9 +- .../src/api/impl/beacon/state/utils.ts | 36 +------ .../src/api/impl/validator/index.ts | 2 +- .../unit/api/impl/beacon/state/utils.test.ts | 100 +----------------- packages/types/src/index.ts | 1 + packages/types/src/utils/validatorStatus.ts | 46 ++++++++ .../types/test/unit/validatorStatus.test.ts | 100 ++++++++++++++++++ 8 files changed, 155 insertions(+), 153 deletions(-) create mode 100644 packages/types/src/utils/validatorStatus.ts create mode 100644 packages/types/test/unit/validatorStatus.test.ts diff --git a/packages/api/src/beacon/routes/beacon/state.ts b/packages/api/src/beacon/routes/beacon/state.ts index e3cfe2e16edf..1489f48c297e 100644 --- a/packages/api/src/beacon/routes/beacon/state.ts +++ b/packages/api/src/beacon/routes/beacon/state.ts @@ -2,7 +2,7 @@ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; -import {phase0, CommitteeIndex, Slot, Epoch, ssz, RootHex, StringType} from "@lodestar/types"; +import {phase0, CommitteeIndex, Slot, Epoch, ssz, RootHex, StringType, ValidatorStatus} from "@lodestar/types"; import {Endpoint, RequestCodec, RouteDefinitions, Schema} from "../../../utils/index.js"; import {ArrayOf, JsonOnlyReq} from "../../../utils/codecs.js"; import {ExecutionOptimisticAndFinalizedCodec, ExecutionOptimisticAndFinalizedMeta} from "../../../utils/metadata.js"; @@ -24,17 +24,7 @@ export type StateArgs = { export type ValidatorId = string | number; -export type ValidatorStatus = - | "active" - | "pending_initialized" - | "pending_queued" - | "active_ongoing" - | "active_exiting" - | "active_slashed" - | "exited_unslashed" - | "exited_slashed" - | "withdrawal_possible" - | "withdrawal_done"; +export type {ValidatorStatus}; export const RandaoResponseType = new ContainerType({ randao: ssz.Root, diff --git a/packages/beacon-node/src/api/impl/beacon/state/index.ts b/packages/beacon-node/src/api/impl/beacon/state/index.ts index 669aaa9d1fb3..2bf758a8e286 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/index.ts @@ -9,16 +9,11 @@ import { getRandaoMix, } from "@lodestar/state-transition"; import {EPOCHS_PER_HISTORICAL_VECTOR} from "@lodestar/params"; +import {getValidatorStatus} from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; import {ApiError} from "../../errors.js"; import {ApiModules} from "../../types.js"; -import { - filterStateValidatorsByStatus, - getStateValidatorIndex, - getValidatorStatus, - getStateResponse, - toValidatorResponse, -} from "./utils.js"; +import {filterStateValidatorsByStatus, getStateValidatorIndex, getStateResponse, toValidatorResponse} from "./utils.js"; export function getBeaconStateApi({ chain, diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index de21c6a244ed..5e9d3be01221 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -1,8 +1,8 @@ import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {routes} from "@lodestar/api"; -import {FAR_FUTURE_EPOCH, GENESIS_SLOT} from "@lodestar/params"; +import {GENESIS_SLOT} from "@lodestar/params"; import {BeaconStateAllForks} from "@lodestar/state-transition"; -import {BLSPubkey, Epoch, phase0, RootHex, Slot, ValidatorIndex} from "@lodestar/types"; +import {BLSPubkey, Epoch, getValidatorStatus, phase0, RootHex, Slot, ValidatorIndex} from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; import {CheckpointWithHex, IForkChoice} from "@lodestar/fork-choice"; import {IBeaconChain} from "../../../../chain/index.js"; @@ -83,38 +83,6 @@ export async function getStateResponseWithRegen( return res; } -/** - * Get the status of the validator - * based on conditions outlined in https://hackmd.io/ofFJ5gOmQpu1jjHilHbdQQ - */ -export function getValidatorStatus(validator: phase0.Validator, currentEpoch: Epoch): routes.beacon.ValidatorStatus { - // pending - if (validator.activationEpoch > currentEpoch) { - if (validator.activationEligibilityEpoch === FAR_FUTURE_EPOCH) { - return "pending_initialized"; - } else if (validator.activationEligibilityEpoch < FAR_FUTURE_EPOCH) { - return "pending_queued"; - } - } - // active - if (validator.activationEpoch <= currentEpoch && currentEpoch < validator.exitEpoch) { - if (validator.exitEpoch === FAR_FUTURE_EPOCH) { - return "active_ongoing"; - } else if (validator.exitEpoch < FAR_FUTURE_EPOCH) { - return validator.slashed ? "active_slashed" : "active_exiting"; - } - } - // exited - if (validator.exitEpoch <= currentEpoch && currentEpoch < validator.withdrawableEpoch) { - return validator.slashed ? "exited_slashed" : "exited_unslashed"; - } - // withdrawal - if (validator.withdrawableEpoch <= currentEpoch) { - return validator.effectiveBalance !== 0 ? "withdrawal_possible" : "withdrawal_done"; - } - throw new Error("ValidatorStatus unknown"); -} - export function toValidatorResponse( index: ValidatorIndex, validator: phase0.Validator, diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 2347d7086d46..8a500125ad06 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -41,6 +41,7 @@ import { BeaconBlock, BlockContents, BlindedBeaconBlock, + getValidatorStatus, } from "@lodestar/types"; import {ExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; import {fromHex, toHex, resolveOrRacePromises, prettyWeiToEth, toRootHex} from "@lodestar/utils"; @@ -61,7 +62,6 @@ import {validateSyncCommitteeGossipContributionAndProof} from "../../../chain/va import {CommitteeSubscription} from "../../../network/subnets/index.js"; import {ApiModules} from "../types.js"; import {RegenCaller} from "../../../chain/regen/index.js"; -import {getValidatorStatus} from "../beacon/state/utils.js"; import {validateGossipFnRetryUnknownRoot} from "../../../network/processor/gossipHandlers.js"; import {SCHEDULER_LOOKAHEAD_FACTOR} from "../../../chain/prepareNextSlot.js"; import {ChainEvent, CheckpointHex, CommonBlockBody} from "../../../chain/index.js"; diff --git a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts index 79a8f3383e5d..39c936c0d025 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts @@ -1,107 +1,9 @@ import {describe, it, expect} from "vitest"; import {toHexString} from "@chainsafe/ssz"; -import {phase0} from "@lodestar/types"; -import {getValidatorStatus, getStateValidatorIndex} from "../../../../../../src/api/impl/beacon/state/utils.js"; +import {getStateValidatorIndex} from "../../../../../../src/api/impl/beacon/state/utils.js"; import {generateCachedAltairState} from "../../../../../utils/state.js"; describe("beacon state api utils", function () { - describe("getValidatorStatus", function () { - it("should return PENDING_INITIALIZED", function () { - const validator = { - activationEpoch: 1, - activationEligibilityEpoch: Infinity, - } as phase0.Validator; - const currentEpoch = 0; - const status = getValidatorStatus(validator, currentEpoch); - expect(status).toBe("pending_initialized"); - }); - it("should return PENDING_QUEUED", function () { - const validator = { - activationEpoch: 1, - activationEligibilityEpoch: 101010101101010, - } as phase0.Validator; - const currentEpoch = 0; - const status = getValidatorStatus(validator, currentEpoch); - expect(status).toBe("pending_queued"); - }); - it("should return ACTIVE_ONGOING", function () { - const validator = { - activationEpoch: 1, - exitEpoch: Infinity, - } as phase0.Validator; - const currentEpoch = 1; - const status = getValidatorStatus(validator, currentEpoch); - expect(status).toBe("active_ongoing"); - }); - it("should return ACTIVE_SLASHED", function () { - const validator = { - activationEpoch: 1, - exitEpoch: 101010101101010, - slashed: true, - } as phase0.Validator; - const currentEpoch = 1; - const status = getValidatorStatus(validator, currentEpoch); - expect(status).toBe("active_slashed"); - }); - it("should return ACTIVE_EXITING", function () { - const validator = { - activationEpoch: 1, - exitEpoch: 101010101101010, - slashed: false, - } as phase0.Validator; - const currentEpoch = 1; - const status = getValidatorStatus(validator, currentEpoch); - expect(status).toBe("active_exiting"); - }); - it("should return EXITED_SLASHED", function () { - const validator = { - exitEpoch: 1, - withdrawableEpoch: 3, - slashed: true, - } as phase0.Validator; - const currentEpoch = 2; - const status = getValidatorStatus(validator, currentEpoch); - expect(status).toBe("exited_slashed"); - }); - it("should return EXITED_UNSLASHED", function () { - const validator = { - exitEpoch: 1, - withdrawableEpoch: 3, - slashed: false, - } as phase0.Validator; - const currentEpoch = 2; - const status = getValidatorStatus(validator, currentEpoch); - expect(status).toBe("exited_unslashed"); - }); - it("should return WITHDRAWAL_POSSIBLE", function () { - const validator = { - withdrawableEpoch: 1, - effectiveBalance: 32, - } as phase0.Validator; - const currentEpoch = 1; - const status = getValidatorStatus(validator, currentEpoch); - expect(status).toBe("withdrawal_possible"); - }); - it("should return WITHDRAWAL_DONE", function () { - const validator = { - withdrawableEpoch: 1, - effectiveBalance: 0, - } as phase0.Validator; - const currentEpoch = 1; - const status = getValidatorStatus(validator, currentEpoch); - expect(status).toBe("withdrawal_done"); - }); - it("should error", function () { - const validator = {} as phase0.Validator; - const currentEpoch = 0; - try { - getValidatorStatus(validator, currentEpoch); - } catch (error) { - expect(error).toHaveProperty("message", "ValidatorStatus unknown"); - } - }); - }); - describe("getStateValidatorIndex", () => { const state = generateCachedAltairState(); const pubkey2index = state.epochCtx.pubkey2index; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index e0745834c7d1..dc9139dc967e 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -9,3 +9,4 @@ export * from "./utils/typeguards.js"; export {StringType, stringType} from "./utils/stringType.js"; // Container utils export * from "./utils/container.js"; +export * from "./utils/validatorStatus.js"; diff --git a/packages/types/src/utils/validatorStatus.ts b/packages/types/src/utils/validatorStatus.ts new file mode 100644 index 000000000000..e14a4b14c412 --- /dev/null +++ b/packages/types/src/utils/validatorStatus.ts @@ -0,0 +1,46 @@ +import {FAR_FUTURE_EPOCH} from "@lodestar/params"; +import {Epoch, phase0} from "../types.js"; + +export type ValidatorStatus = + | "active" + | "pending_initialized" + | "pending_queued" + | "active_ongoing" + | "active_exiting" + | "active_slashed" + | "exited_unslashed" + | "exited_slashed" + | "withdrawal_possible" + | "withdrawal_done"; + +/** + * Get the status of the validator + * based on conditions outlined in https://hackmd.io/ofFJ5gOmQpu1jjHilHbdQQ + */ +export function getValidatorStatus(validator: phase0.Validator, currentEpoch: Epoch): ValidatorStatus { + // pending + if (validator.activationEpoch > currentEpoch) { + if (validator.activationEligibilityEpoch === FAR_FUTURE_EPOCH) { + return "pending_initialized"; + } else if (validator.activationEligibilityEpoch < FAR_FUTURE_EPOCH) { + return "pending_queued"; + } + } + // active + if (validator.activationEpoch <= currentEpoch && currentEpoch < validator.exitEpoch) { + if (validator.exitEpoch === FAR_FUTURE_EPOCH) { + return "active_ongoing"; + } else if (validator.exitEpoch < FAR_FUTURE_EPOCH) { + return validator.slashed ? "active_slashed" : "active_exiting"; + } + } + // exited + if (validator.exitEpoch <= currentEpoch && currentEpoch < validator.withdrawableEpoch) { + return validator.slashed ? "exited_slashed" : "exited_unslashed"; + } + // withdrawal + if (validator.withdrawableEpoch <= currentEpoch) { + return validator.effectiveBalance !== 0 ? "withdrawal_possible" : "withdrawal_done"; + } + throw new Error("ValidatorStatus unknown"); +} diff --git a/packages/types/test/unit/validatorStatus.test.ts b/packages/types/test/unit/validatorStatus.test.ts new file mode 100644 index 000000000000..8d04c0f98e3d --- /dev/null +++ b/packages/types/test/unit/validatorStatus.test.ts @@ -0,0 +1,100 @@ +import {describe, it, expect} from "vitest"; +import {getValidatorStatus} from "../../src/utils/validatorStatus.js"; +import {phase0} from "../../src/types.js"; + +describe("getValidatorStatus", function () { + it("should return PENDING_INITIALIZED", function () { + const validator = { + activationEpoch: 1, + activationEligibilityEpoch: Infinity, + } as phase0.Validator; + const currentEpoch = 0; + const status = getValidatorStatus(validator, currentEpoch); + expect(status).toBe("pending_initialized"); + }); + it("should return PENDING_QUEUED", function () { + const validator = { + activationEpoch: 1, + activationEligibilityEpoch: 101010101101010, + } as phase0.Validator; + const currentEpoch = 0; + const status = getValidatorStatus(validator, currentEpoch); + expect(status).toBe("pending_queued"); + }); + it("should return ACTIVE_ONGOING", function () { + const validator = { + activationEpoch: 1, + exitEpoch: Infinity, + } as phase0.Validator; + const currentEpoch = 1; + const status = getValidatorStatus(validator, currentEpoch); + expect(status).toBe("active_ongoing"); + }); + it("should return ACTIVE_SLASHED", function () { + const validator = { + activationEpoch: 1, + exitEpoch: 101010101101010, + slashed: true, + } as phase0.Validator; + const currentEpoch = 1; + const status = getValidatorStatus(validator, currentEpoch); + expect(status).toBe("active_slashed"); + }); + it("should return ACTIVE_EXITING", function () { + const validator = { + activationEpoch: 1, + exitEpoch: 101010101101010, + slashed: false, + } as phase0.Validator; + const currentEpoch = 1; + const status = getValidatorStatus(validator, currentEpoch); + expect(status).toBe("active_exiting"); + }); + it("should return EXITED_SLASHED", function () { + const validator = { + exitEpoch: 1, + withdrawableEpoch: 3, + slashed: true, + } as phase0.Validator; + const currentEpoch = 2; + const status = getValidatorStatus(validator, currentEpoch); + expect(status).toBe("exited_slashed"); + }); + it("should return EXITED_UNSLASHED", function () { + const validator = { + exitEpoch: 1, + withdrawableEpoch: 3, + slashed: false, + } as phase0.Validator; + const currentEpoch = 2; + const status = getValidatorStatus(validator, currentEpoch); + expect(status).toBe("exited_unslashed"); + }); + it("should return WITHDRAWAL_POSSIBLE", function () { + const validator = { + withdrawableEpoch: 1, + effectiveBalance: 32, + } as phase0.Validator; + const currentEpoch = 1; + const status = getValidatorStatus(validator, currentEpoch); + expect(status).toBe("withdrawal_possible"); + }); + it("should return WITHDRAWAL_DONE", function () { + const validator = { + withdrawableEpoch: 1, + effectiveBalance: 0, + } as phase0.Validator; + const currentEpoch = 1; + const status = getValidatorStatus(validator, currentEpoch); + expect(status).toBe("withdrawal_done"); + }); + it("should error", function () { + const validator = {} as phase0.Validator; + const currentEpoch = 0; + try { + getValidatorStatus(validator, currentEpoch); + } catch (error) { + expect(error).toHaveProperty("message", "ValidatorStatus unknown"); + } + }); +}); From 3cef06f17deb37ed78ff69f327ae549a944a2a0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:28:27 +0100 Subject: [PATCH 136/259] chore(deps): bump rollup from 4.16.1 to 4.22.4 (#7103) Bumps [rollup](https://github.com/rollup/rollup) from 4.16.1 to 4.22.4. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.16.1...v4.22.4) --- updated-dependencies: - dependency-name: rollup dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 196 +++++++++++++++++++++++++++--------------------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/yarn.lock b/yarn.lock index a96092ec2fff..6d080025630a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2713,85 +2713,85 @@ 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" - integrity sha512-92/y0TqNLRYOTXpm6Z7mnpvKAG9P7qmK7yJeRJSdzElNCUnsgbpAsGqerUboYRIQKzgfq4pWu9xVkgpWLfmNsw== - -"@rollup/rollup-android-arm64@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.16.1.tgz#e7bd4f2b8ec5e049f98edbc68d72cb05356f81d8" - integrity sha512-ttWB6ZCfRLuDIUiE0yiu5gcqOsYjA5F7kEV1ggHMj20FwLZ8A1FMeahZJFl/pnOmcnD2QL0z4AcDuo27utGU8A== - -"@rollup/rollup-darwin-arm64@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.16.1.tgz#8fd277b4be6cc956167710e36b4ee365f8a44050" - integrity sha512-QLDvPLetbqjHojTGFw9+nuSP3YY/iz2k1cep6crYlr97sS+ZJ0W43b8Z0zC00+lnFZj6JSNxiA4DjboNQMuh1A== - -"@rollup/rollup-darwin-x64@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.16.1.tgz#5ab829322926fefce42db3529649a1098b420fe3" - integrity sha512-TAUK/D8khRrRIa1KwRzo8JNKk3tcqaeXWdtsiLgA8zmACWwlWLjPCJ4DULGHQrMkeBjp1Cd3Yuwx04lZgFx5Vg== - -"@rollup/rollup-linux-arm-gnueabihf@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.16.1.tgz#0154bc34e6a88fb0147adc827512add8d3a2338c" - integrity sha512-KO+WGZjrh6zyFTD1alIFkfdtxf8B4BC+hqd3kBZHscPLvE5FR/6QKsyuCT0JlERxxYBSUKNUQ/UHyX5uwO1x2A== - -"@rollup/rollup-linux-arm-musleabihf@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.16.1.tgz#0f3fa433a81b389042555133d38b4b886b369e58" - integrity sha512-NqxbllzIB1WoAo4ThUXVtd21iiM5IHMTTXmXySKBLVcZvkU0HIZmatlP7hLzb5yQubcmdIeWmncd2NdsjocEiw== - -"@rollup/rollup-linux-arm64-gnu@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.16.1.tgz#c8f2d523ac4bcff382601306989b27137d536dd6" - integrity sha512-snma5NvV8y7IECQ5rq0sr0f3UUu+92NVmG/913JXJMcXo84h9ak9TA5UI9Cl2XRM9j3m37QwDBtEYnJzRkSmxA== - -"@rollup/rollup-linux-arm64-musl@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.16.1.tgz#86b5104635131182b6b2b6997c4aa5594ce557b7" - integrity sha512-KOvqGprlD84ueivhCi2flvcUwDRD20mAsE3vxQNVEI2Di9tnPGAfEu6UcrSPZbM+jG2w1oSr43hrPo0RNg6GGg== - -"@rollup/rollup-linux-powerpc64le-gnu@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.16.1.tgz#5de8b20105aaaeb36eb86fab0a1020d81c7bd4d5" - integrity sha512-/gsNwtiGLqYwN4vP+EIdUC6Q6LTlpupWqokqIndvZcjn9ig/5P01WyaYCU2wvfL/2Z82jp5kX8c1mDBOvCP3zg== - -"@rollup/rollup-linux-riscv64-gnu@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.16.1.tgz#5319629dcdcb85ba201c6f0f894c9472e7d1013d" - integrity sha512-uU8zuGkQfGqfD9w6VRJZI4IuG4JIfNxxJgEmLMAmPVHREKGsxFVfgHy5c6CexQF2vOfgjB33OsET3Vdn2lln9A== - -"@rollup/rollup-linux-s390x-gnu@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.16.1.tgz#246ac211ed0d78f7a9bc5c1d0653bde4c6cd9f63" - integrity sha512-lsjLtDgtcGFEuBP6yrXwkRN5/wKlvUZtfbKZZu0yaoNpiBL4epgnO21osAALIspVRnl4qZgyLFd8xjCYYWgwfw== - -"@rollup/rollup-linux-x64-gnu@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.16.1.tgz#d0c03203ddeb9454fc6fdde93a39b01c176ac6d9" - integrity sha512-N2ZizKhUryqqrMfdCnjhJhZRgv61C6gK+hwVtCIKC8ts8J+go+vqENnGexwg21nHIOvLN5mBM8a7DI2vlyIOPg== - -"@rollup/rollup-linux-x64-musl@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.16.1.tgz#20235632e2be4689d663aadaceaaf90df03b1a33" - integrity sha512-5ICeMxqg66FrOA2AbnBQ2TJVxfvZsKLxmof0ibvPLaYtbsJqnTUtJOofgWb46Gjd4uZcA4rdsp4JCxegzQPqCg== - -"@rollup/rollup-win32-arm64-msvc@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.16.1.tgz#af113ad682fc13d1f870242c5539031f8cc27cf1" - integrity sha512-1vIP6Ce02L+qWD7uZYRiFiuAJo3m9kARatWmFSnss0gZnVj2Id7OPUU9gm49JPGasgcR3xMqiH3fqBJ8t00yVg== - -"@rollup/rollup-win32-ia32-msvc@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.16.1.tgz#4e7b57e757c95da8e79092056d1b428617515668" - integrity sha512-Y3M92DcVsT6LoP+wrKpoUWPaazaP1fzbNkp0a0ZSj5Y//+pQVfVe/tQdsYQQy7dwXR30ZfALUIc9PCh9Izir6w== - -"@rollup/rollup-win32-x64-msvc@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.1.tgz#5068a893ba292279adbe76fc487316724b15d811" - integrity sha512-x0fvpHMuF7fK5r8oZxSi8VYXkrVmRgubXpO/wcf15Lk3xZ4Jvvh5oG+u7Su1776A7XzVKZhD2eRc4t7H50gL3w== +"@rollup/rollup-android-arm-eabi@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz#8b613b9725e8f9479d142970b106b6ae878610d5" + integrity sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w== + +"@rollup/rollup-android-arm64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz#654ca1049189132ff602bfcf8df14c18da1f15fb" + integrity sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA== + +"@rollup/rollup-darwin-arm64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz#6d241d099d1518ef0c2205d96b3fa52e0fe1954b" + integrity sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q== + +"@rollup/rollup-darwin-x64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz#42bd19d292a57ee11734c980c4650de26b457791" + integrity sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw== + +"@rollup/rollup-linux-arm-gnueabihf@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz#f23555ee3d8fe941c5c5fd458cd22b65eb1c2232" + integrity sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ== + +"@rollup/rollup-linux-arm-musleabihf@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz#f3bbd1ae2420f5539d40ac1fde2b38da67779baa" + integrity sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg== + +"@rollup/rollup-linux-arm64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz#7abe900120113e08a1f90afb84c7c28774054d15" + integrity sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw== + +"@rollup/rollup-linux-arm64-musl@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz#9e655285c8175cd44f57d6a1e8e5dedfbba1d820" + integrity sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA== + +"@rollup/rollup-linux-powerpc64le-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz#9a79ae6c9e9d8fe83d49e2712ecf4302db5bef5e" + integrity sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg== + +"@rollup/rollup-linux-riscv64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz#67ac70eca4ace8e2942fabca95164e8874ab8128" + integrity sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA== + +"@rollup/rollup-linux-s390x-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz#9f883a7440f51a22ed7f99e1d070bd84ea5005fc" + integrity sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q== + +"@rollup/rollup-linux-x64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz#70116ae6c577fe367f58559e2cffb5641a1dd9d0" + integrity sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg== + +"@rollup/rollup-linux-x64-musl@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz#f473f88219feb07b0b98b53a7923be716d1d182f" + integrity sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g== + +"@rollup/rollup-win32-arm64-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz#4349482d17f5d1c58604d1c8900540d676f420e0" + integrity sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw== + +"@rollup/rollup-win32-ia32-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz#a6fc39a15db618040ec3c2a24c1e26cb5f4d7422" + integrity sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g== + +"@rollup/rollup-win32-x64-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz#3dd5d53e900df2a40841882c02e56f866c04d202" + integrity sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q== "@rushstack/node-core-library@4.0.2": version "4.0.2" @@ -11514,28 +11514,28 @@ rollup-plugin-visualizer@^5.12.0: yargs "^17.5.1" rollup@^4.13.0: - version "4.16.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.16.1.tgz#5a60230987fe95ebe68bab517297c116dbb1a88d" - integrity sha512-5CaD3MPDlPKfhqzRvWXK96G6ELJfPZNb3LHiZxTHgDdC6jvwfGz2E8nY+9g1ONk4ttHsK1WaFP19Js4PSr1E3g== + version "4.22.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.22.4.tgz#4135a6446671cd2a2453e1ad42a45d5973ec3a0f" + integrity sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A== dependencies: "@types/estree" "1.0.5" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.16.1" - "@rollup/rollup-android-arm64" "4.16.1" - "@rollup/rollup-darwin-arm64" "4.16.1" - "@rollup/rollup-darwin-x64" "4.16.1" - "@rollup/rollup-linux-arm-gnueabihf" "4.16.1" - "@rollup/rollup-linux-arm-musleabihf" "4.16.1" - "@rollup/rollup-linux-arm64-gnu" "4.16.1" - "@rollup/rollup-linux-arm64-musl" "4.16.1" - "@rollup/rollup-linux-powerpc64le-gnu" "4.16.1" - "@rollup/rollup-linux-riscv64-gnu" "4.16.1" - "@rollup/rollup-linux-s390x-gnu" "4.16.1" - "@rollup/rollup-linux-x64-gnu" "4.16.1" - "@rollup/rollup-linux-x64-musl" "4.16.1" - "@rollup/rollup-win32-arm64-msvc" "4.16.1" - "@rollup/rollup-win32-ia32-msvc" "4.16.1" - "@rollup/rollup-win32-x64-msvc" "4.16.1" + "@rollup/rollup-android-arm-eabi" "4.22.4" + "@rollup/rollup-android-arm64" "4.22.4" + "@rollup/rollup-darwin-arm64" "4.22.4" + "@rollup/rollup-darwin-x64" "4.22.4" + "@rollup/rollup-linux-arm-gnueabihf" "4.22.4" + "@rollup/rollup-linux-arm-musleabihf" "4.22.4" + "@rollup/rollup-linux-arm64-gnu" "4.22.4" + "@rollup/rollup-linux-arm64-musl" "4.22.4" + "@rollup/rollup-linux-powerpc64le-gnu" "4.22.4" + "@rollup/rollup-linux-riscv64-gnu" "4.22.4" + "@rollup/rollup-linux-s390x-gnu" "4.22.4" + "@rollup/rollup-linux-x64-gnu" "4.22.4" + "@rollup/rollup-linux-x64-musl" "4.22.4" + "@rollup/rollup-win32-arm64-msvc" "4.22.4" + "@rollup/rollup-win32-ia32-msvc" "4.22.4" + "@rollup/rollup-win32-x64-msvc" "4.22.4" fsevents "~2.3.2" rrweb-cssom@^0.6.0: From d44c409eaacdb07d0236991f5c64d6c733c5d889 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:28:58 +0100 Subject: [PATCH 137/259] chore(deps): bump micromatch from 4.0.5 to 4.0.8 in /docs (#7117) Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.5 to 4.0.8. - [Release notes](https://github.com/micromatch/micromatch/releases) - [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/micromatch/compare/4.0.5...4.0.8) --- updated-dependencies: - dependency-name: micromatch dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/yarn.lock | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/docs/yarn.lock b/docs/yarn.lock index 27123932fe26..dad4d8ef1c07 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -3187,7 +3187,14 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.2, braces@~3.0.2: +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -4772,6 +4779,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + finalhandler@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" @@ -6965,11 +6979,11 @@ micromark@^4.0.0: micromark-util-types "^2.0.0" micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": From 489accbc90dd88807426c5ad6751f9a53addd754 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 10 Oct 2024 17:28:30 +0100 Subject: [PATCH 138/259] fix: allow to disable peer discovery / discv5 (#7144) * fix: allow to disable peer discovery / discv5 * Explicitly check for false --- packages/cli/src/cmds/beacon/handler.ts | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/cli/src/cmds/beacon/handler.ts b/packages/cli/src/cmds/beacon/handler.ts index d51af66e37d0..81536d7c7b41 100644 --- a/packages/cli/src/cmds/beacon/handler.ts +++ b/packages/cli/src/cmds/beacon/handler.ts @@ -175,14 +175,6 @@ export async function beaconHandlerInit(args: BeaconArgs & GlobalArgs) { // Add detailed version string for API node/version endpoint beaconNodeOptions.set({api: {commit, version}}); - // Combine bootnodes from different sources - const bootnodes = (beaconNodeOptions.get().network?.discv5?.bootEnrs ?? []).concat( - args.bootnodesFile ? readBootnodes(args.bootnodesFile) : [], - isKnownNetworkName(network) ? await getNetworkBootnodes(network) : [] - ); - // Deduplicate and set combined bootnodes - beaconNodeOptions.set({network: {discv5: {bootEnrs: [...new Set(bootnodes)]}}}); - // Set known depositContractDeployBlock if (isKnownNetworkName(network)) { const {depositContractDeployBlock} = getNetworkData(network); @@ -191,8 +183,19 @@ export async function beaconHandlerInit(args: BeaconArgs & GlobalArgs) { const logger = initLogger(args, beaconPaths.dataDir, config); const {peerId, enr} = await initPeerIdAndEnr(args, beaconPaths.beaconDir, logger); - // Inject ENR to beacon options - beaconNodeOptions.set({network: {discv5: {enr: enr.encodeTxt(), config: {enrUpdate: !enr.ip && !enr.ip6}}}}); + + if (args.discv5 !== false) { + // Inject ENR to beacon options + beaconNodeOptions.set({network: {discv5: {enr: enr.encodeTxt(), config: {enrUpdate: !enr.ip && !enr.ip6}}}}); + + // Combine bootnodes from different sources + const bootnodes = (beaconNodeOptions.get().network?.discv5?.bootEnrs ?? []).concat( + args.bootnodesFile ? readBootnodes(args.bootnodesFile) : [], + isKnownNetworkName(network) ? await getNetworkBootnodes(network) : [] + ); + // Deduplicate and set combined bootnodes + beaconNodeOptions.set({network: {discv5: {bootEnrs: [...new Set(bootnodes)]}}}); + } if (args.disableLightClientServer) { beaconNodeOptions.set({chain: {disableLightClientServer: true}}); From 5c359f92dcf0f46e9453b09e8948024b15affa81 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Thu, 10 Oct 2024 18:43:36 +0200 Subject: [PATCH 139/259] deps: migrate to biomejs from eslint (#7108) * Replace eslint with biomejs * Update the inclusion of word * Fix the formatting * Update the lint task to do all checks * Update biome rules from eslint config * Replace eslint with biomejs * Update the inclusion of word * Fix the formatting * Update the lint task to do all checks * Update biome rules from eslint config * Fix all lint issues * Fix formatting * Add extension recomendation for vscode * Enable recommended rules * Enable rule noUselessSwitchCase * Enable rule noUselessConstructor * Fix the types * Fix unit tests * Enforce import extensions * Update the cli command * Enforce useConsistentMemberAccessibility * Update rules * Fix rules * Upgrade biomejs to latest version * Update the rules * Update and format the config file * Fix types break during merge * Fix unused check * Add comment for explicit-return-type * Remove eslint file * Add _e objects for empty catch blocks * Update formatter config * Fix formatting --- .editorconfig | 9 + .eslintrc.js | 275 ------ .github/workflows/test.yml | 3 - .vscode/extensions.json | 5 + .wordlist.txt | 1 - CONTRIBUTING.md | 2 +- biome.jsonc | 376 ++++++++ package.json | 13 +- packages/api/package.json | 4 +- packages/api/src/beacon/client/events.ts | 11 +- .../api/src/beacon/routes/beacon/block.ts | 3 +- packages/api/src/beacon/routes/beacon/pool.ts | 1 - .../api/src/beacon/routes/beacon/rewards.ts | 1 - .../api/src/beacon/routes/beacon/state.ts | 3 +- packages/api/src/beacon/routes/config.ts | 1 - packages/api/src/beacon/routes/debug.ts | 1 - packages/api/src/beacon/routes/events.ts | 2 - packages/api/src/beacon/routes/lightclient.ts | 1 - packages/api/src/beacon/routes/lodestar.ts | 2 +- packages/api/src/beacon/routes/node.ts | 1 - packages/api/src/beacon/routes/proof.ts | 1 - packages/api/src/beacon/routes/validator.ts | 1 - packages/api/src/beacon/server/index.ts | 2 +- packages/api/src/builder/routes.ts | 1 - packages/api/src/keymanager/routes.ts | 1 - packages/api/src/utils/client/eventSource.ts | 1 - packages/api/src/utils/client/fetch.ts | 2 +- packages/api/src/utils/client/httpClient.ts | 3 +- packages/api/src/utils/client/response.ts | 8 +- packages/api/src/utils/codecs.ts | 4 - packages/api/src/utils/metadata.ts | 1 - packages/api/src/utils/serdes.ts | 2 +- packages/api/src/utils/server/handler.ts | 1 - packages/api/src/utils/server/method.ts | 7 +- .../test/perf/compileRouteUrlFormater.test.ts | 2 - .../beacon/genericServerTest/beacon.test.ts | 1 - .../beacon/genericServerTest/config.test.ts | 2 - .../api/test/unit/beacon/oapiSpec.test.ts | 2 - .../api/test/unit/beacon/testData/events.ts | 2 - .../api/test/unit/builder/builder.test.ts | 1 - .../api/test/unit/builder/oapiSpec.test.ts | 2 - packages/api/test/unit/client/fetch.test.ts | 1 - .../unit/client/httpClientFallback.test.ts | 1 - .../api/test/unit/client/urlFormat.test.ts | 2 - .../api/test/unit/keymanager/oapiSpec.test.ts | 1 - packages/api/test/utils/checkAgainstSpec.ts | 5 +- packages/api/test/utils/parseOpenApiSpec.ts | 1 - packages/api/test/utils/utils.ts | 1 - packages/beacon-node/package.json | 4 +- .../src/api/impl/beacon/blocks/index.ts | 22 +- .../src/api/impl/beacon/pool/index.ts | 1 - .../src/api/impl/beacon/state/utils.ts | 2 +- .../src/api/impl/config/constants.ts | 2 - .../beacon-node/src/api/impl/events/index.ts | 3 +- .../beacon-node/src/api/impl/node/utils.ts | 1 + .../src/api/impl/validator/index.ts | 1 - .../beacon-node/src/api/rest/activeSockets.ts | 2 +- .../beacon-node/src/api/rest/swaggerUI.ts | 5 +- .../blocks/verifyBlocksDataAvailability.ts | 3 +- .../src/chain/bls/multithread/index.ts | 3 +- .../src/chain/bls/multithread/poolSize.ts | 2 +- .../src/chain/bls/multithread/worker.ts | 2 +- packages/beacon-node/src/chain/emitter.ts | 2 +- packages/beacon-node/src/chain/initState.ts | 2 +- .../validateBlobsAndKzgCommitments.ts | 3 +- .../src/chain/rewards/attestationsRewards.ts | 4 +- .../src/chain/validation/aggregateAndProof.ts | 2 +- .../src/chain/validation/attesterSlashing.ts | 2 +- .../chain/validation/blsToExecutionChange.ts | 2 +- .../src/chain/validation/proposerSlashing.ts | 2 +- .../src/chain/validation/voluntaryExit.ts | 2 +- .../src/db/repositories/backfilledRanges.ts | 3 +- .../src/db/repositories/checkpointState.ts | 1 - .../src/db/repositories/depositDataRoot.ts | 3 +- .../src/db/repositories/eth1Data.ts | 3 +- .../src/db/repositories/stateArchive.ts | 2 +- .../preGenesisStateLastProcessedBlock.ts | 2 +- .../src/eth1/eth1MergeBlockTracker.ts | 2 - .../src/eth1/provider/eth1Provider.ts | 2 - .../src/eth1/provider/jsonRpcHttpClient.ts | 2 +- packages/beacon-node/src/eth1/provider/jwt.ts | 1 - .../src/execution/builder/index.ts | 1 + .../beacon-node/src/execution/engine/http.ts | 4 +- .../beacon-node/src/execution/engine/index.ts | 2 + .../beacon-node/src/execution/engine/mock.ts | 1 - .../beacon-node/src/execution/engine/types.ts | 2 - .../beacon-node/src/execution/engine/utils.ts | 5 +- .../beacon-node/src/metrics/metrics/beacon.ts | 1 - .../src/metrics/metrics/lodestar.ts | 1 - .../beacon-node/src/monitoring/service.ts | 2 +- packages/beacon-node/src/monitoring/system.ts | 1 - .../beacon-node/src/network/core/metrics.ts | 2 - .../src/network/core/networkCore.ts | 2 +- .../src/network/core/networkCoreWorker.ts | 1 - .../network/core/networkCoreWorkerHandler.ts | 2 +- .../beacon-node/src/network/core/types.ts | 2 +- .../beacon-node/src/network/discv5/index.ts | 2 +- .../beacon-node/src/network/discv5/worker.ts | 1 - packages/beacon-node/src/network/events.ts | 2 +- packages/beacon-node/src/network/forks.ts | 1 - .../src/network/gossip/gossipsub.ts | 1 - .../src/network/gossip/interface.ts | 2 +- .../beacon-node/src/network/gossip/metrics.ts | 1 - .../src/network/gossip/scoringParameters.ts | 2 - .../beacon-node/src/network/gossip/topic.ts | 5 +- .../src/network/peers/datastore.ts | 3 +- .../beacon-node/src/network/peers/discover.ts | 1 - .../src/network/peers/peerManager.ts | 8 +- .../src/network/processor/gossipHandlers.ts | 1 - .../src/network/processor/index.ts | 4 +- .../reqresp/beaconBlocksMaybeBlobsByRange.ts | 1 + .../src/network/reqresp/protocols.ts | 2 - .../src/network/reqresp/rateLimit.ts | 2 +- .../beacon-node/src/network/reqresp/score.ts | 1 - packages/beacon-node/src/network/util.ts | 1 - .../beacon-node/src/sync/backfill/backfill.ts | 5 +- packages/beacon-node/src/sync/range/range.ts | 2 +- .../src/util/asyncIterableToEvents.ts | 2 - packages/beacon-node/src/util/kzg.ts | 3 - packages/beacon-node/src/util/map.ts | 1 - packages/beacon-node/src/util/profile.ts | 2 +- packages/beacon-node/src/util/queue/errors.ts | 6 +- .../beacon-node/src/util/queue/fnQueue.ts | 4 +- .../beacon-node/src/util/queue/itemQueue.ts | 3 +- .../api/impl/beacon/node/endpoints.test.ts | 2 - .../e2e/api/impl/lightclient/endpoint.test.ts | 1 - .../test/e2e/api/lodestar/lodestar.test.ts | 1 - .../test/e2e/chain/lightclient.test.ts | 1 - .../test/e2e/chain/proposerBoostReorg.test.ts | 3 - .../stateCache/nHistoricalStates.test.ts | 1 - .../e2e/doppelganger/doppelganger.test.ts | 5 +- .../e2e/eth1/eth1ForBlockProduction.test.ts | 1 - .../e2e/eth1/eth1MergeBlockTracker.test.ts | 2 - .../test/e2e/eth1/jsonRpcHttpClient.test.ts | 1 - .../test/e2e/interop/genesisState.test.ts | 1 - .../test/e2e/network/gossipsub.test.ts | 30 +- .../beacon-node/test/e2e/network/mdns.test.ts | 2 - .../test/e2e/network/network.test.ts | 1 - .../e2e/network/peers/peerManager.test.ts | 1 - .../test/e2e/network/reqrespEncode.test.ts | 3 - .../test/e2e/sync/finalizedSync.test.ts | 3 +- .../test/e2e/sync/unknownBlockSync.test.ts | 1 - packages/beacon-node/test/globalSetup.ts | 1 - packages/beacon-node/test/memory/bytesHex.ts | 1 - .../beacon-node/test/memory/pubkeysToIndex.ts | 1 - .../test/memory/seenAttestationData.ts | 1 - .../test/memory/testRunnerMemory.ts | 2 - .../test/memory/unfinalizedPubkey2Index.ts | 1 - .../beacon-node/test/mocks/beaconSyncMock.ts | 1 - .../test/mocks/mockedBeaconChain.ts | 4 - .../beacon-node/test/mocks/mockedBeaconDb.ts | 1 - .../beacon-node/test/mocks/mockedNetwork.ts | 1 - .../perf/api/impl/validator/attester.test.ts | 1 - .../opPools/aggregatedAttestationPool.test.ts | 1 - .../test/perf/chain/opPools/opPool.test.ts | 1 - .../produceBlock/produceBlockBody.test.ts | 1 - .../validation/aggregateAndProof.test.ts | 1 - .../perf/chain/validation/attestation.test.ts | 1 - .../perf/chain/verifyImportBlocks.test.ts | 12 +- .../test/scripts/blsPubkeyBytesFrequency.ts | 3 - packages/beacon-node/test/setupPreset.ts | 1 - packages/beacon-node/test/spec/bls/bls.ts | 14 +- packages/beacon-node/test/spec/general/bls.ts | 18 +- .../test/spec/general/index.test.ts | 2 - .../test/spec/general/ssz_generic.ts | 2 +- .../test/spec/general/ssz_generic_types.ts | 2 - .../spec/presets/epoch_processing.test.ts | 4 +- .../test/spec/presets/finality.test.ts | 4 +- .../test/spec/presets/fork.test.ts | 2 +- .../test/spec/presets/fork_choice.test.ts | 2 - .../test/spec/presets/genesis.test.ts | 6 +- .../spec/presets/light_client/index.test.ts | 2 - .../light_client/single_merkle_proof.ts | 10 +- .../test/spec/presets/light_client/sync.ts | 2 - .../presets/light_client/update_ranking.ts | 2 - .../test/spec/presets/merkle.test.ts | 4 +- .../test/spec/presets/operations.test.ts | 4 +- .../test/spec/presets/rewards.test.ts | 4 +- .../test/spec/presets/sanity.test.ts | 6 +- .../test/spec/presets/ssz_static.test.ts | 3 +- .../test/spec/presets/transition.test.ts | 4 +- .../test/spec/specTestVersioning.ts | 1 - .../test/spec/utils/runValidSszTest.ts | 2 +- packages/beacon-node/test/spec/utils/types.ts | 2 - packages/beacon-node/test/tsconfig.json | 2 +- .../test/unit/api/impl/events/events.test.ts | 1 - .../api/impl/validator/produceBlockV3.test.ts | 3 +- .../test/unit/chain/beaconProposerCache.ts | 2 +- .../test/unit/chain/genesis/genesis.test.ts | 1 - .../upgradeLightClientHeader.test.ts | 1 - .../chain/opPools/attestationPool.test.ts | 1 - .../unit/chain/rewards/blockRewards.test.ts | 2 - .../seenCache/seenGossipBlockInput.test.ts | 1 - .../test/unit/chain/shufflingCache.test.ts | 1 - .../validation/aggregateAndProof.test.ts | 2 - ...hufflingForAttestationVerification.test.ts | 1 - .../attestation/validateAttestation.test.ts | 2 - .../test/unit/chain/validation/block.test.ts | 1 - .../lightClientFinalityUpdate.test.ts | 1 - .../lightClientOptimisticUpdate.test.ts | 1 - .../chain/validation/syncCommittee.test.ts | 1 - .../test/unit/db/api/repository.test.ts | 2 - .../unit/eth1/eth1MergeBlockTracker.test.ts | 2 - .../test/unit/eth1/utils/deposits.test.ts | 1 - .../optimizeNextBlockDiffForGenesis.test.ts | 3 - .../test/unit/monitoring/remoteService.ts | 2 +- .../test/unit/monitoring/service.test.ts | 1 - .../beaconBlocksMaybeBlobsByRange.test.ts | 1 - .../unit/network/peers/priorization.test.ts | 2 - .../test/unit/network/peers/score.test.ts | 1 - .../network/subnets/attnetsService.test.ts | 1 - .../test/unit/sync/backfill/verify.test.ts | 5 +- .../test/unit/sync/range/chain.test.ts | 4 +- .../test/unit/sync/unknownBlock.test.ts | 19 +- .../beacon-node/test/unit/util/kzg.test.ts | 3 +- packages/beacon-node/test/utils/clock.ts | 5 +- packages/beacon-node/test/utils/config.ts | 1 - .../beacon-node/test/utils/node/simTest.ts | 4 +- packages/beacon-node/test/utils/runEl.ts | 3 +- .../utils/validationData/aggregateAndProof.ts | 1 - .../test/utils/validationData/attestation.ts | 1 - packages/cli/docsgen/markdown.ts | 1 - packages/cli/package.json | 4 +- packages/cli/src/applyPreset.ts | 4 - packages/cli/src/cmds/beacon/handler.ts | 1 - .../cli/src/cmds/beacon/initPeerIdAndEnr.ts | 4 +- packages/cli/src/cmds/bootnode/handler.ts | 1 - .../keymanager/decryptKeystoreDefinitions.ts | 2 +- .../keymanager/decryptKeystores/poolSize.ts | 2 +- packages/cli/src/cmds/validator/options.ts | 4 +- .../cli/src/cmds/validator/voluntaryExit.ts | 1 - packages/cli/src/index.ts | 2 - packages/cli/src/networks/index.ts | 3 +- .../src/options/beaconNodeOptions/chain.ts | 2 +- .../cli/src/options/beaconNodeOptions/eth1.ts | 4 +- .../options/beaconNodeOptions/execution.ts | 4 +- .../src/options/beaconNodeOptions/network.ts | 13 +- packages/cli/src/util/file.ts | 1 - packages/cli/src/util/gitData/gitDataPath.ts | 1 - packages/cli/src/util/gitData/index.ts | 12 +- packages/cli/src/util/object.ts | 4 +- packages/cli/src/util/process.ts | 1 - packages/cli/src/util/proposerConfig.ts | 2 - packages/cli/src/util/types.ts | 3 +- packages/cli/src/util/version.ts | 1 - .../test/e2e/importKeystoresFromApi.test.ts | 1 - .../e2e/propserConfigfromKeymanager.test.ts | 1 - packages/cli/test/e2e/voluntaryExit.test.ts | 1 - .../cli/test/e2e/voluntaryExitFromApi.test.ts | 1 - .../e2e/voluntaryExitRemoteSigner.test.ts | 1 - packages/cli/test/scripts/e2e_test_env.ts | 1 - .../cli/test/sim/backupEthProvider.test.ts | 1 - packages/cli/test/sim/deneb.test.ts | 1 - packages/cli/test/sim/endpoints.test.ts | 1 - packages/cli/test/sim/mixedClient.test.ts | 1 - packages/cli/test/sim/multiFork.test.ts | 1 - packages/cli/test/unit/cmds/beacon.test.ts | 1 - .../cli/test/unit/config/beaconParams.test.ts | 8 - packages/cli/test/unit/db.test.ts | 2 - .../test/unit/options/paramsOptions.test.ts | 2 - packages/cli/test/unit/util/format.test.ts | 3 +- packages/cli/test/unit/util/gitData.test.ts | 1 - .../validator/parseProposerConfig.test.ts | 2 +- .../crucible/clients/beacon/lighthouse.ts | 1 - .../utils/crucible/clients/beacon/lodestar.ts | 1 - .../crucible/clients/validator/lodestar.ts | 1 - packages/cli/test/utils/crucible/constants.ts | 1 - .../cli/test/utils/crucible/epochClock.ts | 1 - .../utils/crucible/externalSignerServer.ts | 1 - .../cli/test/utils/crucible/interfaces.ts | 1 - .../utils/crucible/runner/dockerRunner.ts | 4 +- .../test/utils/crucible/simulationTracker.ts | 2 +- .../cli/test/utils/crucible/utils/index.ts | 3 +- .../cli/test/utils/crucible/utils/keys.ts | 1 - .../cli/test/utils/crucible/utils/network.ts | 1 - .../cli/test/utils/crucible/utils/syncing.ts | 5 +- .../cli/test/utils/mockBeaconApiServer.ts | 1 - packages/config/package.json | 4 +- .../config/src/chainConfig/configs/mainnet.ts | 1 - .../config/src/chainConfig/configs/minimal.ts | 1 - packages/config/src/chainConfig/default.ts | 3 +- .../config/src/chainConfig/networks/chiado.ts | 1 - .../src/chainConfig/networks/ephemery.ts | 1 - .../config/src/chainConfig/networks/gnosis.ts | 1 - .../src/chainConfig/networks/holesky.ts | 1 - .../src/chainConfig/networks/mainnet.ts | 1 - .../src/chainConfig/networks/sepolia.ts | 1 - packages/config/src/chainConfig/types.ts | 2 - packages/config/test/unit/index.test.ts | 1 - packages/db/package.json | 4 +- packages/db/src/abstractRepository.ts | 2 +- .../db/test/unit/controller/level.test.ts | 2 +- packages/flare/package.json | 4 +- packages/flare/src/index.ts | 2 - packages/fork-choice/package.json | 4 +- packages/fork-choice/src/forkChoice/errors.ts | 6 +- .../fork-choice/src/forkChoice/forkChoice.ts | 4 +- packages/fork-choice/src/forkChoice/store.ts | 8 +- packages/fork-choice/src/protoArray/errors.ts | 6 +- .../fork-choice/src/protoArray/protoArray.ts | 1 - .../test/unit/forkChoice/utils.test.ts | 1 - .../unit/protoArray/getCommonAncestor.test.ts | 2 +- packages/light-client/package.json | 4 +- packages/light-client/src/events.ts | 2 +- packages/light-client/src/index.ts | 1 - packages/light-client/src/spec/utils.ts | 3 - packages/light-client/src/utils/logger.ts | 2 +- .../unit/isValidLightClientHeader.test.ts | 1 - .../light-client/test/unit/sync.node.test.ts | 1 - packages/logger/package.json | 4 +- packages/logger/src/browser.ts | 2 - packages/logger/src/interface.ts | 2 - packages/logger/src/utils/consoleTransport.ts | 1 + packages/logger/src/utils/format.ts | 6 +- packages/logger/src/utils/json.ts | 1 + .../logger/test/e2e/logger/workerLogger.js | 1 - .../logger/test/e2e/logger/workerLogs.test.ts | 1 - packages/logger/test/unit/node.node.test.ts | 1 - packages/logger/test/unit/utils/json.test.ts | 3 - .../logger/test/unit/winston.node.test.ts | 1 - packages/params/package.json | 4 +- packages/params/src/presets/gnosis.ts | 1 - packages/params/src/presets/mainnet.ts | 1 - packages/params/src/presets/minimal.ts | 1 - packages/params/src/types.ts | 2 - .../test/e2e/ensure-config-is-synced.test.ts | 1 - .../params/test/e2e/overridePreset.test.ts | 1 - .../params/test/e2e/overridePresetError.ts | 1 - packages/params/test/e2e/overridePresetOk.ts | 1 - packages/params/test/e2e/setPreset.test.ts | 1 - packages/params/test/yaml.ts | 1 - packages/prover/package.json | 4 +- packages/prover/scripts/generate_fixtures.ts | 11 +- packages/prover/src/cli/applyPreset.ts | 3 - packages/prover/src/cli/cmds/start/options.ts | 4 +- packages/prover/src/cli/index.ts | 3 +- packages/prover/src/interfaces.ts | 2 +- packages/prover/src/types.ts | 7 +- packages/prover/src/utils/conversion.ts | 1 - packages/prover/src/utils/evm.ts | 2 +- packages/prover/src/utils/file.ts | 1 - .../prover/src/utils/gitData/gitDataPath.ts | 1 - packages/prover/src/utils/gitData/index.ts | 12 +- packages/prover/src/utils/process.ts | 2 +- packages/prover/src/utils/version.ts | 1 - .../prover/src/verified_requests/eth_call.ts | 1 - .../src/verified_requests/eth_estimateGas.ts | 1 - .../src/verified_requests/eth_getBalance.ts | 1 - .../verified_requests/eth_getBlockByHash.ts | 1 - .../verified_requests/eth_getBlockByNumber.ts | 1 - .../src/verified_requests/eth_getCode.ts | 1 - .../eth_getTransactionCount.ts | 2 - .../test/fixtures/mainnet/eth_call.json | 2 +- .../eth_estimateGas_contract_call.json | 2 +- .../eth_estimateGas_simple_transfer.json | 2 +- .../sepolia/eth_getBalance_contract.json | 2 +- .../fixtures/sepolia/eth_getBalance_eoa.json | 2 +- .../eth_getBlock_with_contractCreation.json | 7 +- .../eth_getBlock_with_no_accessList.json | 7 +- .../test/fixtures/sepolia/eth_getCode.json | 2 +- .../sepolia/eth_getTransactionCount.json | 2 +- packages/prover/test/mocks/request_handler.ts | 1 - packages/prover/test/tsconfig.json | 2 +- .../eth_getBlockByHash.test.ts | 8 +- .../eth_getBlockByNumber.test.ts | 9 +- packages/prover/test/utils/e2e_env.ts | 1 - packages/reqresp/package.json | 4 +- .../reqresp/src/encoders/responseDecode.ts | 3 +- .../encodingStrategies/sszSnappy/decode.ts | 2 +- .../encodingStrategies/sszSnappy/errors.ts | 6 +- .../sszSnappy/snappyFrames/uncompress.ts | 1 - packages/reqresp/src/metrics.ts | 1 - packages/reqresp/src/request/index.ts | 1 - packages/reqresp/src/response/index.ts | 2 +- packages/reqresp/src/utils/bufferedSource.ts | 2 - .../test/fixtures/encodingStrategies.ts | 1 - packages/reqresp/test/fixtures/messages.ts | 3 - packages/reqresp/test/fixtures/protocols.ts | 2 - packages/spec-test-util/package.json | 4 +- packages/spec-test-util/src/single.ts | 9 +- .../test/e2e/single/index.test.ts | 3 - packages/state-transition/package.json | 4 +- .../src/block/processDeposit.ts | 2 +- packages/state-transition/src/util/balance.ts | 2 +- .../state-transition/src/util/blindedBlock.ts | 16 +- packages/state-transition/src/util/seed.ts | 2 +- packages/state-transition/src/util/shuffle.ts | 1 - .../src/util/weakSubjectivity.ts | 1 - packages/state-transition/test/cache.ts | 1 - .../test/perf/analyzeEpochs.ts | 2 - .../perf/dataStructures/arrayish.memory.ts | 1 - .../perf/epoch/processRegistryUpdates.test.ts | 2 +- .../test/perf/misc/arrayCreation.test.ts | 1 - .../test/perf/misc/bitopts.test.ts | 1 - .../test/perf/shuffle/shuffle.test.ts | 3 +- packages/state-transition/test/perf/util.ts | 3 - .../test/unit/cachedBeaconState.test.ts | 1 - .../test/unit/upgradeState.test.ts | 1 - .../test/unit/util/aggregator.test.ts | 2 - .../test/unit/util/deposit.test.ts | 2 - .../test/utils/beforeValue.ts | 2 +- .../test/utils/beforeValueMocha.ts | 2 +- packages/state-transition/test/utils/rand.ts | 3 +- .../test/utils/specTestCases.ts | 1 - .../test/utils/testFileCache.ts | 1 - packages/test-utils/package.json | 4 +- packages/test-utils/src/childProcess.ts | 4 +- packages/test-utils/src/cli.ts | 1 - packages/test-utils/src/doubles.ts | 2 - packages/test-utils/src/externalSigner.ts | 1 - packages/test-utils/src/http.ts | 1 - packages/types/package.json | 4 +- packages/types/src/sszTypes.ts | 5 +- packages/utils/package.json | 4 +- packages/utils/src/assert.ts | 1 - packages/utils/src/command.ts | 9 +- packages/utils/src/diff.ts | 3 + packages/utils/src/err.ts | 1 - packages/utils/src/logger.ts | 1 - packages/utils/src/objects.ts | 2 +- packages/utils/src/promise.ts | 1 - packages/utils/src/yaml/int.ts | 5 - packages/utils/src/yaml/schema.ts | 2 - packages/utils/test/unit/err.test.ts | 2 +- packages/utils/test/unit/objects.test.ts | 2 - packages/validator/package.json | 4 +- packages/validator/src/genesis.ts | 1 - packages/validator/src/metrics.ts | 1 - packages/validator/src/services/emitter.ts | 2 +- .../slashingProtection/attestation/errors.ts | 6 +- .../src/slashingProtection/block/errors.ts | 6 +- .../slashingProtection/interchange/errors.ts | 6 +- .../interchange/formats/completeV4.ts | 1 - .../interchange/formats/v5.ts | 1 - .../minMaxSurround/errors.ts | 6 +- .../src/util/externalSignerClient.ts | 2 - packages/validator/src/util/params.ts | 2 - packages/validator/test/spec/params.ts | 1 - .../test/unit/services/attestation.test.ts | 1 - .../test/unit/services/doppelganger.test.ts | 4 +- .../unit/services/syncCommitteDuties.test.ts | 3 - .../test/unit/services/syncCommittee.test.ts | 2 - .../interchange/index.test.ts | 1 - .../minMaxSurround/utils.ts | 4 +- .../validator/test/unit/utils/clock.test.ts | 1 - .../test/unit/utils/interopConfigs.ts | 2 - .../validator/test/unit/utils/params.test.ts | 2 - packages/validator/test/utils/spec.ts | 1 - scripts/assert_eslintrc_sorted.mjs | 22 - scripts/release/utils.mjs | 18 +- scripts/vitest/setupFiles/dotenv.ts | 2 - types/vitest/index.d.ts | 4 +- yarn.lock | 894 +++--------------- 453 files changed, 904 insertions(+), 1861 deletions(-) create mode 100644 .editorconfig delete mode 100644 .eslintrc.js create mode 100644 .vscode/extensions.json create mode 100644 biome.jsonc delete mode 100755 scripts/assert_eslintrc_sorted.mjs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000000..ba02b753af34 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 46aca2515c83..000000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,275 +0,0 @@ -module.exports = { - root: true, - env: { - browser: true, - es6: true, - node: true, - // Performance tests still use mocha - mocha: true, - }, - globals: { - BigInt: true, - }, - parser: "@typescript-eslint/parser", - parserOptions: { - ecmaVersion: 10, - project: "./tsconfig.json", - sourceType: "module", - }, - ignorePatterns: [ - "webEsmBundle.browser.test.ts" - ], - plugins: ["@typescript-eslint", "eslint-plugin-import", "@chainsafe/eslint-plugin-node", "prettier"], - extends: [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:import/errors", - "plugin:import/typescript", - "plugin:import/warnings", - ], - rules: { - "@chainsafe/node/file-extension-in-import": ["error", "always", {esm: true}], - "@chainsafe/node/no-deprecated-api": "error", - "@typescript-eslint/await-thenable": "error", - "@typescript-eslint/ban-ts-comment": "error", - "@typescript-eslint/explicit-function-return-type": ["error", {allowExpressions: true}], - "@typescript-eslint/explicit-member-accessibility": ["error", {accessibility: "no-public"}], - "@typescript-eslint/func-call-spacing": "error", - // TODO after upgrading es-lint, member-ordering is now leading to lint errors. Set to warning now and fix in another PR - "@typescript-eslint/member-ordering": "off", - "@typescript-eslint/naming-convention": [ - "error", - {selector: "default", format: ["camelCase"]}, - { - selector: ["classProperty", "objectLiteralProperty", "classMethod", "parameter"], - format: ["camelCase"], - leadingUnderscore: "allow", - }, - //variable must be in camel or upper case - {selector: "variable", format: ["camelCase", "UPPER_CASE"], leadingUnderscore: "allow"}, - //classes and types must be in PascalCase - {selector: ["typeLike", "enum"], format: ["PascalCase"]}, - {selector: "enumMember", format: null}, - //ignore rule for quoted stuff - { - selector: [ - "classProperty", - "objectLiteralProperty", - "typeProperty", - "classMethod", - "objectLiteralMethod", - "typeMethod", - "accessor", - "enumMember", - ], - format: null, - modifiers: ["requiresQuotes"], - }, - //ignore rules on destructured params - {selector: "variable", modifiers: ["destructured"], format: null}, - { - selector: "import", - format: ["camelCase", "PascalCase"], - }, - ], - "@typescript-eslint/no-explicit-any": "error", - "@typescript-eslint/no-floating-promises": "error", - "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-require-imports": "error", - // We usually type-cast these standard types because the concerned function accepts any type - // and we want to TS detect error if original variable type changes - "@typescript-eslint/no-unnecessary-type-assertion": ["error", {typesToIgnore: ["string", "bigint", "number"]}], - "@typescript-eslint/no-unsafe-assignment": "error", - "@typescript-eslint/no-unsafe-call": "error", - "@typescript-eslint/no-unsafe-member-access": "error", - "@typescript-eslint/no-unsafe-return": "error", - "@typescript-eslint/no-unused-expressions": "error", - "@typescript-eslint/no-unused-vars": ["error", {varsIgnorePattern: "^_", argsIgnorePattern: "^_"}], - "@typescript-eslint/no-use-before-define": "off", - "@typescript-eslint/restrict-template-expressions": [ - "error", - {allowNumber: true, allowBoolean: true, allowNullish: true, allowNever: true, allowRegExp: true}, - ], - "@typescript-eslint/return-await": "error", - "@typescript-eslint/semi": "error", - "@typescript-eslint/strict-boolean-expressions": [ - "error", - {allowNullableBoolean: true, allowNullableString: true, allowAny: true}, - ], - - "@typescript-eslint/type-annotation-spacing": "error", - "constructor-super": "off", - "func-call-spacing": "off", - // Force to add names to all functions to ease CPU profiling - "func-names": ["error", "always"], - "import/namespace": "off", - //if --fix is run it messes imports like /lib/presets/minimal & /lib/presets/mainnet - "import/no-duplicates": "off", - "import/no-extraneous-dependencies": [ - "error", - { - devDependencies: false, - optionalDependencies: false, - peerDependencies: false, - }, - ], - "import/no-relative-packages": "error", - // TEMP Disabled while eslint-plugin-import support ESM (Typescript does support it) https://github.com/import-js/eslint-plugin-import/issues/2170 - "import/no-unresolved": "off", - "import/order": [ - "error", - { - groups: ["builtin", "external", "internal", "parent", "sibling", "index"], - pathGroups: [ - {pattern: "@lodestar/**", group: "internal"}, - // We want mocks to be imported before any internal code - {pattern: "**/mocks/**", group: "internal"}, - ], - pathGroupsExcludedImportTypes: ["builtin"], - }, - ], - //doesnt work, it reports false errors - "new-parens": "error", - "no-bitwise": "off", - "no-caller": "error", - "no-cond-assign": "error", - "no-consecutive-blank-lines": 0, - "no-console": "error", - "no-loss-of-precision": "error", - "no-prototype-builtins": 0, - "no-restricted-globals": [ - "error", - { - name: "fetch", - message: "Please use 'fetch' from '@lodestar/api' instead.", - }, - ], - "no-restricted-imports": [ - "error", - { - patterns: ["../lib/*", "@chainsafe/*/lib/*"], - paths: [ - ...restrictNodeModuleImports( - "child_process", - "crypto", - "fs", - "http", - "net", - "os", - "path", - "stream", - "util", - "url", - "worker_threads" - ), - ], - }, - ], - "no-restricted-syntax": ["error", ...restrictImportDestructuring("node:fs", "node:os", "node:path")], - // superseded by @typescript-eslint/return-await, must be disabled as it can report incorrect errors - "no-return-await": "off", - "no-var": "error", - "object-curly-spacing": ["error", "never"], - "object-literal-sort-keys": 0, - "prefer-const": "error", - "prettier/prettier": "error", - quotes: ["error", "double"], - semi: "off", - }, - settings: { - "import/core-modules": [ - "node:child_process", - "node:crypto", - "node:fs", - "node:http", - "node:net", - "node:os", - "node:path", - "node:stream", - "node:util", - "node:url", - ], - "import/resolver": { - typescript: { - project: "packages/*/tsconfig.json", - }, - }, - }, - overrides: [ - { - 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 - "@typescript-eslint/no-require-imports": "off", - // Allow require in CJS modules - "@typescript-eslint/no-var-requires": "off", - // Allow importing packages from dev dependencies - "import/no-extraneous-dependencies": "off", - // Allow importing and mixing different configurations - "import/no-relative-packages": "off", - }, - }, - { - files: ["**/test/**/*.ts"], - rules: { - "@typescript-eslint/no-explicit-any": "off", - "func-names": "off", - "import/no-extraneous-dependencies": "off", - // Turned off as it floods log with warnings. Underlying issue is not critical so switching off is acceptable - "import/no-named-as-default-member": "off", - }, - }, - { - files: ["**/perf/**/*.ts"], - rules: { - // A lot of benchmarks just need to execute expressions without using the result - "@typescript-eslint/no-unused-expressions": "off", - }, - }, - { - files: ["**/test/**/*.test.ts"], - plugins: ["vitest"], - extends: ["plugin:vitest/recommended"], - rules: { - "vitest/consistent-test-it": ["error", {fn: "it", withinDescribe: "it"}], - // We use a lot dynamic assertions so tests may not have usage of expect - "vitest/expect-expect": "off", - "vitest/no-disabled-tests": "warn", - "vitest/no-focused-tests": "error", - "vitest/prefer-called-with": "error", - "vitest/prefer-spy-on": "error", - // Our usage contains dynamic test title, this rule enforce static string value - "vitest/valid-title": "off", - }, - }, - { - files: ["**/types/**/*.ts"], - rules: { - "@typescript-eslint/naming-convention": [ - "off", - {selector: "interface", prefix: ["I"]}, - {selector: "interface", format: ["PascalCase"], prefix: ["I"]}, - ], - }, - }, - ], -}; - -function restrictNodeModuleImports(...modules) { - return modules.map((module) => ({name: module, message: `Please use 'node:${module}' instead.`})); -} - -function restrictImportDestructuring(...modules) { - return modules.map((module) => ({ - selector: `ImportDeclaration[source.value='${module}'] ImportSpecifier`, - message: `Importing from '${module}' using destructuring is restricted.`, - })); -} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c801b0462d60..5514f6e896b7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,9 +64,6 @@ jobs: - name: Assert ESM module exports run: node scripts/assert_exports.mjs - - name: Assert eslintrc rules sorted - run: scripts/assert_eslintrc_sorted.mjs - type-checks: name: Type Checks needs: build diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000000..de51190cd9f3 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "biomejs.biome" + ] +} diff --git a/.wordlist.txt b/.wordlist.txt index 11a5a3746476..a2e642a926a0 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -26,7 +26,6 @@ EIPs EL ENR ENRs -ESLint ETH Edgington Erigon diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9592f3bb0237..24d087810980 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,7 @@ To run tests: - :test_tube: Run `yarn test:spec` for spec tests. - :test_tube: Run `yarn test` to run all tests. - :test_tube: Run `yarn check-types` to check TypeScript types. -- :test_tube: Run `yarn lint` to run the linter (ESLint). +- :test_tube: Run `yarn lint` to run the linter. Note that to run `test:e2e`, first ensure that the environment is correctly setup by running the `run_e2e_env.sh` script. This script requires a running docker engine. diff --git a/biome.jsonc b/biome.jsonc new file mode 100644 index 000000000000..b49fc601600c --- /dev/null +++ b/biome.jsonc @@ -0,0 +1,376 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.3/schema.json", + "vcs": { + "clientKind": "git", + "enabled": true, + "useIgnoreFile": true + }, + "files": { + "include": ["packages/*/src/**/*.ts", "packages/*/test/**/*.ts"] + }, + "formatter": { + "enabled": true, + "formatWithErrors": true, + "useEditorconfig": true, + "lineWidth": 120, + "attributePosition": "auto", + "bracketSpacing": false, + "ignore": ["**/lib", "**/.nyc_output", "./packages/*/spec-tests", "**/node_modules", "./packages/*/node_modules/**"] + }, + "organizeImports": { + "enabled": false + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "complexity": { + "noForEach": "off", + "noStaticOnlyClass": "off", + "noThisInStatic": "off", + "noUselessEmptyExport": "off", + "noUselessTypeConstraint": "error", + "useArrowFunction": "off", + "useFlatMap": "off", + "useLiteralKeys": "off", + "useOptionalChain": "off", + "useRegexLiterals": "off", + "noBannedTypes": "error", + "noUselessThisAlias": "error" + }, + "correctness": { + "noInvalidConstructorSuper": "off", + "noInvalidUseBeforeDeclaration": "off", + "noPrecisionLoss": "error", + "noUnusedVariables": "error", + "noVoidTypeReturn": "off", + "useYield": "off", + "useImportExtensions": { + "level": "error", + "options": { + "suggestedExtensions": { + "ts": { + "module": "js", + "component": "jsx" + } + } + } + }, + "useArrayLiterals": "error", + "noUndeclaredDependencies": "off", // TODO: Need to see why this rule is not detecting monorepo packages + "noUndeclaredVariables": "error" + }, + "performance": { + "noAccumulatingSpread": "off", + "noDelete": "off" + }, + "style": { + "noCommaOperator": "off", + "noInferrableTypes": "off", + "noNonNullAssertion": "error", + "noParameterAssign": "off", + "noRestrictedGlobals": { + "level": "error", + "options": { + "deniedGlobals": ["fetch"] + } + }, + "noUnusedTemplateLiteral": "off", + "noUselessElse": "off", + "noVar": "error", + "useConst": "error", + "useEnumInitializers": "off", + "useExponentiationOperator": "off", + "useExportType": "off", + "useImportType": "off", + "useLiteralEnumMembers": "off", + "useNamingConvention": { + "level": "error", + "options": { + "strictCase": false, + "conventions": [ + { + "selector": { + "kind": "any" + }, + "formats": ["camelCase"] + }, + { + "selector": { + "kind": "classProperty" + }, + "formats": ["camelCase"] + }, + { + "selector": { + "kind": "objectLiteralProperty" + }, + "formats": ["camelCase"] + }, + { + "selector": { + "kind": "classMethod" + }, + "formats": ["camelCase"] + }, + { + "selector": { + "kind": "functionParameter" + }, + "formats": ["camelCase"] + }, + { + "selector": { + "kind": "variable" + }, + "formats": ["camelCase", "CONSTANT_CASE"] + }, + { + "selector": { + "kind": "typeLike" + }, + "formats": ["PascalCase"] + }, + { + "selector": { + "kind": "enum" + }, + "formats": ["PascalCase"] + }, + { + "selector": { + "kind": "enumMember" + }, + "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + }, + { + "selector": { + "kind": "classProperty" + }, + "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + }, + { + "selector": { + "kind": "typeProperty" + }, + "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + }, + { + "selector": { + "kind": "classMember" + }, + "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + }, + { + "selector": { + "kind": "objectLiteralMethod" + }, + "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + }, + { + "selector": { + "kind": "typeMethod" + }, + "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + }, + { + "selector": { + "kind": "variable" + }, + "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + }, + { + "selector": { + "kind": "importAlias" + }, + "formats": ["PascalCase", "camelCase"] + }, + { + "selector": { + "kind": "importNamespace" + }, + "formats": ["PascalCase", "camelCase"] + } + ] + } + }, + "useNumberNamespace": "off", + "useSingleVarDeclarator": "off", + "useTemplate": "off", + "noNamespace": "error", + "useAsConstAssertion": "error" + }, + "suspicious": { + "noAssignInExpressions": "error", + "noAsyncPromiseExecutor": "off", + "noConfusingVoidType": "off", + "noConsoleLog": "error", + "noDoubleEquals": "off", + "noDuplicateTestHooks": "off", + "noExplicitAny": "error", + "noExportsInTest": "off", + "noFallthroughSwitchClause": "off", + "noGlobalIsFinite": "off", + "noGlobalIsNan": "off", + "noImplicitAnyLet": "off", + "noPrototypeBuiltins": "off", + "noRedundantUseStrict": "off", + "noShadowRestrictedNames": "off", + "useDefaultSwitchClauseLast": "off", + "useGetterReturn": "off", + "noExtraNonNullAssertion": "error", + "noMisleadingInstantiator": "error", + "noUnsafeDeclarationMerging": "error", + "noEmptyBlockStatements": "off" // There is a lot of empty code blocks, should be enabled and clean up separately. + }, + "nursery": { + "useConsistentMemberAccessibility": { + "level": "error", + "options": { + "accessibility": "noPublic" + } + }, + "noCommonJs": "error", + "noRestrictedImports": { + "level": "error", + "options": { + "paths": { + "child_process": "Please use node:child_process instead.", + "crypto": "Please use node:crypto instead.", + "fs": "Please use node:fs instead.", + "http": "Please use node:https instead.", + "net": "Please use node:net instead.", + "os": "Please use node:os instead.", + "path": "Please use node:path instead.", + "stream": "Please use node:stream instead.", + "util": "Please use node:util instead.", + "url": "Please use node:url instead.", + "worker_threads": "Please use node:worker_threads instead." + } + } + }, + "noDuplicateElseIf": "error", + "noUselessEscapeInRegex": "error", + "noIrregularWhitespace": "error", + "noOctalEscape": "error", + // Need to enable this rule with exception to anonymous functions + "useExplicitFunctionReturnType": "off" + } + } + }, + "javascript": { + "formatter": { + "jsxQuoteStyle": "double", + "quoteProperties": "asNeeded", + "trailingCommas": "es5", + "semicolons": "always", + "arrowParentheses": "always", + "bracketSpacing": false, + "bracketSameLine": false, + "quoteStyle": "double", + "attributePosition": "auto", + "enabled": true + }, + "linter": { + "enabled": true + }, + "globals": ["BigInt"] + }, + "overrides": [ + { + "include": ["packages/**/test/perf/**/*.test.ts", "packages/state-transition/test/utils/beforeValueMocha.ts"], + "javascript": { + // These are used by mocha + "globals": ["describe", "it", "before", "after"] + } + }, + { + "include": ["packages/cli/src/", "packages/test-utils/src", "packages/flare/src"], + "linter": { + "rules": { + "suspicious": { + "noConsoleLog": "off" + } + } + } + }, + { + "include": [ + "**/*.config.js", + "**/*.config.mjs", + "**/*.config.cjs", + "**/*.config.ts", + "scripts/vitest/**/*.ts", + "scripts/vite/**/*.ts", + "**/types/**/*.ts", + "packages/api/src/beacon/routes/*.ts", + "packages/api/src/**/routes.ts", + "packages/api/src/utils/server/handler.ts", + "packages/api/test/unit/client/urlFormat.test.ts", + "packages/beacon-node/src/api/impl/config/constants.ts", + "packages/beacon-node/src/eth1/provider/eth1Provider.ts", + "" + ], + "linter": { + "rules": { + "style": { + "useNamingConvention": { + "level": "off", + "options": { + "strictCase": false + } + } + } + } + } + }, + { + "include": [ + "**/test/**/*.ts", + "packages/*/test/**/*.js", + "packages/api/src/utils/**/*.ts", + "packages/beacon-node/src/db/repositories/checkpointState.ts", + "packages/spec-test-util/src/single.ts" + ], + "linter": { + "rules": { + "suspicious": { + "noExplicitAny": "off" + } + } + } + }, + { + "include": ["packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts"], + "linter": { + "rules": { + "correctness": { + "noUnusedVariables": "off" + } + } + } + }, + { + "include": ["**/test/**/*.ts", "packages/*/test/**/*.js"], + "linter": { + "rules": { + "suspicious": { + "noConsoleLog": "off" + } + } + } + }, + { + "include": ["**/perf/**/*.ts"], + "linter": { + "rules": {} + } + }, + { + "include": ["**/test/**/*.test.ts"], + "linter": { + "rules": {} + } + } + ] +} diff --git a/package.json b/package.json index 85d9662ab920..7399b4ba6c1e 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,8 @@ "build:bundle": "lerna run build:bundle", "build:watch": "lerna exec --parallel -- 'yarn run build:watch'", "build:ifchanged": "lerna exec -- ../../scripts/build_if_changed.sh", - "lint": "eslint --report-unused-disable-directives --color --ext .ts packages/*/src packages/*/test", - "lint:fix": "yarn lint --fix", + "lint": "biome check", + "lint:fix": "yarn lint --write", "lint-dashboards": "node scripts/lint-grafana-dashboards.mjs ./dashboards", "check-build": "lerna run check-build", "check-bundle": "lerna run check-bundle", @@ -48,22 +48,15 @@ }, "devDependencies": { "@actions/core": "^1.10.1", - "@chainsafe/eslint-plugin-node": "^11.2.3", "@dapplion/benchmark": "^0.2.4", + "@biomejs/biome": "^1.9.3", "@types/mocha": "^10.0.6", "@types/node": "^20.12.8", - "@typescript-eslint/eslint-plugin": "^7.2.0", - "@typescript-eslint/parser": "^7.2.0", "@vitest/browser": "^2.0.4", "@vitest/coverage-v8": "^2.0.4", "crypto-browserify": "^3.12.0", "dotenv": "^16.4.5", "electron": "^26.2.2", - "eslint": "^8.57.0", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-vitest": "^0.3.26", "https-browserify": "^1.0.0", "jsdom": "^23.0.1", "lerna": "^7.3.0", diff --git a/packages/api/package.json b/packages/api/package.json index 7d851d9513ba..58566a0b23f6 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -63,8 +63,8 @@ "build:release": "yarn clean && yarn run build", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" diff --git a/packages/api/src/beacon/client/events.ts b/packages/api/src/beacon/client/events.ts index 34f14f2e8397..9937b850b49a 100644 --- a/packages/api/src/beacon/client/events.ts +++ b/packages/api/src/beacon/client/events.ts @@ -16,10 +16,15 @@ export function getClient(config: ChainForkConfig, baseUrl: string): ApiClient { const eventSerdes = getEventSerdes(config); return { - eventstream: async ({topics, signal, onEvent, onError, onClose}) => { + eventstream: async ({ + topics, + signal, + onEvent, + onError, + onClose, + }): Promise> => { const query = stringifyQuery({topics}); const url = `${urlJoin(baseUrl, definitions.eventstream.url)}?${query}`; - // eslint-disable-next-line @typescript-eslint/naming-convention const EventSource = await getEventSource(); const eventSource = new EventSource(url); @@ -40,7 +45,7 @@ export function getClient(config: ChainForkConfig, baseUrl: string): ApiClient { // EventSource will try to reconnect always on all errors // `eventSource.onerror` events are informative but don't indicate the EventSource closed // The only way to abort the connection from the client is via eventSource.close() - eventSource.onerror = function onerror(err) { + eventSource.onerror = function onerror(err): void { const errEs = err as unknown as EventSourceError; // Ignore noisy errors due to beacon node being offline diff --git a/packages/api/src/beacon/routes/beacon/block.ts b/packages/api/src/beacon/routes/beacon/block.ts index be6789753e0f..04d42cdab81e 100644 --- a/packages/api/src/beacon/routes/beacon/block.ts +++ b/packages/api/src/beacon/routes/beacon/block.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, ListCompositeType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import { @@ -225,7 +224,7 @@ export type Endpoints = { >; }; -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: const blockIdOnlyReq: RequestCodec> = { writeReq: ({blockId}) => ({params: {block_id: blockId.toString()}}), parseReq: ({params}) => ({blockId: params.block_id}), diff --git a/packages/api/src/beacon/routes/beacon/pool.ts b/packages/api/src/beacon/routes/beacon/pool.ts index 4fe3efd4daf2..3f0b8ac74284 100644 --- a/packages/api/src/beacon/routes/beacon/pool.ts +++ b/packages/api/src/beacon/routes/beacon/pool.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {isForkPostElectra} from "@lodestar/params"; diff --git a/packages/api/src/beacon/routes/beacon/rewards.ts b/packages/api/src/beacon/routes/beacon/rewards.ts index c65282625343..d41b5ef705f0 100644 --- a/packages/api/src/beacon/routes/beacon/rewards.ts +++ b/packages/api/src/beacon/routes/beacon/rewards.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {Epoch, ssz} from "@lodestar/types"; diff --git a/packages/api/src/beacon/routes/beacon/state.ts b/packages/api/src/beacon/routes/beacon/state.ts index 1489f48c297e..4127bb1ce793 100644 --- a/packages/api/src/beacon/routes/beacon/state.ts +++ b/packages/api/src/beacon/routes/beacon/state.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; @@ -269,7 +268,7 @@ export type Endpoints = { >; }; -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: const stateIdOnlyReq: RequestCodec> = { writeReq: ({stateId}) => ({params: {state_id: stateId.toString()}}), parseReq: ({params}) => ({stateId: params.state_id}), diff --git a/packages/api/src/beacon/routes/config.ts b/packages/api/src/beacon/routes/config.ts index f8a606af1431..afce0898908c 100644 --- a/packages/api/src/beacon/routes/config.ts +++ b/packages/api/src/beacon/routes/config.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; diff --git a/packages/api/src/beacon/routes/debug.ts b/packages/api/src/beacon/routes/debug.ts index 590ecf71dd9c..349684f62ccd 100644 --- a/packages/api/src/beacon/routes/debug.ts +++ b/packages/api/src/beacon/routes/debug.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, Type, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {ssz, StringType, BeaconState} from "@lodestar/types"; diff --git a/packages/api/src/beacon/routes/events.ts b/packages/api/src/beacon/routes/events.ts index 1f041aa30194..5fa218bc02f3 100644 --- a/packages/api/src/beacon/routes/events.ts +++ b/packages/api/src/beacon/routes/events.ts @@ -188,7 +188,6 @@ export type TypeJson = { }; export function getTypeByEvent(config: ChainForkConfig): {[K in EventType]: TypeJson} { - // eslint-disable-next-line @typescript-eslint/naming-convention const WithVersion = (getType: (fork: ForkName) => TypeJson): TypeJson<{data: T; version: ForkName}> => { return { toJson: ({data, version}) => ({ @@ -289,7 +288,6 @@ export function getTypeByEvent(config: ChainForkConfig): {[K in EventType]: Type }; } -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function getEventSerdes(config: ChainForkConfig) { const typeByEvent = getTypeByEvent(config); diff --git a/packages/api/src/beacon/routes/lightclient.ts b/packages/api/src/beacon/routes/lightclient.ts index ab45323f8f64..decf8982b654 100644 --- a/packages/api/src/beacon/routes/lightclient.ts +++ b/packages/api/src/beacon/routes/lightclient.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ListCompositeType, ValueOf} from "@chainsafe/ssz"; import { LightClientBootstrap, diff --git a/packages/api/src/beacon/routes/lodestar.ts b/packages/api/src/beacon/routes/lodestar.ts index a97d065cfe4d..1d3c62ca2082 100644 --- a/packages/api/src/beacon/routes/lodestar.ts +++ b/packages/api/src/beacon/routes/lodestar.ts @@ -21,7 +21,7 @@ export type SyncChainDebugState = { status: string; startEpoch: number; peers: number; - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: batches: any[]; }; diff --git a/packages/api/src/beacon/routes/node.ts b/packages/api/src/beacon/routes/node.ts index 0744b5f07452..c7a6c2e36361 100644 --- a/packages/api/src/beacon/routes/node.ts +++ b/packages/api/src/beacon/routes/node.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {ssz, stringType} from "@lodestar/types"; diff --git a/packages/api/src/beacon/routes/proof.ts b/packages/api/src/beacon/routes/proof.ts index 2ef4dad15e81..0c6d5a058cea 100644 --- a/packages/api/src/beacon/routes/proof.ts +++ b/packages/api/src/beacon/routes/proof.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {CompactMultiProof, ProofType} from "@chainsafe/persistent-merkle-tree"; import {ByteListType, ContainerType} from "@chainsafe/ssz"; import {fromHex, toHex} from "@lodestar/utils"; diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index a9a1423e4da2..cf30d5748a46 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, Type, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {isForkBlobs, isForkPostElectra} from "@lodestar/params"; diff --git a/packages/api/src/beacon/server/index.ts b/packages/api/src/beacon/server/index.ts index 21c0607d3f14..304f4d42be17 100644 --- a/packages/api/src/beacon/server/index.ts +++ b/packages/api/src/beacon/server/index.ts @@ -25,7 +25,7 @@ export function registerRoutes( // Enforces that we are declaring routes for every routeId in `Endpoints` [K in keyof Endpoints]: () => { // The Endpoints are enforced in each getRoutes return type - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: [K2 in keyof Endpoints[K]]: FastifyRoute; }; } = { diff --git a/packages/api/src/builder/routes.ts b/packages/api/src/builder/routes.ts index 7459e46abd0b..018110e5eded 100644 --- a/packages/api/src/builder/routes.ts +++ b/packages/api/src/builder/routes.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import { ssz, bellatrix, diff --git a/packages/api/src/keymanager/routes.ts b/packages/api/src/keymanager/routes.ts index b6abe8928d77..0db096d14e83 100644 --- a/packages/api/src/keymanager/routes.ts +++ b/packages/api/src/keymanager/routes.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {Epoch, phase0, ssz, stringType} from "@lodestar/types"; diff --git a/packages/api/src/utils/client/eventSource.ts b/packages/api/src/utils/client/eventSource.ts index 6b5b75124034..2e2cf0076068 100644 --- a/packages/api/src/utils/client/eventSource.ts +++ b/packages/api/src/utils/client/eventSource.ts @@ -1,6 +1,5 @@ // This function switches between the native web implementation and a nodejs implemnetation export async function getEventSource(): Promise { - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (globalThis.EventSource) { return EventSource; } else { diff --git a/packages/api/src/utils/client/fetch.ts b/packages/api/src/utils/client/fetch.ts index a338d82e521f..31e52cdbd67f 100644 --- a/packages/api/src/utils/client/fetch.ts +++ b/packages/api/src/utils/client/fetch.ts @@ -6,7 +6,7 @@ async function wrappedFetch(url: string | URL, init?: RequestInit): Promise { try { // This function wraps global `fetch` which should only be directly called here - // eslint-disable-next-line no-restricted-globals + // biome-ignore lint/style/noRestrictedGlobals: return await fetch(url, init); } catch (e) { throw new FetchError(url, e); diff --git a/packages/api/src/utils/client/httpClient.ts b/packages/api/src/utils/client/httpClient.ts index e11e35dc85c7..eec86725fcaa 100644 --- a/packages/api/src/utils/client/httpClient.ts +++ b/packages/api/src/utils/client/httpClient.ts @@ -198,8 +198,7 @@ export class HttpClient implements IHttpClient { this.logger?.debug("Requesting fallback URL", {routeId, baseUrl: printableUrl, score: this.urlsScore[i]}); } - // eslint-disable-next-line @typescript-eslint/naming-convention - const i_ = i; // Keep local copy of i variable to index urlScore after requestMethod() resolves + const i_ = i; // Keep local copy of i variable to index urlScore after requestWithBody() resolves const urlInit = this.urlsInits[i]; if (urlInit === undefined) { diff --git a/packages/api/src/utils/client/response.ts b/packages/api/src/utils/client/response.ts index fdcb2afda943..7a4c4fb98ce4 100644 --- a/packages/api/src/utils/client/response.ts +++ b/packages/api/src/utils/client/response.ts @@ -26,13 +26,15 @@ export class ApiResponse extends Response { wireFormat(): WireFormat | null { if (this._wireFormat === undefined) { if (this.definition.resp.isEmpty) { - return (this._wireFormat = null); + this._wireFormat = null; + return this._wireFormat; } const contentType = this.headers.get(HttpHeader.ContentType); if (contentType === null) { if (this.status === HttpStatusCode.NO_CONTENT) { - return (this._wireFormat = null); + this._wireFormat = null; + return this._wireFormat; } else { throw Error("Content-Type header is required in response"); } @@ -198,7 +200,7 @@ export class ApiResponse extends Response { } else { return errBody; } - } catch (e) { + } catch (_e) { return errBody || this.statusText; } } diff --git a/packages/api/src/utils/codecs.ts b/packages/api/src/utils/codecs.ts index 36d905583098..54214740f435 100644 --- a/packages/api/src/utils/codecs.ts +++ b/packages/api/src/utils/codecs.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ArrayType, ListBasicType, ListCompositeType, Type, isBasicType, isCompositeType} from "@chainsafe/ssz"; import {ForkName} from "@lodestar/params"; import {objectToExpectedCase} from "@lodestar/utils"; @@ -20,11 +19,8 @@ export type EmptyRequest = Record; export type EmptyResponseData = void; export type EmptyMeta = void; -// eslint-disable-next-line @typescript-eslint/no-explicit-any export type AnyEndpoint = Endpoint; -// eslint-disable-next-line @typescript-eslint/no-explicit-any export type EmptyRequestEndpoint = Endpoint; -// eslint-disable-next-line @typescript-eslint/no-explicit-any export type EmptyResponseEndpoint = Endpoint; /** Shortcut for routes that have no params, query */ diff --git a/packages/api/src/utils/metadata.ts b/packages/api/src/utils/metadata.ts index 1eaa4132119f..2ee9b2f51f0e 100644 --- a/packages/api/src/utils/metadata.ts +++ b/packages/api/src/utils/metadata.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ForkName} from "@lodestar/params"; import {StringType, ssz, stringType} from "@lodestar/types"; diff --git a/packages/api/src/utils/serdes.ts b/packages/api/src/utils/serdes.ts index 282c2514e00d..c2080ad2d020 100644 --- a/packages/api/src/utils/serdes.ts +++ b/packages/api/src/utils/serdes.ts @@ -104,7 +104,7 @@ export function fromGraffitiHex(hex?: string): string | undefined { } try { return new TextDecoder("utf8").decode(fromHex(hex)); - } catch { + } catch (_e) { // allow malformed graffiti hex string return hex; } diff --git a/packages/api/src/utils/server/handler.ts b/packages/api/src/utils/server/handler.ts index a3cd9a43a56a..035f4328141a 100644 --- a/packages/api/src/utils/server/handler.ts +++ b/packages/api/src/utils/server/handler.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import type * as fastify from "fastify"; import {HttpHeader, MediaType, SUPPORTED_MEDIA_TYPES, parseAcceptHeader, parseContentTypeHeader} from "../headers.js"; import { diff --git a/packages/api/src/utils/server/method.ts b/packages/api/src/utils/server/method.ts index 080c78869798..6fc99cc49a72 100644 --- a/packages/api/src/utils/server/method.ts +++ b/packages/api/src/utils/server/method.ts @@ -12,10 +12,9 @@ type ApplicationResponseObject = { : {data: E["return"] | (E["return"] extends undefined ? undefined : Uint8Array)}) & (E["meta"] extends EmptyMeta ? {meta?: never} : {meta: E["meta"]}); -export type ApplicationResponse = - HasOnlyOptionalProps> extends true - ? ApplicationResponseObject | void - : ApplicationResponseObject; +export type ApplicationResponse = HasOnlyOptionalProps> extends true + ? ApplicationResponseObject | void + : ApplicationResponseObject; export type ApiContext = { /** diff --git a/packages/api/test/perf/compileRouteUrlFormater.test.ts b/packages/api/test/perf/compileRouteUrlFormater.test.ts index ab16e1a5d14e..60d9e3fea8ee 100644 --- a/packages/api/test/perf/compileRouteUrlFormater.test.ts +++ b/packages/api/test/perf/compileRouteUrlFormater.test.ts @@ -1,7 +1,5 @@ import {compileRouteUrlFormatter} from "../../src/utils/urlFormat.js"; -/* eslint-disable no-console */ - describe("route parse", () => { it.skip("Benchmark compileRouteUrlFormatter", () => { const path = "/eth/v1/validator/:name/attester/:epoch"; diff --git a/packages/api/test/unit/beacon/genericServerTest/beacon.test.ts b/packages/api/test/unit/beacon/genericServerTest/beacon.test.ts index a722e72a4c27..f8c13b33afb6 100644 --- a/packages/api/test/unit/beacon/genericServerTest/beacon.test.ts +++ b/packages/api/test/unit/beacon/genericServerTest/beacon.test.ts @@ -8,7 +8,6 @@ import {testData} from "../testData/beacon.js"; describe("beacon / beacon", () => { runGenericServerTest( - // eslint-disable-next-line @typescript-eslint/naming-convention createChainForkConfig({...defaultChainConfig, ALTAIR_FORK_EPOCH: 1, BELLATRIX_FORK_EPOCH: 2}), getClient, getRoutes, diff --git a/packages/api/test/unit/beacon/genericServerTest/config.test.ts b/packages/api/test/unit/beacon/genericServerTest/config.test.ts index 8b924cf07693..91075f96d1e3 100644 --- a/packages/api/test/unit/beacon/genericServerTest/config.test.ts +++ b/packages/api/test/unit/beacon/genericServerTest/config.test.ts @@ -6,8 +6,6 @@ import {getRoutes} from "../../../../src/beacon/server/config.js"; import {runGenericServerTest} from "../../../utils/genericServerTest.js"; import {testData} from "../testData/config.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - describe("beacon / config", () => { runGenericServerTest(config, getClient, getRoutes, testData); diff --git a/packages/api/test/unit/beacon/oapiSpec.test.ts b/packages/api/test/unit/beacon/oapiSpec.test.ts index 2b8a8254dd6b..0478d503d517 100644 --- a/packages/api/test/unit/beacon/oapiSpec.test.ts +++ b/packages/api/test/unit/beacon/oapiSpec.test.ts @@ -18,7 +18,6 @@ import {testData as validatorTestData} from "./testData/validator.js"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); const version = "v3.0.0-alpha.6"; @@ -28,7 +27,6 @@ const openApiFile: OpenApiFile = { version: RegExp(version), }; -// eslint-disable-next-line @typescript-eslint/naming-convention const config = createChainForkConfig({...defaultChainConfig, ALTAIR_FORK_EPOCH: 1, BELLATRIX_FORK_EPOCH: 2}); const definitions = { diff --git a/packages/api/test/unit/beacon/testData/events.ts b/packages/api/test/unit/beacon/testData/events.ts index 8a7610a26836..3d2ffb708965 100644 --- a/packages/api/test/unit/beacon/testData/events.ts +++ b/packages/api/test/unit/beacon/testData/events.ts @@ -5,8 +5,6 @@ import {GenericServerTestCases} from "../../../utils/genericServerTest.js"; const abortController = new AbortController(); -/* eslint-disable @typescript-eslint/naming-convention */ - export const testData: GenericServerTestCases = { eventstream: { args: {topics: [EventType.head, EventType.chainReorg], signal: abortController.signal, onEvent: () => {}}, diff --git a/packages/api/test/unit/builder/builder.test.ts b/packages/api/test/unit/builder/builder.test.ts index 045a66496b6f..d2e25916069e 100644 --- a/packages/api/test/unit/builder/builder.test.ts +++ b/packages/api/test/unit/builder/builder.test.ts @@ -10,7 +10,6 @@ describe("builder", () => { runGenericServerTest( createChainForkConfig({ ...defaultChainConfig, - /* eslint-disable @typescript-eslint/naming-convention */ ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0, DENEB_FORK_EPOCH: 0, diff --git a/packages/api/test/unit/builder/oapiSpec.test.ts b/packages/api/test/unit/builder/oapiSpec.test.ts index 60168f71d8d8..d972b64905e5 100644 --- a/packages/api/test/unit/builder/oapiSpec.test.ts +++ b/packages/api/test/unit/builder/oapiSpec.test.ts @@ -10,7 +10,6 @@ import {testData} from "./testData.js"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); const version = "v0.2.0"; @@ -23,7 +22,6 @@ const openApiFile: OpenApiFile = { }; const definitions = getDefinitions( - // eslint-disable-next-line @typescript-eslint/naming-convention createChainForkConfig({...defaultChainConfig, ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0}) ); diff --git a/packages/api/test/unit/client/fetch.test.ts b/packages/api/test/unit/client/fetch.test.ts index 80e5f58b164a..0c08c5bbf5a3 100644 --- a/packages/api/test/unit/client/fetch.test.ts +++ b/packages/api/test/unit/client/fetch.test.ts @@ -92,7 +92,6 @@ describe("FetchError", function () { const afterHook = afterHooks.pop(); if (afterHook) await afterHook().catch((e: Error) => { - // eslint-disable-next-line no-console console.error("Error in afterEach hook", e); }); } diff --git a/packages/api/test/unit/client/httpClientFallback.test.ts b/packages/api/test/unit/client/httpClientFallback.test.ts index ea20c3f33982..244fcbe5bf23 100644 --- a/packages/api/test/unit/client/httpClientFallback.test.ts +++ b/packages/api/test/unit/client/httpClientFallback.test.ts @@ -81,7 +81,6 @@ describe("httpClient fallback", () => { fetchStub.mockClear(); - // eslint-disable-next-line no-console if (DEBUG_LOGS) console.log("completed assertions step", step); } diff --git a/packages/api/test/unit/client/urlFormat.test.ts b/packages/api/test/unit/client/urlFormat.test.ts index dc86e2674e13..5132044b7631 100644 --- a/packages/api/test/unit/client/urlFormat.test.ts +++ b/packages/api/test/unit/client/urlFormat.test.ts @@ -7,8 +7,6 @@ import { urlToTokens, } from "../../../src/utils/urlFormat.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - describe("utils / urlFormat", () => { const testCases: { urlTemplate: string; diff --git a/packages/api/test/unit/keymanager/oapiSpec.test.ts b/packages/api/test/unit/keymanager/oapiSpec.test.ts index 97011f5d3660..aab4e1823ab0 100644 --- a/packages/api/test/unit/keymanager/oapiSpec.test.ts +++ b/packages/api/test/unit/keymanager/oapiSpec.test.ts @@ -9,7 +9,6 @@ import {testData} from "./testData.js"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); const version = "v1.1.0"; diff --git a/packages/api/test/utils/checkAgainstSpec.ts b/packages/api/test/utils/checkAgainstSpec.ts index 5e339efcb822..85e9711ae601 100644 --- a/packages/api/test/utils/checkAgainstSpec.ts +++ b/packages/api/test/utils/checkAgainstSpec.ts @@ -127,7 +127,7 @@ export function runTestCheckAgainstSpec>( expect(reqSsz.body).toBeInstanceOf(Uint8Array); expect(reqCodec.onlySupport).not.toBe(WireFormat.json); - } catch { + } catch (_e) { throw Error("Must support ssz request body"); } } @@ -167,7 +167,7 @@ export function runTestCheckAgainstSpec>( expect(sszBytes).toBeInstanceOf(Uint8Array); expect(routeDef.resp.onlySupport).not.toBe(WireFormat.json); - } catch { + } catch (_e) { throw Error("Must support ssz response body"); } } @@ -183,7 +183,6 @@ function validateSchema(schema: Parameters[0], json: unknown try { validate = ajv.compile(schema); } catch (e) { - // eslint-disable-next-line no-console console.error(JSON.stringify(schema, null, 2)); (e as Error).message = `${id} schema - ${(e as Error).message}`; throw e; diff --git a/packages/api/test/utils/parseOpenApiSpec.ts b/packages/api/test/utils/parseOpenApiSpec.ts index 7527fb61abaa..e6e75014312b 100644 --- a/packages/api/test/utils/parseOpenApiSpec.ts +++ b/packages/api/test/utils/parseOpenApiSpec.ts @@ -105,7 +105,6 @@ export function parseOpenApiSpec(openApiJson: OpenApiJson): Map Promise< addSszContentTypeParser(server); server.addHook("onError", (_request, _reply, error, done) => { - // eslint-disable-next-line no-console console.log(`onError: ${error.toString()}`); done(); }); diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 4deaf7c6ac16..8b46bc0038c7 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -75,8 +75,8 @@ "build:release": "yarn clean && yarn run build", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit && yarn test:e2e", "test:unit:minimal": "LODESTAR_PRESET=minimal vitest --run --dir test/unit/", "test:unit:mainnet": "LODESTAR_PRESET=mainnet vitest --run --dir test/unit-mainnet", 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 65e7b9373a22..240f391027a9 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -224,15 +224,17 @@ export function getBeaconBlockApi({ () => network.publishBeaconBlock(signedBlock) as Promise, () => // there is no rush to persist block since we published it to gossip anyway - chain.processBlock(blockForImport, {...opts, eagerPersistBlock: false}).catch((e) => { - if (e instanceof BlockError && e.type.code === BlockErrorCode.PARENT_UNKNOWN) { - network.events.emit(NetworkEvent.unknownBlockParent, { - blockInput: blockForImport, - peer: IDENTITY_PEER_ID, - }); - } - throw e; - }), + chain + .processBlock(blockForImport, {...opts, eagerPersistBlock: false}) + .catch((e) => { + if (e instanceof BlockError && e.type.code === BlockErrorCode.PARENT_UNKNOWN) { + network.events.emit(NetworkEvent.unknownBlockParent, { + blockInput: blockForImport, + peer: IDENTITY_PEER_ID, + }); + } + throw e; + }), ]; await promiseAllMaybeAsync(publishPromises); }; @@ -258,7 +260,7 @@ export function getBeaconBlockApi({ chain.logger.debug("Reconstructing signedBlockOrContents", {slot, blockRoot, source}); const contents = executionPayload - ? chain.producedContentsCache.get(toRootHex(executionPayload.blockHash)) ?? null + ? (chain.producedContentsCache.get(toRootHex(executionPayload.blockHash)) ?? null) : null; const signedBlockOrContents = reconstructFullBlockOrContents(signedBlindedBlock, {executionPayload, contents}); diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index e01b172f1e72..9343dd67a399 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -94,7 +94,6 @@ export function getBeaconPoolApi({ signedAttestations.map(async (attestation, i) => { try { const fork = chain.config.getForkName(chain.clock.currentSlot); - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type const validateFn = () => validateApiAttestation(fork, chain, {attestation, serializedData: null}); const {slot, beaconBlockRoot} = attestation.data; // when a validator is configured with multiple beacon node urls, this attestation data may come from another beacon node diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index 5e9d3be01221..074fa7928d91 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -134,7 +134,7 @@ export function getStateValidatorIndex( if (id.startsWith("0x")) { try { id = fromHex(id); - } catch (e) { + } catch (_e) { return {valid: false, code: 400, reason: "Invalid pubkey hex encoding"}; } } else { diff --git a/packages/beacon-node/src/api/impl/config/constants.ts b/packages/beacon-node/src/api/impl/config/constants.ts index 14ecade15b2e..e951da35bdd2 100644 --- a/packages/beacon-node/src/api/impl/config/constants.ts +++ b/packages/beacon-node/src/api/impl/config/constants.ts @@ -41,8 +41,6 @@ import { FULL_EXIT_REQUEST_AMOUNT, } from "@lodestar/params"; -/* eslint-disable @typescript-eslint/naming-convention */ - /** * Hand-picked list of constants declared in consensus-spec .md files. * This list is asserted to be up-to-date with the test `test/e2e/api/impl/config.test.ts` diff --git a/packages/beacon-node/src/api/impl/events/index.ts b/packages/beacon-node/src/api/impl/events/index.ts index 25659743ddf3..55a49fe0c7e3 100644 --- a/packages/beacon-node/src/api/impl/events/index.ts +++ b/packages/beacon-node/src/api/impl/events/index.ts @@ -10,11 +10,10 @@ export function getEventsApi({ const onAbortFns: (() => void)[] = []; for (const topic of topics) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: const handler = (data: any): void => { // TODO: What happens if this handler throws? Does it break the other chain.emitter listeners? - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment onEvent({type: topic, message: data}); }; diff --git a/packages/beacon-node/src/api/impl/node/utils.ts b/packages/beacon-node/src/api/impl/node/utils.ts index f26539eb0b36..27978a03ec39 100644 --- a/packages/beacon-node/src/api/impl/node/utils.ts +++ b/packages/beacon-node/src/api/impl/node/utils.ts @@ -44,6 +44,7 @@ function getPeerState(status: StreamStatus): routes.node.PeerState { case "closing": return "disconnecting"; case "closed": + return "disconnected"; default: return "disconnected"; } diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 8a500125ad06..f6cbc4e98e98 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -1147,7 +1147,6 @@ export function getValidatorApi( signedAggregateAndProofs.map(async (signedAggregateAndProof, i) => { try { // TODO: Validate in batch - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type const validateFn = () => validateApiAggregateAndProof(fork, chain, signedAggregateAndProof); const {slot, beaconBlockRoot} = signedAggregateAndProof.message.aggregate.data; // when a validator is configured with multiple beacon node urls, this attestation may come from another beacon node diff --git a/packages/beacon-node/src/api/rest/activeSockets.ts b/packages/beacon-node/src/api/rest/activeSockets.ts index 9f1b0f1a78a3..e6a9aa382333 100644 --- a/packages/beacon-node/src/api/rest/activeSockets.ts +++ b/packages/beacon-node/src/api/rest/activeSockets.ts @@ -93,7 +93,7 @@ export class HttpActiveSocketsTracker { await waitFor(() => this.sockets.size === 0, { timeout: GRACEFUL_TERMINATION_TIMEOUT, }); - } catch { + } catch (_e) { // Ignore timeout error } finally { for (const socket of this.sockets) { diff --git a/packages/beacon-node/src/api/rest/swaggerUI.ts b/packages/beacon-node/src/api/rest/swaggerUI.ts index c48f4e51860d..b4db3e43e6b1 100644 --- a/packages/beacon-node/src/api/rest/swaggerUI.ts +++ b/packages/beacon-node/src/api/rest/swaggerUI.ts @@ -41,15 +41,13 @@ async function getAsset(name: string): Promise { const path = await import("node:path"); const fs = await import("node:fs/promises"); const url = await import("node:url"); - // eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); return await fs.readFile(path.join(__dirname, "../../../../../assets/", name)); - } catch (e) { + } catch (_e) { return undefined; } } -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export async function getFavicon() { const content = await getAsset("round-icon.ico"); if (!content) { @@ -67,7 +65,6 @@ export async function getFavicon() { ]; } -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export async function getLogo() { const content = await getAsset("lodestar_icon_text_white.png"); if (!content) { diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts index 8393c91063de..accd3df31ab0 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts @@ -83,7 +83,6 @@ async function maybeValidateBlobs( return {dataAvailabilityStatus: DataAvailabilityStatus.Available, availableBlockInput: blockInput}; } - // eslint-disable-next-line no-fallthrough case BlockInputType.dataPromise: { // run full validation const {block} = blockInput; @@ -136,7 +135,7 @@ async function raceWithCutoff( try { await Promise.race([availabilityPromise, cutoffTimeout]); - } catch (e) { + } catch (_e) { // throw unavailable so that the unknownblock/blobs can be triggered to pull the block throw new BlockError(block, {code: BlockErrorCode.DATA_UNAVAILABLE}); } diff --git a/packages/beacon-node/src/chain/bls/multithread/index.ts b/packages/beacon-node/src/chain/bls/multithread/index.ts index 3725fa4bcb1c..ce9b726c7693 100644 --- a/packages/beacon-node/src/chain/bls/multithread/index.ts +++ b/packages/beacon-node/src/chain/bls/multithread/index.ts @@ -3,9 +3,8 @@ import path from "node:path"; import {spawn, Worker} from "@chainsafe/threads"; // `threads` library creates self global variable which breaks `timeout-abort-controller` https://github.com/jacobheun/timeout-abort-controller/issues/9 // Don't add an eslint disable here as a reminder that this has to be fixed eventually -// eslint-disable-next-line // @ts-ignore -// eslint-disable-next-line +// biome-ignore lint/suspicious/noGlobalAssign: self = undefined; import {PublicKey} from "@chainsafe/blst"; import {Logger} from "@lodestar/utils"; diff --git a/packages/beacon-node/src/chain/bls/multithread/poolSize.ts b/packages/beacon-node/src/chain/bls/multithread/poolSize.ts index 9397f97849cd..2c683e191fd6 100644 --- a/packages/beacon-node/src/chain/bls/multithread/poolSize.ts +++ b/packages/beacon-node/src/chain/bls/multithread/poolSize.ts @@ -6,7 +6,7 @@ try { } else { defaultPoolSize = (await import("node:os")).availableParallelism(); } -} catch (e) { +} catch (_e) { defaultPoolSize = 8; } diff --git a/packages/beacon-node/src/chain/bls/multithread/worker.ts b/packages/beacon-node/src/chain/bls/multithread/worker.ts index 9073920df19c..d2794db2e6bf 100644 --- a/packages/beacon-node/src/chain/bls/multithread/worker.ts +++ b/packages/beacon-node/src/chain/bls/multithread/worker.ts @@ -75,7 +75,7 @@ function verifyManySignatureSets(workReqArr: BlsWorkReq[]): BlsWorkResult { // Re-verify all sigs nonBatchableSets.push(...batchableChunk); } - } catch (e) { + } catch (_e) { // TODO: Ignore this error expecting that the same error will happen when re-verifying the set individually // It's not ideal but '@chainsafe/blst' may throw errors on some conditions batchRetries++; diff --git a/packages/beacon-node/src/chain/emitter.ts b/packages/beacon-node/src/chain/emitter.ts index 9c3ea4a9bf52..10b6455e48f5 100644 --- a/packages/beacon-node/src/chain/emitter.ts +++ b/packages/beacon-node/src/chain/emitter.ts @@ -1,4 +1,4 @@ -import {EventEmitter} from "events"; +import {EventEmitter} from "node:events"; import {StrictEventEmitter} from "strict-event-emitter-types"; import {routes} from "@lodestar/api"; diff --git a/packages/beacon-node/src/chain/initState.ts b/packages/beacon-node/src/chain/initState.ts index 311806fb1be7..2883cdc8388e 100644 --- a/packages/beacon-node/src/chain/initState.ts +++ b/packages/beacon-node/src/chain/initState.ts @@ -132,7 +132,7 @@ export async function initStateFromEth1({ * Restore the latest beacon state from db */ export async function initStateFromDb( - config: ChainForkConfig, + _config: ChainForkConfig, db: IBeaconDb, logger: Logger ): Promise { diff --git a/packages/beacon-node/src/chain/produceBlock/validateBlobsAndKzgCommitments.ts b/packages/beacon-node/src/chain/produceBlock/validateBlobsAndKzgCommitments.ts index ba086ecafc7e..06f17c92156a 100644 --- a/packages/beacon-node/src/chain/produceBlock/validateBlobsAndKzgCommitments.ts +++ b/packages/beacon-node/src/chain/produceBlock/validateBlobsAndKzgCommitments.ts @@ -5,7 +5,8 @@ import {BlobsBundle} from "../../execution/index.js"; * Optionally sanity-check that the KZG commitments match the versioned hashes in the transactions * https://github.com/ethereum/consensus-specs/blob/11a037fd9227e29ee809c9397b09f8cc3383a8c0/specs/eip4844/validator.md#blob-kzg-commitments */ -export function validateBlobsAndKzgCommitments(payload: ExecutionPayload, blobsBundle: BlobsBundle): void { + +export function validateBlobsAndKzgCommitments(_payload: ExecutionPayload, blobsBundle: BlobsBundle): void { // sanity-check that the KZG commitments match the blobs (as produced by the execution engine) if (blobsBundle.blobs.length !== blobsBundle.commitments.length) { throw Error( diff --git a/packages/beacon-node/src/chain/rewards/attestationsRewards.ts b/packages/beacon-node/src/chain/rewards/attestationsRewards.ts index 70fb27de239a..0c74b8610f93 100644 --- a/packages/beacon-node/src/chain/rewards/attestationsRewards.ts +++ b/packages/beacon-node/src/chain/rewards/attestationsRewards.ts @@ -36,9 +36,9 @@ const defaultAttestationsReward = {head: 0, target: 0, source: 0, inclusionDelay const defaultAttestationsPenalty = {target: 0, source: 0}; export async function computeAttestationsRewards( - epoch: Epoch, + _epoch: Epoch, state: CachedBeaconStateAllForks, - config: BeaconConfig, + _config: BeaconConfig, validatorIds?: (ValidatorIndex | string)[] ): Promise { const fork = state.config.getForkName(state.slot); diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 39a3700aacf9..de5f40372c9f 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -6,7 +6,7 @@ import { createAggregateSignatureSetFromComponents, } from "@lodestar/state-transition"; import {toRootHex} from "@lodestar/utils"; -import {IBeaconChain} from ".."; +import {IBeaconChain} from "../index.js"; import {AttestationError, AttestationErrorCode, GossipAction} from "../errors/index.js"; import {RegenCaller} from "../regen/index.js"; import {getSelectionProofSignatureSet, getAggregateAndProofSignatureSet} from "./signatureSets/index.js"; diff --git a/packages/beacon-node/src/chain/validation/attesterSlashing.ts b/packages/beacon-node/src/chain/validation/attesterSlashing.ts index 11a499c9bb53..5da146a67a86 100644 --- a/packages/beacon-node/src/chain/validation/attesterSlashing.ts +++ b/packages/beacon-node/src/chain/validation/attesterSlashing.ts @@ -4,7 +4,7 @@ import { assertValidAttesterSlashing, getAttesterSlashingSignatureSets, } from "@lodestar/state-transition"; -import {IBeaconChain} from ".."; +import {IBeaconChain} from "../index.js"; import {AttesterSlashingError, AttesterSlashingErrorCode, GossipAction} from "../errors/index.js"; export async function validateApiAttesterSlashing( diff --git a/packages/beacon-node/src/chain/validation/blsToExecutionChange.ts b/packages/beacon-node/src/chain/validation/blsToExecutionChange.ts index e5ad56daeb5c..fff399aada50 100644 --- a/packages/beacon-node/src/chain/validation/blsToExecutionChange.ts +++ b/packages/beacon-node/src/chain/validation/blsToExecutionChange.ts @@ -4,7 +4,7 @@ import { getBlsToExecutionChangeSignatureSet, CachedBeaconStateCapella, } from "@lodestar/state-transition"; -import {IBeaconChain} from ".."; +import {IBeaconChain} from "../index.js"; import {BlsToExecutionChangeError, BlsToExecutionChangeErrorCode, GossipAction} from "../errors/index.js"; export async function validateApiBlsToExecutionChange( diff --git a/packages/beacon-node/src/chain/validation/proposerSlashing.ts b/packages/beacon-node/src/chain/validation/proposerSlashing.ts index 7281302aae8d..48fe6db326c9 100644 --- a/packages/beacon-node/src/chain/validation/proposerSlashing.ts +++ b/packages/beacon-node/src/chain/validation/proposerSlashing.ts @@ -1,6 +1,6 @@ import {phase0} from "@lodestar/types"; import {assertValidProposerSlashing, getProposerSlashingSignatureSets} from "@lodestar/state-transition"; -import {IBeaconChain} from ".."; +import {IBeaconChain} from "../index.js"; import {ProposerSlashingError, ProposerSlashingErrorCode, GossipAction} from "../errors/index.js"; export async function validateApiProposerSlashing( diff --git a/packages/beacon-node/src/chain/validation/voluntaryExit.ts b/packages/beacon-node/src/chain/validation/voluntaryExit.ts index 3957b51180d9..2b38b161423e 100644 --- a/packages/beacon-node/src/chain/validation/voluntaryExit.ts +++ b/packages/beacon-node/src/chain/validation/voluntaryExit.ts @@ -1,6 +1,6 @@ import {phase0} from "@lodestar/types"; import {isValidVoluntaryExit, getVoluntaryExitSignatureSet} from "@lodestar/state-transition"; -import {IBeaconChain} from ".."; +import {IBeaconChain} from "../index.js"; import {VoluntaryExitError, VoluntaryExitErrorCode, GossipAction} from "../errors/index.js"; import {RegenCaller} from "../regen/index.js"; diff --git a/packages/beacon-node/src/db/repositories/backfilledRanges.ts b/packages/beacon-node/src/db/repositories/backfilledRanges.ts index 309909b18cb8..f86c20288099 100644 --- a/packages/beacon-node/src/db/repositories/backfilledRanges.ts +++ b/packages/beacon-node/src/db/repositories/backfilledRanges.ts @@ -23,8 +23,7 @@ export class BackfilledRanges extends Repository { return bytesToInt(super.decodeKey(data) as unknown as Uint8Array, "be"); } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - getId(value: Slot): number { + getId(_value: Slot): number { throw new Error("Cannot get the db key from slot"); } } diff --git a/packages/beacon-node/src/db/repositories/checkpointState.ts b/packages/beacon-node/src/db/repositories/checkpointState.ts index 8848f4d26d3a..cb111a497f87 100644 --- a/packages/beacon-node/src/db/repositories/checkpointState.ts +++ b/packages/beacon-node/src/db/repositories/checkpointState.ts @@ -11,7 +11,6 @@ import {Bucket, getBucketNameByValue} from "../buckets.js"; export class CheckpointStateRepository extends Repository { constructor(config: ChainForkConfig, db: Db) { // Pick some type but won't be used. Casted to any because no type can match `BeaconStateAllForks` - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any const type = ssz.phase0.BeaconState as any; const bucket = Bucket.allForks_checkpointState; super(config, db, bucket, type, getBucketNameByValue(bucket)); diff --git a/packages/beacon-node/src/db/repositories/depositDataRoot.ts b/packages/beacon-node/src/db/repositories/depositDataRoot.ts index fa8983f0e5fa..9b872c91bce4 100644 --- a/packages/beacon-node/src/db/repositories/depositDataRoot.ts +++ b/packages/beacon-node/src/db/repositories/depositDataRoot.ts @@ -21,8 +21,7 @@ export class DepositDataRootRepository extends Repository { } // depositDataRoots stored by depositData index - // eslint-disable-next-line @typescript-eslint/no-unused-vars - getId(value: Root): number { + getId(_value: Root): number { throw new Error("Unable to create depositIndex from root"); } diff --git a/packages/beacon-node/src/db/repositories/eth1Data.ts b/packages/beacon-node/src/db/repositories/eth1Data.ts index e0a6c14e4022..f87199a0b80e 100644 --- a/packages/beacon-node/src/db/repositories/eth1Data.ts +++ b/packages/beacon-node/src/db/repositories/eth1Data.ts @@ -14,8 +14,7 @@ export class Eth1DataRepository extends Repository { constructor(config: ChainForkConfig, db: Db) { // Pick some type but won't be used. Casted to any because no type can match `BeaconStateAllForks` - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: const type = ssz.phase0.BeaconState as any; const bucket = Bucket.allForks_stateArchive; super(config, db, bucket, type, getBucketNameByValue(bucket)); diff --git a/packages/beacon-node/src/db/single/preGenesisStateLastProcessedBlock.ts b/packages/beacon-node/src/db/single/preGenesisStateLastProcessedBlock.ts index c958b9de2f0a..37dcb069acc9 100644 --- a/packages/beacon-node/src/db/single/preGenesisStateLastProcessedBlock.ts +++ b/packages/beacon-node/src/db/single/preGenesisStateLastProcessedBlock.ts @@ -10,7 +10,7 @@ export class PreGenesisStateLastProcessedBlock { private readonly db: Db; private readonly key: Uint8Array; - constructor(config: ChainForkConfig, db: Db) { + constructor(_config: ChainForkConfig, db: Db) { this.db = db; this.type = ssz.UintNum64; this.bucket = Bucket.phase0_preGenesisStateLastProcessedBlock; diff --git a/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts b/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts index 9ba4a09a5549..f2ce0a8bb2f5 100644 --- a/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts +++ b/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts @@ -167,7 +167,6 @@ export class Eth1MergeBlockTracker { this.status = {code: StatusCode.SEARCHING}; this.logger.info("Starting search for terminal POW block", { - // eslint-disable-next-line @typescript-eslint/naming-convention TERMINAL_TOTAL_DIFFICULTY: this.config.TERMINAL_TOTAL_DIFFICULTY, }); @@ -268,7 +267,6 @@ export class Eth1MergeBlockTracker { // this class can start eagerly looking for the merge block when not necessary, startPollingMergeBlock() should // only be called when there is certainty that a mergeBlock search is necessary. - // eslint-disable-next-line no-constant-condition while (true) { if (block.totalDifficulty < this.config.TERMINAL_TOTAL_DIFFICULTY) { // TTD not reached yet diff --git a/packages/beacon-node/src/eth1/provider/eth1Provider.ts b/packages/beacon-node/src/eth1/provider/eth1Provider.ts index c86991eb7d15..d284700ddb1d 100644 --- a/packages/beacon-node/src/eth1/provider/eth1Provider.ts +++ b/packages/beacon-node/src/eth1/provider/eth1Provider.ts @@ -21,8 +21,6 @@ import { } from "./jsonRpcHttpClient.js"; import {isJsonRpcTruncatedError, quantityToNum, numToQuantity, dataToBytes} from "./utils.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - /** * Binds return types to Ethereum JSON RPC methods */ diff --git a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts index cbe70ecb7e18..e1a2a001c278 100644 --- a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts +++ b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts @@ -1,4 +1,4 @@ -import {EventEmitter} from "events"; +import {EventEmitter} from "node:events"; import {StrictEventEmitter} from "strict-event-emitter-types"; import {fetch} from "@lodestar/api"; import {ErrorAborted, Gauge, Histogram, TimeoutError, isValidHttpUrl, retry} from "@lodestar/utils"; diff --git a/packages/beacon-node/src/eth1/provider/jwt.ts b/packages/beacon-node/src/eth1/provider/jwt.ts index da1fc1827cdd..1e267120957f 100644 --- a/packages/beacon-node/src/eth1/provider/jwt.ts +++ b/packages/beacon-node/src/eth1/provider/jwt.ts @@ -2,7 +2,6 @@ import type {TAlgorithm} from "jwt-simple"; // TODO: fix jwt-simple types import jwt from "jwt-simple"; -// eslint-disable-next-line import/no-named-as-default-member const {encode, decode} = jwt; /** diff --git a/packages/beacon-node/src/execution/builder/index.ts b/packages/beacon-node/src/execution/builder/index.ts index 2f584ad7dadd..fff66a3e8bc5 100644 --- a/packages/beacon-node/src/execution/builder/index.ts +++ b/packages/beacon-node/src/execution/builder/index.ts @@ -18,6 +18,7 @@ export function initializeExecutionBuilder( ): IExecutionBuilder { switch (opts.mode) { case "http": + return new ExecutionBuilderHttp(opts, config, metrics, logger); default: return new ExecutionBuilderHttp(opts, config, metrics, logger); } diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index b42424b28998..a8206a89250d 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -437,7 +437,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { this.payloadIdCache.prune(); } - async getPayloadBodiesByHash(fork: ForkName, blockHashes: RootHex[]): Promise<(ExecutionPayloadBody | null)[]> { + async getPayloadBodiesByHash(_fork: ForkName, blockHashes: RootHex[]): Promise<(ExecutionPayloadBody | null)[]> { const method = "engine_getPayloadBodiesByHashV1"; assertReqSizeLimit(blockHashes.length, 32); const response = await this.rpc.fetchWithRetries< @@ -448,7 +448,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { } async getPayloadBodiesByRange( - fork: ForkName, + _fork: ForkName, startBlockNumber: number, blockCount: number ): Promise<(ExecutionPayloadBody | null)[]> { diff --git a/packages/beacon-node/src/execution/engine/index.ts b/packages/beacon-node/src/execution/engine/index.ts index a8b878502aff..dd2de2017c22 100644 --- a/packages/beacon-node/src/execution/engine/index.ts +++ b/packages/beacon-node/src/execution/engine/index.ts @@ -55,6 +55,8 @@ export function initializeExecutionEngine( return getExecutionEngineFromBackend(new ExecutionEngineMockBackend(opts), modules); case "http": + return getExecutionEngineHttp(opts, modules); + default: return getExecutionEngineHttp(opts, modules); } diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index 4cff2a8d00f4..bc3a130e604e 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -85,7 +85,6 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { }); this.handlers = { - /* eslint-disable @typescript-eslint/naming-convention */ engine_newPayloadV1: this.notifyNewPayload.bind(this), engine_newPayloadV2: this.notifyNewPayload.bind(this), engine_newPayloadV3: this.notifyNewPayload.bind(this), diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 32fe4cb79d3d..9b4f5e5c83e6 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -19,8 +19,6 @@ import { import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js"; import {WithdrawalV1} from "./payloadIdCache.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - export type EngineApiRpcParamTypes = { /** * 1. Object - Instance of ExecutionPayload diff --git a/packages/beacon-node/src/execution/engine/utils.ts b/packages/beacon-node/src/execution/engine/utils.ts index b56f62bf602b..4d84eda52c44 100644 --- a/packages/beacon-node/src/execution/engine/utils.ts +++ b/packages/beacon-node/src/execution/engine/utils.ts @@ -12,7 +12,7 @@ import {isQueueErrorAborted} from "../../util/queue/errors.js"; import {ExecutionPayloadStatus, ExecutionEngineState} from "./interface.js"; export type JsonRpcBackend = { - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: readonly handlers: Record any>; }; @@ -27,8 +27,7 @@ export class ExecutionEngineMockJsonRpcClient implements IJsonRpcHttpClient { if (handler === undefined) { throw Error(`Unknown method ${payload.method}`); } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: return handler(...(payload.params as any[])) as R; }, payload); } diff --git a/packages/beacon-node/src/metrics/metrics/beacon.ts b/packages/beacon-node/src/metrics/metrics/beacon.ts index 949999dbb1f4..6e86328ee561 100644 --- a/packages/beacon-node/src/metrics/metrics/beacon.ts +++ b/packages/beacon-node/src/metrics/metrics/beacon.ts @@ -11,7 +11,6 @@ export type BeaconMetrics = ReturnType; * https://github.com/ethereum/beacon-metrics/ and * https://hackmd.io/D5FmoeFZScim_squBFl8oA */ -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function createBeaconMetrics(register: RegistryMetricCreator) { return { // From https://github.com/ethereum/beacon-metrics/blob/master/metrics.md diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index bac740b7ee04..f15e195faa20 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -25,7 +25,6 @@ export type LodestarMetrics = ReturnType; /** * Extra Lodestar custom metrics */ -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function createLodestarMetrics( register: RegistryMetricCreator, metadata?: LodestarMetadata, diff --git a/packages/beacon-node/src/monitoring/service.ts b/packages/beacon-node/src/monitoring/service.ts index 9581c5f11c92..bd2388738d1f 100644 --- a/packages/beacon-node/src/monitoring/service.ts +++ b/packages/beacon-node/src/monitoring/service.ts @@ -229,7 +229,7 @@ export class MonitoringService { } return url; - } catch { + } catch (_e) { throw new Error(`Monitoring endpoint must be a valid URL: ${endpoint}`); } } diff --git a/packages/beacon-node/src/monitoring/system.ts b/packages/beacon-node/src/monitoring/system.ts index a1a79b1bd277..83507443be01 100644 --- a/packages/beacon-node/src/monitoring/system.ts +++ b/packages/beacon-node/src/monitoring/system.ts @@ -3,7 +3,6 @@ import os from "node:os"; import path from "node:path"; // We want to keep `system` export as it's more readable and easier to understand -// eslint-disable-next-line import/no-named-as-default import system from "systeminformation"; import {Logger} from "@lodestar/utils"; diff --git a/packages/beacon-node/src/network/core/metrics.ts b/packages/beacon-node/src/network/core/metrics.ts index c267ec069d88..7d0ef47d84af 100644 --- a/packages/beacon-node/src/network/core/metrics.ts +++ b/packages/beacon-node/src/network/core/metrics.ts @@ -5,7 +5,6 @@ import {SubnetSource} from "../subnets/attnetsService.js"; export type NetworkCoreMetrics = ReturnType; -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function createNetworkCoreMetrics(register: RegistryMetricCreator) { return { register, @@ -254,7 +253,6 @@ export function createNetworkCoreMetrics(register: RegistryMetricCreator) { export type NetworkCoreWorkerMetrics = ReturnType; -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function getNetworkCoreWorkerMetrics(register: RegistryMetricCreator) { return { reqRespBridgeRespCallerPending: register.gauge({ diff --git a/packages/beacon-node/src/network/core/networkCore.ts b/packages/beacon-node/src/network/core/networkCore.ts index 83ef4c4fb063..1a497925e4fd 100644 --- a/packages/beacon-node/src/network/core/networkCore.ts +++ b/packages/beacon-node/src/network/core/networkCore.ts @@ -149,7 +149,7 @@ export class NetworkCore implements INetworkCore { // Bind discv5's ENR to local metadata // resolve circular dependency by setting `discv5` variable after the peer manager is instantiated - // eslint-disable-next-line prefer-const + // biome-ignore lint/style/useConst: let discv5: Discv5Worker | undefined; const onMetadataSetValue = function onMetadataSetValue(key: string, value: Uint8Array): void { discv5?.setEnrValue(key, value).catch((e) => logger.error("error on setEnrValue", {key}, e)); diff --git a/packages/beacon-node/src/network/core/networkCoreWorker.ts b/packages/beacon-node/src/network/core/networkCoreWorker.ts index 1df348335582..5e4b057402d8 100644 --- a/packages/beacon-node/src/network/core/networkCoreWorker.ts +++ b/packages/beacon-node/src/network/core/networkCoreWorker.ts @@ -28,7 +28,6 @@ import { // Cloned data from instantiation const workerData = worker.workerData as NetworkWorkerData; const parentPort = worker.parentPort; -// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (!workerData) throw Error("workerData must be defined"); if (!parentPort) throw Error("parentPort must be defined"); diff --git a/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts b/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts index 19cca27eaaac..bd66a21e726b 100644 --- a/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts +++ b/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts @@ -136,7 +136,7 @@ export class WorkerNetworkCore implements INetworkCore { resourceLimits: {maxYoungGenerationSizeMb: opts.maxYoungGenerationSizeMb}, } as ConstructorParameters[1]); - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: const networkThreadApi = (await spawn(worker, { // A Lodestar Node may do very expensive task at start blocking the event loop and causing // the initialization to timeout. The number below is big enough to almost disable the timeout diff --git a/packages/beacon-node/src/network/core/types.ts b/packages/beacon-node/src/network/core/types.ts index 41b7f669eaac..4eeaf96e1903 100644 --- a/packages/beacon-node/src/network/core/types.ts +++ b/packages/beacon-node/src/network/core/types.ts @@ -90,7 +90,7 @@ export type NetworkWorkerData = { */ export type NetworkWorkerApi = INetworkCorePublic & { // To satisfy the constraint of `ModuleThread` type - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: [string: string]: (...args: any[]) => Promise | any; // Async method through worker boundary reportPeer(peer: PeerIdStr, action: PeerAction, actionName: string): Promise; diff --git a/packages/beacon-node/src/network/discv5/index.ts b/packages/beacon-node/src/network/discv5/index.ts index b2136658dfe7..745b3171c38d 100644 --- a/packages/beacon-node/src/network/discv5/index.ts +++ b/packages/beacon-node/src/network/discv5/index.ts @@ -1,4 +1,4 @@ -import EventEmitter from "events"; +import EventEmitter from "node:events"; import {PeerId, Secp256k1PeerId} from "@libp2p/interface"; import {StrictEventEmitter} from "strict-event-emitter-types"; import {exportToProtobuf} from "@libp2p/peer-id-factory"; diff --git a/packages/beacon-node/src/network/discv5/worker.ts b/packages/beacon-node/src/network/discv5/worker.ts index be8fdc4af601..8e96751d5fe7 100644 --- a/packages/beacon-node/src/network/discv5/worker.ts +++ b/packages/beacon-node/src/network/discv5/worker.ts @@ -22,7 +22,6 @@ import {enrRelevance, ENRRelevance} from "./utils.js"; // Cloned data from instatiation const workerData = worker.workerData as Discv5WorkerData; -// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (!workerData) throw Error("workerData must be defined"); const logger = getNodeLogger(workerData.loggerOpts); diff --git a/packages/beacon-node/src/network/events.ts b/packages/beacon-node/src/network/events.ts index 45759de61073..a95b52394163 100644 --- a/packages/beacon-node/src/network/events.ts +++ b/packages/beacon-node/src/network/events.ts @@ -1,4 +1,4 @@ -import {EventEmitter} from "events"; +import {EventEmitter} from "node:events"; import {PeerId, TopicValidatorResult} from "@libp2p/interface"; import {phase0, RootHex} from "@lodestar/types"; import {BlockInput, NullBlockInput} from "../chain/blocks/types.js"; diff --git a/packages/beacon-node/src/network/forks.ts b/packages/beacon-node/src/network/forks.ts index 47575cf6d9c6..1c613f4cee94 100644 --- a/packages/beacon-node/src/network/forks.ts +++ b/packages/beacon-node/src/network/forks.ts @@ -86,7 +86,6 @@ export function getCurrentAndNextFork( } return { - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions currentFork: forks[currentForkIdx] || forks[0], nextFork: hasNextFork ? forks[nextForkIdx] : undefined, }; diff --git a/packages/beacon-node/src/network/gossip/gossipsub.ts b/packages/beacon-node/src/network/gossip/gossipsub.ts index e6977abe8ce6..1fc326ba1e58 100644 --- a/packages/beacon-node/src/network/gossip/gossipsub.ts +++ b/packages/beacon-node/src/network/gossip/gossipsub.ts @@ -26,7 +26,6 @@ import { GOSSIP_D_LOW, } from "./scoringParameters.js"; -/* eslint-disable @typescript-eslint/naming-convention */ /** As specified in https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md */ const GOSSIPSUB_HEARTBEAT_INTERVAL = 0.7 * 1000; diff --git a/packages/beacon-node/src/network/gossip/interface.ts b/packages/beacon-node/src/network/gossip/interface.ts index af5e3888d04f..ff1bfa088c17 100644 --- a/packages/beacon-node/src/network/gossip/interface.ts +++ b/packages/beacon-node/src/network/gossip/interface.ts @@ -203,7 +203,7 @@ export type BatchGossipHandler = ( gossipHandlerParams: GossipHandlerParamGeneric[] ) => Promise<(null | GossipActionError)[]>; -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: export type ResolvedType Promise> = F extends (...args: any) => Promise ? T : never; diff --git a/packages/beacon-node/src/network/gossip/metrics.ts b/packages/beacon-node/src/network/gossip/metrics.ts index c2b5d0b32338..5ca5d22154c2 100644 --- a/packages/beacon-node/src/network/gossip/metrics.ts +++ b/packages/beacon-node/src/network/gossip/metrics.ts @@ -4,7 +4,6 @@ import {GossipType} from "./interface.js"; export type Eth2GossipsubMetrics = ReturnType; -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function createEth2GossipsubMetrics(register: RegistryMetricCreator) { return { gossipPeer: { diff --git a/packages/beacon-node/src/network/gossip/scoringParameters.ts b/packages/beacon-node/src/network/gossip/scoringParameters.ts index 7e1be07f2ca7..3ba32614afeb 100644 --- a/packages/beacon-node/src/network/gossip/scoringParameters.ts +++ b/packages/beacon-node/src/network/gossip/scoringParameters.ts @@ -12,8 +12,6 @@ import {Eth2Context, Eth2GossipsubModules} from "./gossipsub.js"; import {GossipType} from "./interface.js"; import {stringifyGossipTopic} from "./topic.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - export const GOSSIP_D = 8; export const GOSSIP_D_LOW = 6; export const GOSSIP_D_HIGH = 12; diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index b7c7425584c5..c44e29274bca 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -78,7 +78,6 @@ function stringifyGossipTopicType(topic: GossipTopic): string { } } -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function getGossipSSZType(topic: GossipTopic) { switch (topic.type) { case GossipType.beacon_block: @@ -120,7 +119,7 @@ export function sszDeserialize(topic: T, serializedData: const sszType = getGossipSSZType(topic); try { return sszType.deserialize(serializedData) as SSZTypeOfGossipTopic; - } catch (e) { + } catch (_e) { throw new GossipActionError(GossipAction.REJECT, {code: GossipErrorCode.INVALID_SERIALIZED_BYTES_ERROR_CODE}); } } @@ -131,7 +130,7 @@ export function sszDeserialize(topic: T, serializedData: export function sszDeserializeAttestation(fork: ForkName, serializedData: Uint8Array): Attestation { try { return sszTypesFor(fork).Attestation.deserialize(serializedData); - } catch (e) { + } catch (_e) { throw new GossipActionError(GossipAction.REJECT, {code: GossipErrorCode.INVALID_SERIALIZED_BYTES_ERROR_CODE}); } } diff --git a/packages/beacon-node/src/network/peers/datastore.ts b/packages/beacon-node/src/network/peers/datastore.ts index 762e99dc45b4..88a7a6f5f2d6 100644 --- a/packages/beacon-node/src/network/peers/datastore.ts +++ b/packages/beacon-node/src/network/peers/datastore.ts @@ -147,8 +147,7 @@ export class Eth2PeerDataStore extends BaseDatastore { if (this._dirtyItems.size >= this._threshold) { try { await this._commitData(); - // eslint-disable-next-line no-empty - } catch (e) {} + } catch (_e) {} } } diff --git a/packages/beacon-node/src/network/peers/discover.ts b/packages/beacon-node/src/network/peers/discover.ts index 79603f780e3d..9e06a39b4fb4 100644 --- a/packages/beacon-node/src/network/peers/discover.ts +++ b/packages/beacon-node/src/network/peers/discover.ts @@ -304,7 +304,6 @@ export class PeerDiscovery { const {id, multiaddrs} = evt.detail; // libp2p may send us PeerInfos without multiaddrs https://github.com/libp2p/js-libp2p/issues/1873 - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (!multiaddrs || multiaddrs.length === 0) { this.metrics?.discovery.discoveredStatus.inc({status: DiscoveredPeerStatus.no_multiaddrs}); return; diff --git a/packages/beacon-node/src/network/peers/peerManager.ts b/packages/beacon-node/src/network/peers/peerManager.ts index 43fbee723f0e..3971e2147707 100644 --- a/packages/beacon-node/src/network/peers/peerManager.ts +++ b/packages/beacon-node/src/network/peers/peerManager.ts @@ -383,7 +383,7 @@ export class PeerManager { private async requestMetadata(peer: PeerId): Promise { try { this.onMetadata(peer, await this.reqResp.sendMetadata(peer)); - } catch (e) { + } catch (_e) { // TODO: Downvote peer here or in the reqResp layer } } @@ -395,7 +395,7 @@ export class PeerManager { // If peer replies a PING request also update lastReceivedMsg const peerData = this.connectedPeers.get(peer.toString()); if (peerData) peerData.lastReceivedMsgUnixTsMs = Date.now(); - } catch (e) { + } catch (_e) { // TODO: Downvote peer here or in the reqResp layer } } @@ -403,7 +403,7 @@ export class PeerManager { private async requestStatus(peer: PeerId, localStatus: phase0.Status): Promise { try { this.onStatus(peer, await this.reqResp.sendStatus(peer, localStatus)); - } catch (e) { + } catch (_e) { // TODO: Failed to get peer latest status: downvote but don't disconnect } } @@ -423,7 +423,7 @@ export class PeerManager { * NOTE: Discovery should only add a new query if one isn't already queued. */ private heartbeat(): void { - // timer is safe without a try {} catch {}, in case of error the metric won't register and timer is GC'ed + // timer is safe without a try {} catch (_e) {}, in case of error the metric won't register and timer is GC'ed const timer = this.metrics?.peerManager.heartbeatDuration.startTimer(); const connectedPeers = this.getConnectedPeerIds(); diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index 90c131a943ed..dab3af0df8ba 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -680,7 +680,6 @@ export async function validateGossipFnRetryUnknownRoot( blockRoot: Root ): Promise { let unknownBlockRootRetries = 0; - // eslint-disable-next-line no-constant-condition while (true) { try { return await fn(); diff --git a/packages/beacon-node/src/network/processor/index.ts b/packages/beacon-node/src/network/processor/index.ts index 5cfed6c20346..ec0edf54644f 100644 --- a/packages/beacon-node/src/network/processor/index.ts +++ b/packages/beacon-node/src/network/processor/index.ts @@ -396,7 +396,9 @@ export class NetworkProcessor { if (item) { this.gossipTopicConcurrency[topic] += numMessages; this.processPendingGossipsubMessage(item) - .finally(() => (this.gossipTopicConcurrency[topic] -= numMessages)) + .finally(() => { + this.gossipTopicConcurrency[topic] -= numMessages; + }) .catch((e) => this.logger.error("processGossipAttestations must not throw", {}, e)); jobsSubmitted += numMessages; diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts index 4dae4831d716..74b6d8f13b2e 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts @@ -80,6 +80,7 @@ export function matchBlockWithBlobs( let blobSidecar: deneb.BlobSidecar; while ( + // biome-ignore lint/suspicious/noAssignInExpressions: (blobSidecar = allBlobSidecars[blobSideCarIndex])?.signedBlockHeader.message.slot === block.data.message.slot ) { blobSidecars.push(blobSidecar); diff --git a/packages/beacon-node/src/network/reqresp/protocols.ts b/packages/beacon-node/src/network/reqresp/protocols.ts index a0fa9576c93c..e63df4b1341b 100644 --- a/packages/beacon-node/src/network/reqresp/protocols.ts +++ b/packages/beacon-node/src/network/reqresp/protocols.ts @@ -3,8 +3,6 @@ import {ForkDigestContext} from "@lodestar/config"; import {ProtocolNoHandler, ReqRespMethod, Version, requestSszTypeByMethod, responseSszTypeByMethod} from "./types.js"; import {rateLimitQuotas} from "./rateLimit.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - export const Goodbye = toProtocol({ method: ReqRespMethod.Goodbye, version: Version.V1, diff --git a/packages/beacon-node/src/network/reqresp/rateLimit.ts b/packages/beacon-node/src/network/reqresp/rateLimit.ts index 881ab36bc05d..b6dacd6ba8e5 100644 --- a/packages/beacon-node/src/network/reqresp/rateLimit.ts +++ b/packages/beacon-node/src/network/reqresp/rateLimit.ts @@ -76,7 +76,7 @@ function getRequestCountFn( return (reqData: Uint8Array) => { try { return (type && fn(type.deserialize(reqData))) ?? 1; - } catch (e) { + } catch (_e) { return 1; } }; diff --git a/packages/beacon-node/src/network/reqresp/score.ts b/packages/beacon-node/src/network/reqresp/score.ts index c74b645c9909..647481162c78 100644 --- a/packages/beacon-node/src/network/reqresp/score.ts +++ b/packages/beacon-node/src/network/reqresp/score.ts @@ -8,7 +8,6 @@ import {ReqRespMethod} from "./types.js"; * https://github.com/libp2p/js-libp2p/blob/6350a187c7c207086e42436ccbcabd59af6f5e3d/src/errors.js#L32 */ const libp2pErrorCodes = { - // eslint-disable-next-line @typescript-eslint/naming-convention ERR_UNSUPPORTED_PROTOCOL: "ERR_UNSUPPORTED_PROTOCOL", }; diff --git a/packages/beacon-node/src/network/util.ts b/packages/beacon-node/src/network/util.ts index dd317b5a0427..835096afbfc8 100644 --- a/packages/beacon-node/src/network/util.ts +++ b/packages/beacon-node/src/network/util.ts @@ -15,7 +15,6 @@ export function prettyPrintPeerIdStr(id: PeerIdStr): string { */ // Compat function for efficiency reasons export function getConnectionsMap(libp2p: Libp2p): Map { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return libp2p.services.components.connectionManager.getConnectionsMap()["map"]; } diff --git a/packages/beacon-node/src/sync/backfill/backfill.ts b/packages/beacon-node/src/sync/backfill/backfill.ts index 77d2836bdcc3..f60e28a19e1d 100644 --- a/packages/beacon-node/src/sync/backfill/backfill.ts +++ b/packages/beacon-node/src/sync/backfill/backfill.ts @@ -1,4 +1,4 @@ -import {EventEmitter} from "events"; +import {EventEmitter} from "node:events"; import {StrictEventEmitter} from "strict-event-emitter-types"; import {BeaconStateAllForks, blockToHeader, computeAnchorCheckpoint} from "@lodestar/state-transition"; import {BeaconConfig, ChainForkConfig} from "@lodestar/config"; @@ -13,7 +13,7 @@ import {INetwork, NetworkEvent, NetworkEventData, PeerAction} from "../../networ import {ItTrigger} from "../../util/itTrigger.js"; import {PeerIdStr} from "../../util/peerId.js"; import {shuffleOne} from "../../util/shuffle.js"; -import {Metrics} from "../../metrics/metrics"; +import {Metrics} from "../../metrics/metrics.js"; import {byteArrayEquals} from "../../util/bytes.js"; import {verifyBlockProposerSignature, verifyBlockSequence, BackfillBlockHeader, BackfillBlock} from "./verify.js"; import {BackfillSyncError, BackfillSyncErrorCode} from "./errors.js"; @@ -680,6 +680,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} let isPrevFinWsConfirmedAnchorParent = false; while ( backCount !== this.opts.backfillBatchSize && + // biome-ignore lint/suspicious/noAssignInExpressions: (parentBlock = await this.db.blockArchive.getByRoot(anchorBlock.message.parentRoot)) ) { // Before moving anchorBlock back, we need check for prevFinalizedCheckpointBlock diff --git a/packages/beacon-node/src/sync/range/range.ts b/packages/beacon-node/src/sync/range/range.ts index 887a86a3aaf2..efdf84cf7af1 100644 --- a/packages/beacon-node/src/sync/range/range.ts +++ b/packages/beacon-node/src/sync/range/range.ts @@ -1,4 +1,4 @@ -import {EventEmitter} from "events"; +import {EventEmitter} from "node:events"; import {StrictEventEmitter} from "strict-event-emitter-types"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; diff --git a/packages/beacon-node/src/util/asyncIterableToEvents.ts b/packages/beacon-node/src/util/asyncIterableToEvents.ts index 0468ca2b431b..836983d8e4f0 100644 --- a/packages/beacon-node/src/util/asyncIterableToEvents.ts +++ b/packages/beacon-node/src/util/asyncIterableToEvents.ts @@ -46,7 +46,6 @@ export class AsyncIterableBridgeCaller { } getAsyncIterable(callArgs: Args): AsyncIterable { - // eslint-disable-next-line @typescript-eslint/no-this-alias const self = this; return { @@ -67,7 +66,6 @@ export class AsyncIterableBridgeCaller { return { async next() { - // eslint-disable-next-line no-constant-condition while (true) { const item = req.items.shift(); if (item !== null) { diff --git a/packages/beacon-node/src/util/kzg.ts b/packages/beacon-node/src/util/kzg.ts index e20a379d62ff..efc6dd34ee1c 100644 --- a/packages/beacon-node/src/util/kzg.ts +++ b/packages/beacon-node/src/util/kzg.ts @@ -3,8 +3,6 @@ import fs from "node:fs"; import {fileURLToPath} from "node:url"; import {fromHex, toHex} from "@lodestar/utils"; -/* eslint-disable @typescript-eslint/naming-convention */ - // "c-kzg" has hardcoded the mainnet value, do not use params export const FIELD_ELEMENTS_PER_BLOB_MAINNET = 4096; @@ -87,7 +85,6 @@ export function loadEthereumTrustedSetup(mode: TrustedFileMode = TrustedFileMode } } -/* eslint-disable @typescript-eslint/naming-convention */ export interface TrustedSetupJSON { setup_G1: string[]; setup_G2: string[]; diff --git a/packages/beacon-node/src/util/map.ts b/packages/beacon-node/src/util/map.ts index 6cc8f37155b1..1b8fc6222032 100644 --- a/packages/beacon-node/src/util/map.ts +++ b/packages/beacon-node/src/util/map.ts @@ -43,7 +43,6 @@ export class OrderedMap { } values(): IterableIterator { - // eslint-disable-next-line @typescript-eslint/no-this-alias const _self = this; return (function* generateValues() { for (const key of _self.keys()) { diff --git a/packages/beacon-node/src/util/profile.ts b/packages/beacon-node/src/util/profile.ts index 7085c329c823..ccb5b098be31 100644 --- a/packages/beacon-node/src/util/profile.ts +++ b/packages/beacon-node/src/util/profile.ts @@ -37,7 +37,7 @@ export async function profileNodeJS(durationMs: number): Promise { export async function writeHeapSnapshot(prefix: string, dirpath: string): Promise { // Lazily import NodeJS only modules const fs = await import("node:fs"); - const v8 = await import("v8"); + const v8 = await import("node:v8"); const snapshotStream = v8.getHeapSnapshot(); const filepath = `${dirpath}/${prefix}_${new Date().toISOString()}.heapsnapshot`; const fileStream = fs.createWriteStream(filepath); diff --git a/packages/beacon-node/src/util/queue/errors.ts b/packages/beacon-node/src/util/queue/errors.ts index edb0b3b87374..7117b5629372 100644 --- a/packages/beacon-node/src/util/queue/errors.ts +++ b/packages/beacon-node/src/util/queue/errors.ts @@ -7,11 +7,7 @@ export enum QueueErrorCode { export type QueueErrorCodeType = {code: QueueErrorCode.QUEUE_ABORTED} | {code: QueueErrorCode.QUEUE_MAX_LENGTH}; -export class QueueError extends LodestarError { - constructor(type: QueueErrorCodeType) { - super(type); - } -} +export class QueueError extends LodestarError {} export function isQueueErrorAborted(e: unknown): e is QueueError { return e instanceof QueueError && e.type.code === QueueErrorCode.QUEUE_ABORTED; diff --git a/packages/beacon-node/src/util/queue/fnQueue.ts b/packages/beacon-node/src/util/queue/fnQueue.ts index ec3267bdf93a..80e179f8e8f3 100644 --- a/packages/beacon-node/src/util/queue/fnQueue.ts +++ b/packages/beacon-node/src/util/queue/fnQueue.ts @@ -1,10 +1,10 @@ import {JobItemQueue} from "./itemQueue.js"; import {QueueMetrics, JobQueueOpts} from "./options.js"; -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: type Fn = (...args: any) => Promise; -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: export class JobFnQueue extends JobItemQueue<[Fn], any> { constructor(opts: JobQueueOpts, metrics?: QueueMetrics) { super((fn) => fn(), opts, metrics); diff --git a/packages/beacon-node/src/util/queue/itemQueue.ts b/packages/beacon-node/src/util/queue/itemQueue.ts index 7da7b6cdd8cb..f380a15f5eaf 100644 --- a/packages/beacon-node/src/util/queue/itemQueue.ts +++ b/packages/beacon-node/src/util/queue/itemQueue.ts @@ -7,7 +7,8 @@ import {defaultQueueOpts, QueueMetrics, JobQueueOpts, QueueType} from "./options * JobQueue that stores arguments in the job array instead of closures. * Supports a single itemProcessor, for arbitrary functions use the JobFnQueue */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any + +// biome-ignore lint/suspicious/noExplicitAny: export class JobItemQueue { private readonly opts: Required; /** diff --git a/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts b/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts index 2d2a0a37c59e..0789932e61e4 100644 --- a/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts @@ -67,9 +67,7 @@ describe("beacon node api", function () { const bnElOffline = await getDevBeaconNode({ params: { ...chainConfigDef, - // eslint-disable-next-line @typescript-eslint/naming-convention ALTAIR_FORK_EPOCH: 0, - // eslint-disable-next-line @typescript-eslint/naming-convention BELLATRIX_FORK_EPOCH: 0, }, options: { diff --git a/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts b/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts index c746746741cf..8f05ae41c468 100644 --- a/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts @@ -13,7 +13,6 @@ import {getAndInitDevValidators} from "../../../../utils/node/validator.js"; import {BeaconNode} from "../../../../../src/node/nodejs.js"; import {waitForEvent} from "../../../../utils/events/resolver.js"; -/* eslint-disable @typescript-eslint/naming-convention */ describe("lightclient api", function () { const SECONDS_PER_SLOT = 1; const ALTAIR_FORK_EPOCH = 0; diff --git a/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts b/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts index 5cccb2aa0772..d505e38b3f9a 100644 --- a/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts +++ b/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts @@ -20,7 +20,6 @@ describe("api / impl / validator", function () { const validatorCount = 8; const restPort = 9596; const testParams: Pick = { - /* eslint-disable @typescript-eslint/naming-convention */ SECONDS_PER_SLOT: SECONDS_PER_SLOT, ALTAIR_FORK_EPOCH: ALTAIR_FORK_EPOCH, }; diff --git a/packages/beacon-node/test/e2e/chain/lightclient.test.ts b/packages/beacon-node/test/e2e/chain/lightclient.test.ts index c501a2618049..5e7b7f36fff2 100644 --- a/packages/beacon-node/test/e2e/chain/lightclient.test.ts +++ b/packages/beacon-node/test/e2e/chain/lightclient.test.ts @@ -34,7 +34,6 @@ describe("chain / lightclient", function () { const restPort = 9000; const testParams: Pick = { - /* eslint-disable @typescript-eslint/naming-convention */ SECONDS_PER_SLOT: 1, ALTAIR_FORK_EPOCH: 0, }; diff --git a/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts b/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts index 594e20ec4cb0..ad32e2d5b270 100644 --- a/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts +++ b/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts @@ -17,13 +17,10 @@ describe("proposer boost reorg", function () { const validatorCount = 8; const testParams: Pick = { - // eslint-disable-next-line @typescript-eslint/naming-convention SECONDS_PER_SLOT: 2, // need this to make block `reorgSlot - 1` strong enough - // eslint-disable-next-line @typescript-eslint/naming-convention REORG_PARENT_WEIGHT_THRESHOLD: 80, // need this to make block `reorgSlot + 1` to become the head - // eslint-disable-next-line @typescript-eslint/naming-convention PROPOSER_SCORE_BOOST: 120, }; diff --git a/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts b/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts index fd14b7b8b8c0..b6c5c30dace4 100644 --- a/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts +++ b/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts @@ -24,7 +24,6 @@ describe("regen/reload states with n-historical states configuration", function const validatorCount = 8; const testParams: Pick = { - // eslint-disable-next-line @typescript-eslint/naming-convention SECONDS_PER_SLOT: 2, }; diff --git a/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts b/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts index ab9061f1eacd..bdfcbde056cd 100644 --- a/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts +++ b/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts @@ -34,7 +34,6 @@ describe.skip("doppelganger / doppelganger test", function () { const validatorCount = 1; const genesisSlotsDelay = 5; const beaconParams: Pick = { - // eslint-disable-next-line @typescript-eslint/naming-convention SECONDS_PER_SLOT: 2, }; @@ -123,7 +122,7 @@ describe.skip("doppelganger / doppelganger test", function () { doppelgangerProtection: true, }); - const {beaconNode: bn2, validators: validators} = await createBNAndVC({ + const {beaconNode: bn2, validators} = await createBNAndVC({ genesisTime: bn.chain.getHeadState().genesisTime, }); @@ -202,7 +201,7 @@ describe.skip("doppelganger / doppelganger test", function () { doppelgangerProtection, }); - const {beaconNode: bn2, validators: validators} = await createBNAndVC({ + const {beaconNode: bn2, validators} = await createBNAndVC({ genesisTime: bn.chain.getHeadState().genesisTime, doppelgangerProtection: false, }); diff --git a/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts b/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts index 17692cfcca3a..837a765d1710 100644 --- a/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts +++ b/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts @@ -68,7 +68,6 @@ describe.skip("eth1 / Eth1Provider", function () { // Resolves when Eth1ForBlockProduction has fetched both blocks and deposits const {eth1Datas, deposits} = await (async function resolveWithEth1DataAndDeposits() { - // eslint-disable-next-line no-constant-condition while (true) { const eth1Datas = await db.eth1Data.entries(); const deposits = await db.depositEvent.values(); diff --git a/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts b/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts index ae3e0c707542..034493482c21 100644 --- a/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts +++ b/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts @@ -10,8 +10,6 @@ import {quantityToBigint} from "../../../src/eth1/provider/utils.js"; import {ZERO_HASH} from "../../../src/constants/index.js"; import {getGoerliRpcUrl} from "../../testParams.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - // This test is constantly failing. We must unblock PR so this issue is a TODO to debug it and re-enable latter. // It's OKAY to disable temporarily since this functionality is tested indirectly by the sim merge tests. // See https://github.com/ChainSafe/lodestar/issues/4197 diff --git a/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts b/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts index 4e290c6d6318..fac0e3810b6d 100644 --- a/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts +++ b/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts @@ -174,7 +174,6 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () { const afterHook = afterHooks.pop(); if (afterHook) await afterHook().catch((e: Error) => { - // eslint-disable-next-line no-console console.error("Error in afterEach hook", e); }); } diff --git a/packages/beacon-node/test/e2e/interop/genesisState.test.ts b/packages/beacon-node/test/e2e/interop/genesisState.test.ts index 2287c6a1deb8..739319a4257c 100644 --- a/packages/beacon-node/test/e2e/interop/genesisState.test.ts +++ b/packages/beacon-node/test/e2e/interop/genesisState.test.ts @@ -9,7 +9,6 @@ describe("interop / initDevState", () => { it("Create interop deposits", () => { const deposits = interopDeposits(config, ssz.phase0.DepositDataRootList.defaultViewDU(), 1); - /* eslint-disable @typescript-eslint/naming-convention */ expect(deposits.map((deposit) => ssz.phase0.Deposit.toJson(deposit))).toEqual([ { proof: [ diff --git a/packages/beacon-node/test/e2e/network/gossipsub.test.ts b/packages/beacon-node/test/e2e/network/gossipsub.test.ts index c19f3c7c4388..3d8b1e07bbd7 100644 --- a/packages/beacon-node/test/e2e/network/gossipsub.test.ts +++ b/packages/beacon-node/test/e2e/network/gossipsub.test.ts @@ -35,7 +35,6 @@ function runTests({useWorker}: {useWorker: boolean}): void { }); // Schedule all forks at ALTAIR_FORK_EPOCH to avoid generating the pubkeys cache - /* eslint-disable @typescript-eslint/naming-convention */ const config = createChainForkConfig({ ...defaultChainConfig, ALTAIR_FORK_EPOCH: 1, @@ -44,7 +43,6 @@ function runTests({useWorker}: {useWorker: boolean}): void { }); const START_SLOT = computeStartSlotAtEpoch(config.ALTAIR_FORK_EPOCH); - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type async function mockModules(gossipHandlersPartial?: Partial) { const [netA, closeA] = await getNetworkForTest(`gossipsub-${useWorker ? "worker" : "main"}-A`, config, { opts: {useWorker}, @@ -65,7 +63,9 @@ function runTests({useWorker}: {useWorker: boolean}): void { it("Publish and receive a voluntaryExit", async function () { let onVoluntaryExit: (ve: Uint8Array) => void; - const onVoluntaryExitPromise = new Promise((resolve) => (onVoluntaryExit = resolve)); + const onVoluntaryExitPromise = new Promise((resolve) => { + onVoluntaryExit = resolve; + }); const {netA, netB} = await mockModules({ [GossipType.voluntary_exit]: async ({gossipData}: GossipHandlerParamGeneric) => { @@ -100,7 +100,9 @@ function runTests({useWorker}: {useWorker: boolean}): void { it("Publish and receive a blsToExecutionChange", async function () { let onBlsToExecutionChange: (blsToExec: Uint8Array) => void; - const onBlsToExecutionChangePromise = new Promise((resolve) => (onBlsToExecutionChange = resolve)); + const onBlsToExecutionChangePromise = new Promise((resolve) => { + onBlsToExecutionChange = resolve; + }); const {netA, netB} = await mockModules({ [GossipType.bls_to_execution_change]: async ({ @@ -136,7 +138,9 @@ function runTests({useWorker}: {useWorker: boolean}): void { it("Publish and receive an attesterSlashing", async function () { let onAttesterSlashingChange: (payload: Uint8Array) => void; - const onAttesterSlashingChangePromise = new Promise((resolve) => (onAttesterSlashingChange = resolve)); + const onAttesterSlashingChangePromise = new Promise((resolve) => { + onAttesterSlashingChange = resolve; + }); const {netA, netB} = await mockModules({ [GossipType.attester_slashing]: async ({gossipData}: GossipHandlerParamGeneric) => { @@ -168,7 +172,9 @@ function runTests({useWorker}: {useWorker: boolean}): void { it("Publish and receive a proposerSlashing", async function () { let onProposerSlashingChange: (payload: Uint8Array) => void; - const onProposerSlashingChangePromise = new Promise((resolve) => (onProposerSlashingChange = resolve)); + const onProposerSlashingChangePromise = new Promise((resolve) => { + onProposerSlashingChange = resolve; + }); const {netA, netB} = await mockModules({ [GossipType.proposer_slashing]: async ({gossipData}: GossipHandlerParamGeneric) => { @@ -200,9 +206,9 @@ function runTests({useWorker}: {useWorker: boolean}): void { it("Publish and receive a LightClientOptimisticUpdate", async function () { let onLightClientOptimisticUpdate: (ou: Uint8Array) => void; - const onLightClientOptimisticUpdatePromise = new Promise( - (resolve) => (onLightClientOptimisticUpdate = resolve) - ); + const onLightClientOptimisticUpdatePromise = new Promise((resolve) => { + onLightClientOptimisticUpdate = resolve; + }); const {netA, netB} = await mockModules({ [GossipType.light_client_optimistic_update]: async ({ @@ -239,9 +245,9 @@ function runTests({useWorker}: {useWorker: boolean}): void { it("Publish and receive a LightClientFinalityUpdate", async function () { let onLightClientFinalityUpdate: (fu: Uint8Array) => void; - const onLightClientFinalityUpdatePromise = new Promise( - (resolve) => (onLightClientFinalityUpdate = resolve) - ); + const onLightClientFinalityUpdatePromise = new Promise((resolve) => { + onLightClientFinalityUpdate = resolve; + }); const {netA, netB} = await mockModules({ [GossipType.light_client_finality_update]: async ({ diff --git a/packages/beacon-node/test/e2e/network/mdns.test.ts b/packages/beacon-node/test/e2e/network/mdns.test.ts index d8e148e191fe..4c49ca319a42 100644 --- a/packages/beacon-node/test/e2e/network/mdns.test.ts +++ b/packages/beacon-node/test/e2e/network/mdns.test.ts @@ -68,7 +68,6 @@ describe.skip("mdns", function () { return {block, state, config: beaconConfig}; }); - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type async function createTestNode(nodeName: string) { const {config} = getStaticData(); const chain = getMockedBeaconChain(); @@ -111,7 +110,6 @@ describe.skip("mdns", function () { return {network, chain}; } - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type async function createTestNodesAB() { return Promise.all([createTestNode("mdns-A"), createTestNode("mdns-B")]); } diff --git a/packages/beacon-node/test/e2e/network/network.test.ts b/packages/beacon-node/test/e2e/network/network.test.ts index 094a75280e8b..a1c1546ef4fc 100644 --- a/packages/beacon-node/test/e2e/network/network.test.ts +++ b/packages/beacon-node/test/e2e/network/network.test.ts @@ -38,7 +38,6 @@ function runTests({useWorker}: {useWorker: boolean}): void { }); afterEach(() => controller.abort()); - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type async function createTestNode(nodeName: string) { const [network, closeAll] = await getNetworkForTest(nodeName, config, {opts: {useWorker}}); diff --git a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts index 795a4bf67ecc..b690b9ab4988 100644 --- a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts +++ b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts @@ -33,7 +33,6 @@ describe("network / peers / PeerManager", function () { } }); - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type async function mockModules() { // Setup fake chain const block = ssz.phase0.SignedBeaconBlock.defaultValue(); diff --git a/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts b/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts index d96f405eae7c..d8d02c203dd9 100644 --- a/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts +++ b/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts @@ -35,7 +35,6 @@ describe("reqresp encoder", () => { } }); - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type async function getLibp2p() { const listen = `/ip4/127.0.0.1/tcp/${port++}`; const libp2p = await createLibp2p({ @@ -50,7 +49,6 @@ describe("reqresp encoder", () => { return {libp2p, multiaddr: multiaddr(`${listen}/p2p/${libp2p.peerId.toString()}`)}; } - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type async function getReqResp(getHandler?: GetReqRespHandlerFn) { const {libp2p, multiaddr} = await getLibp2p(); @@ -76,7 +74,6 @@ describe("reqresp encoder", () => { return {libp2p, multiaddr, reqresp: new ReqRespBeaconNode(modules)}; } - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type async function dialProtocol({ dialer, toMultiaddr, diff --git a/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts b/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts index 01293285d756..ed19617f0822 100644 --- a/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts +++ b/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts @@ -20,7 +20,6 @@ describe("sync / finalized sync", function () { const validatorCount = 8; const testParams: Pick = { - // eslint-disable-next-line @typescript-eslint/naming-convention SECONDS_PER_SLOT: 2, }; @@ -114,7 +113,7 @@ describe("sync / finalized sync", function () { try { await waitForSynced; loggerNodeB.info("Node B synced to Node A, received head block", {slot: head.message.slot}); - } catch (e) { + } catch (_e) { assert.fail("Failed to sync to other node in time"); } }); diff --git a/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts b/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts index 31f640269db7..7d31d25a07d3 100644 --- a/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts +++ b/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts @@ -22,7 +22,6 @@ describe("sync / unknown block sync", function () { const validatorCount = 8; const testParams: Pick = { - // eslint-disable-next-line @typescript-eslint/naming-convention SECONDS_PER_SLOT: 2, }; diff --git a/packages/beacon-node/test/globalSetup.ts b/packages/beacon-node/test/globalSetup.ts index 8194c76662df..f41a7f249b9b 100644 --- a/packages/beacon-node/test/globalSetup.ts +++ b/packages/beacon-node/test/globalSetup.ts @@ -11,7 +11,6 @@ export async function setup(): Promise { // Override FIELD_ELEMENTS_PER_BLOB if its a dev run, mostly to distinguish from // spec runs if (process.env.LODESTAR_PRESET === "minimal" && process.env.DEV_RUN) { - // eslint-disable-next-line @typescript-eslint/naming-convention setActivePreset(PresetName.minimal, {FIELD_ELEMENTS_PER_BLOB: 4096}); } } diff --git a/packages/beacon-node/test/memory/bytesHex.ts b/packages/beacon-node/test/memory/bytesHex.ts index 44115d345b2c..c7429869dac7 100644 --- a/packages/beacon-node/test/memory/bytesHex.ts +++ b/packages/beacon-node/test/memory/bytesHex.ts @@ -45,7 +45,6 @@ function testRunnerMemoryBpi(testCases: {getInstance: (bytes: number) => unknown convergeFactor: 0.2 / 100, }); - // eslint-disable-next-line no-console console.log(`${id.padEnd(longestId)} - ${bpi.toFixed(1)} bytes / instance`); } } diff --git a/packages/beacon-node/test/memory/pubkeysToIndex.ts b/packages/beacon-node/test/memory/pubkeysToIndex.ts index b647d153dba2..32cdf6e82296 100644 --- a/packages/beacon-node/test/memory/pubkeysToIndex.ts +++ b/packages/beacon-node/test/memory/pubkeysToIndex.ts @@ -52,7 +52,6 @@ function testRunnerMemoryBpi(testCases: {getInstance: (bytes: number) => unknown sampleEvery: 5, }); - // eslint-disable-next-line no-console console.log(`${id.padEnd(longestId)} - ${bpi.toFixed(1)} bytes / instance`); } } diff --git a/packages/beacon-node/test/memory/seenAttestationData.ts b/packages/beacon-node/test/memory/seenAttestationData.ts index c6735bd861e9..44a82dcd5841 100644 --- a/packages/beacon-node/test/memory/seenAttestationData.ts +++ b/packages/beacon-node/test/memory/seenAttestationData.ts @@ -53,7 +53,6 @@ function testRunnerMemoryBpi(testCases: {getInstance: (bytes: number) => unknown sampleEvery: 5, }); - // eslint-disable-next-line no-console console.log(`${id.padEnd(longestId)} - ${bpi.toFixed(1)} bytes / instance`); } } diff --git a/packages/beacon-node/test/memory/testRunnerMemory.ts b/packages/beacon-node/test/memory/testRunnerMemory.ts index a5c4df9e5794..05e7c8afab01 100644 --- a/packages/beacon-node/test/memory/testRunnerMemory.ts +++ b/packages/beacon-node/test/memory/testRunnerMemory.ts @@ -57,7 +57,6 @@ export async function testRunnerMemoryGc(opts: TestRunnerMemoryOpts): Prom usedMemoryArr.push(totalUsedMemoryDiff); const usedMemoryReg = linearRegression(xs, usedMemoryArr); - // eslint-disable-next-line no-console console.log("totalUsedMemoryDiff", totalUsedMemoryDiff, usedMemoryReg); } } @@ -137,7 +136,6 @@ export function testRunnerMemory(opts: TestRunnerMemoryOpts): number { } if (logEachSample) { - // eslint-disable-next-line no-console console.log(i, memoryUsage.rss / maxRssBytes, {m}); } diff --git a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts index b37967d16ca4..247f8a4ea95a 100644 --- a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts +++ b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts @@ -48,7 +48,6 @@ function testRunnerMemoryBpi(testCases: {getInstance: (bytes: number) => unknown sampleEvery: 5, }); - // eslint-disable-next-line no-console console.log(`${id.padEnd(longestId)} - ${bpi.toFixed(1)} bytes / instance`); } } diff --git a/packages/beacon-node/test/mocks/beaconSyncMock.ts b/packages/beacon-node/test/mocks/beaconSyncMock.ts index 00ef193fdf6e..4d9f11ba90fd 100644 --- a/packages/beacon-node/test/mocks/beaconSyncMock.ts +++ b/packages/beacon-node/test/mocks/beaconSyncMock.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {Mocked, vi} from "vitest"; import {BeaconSync} from "../../src/sync/index.js"; diff --git a/packages/beacon-node/test/mocks/mockedBeaconChain.ts b/packages/beacon-node/test/mocks/mockedBeaconChain.ts index addeacf26a89..1d597bf4424d 100644 --- a/packages/beacon-node/test/mocks/mockedBeaconChain.ts +++ b/packages/beacon-node/test/mocks/mockedBeaconChain.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {vi, Mocked, Mock} from "vitest"; import {config as defaultConfig} from "@lodestar/config/default"; import {ChainForkConfig} from "@lodestar/config"; @@ -120,12 +119,10 @@ vi.mock("../../src/chain/chain.js", async (importActual) => { getClientVersion: vi.fn(), }, executionBuilder: {}, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error eth1: new Eth1ForBlockProduction(), opPool: new OpPool(), aggregatedAttestationPool: new AggregatedAttestationPool(config), - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error beaconProposerCache: new BeaconProposerCache(), shufflingCache: new ShufflingCache(), @@ -169,7 +166,6 @@ export type MockedBeaconChainOptions = { export function getMockedBeaconChain(opts?: Partial): MockedBeaconChain { const {clock, genesisTime, config} = opts ?? {}; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error return new BeaconChain({ clock: clock ?? "fake", diff --git a/packages/beacon-node/test/mocks/mockedBeaconDb.ts b/packages/beacon-node/test/mocks/mockedBeaconDb.ts index 8b99c85d2345..eb209c9b44fb 100644 --- a/packages/beacon-node/test/mocks/mockedBeaconDb.ts +++ b/packages/beacon-node/test/mocks/mockedBeaconDb.ts @@ -62,7 +62,6 @@ vi.mock("../../src/db/index.js", async (importActual) => { return { ...mod, - // eslint-disable-next-line @typescript-eslint/naming-convention BeaconDb: mockedBeaconDb, }; }); diff --git a/packages/beacon-node/test/mocks/mockedNetwork.ts b/packages/beacon-node/test/mocks/mockedNetwork.ts index ddf70aa1b5aa..9258acc9bc1b 100644 --- a/packages/beacon-node/test/mocks/mockedNetwork.ts +++ b/packages/beacon-node/test/mocks/mockedNetwork.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {vi, Mocked} from "vitest"; import {Network, INetwork} from "../../src/network/index.js"; diff --git a/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts b/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts index 803d6c84c408..807e29c55b52 100644 --- a/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts +++ b/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts @@ -1,5 +1,4 @@ import {itBench} from "@dapplion/benchmark"; -// eslint-disable-next-line import/no-relative-packages import {generatePerfTestCachedStatePhase0, numValidators} from "../../../../../../state-transition/test/perf/util.js"; import {getPubkeysForIndices} from "../../../../../src/api/impl/validator/utils.js"; import {linspace} from "../../../../../src/util/numpy.js"; diff --git a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts index 45fc07281c3b..89bd76f34eb3 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -13,7 +13,6 @@ import {ExecutionStatus, ForkChoice, IForkChoiceStore, ProtoArray, DataAvailabil import {ssz} from "@lodestar/types"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -// eslint-disable-next-line import/no-relative-packages import {generatePerfTestCachedStateAltair} from "../../../../../state-transition/test/perf/util.js"; import {AggregatedAttestationPool} from "../../../../src/chain/opPools/aggregatedAttestationPool.js"; diff --git a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts index 6e420f0e1011..9d518c03eec9 100644 --- a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts @@ -7,7 +7,6 @@ import { } from "@lodestar/params"; import {CachedBeaconStateAltair} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; -// eslint-disable-next-line import/no-relative-packages import {generatePerfTestCachedStateAltair} from "../../../../../state-transition/test/perf/util.js"; import {OpPool} from "../../../../src/chain/opPools/opPool.js"; import {generateBlsToExecutionChanges} from "../../../fixtures/capella.js"; diff --git a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts index 7bf8c2f7252f..fdd6f60f5a47 100644 --- a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts +++ b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts @@ -5,7 +5,6 @@ import {LevelDbController} from "@lodestar/db"; import {SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY} from "@lodestar/params"; import {defaultOptions as defaultValidatorOptions} from "@lodestar/validator"; import {CachedBeaconStateAltair} from "@lodestar/state-transition"; -// eslint-disable-next-line import/no-relative-packages import {generatePerfTestCachedStateAltair} from "../../../../../state-transition/test/perf/util.js"; import {BeaconChain} from "../../../../src/chain/index.js"; import {BlockType, produceBlockBody} from "../../../../src/chain/produceBlock/produceBlockBody.js"; diff --git a/packages/beacon-node/test/perf/chain/validation/aggregateAndProof.test.ts b/packages/beacon-node/test/perf/chain/validation/aggregateAndProof.test.ts index 3fc7efe9d675..5e28a7c3b898 100644 --- a/packages/beacon-node/test/perf/chain/validation/aggregateAndProof.test.ts +++ b/packages/beacon-node/test/perf/chain/validation/aggregateAndProof.test.ts @@ -1,6 +1,5 @@ import {itBench} from "@dapplion/benchmark"; import {ssz} from "@lodestar/types"; -// eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../state-transition/test/perf/util.js"; import {validateApiAggregateAndProof, validateGossipAggregateAndProof} from "../../../../src/chain/validation/index.js"; import {getAggregateAndProofValidData} from "../../../utils/validationData/aggregateAndProof.js"; diff --git a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts index e942e1ea17d0..696b6bdb1871 100644 --- a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts +++ b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts @@ -1,7 +1,6 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {expect} from "chai"; import {ssz} from "@lodestar/types"; -// eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../state-transition/test/perf/util.js"; import {validateGossipAttestationsSameAttData} from "../../../../src/chain/validation/index.js"; import {getAttestationValidData} from "../../../utils/validationData/attestation.js"; diff --git a/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts b/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts index a21c28adaec0..6ae7112f5e3d 100644 --- a/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts +++ b/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts @@ -4,17 +4,9 @@ import {SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY, SLOTS_PER_EPOCH} from "@lodestar/pa import {LevelDbController} from "@lodestar/db"; import {sleep} from "@lodestar/utils"; import {defaultOptions as defaultValidatorOptions} from "@lodestar/validator"; -// eslint-disable-next-line import/no-relative-packages import {rangeSyncTest} from "../../../../state-transition/test/perf/params.js"; -import { - getNetworkCachedState, - getNetworkCachedBlock, - // eslint-disable-next-line import/no-relative-packages -} from "../../../../state-transition/test/utils/testFileCache.js"; -import { - beforeValue, - // eslint-disable-next-line import/no-relative-packages -} from "../../../../state-transition/test/utils/beforeValueMocha.js"; +import {getNetworkCachedState, getNetworkCachedBlock} from "../../../../state-transition/test/utils/testFileCache.js"; +import {beforeValue} from "../../../../state-transition/test/utils/beforeValueMocha.js"; import {BeaconChain} from "../../../src/chain/index.js"; import {ExecutionEngineDisabled} from "../../../src/execution/engine/index.js"; import {Eth1ForBlockProductionDisabled} from "../../../src/eth1/index.js"; diff --git a/packages/beacon-node/test/scripts/blsPubkeyBytesFrequency.ts b/packages/beacon-node/test/scripts/blsPubkeyBytesFrequency.ts index 1889cacf1496..aaf882a86bff 100644 --- a/packages/beacon-node/test/scripts/blsPubkeyBytesFrequency.ts +++ b/packages/beacon-node/test/scripts/blsPubkeyBytesFrequency.ts @@ -58,7 +58,6 @@ function analyzeBytesFrequencies(pubkeys: string[]): void { byte0Freq[byte0] = 1 + (byte0Freq[byte0] ?? 0); } - // eslint-disable-next-line no-console console.log( `Byte[${i}] frequency distribution`, JSON.stringify( @@ -95,7 +94,6 @@ function analyzeBytesCollisions(pubkeys: string[]): void { } } - // eslint-disable-next-line no-console console.log(`bytes ${i}, collision rate ${collisions.size / 256 ** i}`); } } @@ -120,7 +118,6 @@ async function writePubkeys(): Promise { } run().catch((e) => { - // eslint-disable-next-line no-console console.error(e); process.exit(1); }); diff --git a/packages/beacon-node/test/setupPreset.ts b/packages/beacon-node/test/setupPreset.ts index b25c1d87835e..968c6e12c668 100644 --- a/packages/beacon-node/test/setupPreset.ts +++ b/packages/beacon-node/test/setupPreset.ts @@ -7,6 +7,5 @@ if (process.env.LODESTAR_PRESET === undefined) { // Override FIELD_ELEMENTS_PER_BLOB if its a dev run, mostly to distinguish from // spec runs if (process.env.LODESTAR_PRESET === "minimal" && process.env.DEV_RUN) { - // eslint-disable-next-line @typescript-eslint/naming-convention setActivePreset(PresetName.minimal, {FIELD_ELEMENTS_PER_BLOB: 4096}); } diff --git a/packages/beacon-node/test/spec/bls/bls.ts b/packages/beacon-node/test/spec/bls/bls.ts index 5af15bcb8eb2..76c511215b61 100644 --- a/packages/beacon-node/test/spec/bls/bls.ts +++ b/packages/beacon-node/test/spec/bls/bls.ts @@ -10,8 +10,6 @@ import { } from "@chainsafe/blst"; import {fromHexString} from "@chainsafe/ssz"; -/* eslint-disable @typescript-eslint/naming-convention */ - export const testFnByType: Record any)> = { aggregate_verify, aggregate, @@ -44,7 +42,7 @@ function aggregate_verify(input: {pubkeys: string[]; messages: string[]; signatu pubkeys.map((pk) => PublicKey.fromHex(pk)), Signature.fromHex(signature) ); - } catch (e) { + } catch (_e) { return false; } } @@ -78,7 +76,7 @@ function fast_aggregate_verify(input: {pubkeys: string[]; message: string; signa pubkeys.map((hex) => PublicKey.fromHex(hex, true)), Signature.fromHex(signature, true) ); - } catch (e) { + } catch (_e) { return false; } } @@ -103,7 +101,7 @@ function batch_verify(input: {pubkeys: string[]; messages: string[]; signatures: sig: Signature.fromHex(signatures[i], true), })) ); - } catch (e) { + } catch (_e) { return false; } } @@ -137,7 +135,7 @@ function verify(input: {pubkey: string; message: string; signature: string}): bo const {pubkey, message, signature} = input; try { return _verify(fromHexString(message), PublicKey.fromHex(pubkey), Signature.fromHex(signature)); - } catch (e) { + } catch (_e) { return false; } } @@ -153,7 +151,7 @@ function deserialization_G1(input: {pubkey: string}): boolean { try { PublicKey.fromHex(input.pubkey, true); return true; - } catch (e) { + } catch (_e) { return false; } } @@ -169,7 +167,7 @@ function deserialization_G2(input: {signature: string}): boolean { try { Signature.fromHex(input.signature, true); return true; - } catch (e) { + } catch (_e) { return false; } } diff --git a/packages/beacon-node/test/spec/general/bls.ts b/packages/beacon-node/test/spec/general/bls.ts index 010a5b9be53d..fca8529e4e3b 100644 --- a/packages/beacon-node/test/spec/general/bls.ts +++ b/packages/beacon-node/test/spec/general/bls.ts @@ -12,8 +12,6 @@ import { import {InputType} from "@lodestar/spec-test-util"; import {TestRunnerFn} from "../utils/types.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - const testFnByType: Record any> = { aggregate, aggregate_verify, @@ -29,7 +27,7 @@ const G2_POINT_AT_INFINITY = const G1_POINT_AT_INFINITY = "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; -export const blsTestRunner: TestRunnerFn = (fork, testName) => { +export const blsTestRunner: TestRunnerFn = (_fork, testName) => { return { testFunction: ({data}) => { const testFn = testFnByType[testName]; @@ -75,7 +73,7 @@ function aggregate(input: string[]): string | null { const pks = input.map((pkHex) => Signature.fromHex(pkHex)); const agg = aggregateSignatures(pks); return agg.toHex(); - } catch (e) { + } catch (_e) { return null; } } @@ -97,7 +95,7 @@ function aggregate_verify(input: {pubkeys: string[]; messages: string[]; signatu pubkeys.map((pk) => PublicKey.fromHex(pk)), Signature.fromHex(signature) ); - } catch (e) { + } catch (_e) { return false; } } @@ -116,7 +114,7 @@ function eth_aggregate_pubkeys(input: string[]): string | null { try { return aggregateSerializedPublicKeys(input.map((hex) => fromHexString(hex))).toHex(); - } catch (e) { + } catch (_e) { return null; } } @@ -148,7 +146,7 @@ function eth_fast_aggregate_verify(input: {pubkeys: string[]; message: string; s pubkeys.map((hex) => PublicKey.fromHex(hex)), Signature.fromHex(signature) ); - } catch (e) { + } catch (_e) { return false; } } @@ -170,7 +168,7 @@ function fast_aggregate_verify(input: {pubkeys: string[]; message: string; signa pubkeys.map((hex) => PublicKey.fromHex(hex, true)), Signature.fromHex(signature, true) ); - } catch (e) { + } catch (_e) { return false; } } @@ -185,7 +183,7 @@ function sign(input: {privkey: string; message: string}): string | null { const {privkey, message} = input; try { return SecretKey.fromHex(privkey).sign(fromHexString(message)).toHex(); - } catch (e) { + } catch (_e) { return null; } } @@ -201,7 +199,7 @@ function verify(input: {pubkey: string; message: string; signature: string}): bo const {pubkey, message, signature} = input; try { return _verify(fromHexString(message), PublicKey.fromHex(pubkey), Signature.fromHex(signature)); - } catch (e) { + } catch (_e) { return false; } } diff --git a/packages/beacon-node/test/spec/general/index.test.ts b/packages/beacon-node/test/spec/general/index.test.ts index f6bfb0b7b2a1..063f128c3142 100644 --- a/packages/beacon-node/test/spec/general/index.test.ts +++ b/packages/beacon-node/test/spec/general/index.test.ts @@ -5,8 +5,6 @@ import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {blsTestRunner} from "./bls.js"; import {sszGeneric} from "./ssz_generic.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - // NOTE: You MUST always provide a detailed reason of why a spec test is skipped plus link // to an issue marking it as pending to re-enable and an aproximate timeline of when it will // be fixed. diff --git a/packages/beacon-node/test/spec/general/ssz_generic.ts b/packages/beacon-node/test/spec/general/ssz_generic.ts index e791ca62eefe..64e6b4455941 100644 --- a/packages/beacon-node/test/spec/general/ssz_generic.ts +++ b/packages/beacon-node/test/spec/general/ssz_generic.ts @@ -15,7 +15,7 @@ import {getTestType} from "./ssz_generic_types.js"; export const sszGeneric = (skippedTypes: string[]): TestRunnerCustom => - (fork, typeName, testSuite, testSuiteDirpath) => { + (_fork, typeName, testSuite, testSuiteDirpath) => { if (testSuite === "invalid") { for (const testCase of fs.readdirSync(testSuiteDirpath)) { it(testCase, () => { diff --git a/packages/beacon-node/test/spec/general/ssz_generic_types.ts b/packages/beacon-node/test/spec/general/ssz_generic_types.ts index cd95a5dec79e..aa231c962ae3 100644 --- a/packages/beacon-node/test/spec/general/ssz_generic_types.ts +++ b/packages/beacon-node/test/spec/general/ssz_generic_types.ts @@ -20,8 +20,6 @@ const uint64 = new UintBigintType(8); const uint128 = new UintBigintType(16); const uint256 = new UintBigintType(32); -/* eslint-disable @typescript-eslint/naming-convention */ - // class SingleFieldTestStruct(Container): // A: byte const SingleFieldTestStruct = new ContainerType({ diff --git a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts index 604243400aa0..17347269c6f6 100644 --- a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts +++ b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts @@ -20,8 +20,6 @@ import {specTestIterator} from "../utils/specTestIterator.js"; export type EpochTransitionFn = (state: CachedBeaconStateAllForks, epochTransitionCache: EpochTransitionCache) => void; -/* eslint-disable @typescript-eslint/naming-convention */ - const epochTransitionFns: Record = { effective_balance_updates: (state, epochTransitionCache) => { const fork = state.config.getForkSeq(state.slot); @@ -99,7 +97,7 @@ const epochProcessing = post: ssz[fork].BeaconState, }, getExpected: (testCase) => testCase.post, - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expectEqualBeaconState(fork, expected, actual); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts diff --git a/packages/beacon-node/test/spec/presets/finality.test.ts b/packages/beacon-node/test/spec/presets/finality.test.ts index 0ec4017064f4..1dce91e360e5 100644 --- a/packages/beacon-node/test/spec/presets/finality.test.ts +++ b/packages/beacon-node/test/spec/presets/finality.test.ts @@ -15,8 +15,6 @@ import {assertCorrectProgressiveBalances} from "../config.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - const finality: TestRunnerFn = (fork) => { return { testFunction: (testcase) => { @@ -49,7 +47,7 @@ const finality: TestRunnerFn = (fork) => shouldError: (testCase) => !testCase.post, timeout: 10000, getExpected: (testCase) => testCase.post, - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expectEqualBeaconState(fork, expected, actual); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts diff --git a/packages/beacon-node/test/spec/presets/fork.test.ts b/packages/beacon-node/test/spec/presets/fork.test.ts index c121e651fcea..626d6477bcb1 100644 --- a/packages/beacon-node/test/spec/presets/fork.test.ts +++ b/packages/beacon-node/test/spec/presets/fork.test.ts @@ -50,7 +50,7 @@ const fork: TestRunnerFn = (forkNext) => { timeout: 10000, shouldError: (testCase) => testCase.post === undefined, getExpected: (testCase) => testCase.post, - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expectEqualBeaconState(forkNext, expected, actual); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts 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 7cb6e3c3d692..72515e703582 100644 --- a/packages/beacon-node/test/spec/presets/fork_choice.test.ts +++ b/packages/beacon-node/test/spec/presets/fork_choice.test.ts @@ -46,8 +46,6 @@ import {initCKZG, loadEthereumTrustedSetup} from "../../../src/util/kzg.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - const ANCHOR_STATE_FILE_NAME = "anchor_state"; const ANCHOR_BLOCK_FILE_NAME = "anchor_block"; const BLOCK_FILE_NAME = "^(block)_([0-9a-zA-Z]+)$"; diff --git a/packages/beacon-node/test/spec/presets/genesis.test.ts b/packages/beacon-node/test/spec/presets/genesis.test.ts index 773debe3bb19..140fa3686e67 100644 --- a/packages/beacon-node/test/spec/presets/genesis.test.ts +++ b/packages/beacon-node/test/spec/presets/genesis.test.ts @@ -22,8 +22,6 @@ import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; // The aim of the genesis tests is to provide a baseline to test genesis-state initialization and test if the // proposed genesis-validity conditions are working. -/* eslint-disable @typescript-eslint/naming-convention */ - const genesis: TestRunnerFn = (fork, testName, testSuite) => { const testFn = genesisTestFns[testName]; if (testFn === undefined) { @@ -86,7 +84,7 @@ const genesisInitialization: TestRunnerFn testCase.state, - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expectEqualBeaconState(fork, expected, actual); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts @@ -108,7 +106,7 @@ const genesisValidity: TestRunnerFn = (fork) = genesis: ssz[fork].BeaconState, }, getExpected: (testCase) => testCase.is_valid, - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expect(actual).toEqualWithMessage(expected, "isValidGenesisState is not" + expected); }, }, diff --git a/packages/beacon-node/test/spec/presets/light_client/index.test.ts b/packages/beacon-node/test/spec/presets/light_client/index.test.ts index 0a44772cab4b..a8cc12238675 100644 --- a/packages/beacon-node/test/spec/presets/light_client/index.test.ts +++ b/packages/beacon-node/test/spec/presets/light_client/index.test.ts @@ -7,8 +7,6 @@ import {singleMerkleProof} from "./single_merkle_proof.js"; import {sync} from "./sync.js"; import {updateRanking} from "./update_ranking.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - const lightClient: TestRunnerFn = (fork, testName, testSuite) => { const testFn = lightclientTestFns[testName]; if (testFn === undefined) { diff --git a/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts b/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts index d230bc926b0d..08dcd0ab8acf 100644 --- a/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts +++ b/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts @@ -7,8 +7,6 @@ import {ForkName} from "@lodestar/params"; import {toHex} from "@lodestar/utils"; import {TestRunnerFn} from "../../utils/types.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - // https://github.com/ethereum/consensus-specs/blob/da3f5af919be4abb5a6db5a80b235deb8b4b5cba/tests/formats/light_client/single_merkle_proof.md type SingleMerkleProofTestCase = { meta?: any; @@ -23,7 +21,11 @@ type SingleMerkleProofTestCase = { }; }; -export const singleMerkleProof: TestRunnerFn = (fork, testHandler, testSuite) => { +export const singleMerkleProof: TestRunnerFn = ( + fork, + _testHandler, + testSuite +) => { return { testFunction: (testcase) => { // Assert correct proof generation @@ -39,7 +41,7 @@ export const singleMerkleProof: TestRunnerFn testCase.proof.branch, - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expect(actual).deep.equals(expected); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts diff --git a/packages/beacon-node/test/spec/presets/light_client/sync.ts b/packages/beacon-node/test/spec/presets/light_client/sync.ts index bfd3d0d0bb3d..d931a5f310a8 100644 --- a/packages/beacon-node/test/spec/presets/light_client/sync.ts +++ b/packages/beacon-node/test/spec/presets/light_client/sync.ts @@ -9,8 +9,6 @@ import {computeSyncPeriodAtSlot} from "@lodestar/state-transition"; import {TestRunnerFn} from "../../utils/types.js"; import {testLogger} from "../../../utils/logger.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - // https://github.com/ethereum/consensus-specs/blob/da3f5af919be4abb5a6db5a80b235deb8b4b5cba/tests/formats/light_client/single_merkle_proof.md type SyncTestCase = { meta: { diff --git a/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts b/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts index a2e60c1cc84a..b51219dd4e54 100644 --- a/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts +++ b/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts @@ -5,8 +5,6 @@ import {InputType} from "@lodestar/spec-test-util"; import {isBetterUpdate, LightClientUpdateSummary, toLightClientUpdateSummary} from "@lodestar/light-client/spec"; import {TestRunnerFn} from "../../utils/types.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - // https://github.com/ethereum/consensus-specs/blob/da3f5af919be4abb5a6db5a80b235deb8b4b5cba/tests/formats/light_client/update_ranking.md type UpdateRankingTestCase = { meta: { diff --git a/packages/beacon-node/test/spec/presets/merkle.test.ts b/packages/beacon-node/test/spec/presets/merkle.test.ts index d3f6890527e9..71cebdbd0b5b 100644 --- a/packages/beacon-node/test/spec/presets/merkle.test.ts +++ b/packages/beacon-node/test/spec/presets/merkle.test.ts @@ -11,8 +11,6 @@ import {RunnerType, TestRunnerFn} from "../utils/types.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - const merkle: TestRunnerFn = (fork) => { return { testFunction: (testcase) => { @@ -47,7 +45,7 @@ const merkle: TestRunnerFn = (fork) => { }), timeout: 10000, getExpected: (testCase) => testCase.proof, - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expect(actual).toEqualWithMessage(expected, "incorrect proof"); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index 7e2e9c1e9c5d..1ab8c19da5ef 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -20,8 +20,6 @@ import {BaseSpecTest, RunnerType, shouldVerify, TestRunnerFn} from "../utils/typ import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - // Define above to re-use in sync_aggregate and sync_aggregate_random const sync_aggregate: BlockProcessFn = ( state, @@ -156,7 +154,7 @@ const operations: TestRunnerFn = (fork, }, shouldError: (testCase) => testCase.post === undefined, getExpected: (testCase) => testCase.post, - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expectEqualBeaconState(fork, expected, actual); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts diff --git a/packages/beacon-node/test/spec/presets/rewards.test.ts b/packages/beacon-node/test/spec/presets/rewards.test.ts index 426245242d84..df43c8ca612e 100644 --- a/packages/beacon-node/test/spec/presets/rewards.test.ts +++ b/packages/beacon-node/test/spec/presets/rewards.test.ts @@ -13,8 +13,6 @@ import {assertCorrectProgressiveBalances} from "../config.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - const deltasType = new VectorCompositeType(ssz.phase0.Balances, 2); const rewards: TestRunnerFn = (fork) => { @@ -57,7 +55,7 @@ const rewards: TestRunnerFn = (fork) => { ...(testCase.inclusion_delay_deltas ? [testCase.inclusion_delay_deltas] : []), testCase.inactivity_penalty_deltas, ]), - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expect(actual).toEqual(expected); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts diff --git a/packages/beacon-node/test/spec/presets/sanity.test.ts b/packages/beacon-node/test/spec/presets/sanity.test.ts index 3ec1efb84fde..cd266483c7f8 100644 --- a/packages/beacon-node/test/spec/presets/sanity.test.ts +++ b/packages/beacon-node/test/spec/presets/sanity.test.ts @@ -18,8 +18,6 @@ import {assertCorrectProgressiveBalances} from "../config.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - const sanity: TestRunnerFn = (fork, testName, testSuite) => { switch (testName) { case "slots": @@ -50,7 +48,7 @@ const sanitySlots: TestRunnerFn = (for shouldError: (testCase) => !testCase.post, timeout: 10000, getExpected: (testCase) => testCase.post, - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expectEqualBeaconState(fork, expected, actual); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts @@ -88,7 +86,7 @@ const sanityBlocks: TestRunnerFn = (f shouldError: (testCase) => testCase.post === undefined, timeout: 10000, getExpected: (testCase) => testCase.post, - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expectEqualBeaconState(fork, expected, actual); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index 6e43d851ef66..06c7aa1fd98d 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -32,7 +32,7 @@ type Types = Record>; const sszStatic = (skippedFork: string, skippedTypes?: string[]) => - (fork: ForkName, typeName: string, testSuite: string, testSuiteDirpath: string): void => { + (fork: ForkName, typeName: string, _testSuite: string, testSuiteDirpath: string): void => { if (fork === skippedFork) { return; } @@ -78,7 +78,6 @@ const sszStatic = }; specTestIterator(path.join(ethereumConsensusSpecsTests.outputDir, "tests", ACTIVE_PRESET), { - // eslint-disable-next-line @typescript-eslint/naming-convention ssz_static: { type: RunnerType.custom, // starting from v1.4.0-beta.6, there is "whisk" fork in ssz_static tests but we ignore them diff --git a/packages/beacon-node/test/spec/presets/transition.test.ts b/packages/beacon-node/test/spec/presets/transition.test.ts index cae7c667b590..df818f701c5d 100644 --- a/packages/beacon-node/test/spec/presets/transition.test.ts +++ b/packages/beacon-node/test/spec/presets/transition.test.ts @@ -78,7 +78,7 @@ const transition = shouldError: (testCase) => testCase.post === undefined, timeout: 10000, getExpected: (testCase) => testCase.post, - expectFunc: (testCase, expected, actual) => { + expectFunc: (_testCase, expected, actual) => { expectEqualBeaconState(forkNext, expected, actual); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts @@ -88,8 +88,6 @@ const transition = }; }; -/* eslint-disable @typescript-eslint/naming-convention */ - function getTransitionConfig(fork: ForkName, forkEpoch: number): Partial { switch (fork) { case ForkName.phase0: diff --git a/packages/beacon-node/test/spec/specTestVersioning.ts b/packages/beacon-node/test/spec/specTestVersioning.ts index d4bc192f6cad..5e15b696e4a1 100644 --- a/packages/beacon-node/test/spec/specTestVersioning.ts +++ b/packages/beacon-node/test/spec/specTestVersioning.ts @@ -11,7 +11,6 @@ import {DownloadTestsOptions} from "@lodestar/spec-test-util/downloadTests"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const ethereumConsensusSpecsTests: DownloadTestsOptions = { diff --git a/packages/beacon-node/test/spec/utils/runValidSszTest.ts b/packages/beacon-node/test/spec/utils/runValidSszTest.ts index e5f249ab5257..7ca02cec2d1e 100644 --- a/packages/beacon-node/test/spec/utils/runValidSszTest.ts +++ b/packages/beacon-node/test/spec/utils/runValidSszTest.ts @@ -21,7 +21,7 @@ export function runValidSszTest(type: Type, testData: ValidTestCaseData console.log( JSON.stringify( testData.jsonValue, - (key, value: unknown) => (typeof value === "bigint" ? value.toString() : value), + (_key, value: unknown) => (typeof value === "bigint" ? value.toString() : value), 2 ) ); diff --git a/packages/beacon-node/test/spec/utils/types.ts b/packages/beacon-node/test/spec/utils/types.ts index 94ad7b73de3f..00bebffd7d7e 100644 --- a/packages/beacon-node/test/spec/utils/types.ts +++ b/packages/beacon-node/test/spec/utils/types.ts @@ -26,8 +26,6 @@ export type TestRunner = | {type: RunnerType.default; fn: TestRunnerFn} | {type: RunnerType.custom; fn: TestRunnerCustom}; -/* eslint-disable @typescript-eslint/naming-convention */ - export type BaseSpecTest = { meta?: { bls_setting?: bigint; diff --git a/packages/beacon-node/test/tsconfig.json b/packages/beacon-node/test/tsconfig.json index 7e6bad81b22f..f4241fc1fbcd 100644 --- a/packages/beacon-node/test/tsconfig.json +++ b/packages/beacon-node/test/tsconfig.json @@ -3,4 +3,4 @@ "compilerOptions": { "noEmit": false } -} \ No newline at end of file +} diff --git a/packages/beacon-node/test/unit/api/impl/events/events.test.ts b/packages/beacon-node/test/unit/api/impl/events/events.test.ts index e031c3ac9958..a5dd21d14fd3 100644 --- a/packages/beacon-node/test/unit/api/impl/events/events.test.ts +++ b/packages/beacon-node/test/unit/api/impl/events/events.test.ts @@ -11,7 +11,6 @@ vi.mock("../../../../../src/chain/index.js", async (importActual) => { return { ...mod, - // eslint-disable-next-line @typescript-eslint/naming-convention BeaconChain: vi.spyOn(mod, "BeaconChain").mockImplementation(() => { return { emitter: new ChainEventEmitter(), diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts index a7299aa3b956..d8f1b9a317b9 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts @@ -12,7 +12,6 @@ import {CommonBlockBody} from "../../../../../src/chain/interface.js"; import {zeroProtoBlock} from "../../../../utils/state.js"; import {defaultApiOptions} from "../../../../../src/api/options.js"; -/* eslint-disable @typescript-eslint/naming-convention */ describe("api/validator - produceBlockV3", function () { let modules: ApiTestModules; let api: ReturnType; @@ -143,7 +142,7 @@ describe("api/validator - produceBlockV3", function () { }); const expectedBlock = finalSelection === "builder" ? blindedBlock : fullBlock; - const expectedExecution = finalSelection === "builder" ? true : false; + const expectedExecution = finalSelection === "builder"; expect(block).toEqual(expectedBlock); expect(meta.executionPayloadBlinded).toEqual(expectedExecution); diff --git a/packages/beacon-node/test/unit/chain/beaconProposerCache.ts b/packages/beacon-node/test/unit/chain/beaconProposerCache.ts index 4545ef0c94b2..538fe8518458 100644 --- a/packages/beacon-node/test/unit/chain/beaconProposerCache.ts +++ b/packages/beacon-node/test/unit/chain/beaconProposerCache.ts @@ -1,4 +1,4 @@ -import {expect} from "vitest"; +import {expect, describe, it, beforeEach} from "vitest"; import {BeaconProposerCache} from "../../../src/chain/beaconProposerCache.js"; const suggestedFeeRecipient = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; diff --git a/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts b/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts index f836e3621cc9..5b48ca9fd953 100644 --- a/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts +++ b/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {toHexString} from "@chainsafe/ssz"; import {describe, it, expect} from "vitest"; import {PublicKey, SecretKey} from "@chainsafe/blst"; diff --git a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts index 6da728be46e9..ab8f166076b9 100644 --- a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts +++ b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts @@ -8,7 +8,6 @@ describe("UpgradeLightClientHeader", function () { let lcHeaderByFork: Record; let testSlots: Record; - /* eslint-disable @typescript-eslint/naming-convention */ const chainConfig = createChainForkConfig({ ...defaultChainConfig, ALTAIR_FORK_EPOCH: 1, diff --git a/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts index 68efd0751585..eba01888fa7c 100644 --- a/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts @@ -13,7 +13,6 @@ export const validSignature = fromHexString( ); describe("AttestationPool", function () { - /* eslint-disable @typescript-eslint/naming-convention */ const config = createChainForkConfig({ ...defaultChainConfig, ELECTRA_FORK_EPOCH: 5, diff --git a/packages/beacon-node/test/unit/chain/rewards/blockRewards.test.ts b/packages/beacon-node/test/unit/chain/rewards/blockRewards.test.ts index f0d85ce3220f..d417d83e2da9 100644 --- a/packages/beacon-node/test/unit/chain/rewards/blockRewards.test.ts +++ b/packages/beacon-node/test/unit/chain/rewards/blockRewards.test.ts @@ -10,9 +10,7 @@ import { import { generatePerfTestCachedStateAltair, cachedStateAltairPopulateCaches, - // eslint-disable-next-line import/no-relative-packages } from "../../../../../state-transition/test/perf/util.js"; -// eslint-disable-next-line import/no-relative-packages import {BlockAltairOpts, getBlockAltair} from "../../../../../state-transition/test/perf/block/util.js"; import {computeBlockRewards} from "../../../../src/chain/rewards/blockRewards.js"; diff --git a/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts b/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts index 2a3275536f22..27b5eadecf11 100644 --- a/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts +++ b/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts @@ -5,7 +5,6 @@ import {ssz} from "@lodestar/types"; import {SeenGossipBlockInput} from "../../../../src/chain/seenCache/seenGossipBlockInput.js"; import {BlockInputType, GossipedInputType, BlockInput} from "../../../../src/chain/blocks/types.js"; -/* eslint-disable @typescript-eslint/naming-convention */ describe("SeenGossipBlockInput", () => { const chainConfig = createChainForkConfig({ ...defaultChainConfig, diff --git a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts index 62b02cbf2b12..3c1824b8c01d 100644 --- a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts +++ b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts @@ -1,5 +1,4 @@ import {describe, it, expect, beforeEach} from "vitest"; -// eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../state-transition/test/perf/util.js"; import {ShufflingCache} from "../../../src/chain/shufflingCache.js"; 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 f2c20fd5cbe4..e2bc392b4ea2 100644 --- a/packages/beacon-node/test/unit/chain/validation/aggregateAndProof.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/aggregateAndProof.test.ts @@ -2,7 +2,6 @@ import {BitArray, toHexString} from "@chainsafe/ssz"; import {describe, it} from "vitest"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {phase0, ssz} from "@lodestar/types"; -// eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../state-transition/test/perf/util.js"; import {IBeaconChain} from "../../../../src/chain/index.js"; import {AttestationErrorCode} from "../../../../src/chain/errors/index.js"; @@ -24,7 +23,6 @@ describe("chain / validation / aggregateAndProof", () => { const getState = memoOnce(() => generateTestCachedBeaconStateOnlyValidators({vc, slot: stateSlot})); - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type function getValidData(opts?: Partial) { return getAggregateAndProofValidData({ currentSlot: stateSlot, diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts index a0eb147db8e8..9aa7c29c7825 100644 --- a/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts @@ -1,6 +1,5 @@ import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; // We need to import the mock before the packages -// eslint-disable-next-line import/order import {MockedBeaconChain, getMockedBeaconChain} from "../../../../mocks/mockedBeaconChain.js"; import {EpochShuffling, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {EpochDifference, ProtoBlock} from "@lodestar/fork-choice"; diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts index 90d37a74289d..be9fd3587b7c 100644 --- a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts @@ -3,7 +3,6 @@ import {describe, expect, it} from "vitest"; import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ssz} from "@lodestar/types"; import {LodestarError} from "@lodestar/utils"; -// eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../../state-transition/test/perf/util.js"; import {AttestationErrorCode, GossipErrorCode} from "../../../../../src/chain/errors/index.js"; import {IBeaconChain} from "../../../../../src/chain/index.js"; @@ -31,7 +30,6 @@ describe("validateAttestation", () => { const getState = memoOnce(() => generateTestCachedBeaconStateOnlyValidators({vc, slot: stateSlot})); - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type function getValidData(opts?: Partial) { return getAttestationValidData({ currentSlot: stateSlot, diff --git a/packages/beacon-node/test/unit/chain/validation/block.test.ts b/packages/beacon-node/test/unit/chain/validation/block.test.ts index d90ca4a54d24..28375f1625e1 100644 --- a/packages/beacon-node/test/unit/chain/validation/block.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/block.test.ts @@ -33,7 +33,6 @@ describe("gossip block validation", function () { chain.forkChoice = forkChoice; regen = chain.regen; - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access (chain as any).opts = {maxSkipSlots}; verifySignature = chain.bls.verifySignatureSets; diff --git a/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts b/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts index ef4364abc366..76eb18fc38eb 100644 --- a/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts @@ -12,7 +12,6 @@ describe("Light Client Finality Update validation", function () { const afterEachCallbacks: (() => Promise | void)[] = []; const config = createChainForkConfig({ ...defaultChainConfig, - /* eslint-disable @typescript-eslint/naming-convention */ ALTAIR_FORK_EPOCH: 1, BELLATRIX_FORK_EPOCH: 3, CAPELLA_FORK_EPOCH: Infinity, diff --git a/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts b/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts index b63a08757380..7e35f1272ad6 100644 --- a/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts @@ -12,7 +12,6 @@ describe("Light Client Optimistic Update validation", function () { const afterEachCallbacks: (() => Promise | void)[] = []; const config = createChainForkConfig({ ...defaultChainConfig, - /* eslint-disable @typescript-eslint/naming-convention */ ALTAIR_FORK_EPOCH: 1, BELLATRIX_FORK_EPOCH: 3, CAPELLA_FORK_EPOCH: Infinity, diff --git a/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts b/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts index b498333ae738..26571ab19a77 100644 --- a/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts @@ -20,7 +20,6 @@ describe("Sync Committee Signature validation", function () { let altairForkEpochBk: Epoch; const altairForkEpoch = 2020; const currentSlot = SLOTS_PER_EPOCH * (altairForkEpoch + 1); - // eslint-disable-next-line @typescript-eslint/naming-convention const config = createChainForkConfig(Object.assign({}, defaultChainConfig, {ALTAIR_FORK_EPOCH: altairForkEpoch})); // all validators have same pubkey const validatorIndexInSyncCommittee = 15; diff --git a/packages/beacon-node/test/unit/db/api/repository.test.ts b/packages/beacon-node/test/unit/db/api/repository.test.ts index 07c199632125..28065c84c7ea 100644 --- a/packages/beacon-node/test/unit/db/api/repository.test.ts +++ b/packages/beacon-node/test/unit/db/api/repository.test.ts @@ -11,7 +11,6 @@ vi.mock("@lodestar/db", async (importOriginal) => { return { ...mod, - // eslint-disable-next-line @typescript-eslint/naming-convention LevelDbController: vi.spyOn(mod, "LevelDbController").mockImplementation(() => { return { get: vi.fn(), @@ -31,7 +30,6 @@ interface TestType { bytes: Bytes32; } -// eslint-disable-next-line @typescript-eslint/naming-convention const TestSSZType = new ContainerType({ bool: ssz.Boolean, bytes: ssz.Bytes32, diff --git a/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts b/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts index 151f3931cfde..edf571b905b3 100644 --- a/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts +++ b/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts @@ -8,8 +8,6 @@ import {Eth1MergeBlockTracker, StatusCode, toPowBlock} from "../../../src/eth1/e import {Eth1ProviderState, EthJsonRpcBlockRaw} from "../../../src/eth1/interface.js"; import {testLogger} from "../../utils/logger.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - describe("eth1 / Eth1MergeBlockTracker", () => { const logger = testLogger(); diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index 316f75efc5ce..88d2796a12de 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -99,7 +99,6 @@ describe("eth1 / util / deposits", function () { }, ]; - /* eslint-disable @typescript-eslint/naming-convention */ const postElectraConfig = createChainForkConfig({ ALTAIR_FORK_EPOCH: 1, BELLATRIX_FORK_EPOCH: 2, diff --git a/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts b/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts index cacfd7dc685f..0521823d1283 100644 --- a/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts @@ -5,11 +5,8 @@ import {Eth1Block} from "../../../../src/eth1/interface.js"; describe("eth1 / utils / optimizeNextBlockDiffForGenesis", function () { it("should return optimized block diff to find genesis time", () => { const params = { - // eslint-disable-next-line @typescript-eslint/naming-convention MIN_GENESIS_TIME: 1578009600, - // eslint-disable-next-line @typescript-eslint/naming-convention GENESIS_DELAY: 172800, - // eslint-disable-next-line @typescript-eslint/naming-convention SECONDS_PER_ETH1_BLOCK: 14, }; const initialTimeDiff = params.GENESIS_DELAY * 2; diff --git a/packages/beacon-node/test/unit/monitoring/remoteService.ts b/packages/beacon-node/test/unit/monitoring/remoteService.ts index c5ce0e9ef0b3..bea50eee3bdd 100644 --- a/packages/beacon-node/test/unit/monitoring/remoteService.ts +++ b/packages/beacon-node/test/unit/monitoring/remoteService.ts @@ -77,7 +77,7 @@ function validateClientStats(data: ReceivedData, schema: ClientStatsSchema): voi schema.forEach((s) => { try { expect(data[s.key]).toBeInstanceOf(s.type); - } catch { + } catch (_e) { throw new Error( `Validation of property "${s.key}" failed. Expected type "${s.type}" but received "${typeof data[s.key]}".` ); diff --git a/packages/beacon-node/test/unit/monitoring/service.test.ts b/packages/beacon-node/test/unit/monitoring/service.test.ts index 43936ff1756d..0795a165538e 100644 --- a/packages/beacon-node/test/unit/monitoring/service.test.ts +++ b/packages/beacon-node/test/unit/monitoring/service.test.ts @@ -108,7 +108,6 @@ describe("monitoring / service", () => { expect(logger.info).toHaveBeenCalledWith( "Started monitoring service", // TODO: Debug why `expect.any` causing type error - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment expect.objectContaining({interval: expect.any(Number), machine: null, remote: expect.any(String)}) ); }); diff --git a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts index d1dc7ba57fa9..dda4959c7b3e 100644 --- a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts +++ b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts @@ -17,7 +17,6 @@ describe("beaconBlocksMaybeBlobsByRange", () => { const peerId = "Qma9T5YraSnpRDZqRR4krcSJabThc8nwZuJV3LercPHufi"; - /* eslint-disable @typescript-eslint/naming-convention */ const chainConfig = createChainForkConfig({ ...defaultChainConfig, ALTAIR_FORK_EPOCH: 0, diff --git a/packages/beacon-node/test/unit/network/peers/priorization.test.ts b/packages/beacon-node/test/unit/network/peers/priorization.test.ts index 3ec770051275..cc9ef9b7d711 100644 --- a/packages/beacon-node/test/unit/network/peers/priorization.test.ts +++ b/packages/beacon-node/test/unit/network/peers/priorization.test.ts @@ -14,7 +14,6 @@ import {RequestedSubnet} from "../../../../src/network/peers/utils/index.js"; type Result = ReturnType; -// eslint-disable-next-line vitest/valid-describe-callback describe("network / peers / priorization", async () => { const peers: PeerId[] = []; for (let i = 0; i < 8; i++) { @@ -264,7 +263,6 @@ describe("network / peers / priorization", async () => { } }); -// eslint-disable-next-line vitest/valid-describe-callback describe("sortPeersToPrune", async function () { const peers: PeerId[] = []; for (let i = 0; i < 8; i++) { diff --git a/packages/beacon-node/test/unit/network/peers/score.test.ts b/packages/beacon-node/test/unit/network/peers/score.test.ts index df842f9a1310..54cb721a4c21 100644 --- a/packages/beacon-node/test/unit/network/peers/score.test.ts +++ b/packages/beacon-node/test/unit/network/peers/score.test.ts @@ -24,7 +24,6 @@ describe("simple block provider score tracking", function () { const MIN_SCORE = -100; const actionName = "test-action"; - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type function mockStore() { const scoreStore = new PeerRpcScoreStore(); const peerScores = scoreStore["scores"] as MapDef; diff --git a/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts b/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts index 0c7b3df98268..cf9345172083 100644 --- a/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts +++ b/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts @@ -26,7 +26,6 @@ describe("AttnetsService", () => { "be" ); const ALTAIR_FORK_EPOCH = 100; - // eslint-disable-next-line @typescript-eslint/naming-convention const config = createBeaconConfig({ALTAIR_FORK_EPOCH}, ZERO_HASH); // const {SECONDS_PER_SLOT} = config; let service: AttnetsService; diff --git a/packages/beacon-node/test/unit/sync/backfill/verify.test.ts b/packages/beacon-node/test/unit/sync/backfill/verify.test.ts index 08ffdc4c3b02..3d1a2cd7e7e5 100644 --- a/packages/beacon-node/test/unit/sync/backfill/verify.test.ts +++ b/packages/beacon-node/test/unit/sync/backfill/verify.test.ts @@ -12,7 +12,6 @@ import {BackfillSyncErrorCode, BackfillSyncError} from "./../../../../src/sync/b // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); describe("backfill sync - verify block sequence", function () { @@ -43,7 +42,9 @@ describe("backfill sync - verify block sequence", function () { const {error} = verifyBlockSequence( beaconConfig, // remove middle block - blocks.filter((b) => b.data.message.slot !== 2).slice(0, blocks.length - 2), + blocks + .filter((b) => b.data.message.slot !== 2) + .slice(0, blocks.length - 2), blocks[blocks.length - 1].data.message.parentRoot ); if (error != null) throw new BackfillSyncError({code: error}); diff --git a/packages/beacon-node/test/unit/sync/range/chain.test.ts b/packages/beacon-node/test/unit/sync/range/chain.test.ts index 44d5cc7c173a..658f950b2c18 100644 --- a/packages/beacon-node/test/unit/sync/range/chain.test.ts +++ b/packages/beacon-node/test/unit/sync/range/chain.test.ts @@ -72,7 +72,7 @@ describe("sync / range / chain", () => { } }; - const downloadBeaconBlocksByRange: SyncChainFns["downloadBeaconBlocksByRange"] = async (peerId, request) => { + const downloadBeaconBlocksByRange: SyncChainFns["downloadBeaconBlocksByRange"] = async (_peerId, request) => { const blocks: BlockInput[] = []; for (let i = request.startSlot; i < request.startSlot + request.count; i += request.step) { if (skippedSlots?.has(i)) { @@ -124,7 +124,7 @@ describe("sync / range / chain", () => { const peers = [peer]; const processChainSegment: SyncChainFns["processChainSegment"] = async () => {}; - const downloadBeaconBlocksByRange: SyncChainFns["downloadBeaconBlocksByRange"] = async (peer, request) => { + const downloadBeaconBlocksByRange: SyncChainFns["downloadBeaconBlocksByRange"] = async (_peer, request) => { const blocks: BlockInput[] = []; for (let i = request.startSlot; i < request.startSlot + request.count; i += request.step) { blocks.push( diff --git a/packages/beacon-node/test/unit/sync/unknownBlock.test.ts b/packages/beacon-node/test/unit/sync/unknownBlock.test.ts index f6791fc29e9c..4805bd123898 100644 --- a/packages/beacon-node/test/unit/sync/unknownBlock.test.ts +++ b/packages/beacon-node/test/unit/sync/unknownBlock.test.ts @@ -22,7 +22,6 @@ import {ZERO_HASH} from "../../../src/constants/constants.js"; describe("sync by UnknownBlockSync", () => { const logger = testLogger(); const slotSec = 0.3; - // eslint-disable-next-line @typescript-eslint/naming-convention const config = createChainForkConfig({...minimalConfig, SECONDS_PER_SLOT: slotSec}); beforeEach(() => { @@ -119,11 +118,13 @@ describe("sync by UnknownBlockSync", () => { ]); let reportPeerResolveFn: (value: Parameters) => void; - const reportPeerPromise = new Promise>((r) => (reportPeerResolveFn = r)); + const reportPeerPromise = new Promise>((r) => { + reportPeerResolveFn = r; + }); let sendBeaconBlocksByRootResolveFn: (value: Parameters) => void; - const sendBeaconBlocksByRootPromise = new Promise>( - (r) => (sendBeaconBlocksByRootResolveFn = r) - ); + const sendBeaconBlocksByRootPromise = new Promise>((r) => { + sendBeaconBlocksByRootResolveFn = r; + }); const network: Partial = { events: new NetworkEventBus(), @@ -157,8 +158,12 @@ describe("sync by UnknownBlockSync", () => { let blockAResolver: () => void; let blockCResolver: () => void; - const blockAProcessed = new Promise((resolve) => (blockAResolver = resolve)); - const blockCProcessed = new Promise((resolve) => (blockCResolver = resolve)); + const blockAProcessed = new Promise((resolve) => { + blockAResolver = resolve; + }); + const blockCProcessed = new Promise((resolve) => { + blockCResolver = resolve; + }); const chain: Partial = { clock: new ClockStopped(0), diff --git a/packages/beacon-node/test/unit/util/kzg.test.ts b/packages/beacon-node/test/unit/util/kzg.test.ts index e170aed1a2de..13cea96d87a6 100644 --- a/packages/beacon-node/test/unit/util/kzg.test.ts +++ b/packages/beacon-node/test/unit/util/kzg.test.ts @@ -31,7 +31,6 @@ describe("C-KZG", () => { expect(ckzg.verifyBlobKzgProofBatch(blobs, commitments, proofs)).toBe(true); }); - /* eslint-disable @typescript-eslint/naming-convention */ it("BlobSidecars", async () => { const chainConfig = createChainForkConfig({ ...defaultChainConfig, @@ -67,7 +66,7 @@ describe("C-KZG", () => { blobSidecars.forEach(async (blobSidecar) => { try { await validateGossipBlobSidecar(chain, blobSidecar, blobSidecar.index); - } catch (error) { + } catch (_e) { // We expect some error from here // console.log(error); } diff --git a/packages/beacon-node/test/utils/clock.ts b/packages/beacon-node/test/utils/clock.ts index ea14c866c1b0..390d7dd095dd 100644 --- a/packages/beacon-node/test/utils/clock.ts +++ b/packages/beacon-node/test/utils/clock.ts @@ -4,11 +4,14 @@ import {Slot, Epoch} from "@lodestar/types"; import {IClock} from "../../src/util/clock.js"; export class ClockStatic extends EventEmitter implements IClock { + genesisTime: number; + constructor( readonly currentSlot: Slot, - public genesisTime = 0 + genesisTime = 0 ) { super(); + this.genesisTime = genesisTime; } get currentEpoch(): Epoch { diff --git a/packages/beacon-node/test/utils/config.ts b/packages/beacon-node/test/utils/config.ts index 2aad1c14c03e..f5d566560b65 100644 --- a/packages/beacon-node/test/utils/config.ts +++ b/packages/beacon-node/test/utils/config.ts @@ -6,7 +6,6 @@ import {ZERO_HASH} from "../../src/constants/index.js"; /** default config with ZERO_HASH as genesisValidatorsRoot */ export const config = createBeaconConfig(chainConfig, ZERO_HASH); -/* eslint-disable @typescript-eslint/naming-convention */ export function getConfig(fork: ForkName, forkEpoch = 0): ChainForkConfig { switch (fork) { case ForkName.phase0: diff --git a/packages/beacon-node/test/utils/node/simTest.ts b/packages/beacon-node/test/utils/node/simTest.ts index e94c32cefb10..7b771b8534ed 100644 --- a/packages/beacon-node/test/utils/node/simTest.ts +++ b/packages/beacon-node/test/utils/node/simTest.ts @@ -112,7 +112,7 @@ function avg(arr: number[]): number { /** * Print a table grid of (Y) epoch / (X) slot_per_epoch */ -function printEpochSlotGrid(map: Map, config: BeaconConfig, title: string): void { +function printEpochSlotGrid(map: Map, _config: BeaconConfig, title: string): void { const lastSlot = Array.from(map.keys())[map.size - 1]; const lastEpoch = computeEpochAtSlot(lastSlot); const rowsByEpochBySlot = linspace(0, lastEpoch).map((epoch) => { @@ -132,7 +132,7 @@ function printEpochGrid(maps: Record>, title: string) return epoch > max ? epoch : max; }, 0); const epochGrid = linspace(0, lastEpoch).map((epoch) => - mapValues(maps, (val, key) => formatValue(maps[key].get(epoch))) + mapValues(maps, (_val, key) => formatValue(maps[key].get(epoch))) ); console.log(renderTitle(title)); console.table(epochGrid); diff --git a/packages/beacon-node/test/utils/runEl.ts b/packages/beacon-node/test/utils/runEl.ts index 9adf1a83c151..f7a2b2f52e58 100644 --- a/packages/beacon-node/test/utils/runEl.ts +++ b/packages/beacon-node/test/utils/runEl.ts @@ -7,7 +7,6 @@ import {Eth1Provider} from "../../src/index.js"; import {ZERO_HASH} from "../../src/constants/index.js"; import {shell} from "../sim/shell.js"; -/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable no-console */ let txRpcId = 1; @@ -84,7 +83,7 @@ async function waitForELOnline(url: string, signal: AbortSignal): Promise console.log("Waiting for few seconds for EL to fully setup, for e.g. unlock the account..."); await sleep(5000, signal); return; // Done - } catch (e) { + } catch (_e) { await sleep(1000, signal); } } diff --git a/packages/beacon-node/test/utils/validationData/aggregateAndProof.ts b/packages/beacon-node/test/utils/validationData/aggregateAndProof.ts index 45adfec433e4..462502719134 100644 --- a/packages/beacon-node/test/utils/validationData/aggregateAndProof.ts +++ b/packages/beacon-node/test/utils/validationData/aggregateAndProof.ts @@ -1,7 +1,6 @@ import {computeSigningRoot} from "@lodestar/state-transition"; import {DOMAIN_AGGREGATE_AND_PROOF, DOMAIN_SELECTION_PROOF} from "@lodestar/params"; import {phase0, ssz} from "@lodestar/types"; -// eslint-disable-next-line import/no-relative-packages import {getSecretKeyFromIndexCached} from "../../../../state-transition/test/perf/util.js"; import {IBeaconChain} from "../../../src/chain/index.js"; import {SeenAggregators} from "../../../src/chain/seenCache/index.js"; diff --git a/packages/beacon-node/test/utils/validationData/attestation.ts b/packages/beacon-node/test/utils/validationData/attestation.ts index 22f551cbb663..6715512ac667 100644 --- a/packages/beacon-node/test/utils/validationData/attestation.ts +++ b/packages/beacon-node/test/utils/validationData/attestation.ts @@ -6,7 +6,6 @@ import {phase0, Slot, ssz} from "@lodestar/types"; import { generateTestCachedBeaconStateOnlyValidators, getSecretKeyFromIndexCached, - // eslint-disable-next-line import/no-relative-packages } from "../../../../state-transition/test/perf/util.js"; import {IBeaconChain} from "../../../src/chain/index.js"; import {IStateRegenerator} from "../../../src/chain/regen/index.js"; diff --git a/packages/cli/docsgen/markdown.ts b/packages/cli/docsgen/markdown.ts index 5c3033e9c0df..9c7a4d0ca279 100644 --- a/packages/cli/docsgen/markdown.ts +++ b/packages/cli/docsgen/markdown.ts @@ -117,7 +117,6 @@ function renderOption(optionName: string, option: CliOptionDefinition): string | defaultValue = `"${defaultValue}"`; } if (option.type === "array") { - // eslint-disable-next-line quotes if (!defaultValue.includes(`"`)) { defaultValue = `"${defaultValue}"`; } diff --git a/packages/cli/package.json b/packages/cli/package.json index a5527a8eee87..b4fc206e5a44 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -28,8 +28,8 @@ "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\" lodestar --help", "check-types": "tsc", "docs:build": "node --loader ts-node/esm ./docsgen/index.ts", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test:unit": "vitest --run --dir test/unit/", "test:e2e": "vitest --run --config vitest.e2e.config.ts --dir test/e2e/", "test:sim:multifork": "LODESTAR_PRESET=minimal DOTENV_CONFIG_PATH=../../.env.test node -r dotenv/config --loader ts-node/esm test/sim/multiFork.test.ts", diff --git a/packages/cli/src/applyPreset.ts b/packages/cli/src/applyPreset.ts index 25f78b7d32ac..e40ac98841c0 100644 --- a/packages/cli/src/applyPreset.ts +++ b/packages/cli/src/applyPreset.ts @@ -1,8 +1,6 @@ // MUST import this file first before anything and not import any Lodestar code. -// eslint-disable-next-line no-restricted-imports import {hasher} from "@chainsafe/persistent-merkle-tree/lib/hasher/as-sha256.js"; -// eslint-disable-next-line no-restricted-imports import {setHasher} from "@chainsafe/persistent-merkle-tree/lib/hasher/index.js"; // without setting this first, persistent-merkle-tree will use noble instead @@ -45,7 +43,6 @@ else if (network) { if (network === "dev") { process.env.LODESTAR_PRESET = "minimal"; // "c-kzg" has hardcoded the mainnet value, do not use presets - // eslint-disable-next-line @typescript-eslint/naming-convention setActivePreset(PresetName.minimal, {FIELD_ELEMENTS_PER_BLOB: 4096}); } else if (network === "gnosis" || network === "chiado") { process.env.LODESTAR_PRESET = "gnosis"; @@ -57,7 +54,6 @@ else if (process.argv[2] === "dev") { process.env.LODESTAR_PRESET = "minimal"; process.env.LODESTAR_NETWORK = "dev"; // "c-kzg" has hardcoded the mainnet value, do not use presets - // eslint-disable-next-line @typescript-eslint/naming-convention setActivePreset(PresetName.minimal, {FIELD_ELEMENTS_PER_BLOB: 4096}); } diff --git a/packages/cli/src/cmds/beacon/handler.ts b/packages/cli/src/cmds/beacon/handler.ts index 81536d7c7b41..ea424e04824a 100644 --- a/packages/cli/src/cmds/beacon/handler.ts +++ b/packages/cli/src/cmds/beacon/handler.ts @@ -158,7 +158,6 @@ export async function beaconHandler(args: BeaconArgs & GlobalArgs): Promise = { string: true, coerce: (urls: string[]): string[] => // Parse ["url1,url2"] to ["url1", "url2"] - urls.map((item) => item.split(",")).flat(1), + urls + .map((item) => item.split(",")) + .flat(1), alias: ["server"], // for backwards compatibility }, diff --git a/packages/cli/src/cmds/validator/voluntaryExit.ts b/packages/cli/src/cmds/validator/voluntaryExit.ts index 02f1591b59ed..c3982d8d45ee 100644 --- a/packages/cli/src/cmds/validator/voluntaryExit.ts +++ b/packages/cli/src/cmds/validator/voluntaryExit.ts @@ -203,7 +203,6 @@ function selectSignersToExit(args: VoluntaryExitArgs, signers: Signer[]): Signer } } -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type async function resolveValidatorIndexes(client: ApiClient, signersToExit: SignerPubkey[]) { const pubkeys = signersToExit.map(({pubkey}) => pubkey); diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 5cdccbacfeec..0d509af17ab0 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -14,7 +14,6 @@ void lodestar // Show command help message when no command is provided if (msg.includes("Not enough non-option arguments")) { yarg.showHelp(); - // eslint-disable-next-line no-console console.log("\n"); } } @@ -22,7 +21,6 @@ void lodestar const errorMessage = err !== undefined ? (err instanceof YargsError ? err.message : err.stack) : msg || "Unknown error"; - // eslint-disable-next-line no-console console.error(` ✖ ${errorMessage}\n`); process.exit(1); }) diff --git a/packages/cli/src/networks/index.ts b/packages/cli/src/networks/index.ts index 0831b78cd2f6..ba42cf4c7798 100644 --- a/packages/cli/src/networks/index.ts +++ b/packages/cli/src/networks/index.ts @@ -109,7 +109,6 @@ export async function getNetworkBootnodes(network: NetworkName): Promise persistInvalidSszObjectsDir: undefined as any, proposerBoost: args["chain.proposerBoost"], proposerBoostReorg: args["chain.proposerBoostReorg"], diff --git a/packages/cli/src/options/beaconNodeOptions/eth1.ts b/packages/cli/src/options/beaconNodeOptions/eth1.ts index 46654cca6b2e..c558bda61b4e 100644 --- a/packages/cli/src/options/beaconNodeOptions/eth1.ts +++ b/packages/cli/src/options/beaconNodeOptions/eth1.ts @@ -59,7 +59,9 @@ export const options: CliCommandOptions = { string: true, coerce: (urls: string[]): string[] => // Parse ["url1,url2"] to ["url1", "url2"] - urls.map((item) => item.split(",")).flat(1), + urls + .map((item) => item.split(",")) + .flat(1), group: "eth1", }, diff --git a/packages/cli/src/options/beaconNodeOptions/execution.ts b/packages/cli/src/options/beaconNodeOptions/execution.ts index 85b81a5e708b..d60a621d1cdb 100644 --- a/packages/cli/src/options/beaconNodeOptions/execution.ts +++ b/packages/cli/src/options/beaconNodeOptions/execution.ts @@ -45,7 +45,9 @@ export const options: CliCommandOptions = { string: true, coerce: (urls: string[]): string[] => // Parse ["url1,url2"] to ["url1", "url2"] - urls.map((item) => item.split(",")).flat(1), + urls + .map((item) => item.split(",")) + .flat(1), group: "execution", }, diff --git a/packages/cli/src/options/beaconNodeOptions/network.ts b/packages/cli/src/options/beaconNodeOptions/network.ts index bfe9c7710e86..fc13f3293c29 100644 --- a/packages/cli/src/options/beaconNodeOptions/network.ts +++ b/packages/cli/src/options/beaconNodeOptions/network.ts @@ -57,18 +57,17 @@ function validateMultiaddrArg>(args } } -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function parseListenArgs(args: NetworkArgs) { // If listenAddress is explicitly set, use it // If listenAddress6 is not set, use defaultListenAddress const listenAddress = args.listenAddress ?? (args.listenAddress6 ? undefined : defaultListenAddress); - const port = listenAddress ? args.port ?? defaultP2pPort : undefined; - const discoveryPort = listenAddress ? args.discoveryPort ?? args.port ?? defaultP2pPort : undefined; + const port = listenAddress ? (args.port ?? defaultP2pPort) : undefined; + const discoveryPort = listenAddress ? (args.discoveryPort ?? args.port ?? defaultP2pPort) : undefined; // Only use listenAddress6 if it is explicitly set const listenAddress6 = args.listenAddress6; - const port6 = listenAddress6 ? args.port6 ?? defaultP2pPort6 : undefined; - const discoveryPort6 = listenAddress6 ? args.discoveryPort6 ?? args.port6 ?? defaultP2pPort6 : undefined; + const port6 = listenAddress6 ? (args.port6 ?? defaultP2pPort6) : undefined; + const discoveryPort6 = listenAddress6 ? (args.discoveryPort6 ?? args.port6 ?? defaultP2pPort6) : undefined; return {listenAddress, port, discoveryPort, listenAddress6, port6, discoveryPort6}; } @@ -115,7 +114,7 @@ export function parseArgs(args: NetworkArgs): IBeaconNodeOptions["network"] { for (const enrStr of bootEnrs) { try { ENR.decodeTxt(enrStr); - } catch (e) { + } catch (_e) { throw new YargsError(`Provided ENR in bootnodes is invalid:\n ${enrStr}`); } } @@ -129,7 +128,7 @@ export function parseArgs(args: NetworkArgs): IBeaconNodeOptions["network"] { ip6: bindMu6, }, bootEnrs, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: enr: undefined as any, } : null, diff --git a/packages/cli/src/util/file.ts b/packages/cli/src/util/file.ts index 99e93a96dc59..5415cf2affa6 100644 --- a/packages/cli/src/util/file.ts +++ b/packages/cli/src/util/file.ts @@ -13,7 +13,6 @@ export const yamlSchema = FAILSAFE_SCHEMA.extend({ new Type("tag:yaml.org,2002:str", { kind: "scalar", construct: function construct(data) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return data !== null ? data : ""; }, }), diff --git a/packages/cli/src/util/gitData/gitDataPath.ts b/packages/cli/src/util/gitData/gitDataPath.ts index e243ca433f2d..1ad3104aafc6 100644 --- a/packages/cli/src/util/gitData/gitDataPath.ts +++ b/packages/cli/src/util/gitData/gitDataPath.ts @@ -4,7 +4,6 @@ import {fileURLToPath} from "node:url"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); // Persist git data and distribute through NPM so CLI consumers can know exactly diff --git a/packages/cli/src/util/gitData/index.ts b/packages/cli/src/util/gitData/index.ts index 96c5e4bbaef2..0720d39d9e30 100644 --- a/packages/cli/src/util/gitData/index.ts +++ b/packages/cli/src/util/gitData/index.ts @@ -11,7 +11,7 @@ export function readAndGetGitData(): GitData { let persistedGitData: Partial; try { persistedGitData = readGitDataFile(); - } catch (e) { + } catch (_e) { persistedGitData = {}; } @@ -23,13 +23,13 @@ export function readAndGetGitData(): GitData { branch: currentGitData.branch && currentGitData.branch.length > 0 ? currentGitData.branch - : persistedGitData.branch ?? "", + : (persistedGitData.branch ?? ""), commit: currentGitData.commit && currentGitData.commit.length > 0 ? currentGitData.commit - : persistedGitData.commit ?? "", + : (persistedGitData.commit ?? ""), }; - } catch (e) { + } catch (_e) { return { branch: "", commit: "", @@ -49,7 +49,7 @@ export function getGitData(): GitData { function getBranch(): string { try { return shellSilent("git rev-parse --abbrev-ref HEAD"); - } catch (e) { + } catch (_e) { return ""; } } @@ -58,7 +58,7 @@ function getBranch(): string { function getCommit(): string { try { return shellSilent("git rev-parse --verify HEAD"); - } catch (e) { + } catch (_e) { return ""; } } diff --git a/packages/cli/src/util/object.ts b/packages/cli/src/util/object.ts index d37f41ea6655..7f2e8a49d6c8 100644 --- a/packages/cli/src/util/object.ts +++ b/packages/cli/src/util/object.ts @@ -3,10 +3,10 @@ import {RecursivePartial} from "@lodestar/utils"; /** * Removes (mutates) all properties with a value === undefined, recursively */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any + +// biome-ignore lint/suspicious/noExplicitAny: export function removeUndefinedRecursive(obj: T): RecursivePartial { for (const key of Object.keys(obj)) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const value = obj[key]; if (value && typeof value === "object") removeUndefinedRecursive(value); else if (value === undefined) delete obj[key]; diff --git a/packages/cli/src/util/process.ts b/packages/cli/src/util/process.ts index cd040bdffb55..e274d782b8ba 100644 --- a/packages/cli/src/util/process.ts +++ b/packages/cli/src/util/process.ts @@ -8,7 +8,6 @@ const exitSignals = ["SIGTERM", "SIGINT"] as NodeJS.Signals[]; */ export function onGracefulShutdown( cleanUpFunction: () => Promise, - // eslint-disable-next-line no-console logFn: (msg: string) => void = console.log ): void { for (const signal of exitSignals) { diff --git a/packages/cli/src/util/proposerConfig.ts b/packages/cli/src/util/proposerConfig.ts index 509dc8213df1..2c12ce8f8524 100644 --- a/packages/cli/src/util/proposerConfig.ts +++ b/packages/cli/src/util/proposerConfig.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ - import fs from "node:fs"; import path from "node:path"; import {ValidatorProposerConfig} from "@lodestar/validator"; diff --git a/packages/cli/src/util/types.ts b/packages/cli/src/util/types.ts index ced3bf34b1f6..bf194170f3e2 100644 --- a/packages/cli/src/util/types.ts +++ b/packages/cli/src/util/types.ts @@ -1,7 +1,8 @@ /** * Typed `Object.keys(o: T)` function, returning `(keyof T)[]` */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/naming-convention + +// biome-ignore lint/suspicious/noExplicitAny: export function ObjectKeys(o: T): (keyof T)[] { return Object.keys(o); } diff --git a/packages/cli/src/util/version.ts b/packages/cli/src/util/version.ts index 4752856e5b1d..624412107603 100644 --- a/packages/cli/src/util/version.ts +++ b/packages/cli/src/util/version.ts @@ -6,7 +6,6 @@ import {readAndGetGitData} from "./gitData/index.js"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); type VersionJson = { diff --git a/packages/cli/test/e2e/importKeystoresFromApi.test.ts b/packages/cli/test/e2e/importKeystoresFromApi.test.ts index b7abe1e8d293..584ded47bfdd 100644 --- a/packages/cli/test/e2e/importKeystoresFromApi.test.ts +++ b/packages/cli/test/e2e/importKeystoresFromApi.test.ts @@ -30,7 +30,6 @@ describe("import keystores from api", function () { const genesisValidatorsRoot = "0x0000000000000000000000000000000000000000000000000000000000000000"; const slashingProtection: Interchange = { - /* eslint-disable @typescript-eslint/naming-convention */ metadata: { interchange_format_version: "5", genesis_validators_root: genesisValidatorsRoot, diff --git a/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts b/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts index ffeb40460f40..6a6c391b4014 100644 --- a/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts +++ b/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts @@ -39,7 +39,6 @@ describe("import keystores from api, test DefaultProposerConfig", function () { const genesisValidatorsRoot = "0x0000000000000000000000000000000000000000000000000000000000000000"; const slashingProtection: Interchange = { - /* eslint-disable @typescript-eslint/naming-convention */ metadata: { interchange_format_version: "5", genesis_validators_root: genesisValidatorsRoot, diff --git a/packages/cli/test/e2e/voluntaryExit.test.ts b/packages/cli/test/e2e/voluntaryExit.test.ts index 49499e891731..25d4ab345aa7 100644 --- a/packages/cli/test/e2e/voluntaryExit.test.ts +++ b/packages/cli/test/e2e/voluntaryExit.test.ts @@ -79,7 +79,6 @@ describe("voluntaryExit cmd", function () { if (validator.status !== "active_exiting") { throw Error("Validator not exiting"); } else { - // eslint-disable-next-line no-console console.log(`Confirmed validator ${pubkey} = ${validator.status}`); } }, diff --git a/packages/cli/test/e2e/voluntaryExitFromApi.test.ts b/packages/cli/test/e2e/voluntaryExitFromApi.test.ts index 664091d5c520..21a9c0fc6872 100644 --- a/packages/cli/test/e2e/voluntaryExitFromApi.test.ts +++ b/packages/cli/test/e2e/voluntaryExitFromApi.test.ts @@ -86,7 +86,6 @@ describe("voluntary exit from api", function () { if (validator.status !== "active_exiting") { throw Error("Validator not exiting"); } else { - // eslint-disable-next-line no-console console.log(`Confirmed validator ${pubkeyToExit} = ${validator.status}`); } }, diff --git a/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts b/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts index a9cf2f48a168..8cb5f0d44d95 100644 --- a/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts +++ b/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts @@ -101,7 +101,6 @@ describe("voluntaryExit using remote signer", function () { if (validator.status !== "active_exiting") { throw Error("Validator not exiting"); } else { - // eslint-disable-next-line no-console console.log(`Confirmed validator ${pubkey} = ${validator.status}`); } }, diff --git a/packages/cli/test/scripts/e2e_test_env.ts b/packages/cli/test/scripts/e2e_test_env.ts index 24d0142827a8..fcecfac5e1c7 100644 --- a/packages/cli/test/scripts/e2e_test_env.ts +++ b/packages/cli/test/scripts/e2e_test_env.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; import {BeaconClient, ExecutionClient} from "../utils/crucible/interfaces.js"; import {Simulation} from "../utils/crucible/simulation.js"; diff --git a/packages/cli/test/sim/backupEthProvider.test.ts b/packages/cli/test/sim/backupEthProvider.test.ts index 1310119c9c3e..4ccc131a58bc 100644 --- a/packages/cli/test/sim/backupEthProvider.test.ts +++ b/packages/cli/test/sim/backupEthProvider.test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; import {activePreset} from "@lodestar/params"; import {Simulation} from "../utils/crucible/simulation.js"; diff --git a/packages/cli/test/sim/deneb.test.ts b/packages/cli/test/sim/deneb.test.ts index b9c30a5ff523..865540ae7635 100644 --- a/packages/cli/test/sim/deneb.test.ts +++ b/packages/cli/test/sim/deneb.test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; import {Simulation} from "../utils/crucible/simulation.js"; import {BeaconClient, ExecutionClient, ValidatorClient} from "../utils/crucible/interfaces.js"; diff --git a/packages/cli/test/sim/endpoints.test.ts b/packages/cli/test/sim/endpoints.test.ts index 6a119fc219d7..308ac6a0053c 100644 --- a/packages/cli/test/sim/endpoints.test.ts +++ b/packages/cli/test/sim/endpoints.test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; import assert from "node:assert"; import {toHexString} from "@chainsafe/ssz"; diff --git a/packages/cli/test/sim/mixedClient.test.ts b/packages/cli/test/sim/mixedClient.test.ts index bfb2a5a99b1b..45029a1b26b4 100644 --- a/packages/cli/test/sim/mixedClient.test.ts +++ b/packages/cli/test/sim/mixedClient.test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; import {Simulation} from "../utils/crucible/simulation.js"; import {nodeAssertion} from "../utils/crucible/assertions/nodeAssertion.js"; diff --git a/packages/cli/test/sim/multiFork.test.ts b/packages/cli/test/sim/multiFork.test.ts index 47ad59a165b6..047d9196239d 100644 --- a/packages/cli/test/sim/multiFork.test.ts +++ b/packages/cli/test/sim/multiFork.test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; import {Match, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/crucible/interfaces.js"; import {Simulation} from "../utils/crucible/simulation.js"; diff --git a/packages/cli/test/unit/cmds/beacon.test.ts b/packages/cli/test/unit/cmds/beacon.test.ts index fc1f50ad1251..6e7b7f389a29 100644 --- a/packages/cli/test/unit/cmds/beacon.test.ts +++ b/packages/cli/test/unit/cmds/beacon.test.ts @@ -186,7 +186,6 @@ describe("initPeerIdAndEnr", () => { }); }); -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type async function runBeaconHandlerInit(args: Partial) { return beaconHandlerInit({ logLevel: LogLevel.info, diff --git a/packages/cli/test/unit/config/beaconParams.test.ts b/packages/cli/test/unit/config/beaconParams.test.ts index a7ce463200d0..2a78d498bf89 100644 --- a/packages/cli/test/unit/config/beaconParams.test.ts +++ b/packages/cli/test/unit/config/beaconParams.test.ts @@ -16,7 +16,6 @@ describe("config / beaconParams", () => { const testCases: { id: string; kwargs: Parameters[0]; - // eslint-disable-next-line @typescript-eslint/naming-convention GENESIS_FORK_VERSION: string; }[] = [ { @@ -24,7 +23,6 @@ describe("config / beaconParams", () => { kwargs: { additionalParamsCli: {}, }, - // eslint-disable-next-line @typescript-eslint/naming-convention GENESIS_FORK_VERSION: GENESIS_FORK_VERSION_MAINNET, }, { @@ -33,7 +31,6 @@ describe("config / beaconParams", () => { network: networkName, additionalParamsCli: {}, }, - // eslint-disable-next-line @typescript-eslint/naming-convention GENESIS_FORK_VERSION: GENESIS_FORK_VERSION_HOLESKY, }, { @@ -43,7 +40,6 @@ describe("config / beaconParams", () => { paramsFile: paramsFilepath, additionalParamsCli: {}, }, - // eslint-disable-next-line @typescript-eslint/naming-convention GENESIS_FORK_VERSION: GENESIS_FORK_VERSION_FILE, }, { @@ -51,16 +47,13 @@ describe("config / beaconParams", () => { kwargs: { network: networkName, paramsFile: paramsFilepath, - // eslint-disable-next-line @typescript-eslint/naming-convention additionalParamsCli: {GENESIS_FORK_VERSION: GENESIS_FORK_VERSION_CLI}, }, - // eslint-disable-next-line @typescript-eslint/naming-convention GENESIS_FORK_VERSION: GENESIS_FORK_VERSION_CLI, }, ]; beforeAll(() => { - // eslint-disable-next-line @typescript-eslint/naming-convention fs.writeFileSync(paramsFilepath, yaml.dump({GENESIS_FORK_VERSION: GENESIS_FORK_VERSION_FILE})); }); @@ -68,7 +61,6 @@ describe("config / beaconParams", () => { if (fs.existsSync(paramsFilepath)) fs.unlinkSync(paramsFilepath); }); - // eslint-disable-next-line @typescript-eslint/naming-convention it.each(testCases)("$id", ({kwargs, GENESIS_FORK_VERSION}) => { const params = getBeaconParams(kwargs); expect(toHexString(params.GENESIS_FORK_VERSION)).toBe(GENESIS_FORK_VERSION); diff --git a/packages/cli/test/unit/db.test.ts b/packages/cli/test/unit/db.test.ts index 1e19e514e9e5..b39c9492c9cb 100644 --- a/packages/cli/test/unit/db.test.ts +++ b/packages/cli/test/unit/db.test.ts @@ -1,7 +1,5 @@ import {describe, it} from "vitest"; -// eslint-disable-next-line import/no-relative-packages import {Bucket as BeaconBucket} from "../../../beacon-node/src/db/buckets.js"; -// eslint-disable-next-line import/no-relative-packages import {Bucket as ValidatorBucket} from "../../../validator/src/buckets.js"; describe("no db bucket overlap", () => { diff --git a/packages/cli/test/unit/options/paramsOptions.test.ts b/packages/cli/test/unit/options/paramsOptions.test.ts index a08c70008612..d6563203e652 100644 --- a/packages/cli/test/unit/options/paramsOptions.test.ts +++ b/packages/cli/test/unit/options/paramsOptions.test.ts @@ -11,9 +11,7 @@ describe("options / paramsOptions", () => { }; const expectedBeaconParams: Partial = { - // eslint-disable-next-line @typescript-eslint/naming-convention GENESIS_FORK_VERSION: "0x00000001", - // eslint-disable-next-line @typescript-eslint/naming-convention DEPOSIT_CONTRACT_ADDRESS: "0x1234567890123456789012345678901234567890", }; diff --git a/packages/cli/test/unit/util/format.test.ts b/packages/cli/test/unit/util/format.test.ts index c06259cc1842..194cc1dcbde7 100644 --- a/packages/cli/test/unit/util/format.test.ts +++ b/packages/cli/test/unit/util/format.test.ts @@ -17,8 +17,7 @@ describe("util / format / parseRange", () => { describe("util / format / isValidatePubkeyHex", () => { const testCases: Record = { - "../../malicious_link/0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95": - false, + "../../malicious_link/0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95": false, "0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95": true, "0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c9": false, "0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95f": false, diff --git a/packages/cli/test/unit/util/gitData.test.ts b/packages/cli/test/unit/util/gitData.test.ts index 206dd070b545..12a6b5b18339 100644 --- a/packages/cli/test/unit/util/gitData.test.ts +++ b/packages/cli/test/unit/util/gitData.test.ts @@ -8,7 +8,6 @@ import {getGitData} from "../../../src/util/index.js"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); describe("util / gitData", function () { diff --git a/packages/cli/test/unit/validator/parseProposerConfig.test.ts b/packages/cli/test/unit/validator/parseProposerConfig.test.ts index 66220ca3329a..83c8c63ef877 100644 --- a/packages/cli/test/unit/validator/parseProposerConfig.test.ts +++ b/packages/cli/test/unit/validator/parseProposerConfig.test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; import {fileURLToPath} from "node:url"; import {describe, it, expect} from "vitest"; @@ -27,6 +26,7 @@ const testValue = { builder: { gasLimit: 35000000, selection: routes.validator.BuilderSelection.BuilderAlways, + // biome-ignore lint/correctness/noPrecisionLoss: boostFactor: BigInt(18446744073709551616), }, }, diff --git a/packages/cli/test/utils/crucible/clients/beacon/lighthouse.ts b/packages/cli/test/utils/crucible/clients/beacon/lighthouse.ts index 89802149024a..515418f7e558 100644 --- a/packages/cli/test/utils/crucible/clients/beacon/lighthouse.ts +++ b/packages/cli/test/utils/crucible/clients/beacon/lighthouse.ts @@ -109,7 +109,6 @@ export const generateLighthouseBeaconNode: BeaconNodeGenerator { - // eslint-disable-next-line no-console if (!silent) console.log("Waiting for start of slot", {target: slot, current: this.currentSlot}); const slotTime = this.getSlotTime(slot) * MS_IN_SEC - Date.now(); await sleep(slotTime, this.signal); diff --git a/packages/cli/test/utils/crucible/externalSignerServer.ts b/packages/cli/test/utils/crucible/externalSignerServer.ts index bd8576d214c2..4282f1761db9 100644 --- a/packages/cli/test/utils/crucible/externalSignerServer.ts +++ b/packages/cli/test/utils/crucible/externalSignerServer.ts @@ -29,7 +29,6 @@ export class ExternalSignerServer { return [...this.secretKeyMap.keys()]; }); - /* eslint-disable @typescript-eslint/naming-convention */ this.server.post<{ Params: { /** BLS public key as a hex string. */ diff --git a/packages/cli/test/utils/crucible/interfaces.ts b/packages/cli/test/utils/crucible/interfaces.ts index db4b1f3b8901..84b5043ba983 100644 --- a/packages/cli/test/utils/crucible/interfaces.ts +++ b/packages/cli/test/utils/crucible/interfaces.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {ChildProcess} from "node:child_process"; import {Web3} from "web3"; import {SecretKey} from "@chainsafe/blst"; diff --git a/packages/cli/test/utils/crucible/runner/dockerRunner.ts b/packages/cli/test/utils/crucible/runner/dockerRunner.ts index cfa52c9b9ebf..bc5b97811cf4 100644 --- a/packages/cli/test/utils/crucible/runner/dockerRunner.ts +++ b/packages/cli/test/utils/crucible/runner/dockerRunner.ts @@ -22,7 +22,7 @@ export class DockerRunner implements RunnerEnv { await execChildProcess(`docker network create --subnet ${dockerNetworkIpRange}.0/24 ${dockerNetworkName}`, { logger: this.logger, }); - } catch { + } catch (_e) { // During multiple sim tests files the network might already exist } } @@ -35,7 +35,7 @@ export class DockerRunner implements RunnerEnv { logger: this.logger, }); return; - } catch { + } catch (_e) { await sleep(5000); } } diff --git a/packages/cli/test/utils/crucible/simulationTracker.ts b/packages/cli/test/utils/crucible/simulationTracker.ts index e374d3b6c328..778a7ad2a771 100644 --- a/packages/cli/test/utils/crucible/simulationTracker.ts +++ b/packages/cli/test/utils/crucible/simulationTracker.ts @@ -68,7 +68,7 @@ async function pathExists(filePath: string): Promise { try { await fs.access(filePath); return true; - } catch { + } catch (_e) { return false; } } diff --git a/packages/cli/test/utils/crucible/utils/index.ts b/packages/cli/test/utils/crucible/utils/index.ts index 0b6ae1bba1e5..0e016778cdce 100644 --- a/packages/cli/test/utils/crucible/utils/index.ts +++ b/packages/cli/test/utils/crucible/utils/index.ts @@ -73,7 +73,6 @@ export function defineSimTestConfig( additionalSlots: opts.additionalSlotsForTTD ?? 2, }); - /* eslint-disable @typescript-eslint/naming-convention */ const forkConfig = createChainForkConfig({ ...opts, GENESIS_DELAY: genesisDelaySeconds, @@ -157,7 +156,7 @@ export const arrayGroupBy = ( ): Record => array.reduce( (acc, value, index, array) => { - (acc[predicate(value, index, array)] ||= []).push(value); + acc[predicate(value, index, array)]?.push(value); return acc; }, {} as {[key: string]: T[]} diff --git a/packages/cli/test/utils/crucible/utils/keys.ts b/packages/cli/test/utils/crucible/utils/keys.ts index 27983c04cd38..8915e85b529e 100644 --- a/packages/cli/test/utils/crucible/utils/keys.ts +++ b/packages/cli/test/utils/crucible/utils/keys.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {readFile, writeFile} from "node:fs/promises"; import path from "node:path"; import yaml from "js-yaml"; diff --git a/packages/cli/test/utils/crucible/utils/network.ts b/packages/cli/test/utils/crucible/utils/network.ts index e3555fc149b9..7f41b87aff04 100644 --- a/packages/cli/test/utils/crucible/utils/network.ts +++ b/packages/cli/test/utils/crucible/utils/network.ts @@ -74,7 +74,6 @@ export async function waitForNodeSync( } 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()).value(); if (!result.isSyncing) { diff --git a/packages/cli/test/utils/crucible/utils/syncing.ts b/packages/cli/test/utils/crucible/utils/syncing.ts index 4a8913105335..d31575e74e5d 100644 --- a/packages/cli/test/utils/crucible/utils/syncing.ts +++ b/packages/cli/test/utils/crucible/utils/syncing.ts @@ -148,7 +148,9 @@ export async function assertUnknownBlockSync(env: Simulation): Promise { } catch (error) { if (!(error as Error).message.includes("BLOCK_ERROR_PARENT_UNKNOWN")) { env.tracker.record({ - message: `Publishing unknown block should return "BLOCK_ERROR_PARENT_UNKNOWN" got "${(error as Error).message}"`, + message: `Publishing unknown block should return "BLOCK_ERROR_PARENT_UNKNOWN" got "${ + (error as Error).message + }"`, slot: env.clock.currentSlot, assertionId: "unknownBlockParent", }); @@ -178,7 +180,6 @@ export async function waitForNodeSync( } 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()).value(); if (!result.isSyncing) { diff --git a/packages/cli/test/utils/mockBeaconApiServer.ts b/packages/cli/test/utils/mockBeaconApiServer.ts index 80ce282e102c..e7e80338686f 100644 --- a/packages/cli/test/utils/mockBeaconApiServer.ts +++ b/packages/cli/test/utils/mockBeaconApiServer.ts @@ -5,7 +5,6 @@ import {ChainForkConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; import {fromHex, toHex} from "@lodestar/utils"; -// eslint-disable-next-line import/no-relative-packages import {testLogger} from "../../../beacon-node/test/utils/logger.js"; const ZERO_HASH_HEX = toHex(Buffer.alloc(32, 0)); diff --git a/packages/config/package.json b/packages/config/package.json index f257db65cf6e..434000db2a0f 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -47,8 +47,8 @@ "build:watch": "yarn run build --watch", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit", "test:unit": "yarn vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" diff --git a/packages/config/src/chainConfig/configs/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts index e5792a87ac70..5da5f8d2acb0 100644 --- a/packages/config/src/chainConfig/configs/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {fromHex as b} from "@lodestar/utils"; import {PresetName} from "@lodestar/params"; import {ChainConfig} from "../types.js"; diff --git a/packages/config/src/chainConfig/configs/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts index 53229d283511..f1a52e956f4d 100644 --- a/packages/config/src/chainConfig/configs/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {fromHex as b} from "@lodestar/utils"; import {PresetName} from "@lodestar/params"; import {ChainConfig} from "../types.js"; diff --git a/packages/config/src/chainConfig/default.ts b/packages/config/src/chainConfig/default.ts index d778c9b82447..ef2b9743a1d2 100644 --- a/packages/config/src/chainConfig/default.ts +++ b/packages/config/src/chainConfig/default.ts @@ -10,9 +10,10 @@ switch (ACTIVE_PRESET) { defaultChainConfig = minimal; break; case PresetName.mainnet: - default: defaultChainConfig = mainnet; break; + default: + defaultChainConfig = mainnet; } export {defaultChainConfig}; diff --git a/packages/config/src/chainConfig/networks/chiado.ts b/packages/config/src/chainConfig/networks/chiado.ts index d96bd7510c65..096942af672c 100644 --- a/packages/config/src/chainConfig/networks/chiado.ts +++ b/packages/config/src/chainConfig/networks/chiado.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; import {gnosisChainConfig as gnosis} from "./gnosis.js"; diff --git a/packages/config/src/chainConfig/networks/ephemery.ts b/packages/config/src/chainConfig/networks/ephemery.ts index 6fefc1800bfc..d1c17c36f0ab 100644 --- a/packages/config/src/chainConfig/networks/ephemery.ts +++ b/packages/config/src/chainConfig/networks/ephemery.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; diff --git a/packages/config/src/chainConfig/networks/gnosis.ts b/packages/config/src/chainConfig/networks/gnosis.ts index 2f58ffd4d045..a25162ae5028 100644 --- a/packages/config/src/chainConfig/networks/gnosis.ts +++ b/packages/config/src/chainConfig/networks/gnosis.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {fromHex as b} from "@lodestar/utils"; import {PresetName} from "@lodestar/params"; import {ChainConfig} from "../types.js"; diff --git a/packages/config/src/chainConfig/networks/holesky.ts b/packages/config/src/chainConfig/networks/holesky.ts index 16c462a9468e..46c32606931f 100644 --- a/packages/config/src/chainConfig/networks/holesky.ts +++ b/packages/config/src/chainConfig/networks/holesky.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; diff --git a/packages/config/src/chainConfig/networks/mainnet.ts b/packages/config/src/chainConfig/networks/mainnet.ts index c137c578fc0e..13225b463da9 100644 --- a/packages/config/src/chainConfig/networks/mainnet.ts +++ b/packages/config/src/chainConfig/networks/mainnet.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; diff --git a/packages/config/src/chainConfig/networks/sepolia.ts b/packages/config/src/chainConfig/networks/sepolia.ts index 39e72a24f3f6..e7e5dc76f691 100644 --- a/packages/config/src/chainConfig/networks/sepolia.ts +++ b/packages/config/src/chainConfig/networks/sepolia.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; diff --git a/packages/config/src/chainConfig/types.ts b/packages/config/src/chainConfig/types.ts index 05fff02f2eaf..5c06b205c2f6 100644 --- a/packages/config/src/chainConfig/types.ts +++ b/packages/config/src/chainConfig/types.ts @@ -1,7 +1,5 @@ import {PresetName} from "@lodestar/params"; -/* eslint-disable @typescript-eslint/naming-convention */ - /** * Run-time chain configuration */ diff --git a/packages/config/test/unit/index.test.ts b/packages/config/test/unit/index.test.ts index a6fca7ad643a..bde31f6b1477 100644 --- a/packages/config/test/unit/index.test.ts +++ b/packages/config/test/unit/index.test.ts @@ -31,7 +31,6 @@ describe("forks", () => { }); it("correctly handle pre-genesis", () => { - // eslint-disable-next-line @typescript-eslint/naming-convention const postMergeTestnet = createForkConfig({...chainConfig, ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0}); expect(postMergeTestnet.getForkName(-1)).toBe(ForkName.bellatrix); }); diff --git a/packages/db/package.json b/packages/db/package.json index 0e3a2c847d4b..2a10d36766bf 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -28,8 +28,8 @@ "build:release": "yarn clean && yarn run build", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" diff --git a/packages/db/src/abstractRepository.ts b/packages/db/src/abstractRepository.ts index e0462d162ddc..5d5b0763ba26 100644 --- a/packages/db/src/abstractRepository.ts +++ b/packages/db/src/abstractRepository.ts @@ -142,7 +142,7 @@ export abstract class Repository { async batchRemove(values: T[]): Promise { // handle single value in batchDelete - await this.batchDelete(Array.from({length: values.length}, (ignored, i) => this.getId(values[i]))); + await this.batchDelete(Array.from({length: values.length}, (_ignored, i) => this.getId(values[i]))); } async keys(opts?: FilterOptions): Promise { diff --git a/packages/db/test/unit/controller/level.test.ts b/packages/db/test/unit/controller/level.test.ts index 11ef0f929fda..16f20e770c93 100644 --- a/packages/db/test/unit/controller/level.test.ts +++ b/packages/db/test/unit/controller/level.test.ts @@ -137,7 +137,7 @@ describe("LevelDB controller", () => { if (res?.startsWith("Usage: gdu ")) { return "gdu"; } - } catch { + } catch (_e) { /* eslint-disable no-console */ console.error("Cannot find gdu command, falling back to du"); } diff --git a/packages/flare/package.json b/packages/flare/package.json index 3a11e9b49ebf..a08e5fe0edc1 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -41,8 +41,8 @@ "build:watch": "yarn run build --watch", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\" flare --help", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" diff --git a/packages/flare/src/index.ts b/packages/flare/src/index.ts index bc10fff9181c..5f3b85b459c1 100644 --- a/packages/flare/src/index.ts +++ b/packages/flare/src/index.ts @@ -12,7 +12,6 @@ void flare // Show command help message when no command is provided if (msg.includes("Not enough non-option arguments")) { yarg.showHelp(); - // eslint-disable-next-line no-console console.log("\n"); } } @@ -20,7 +19,6 @@ void flare const errorMessage = err !== undefined ? (err instanceof YargsError ? err.message : err.stack) : msg || "Unknown error"; - // eslint-disable-next-line no-console console.error(` ✖ ${errorMessage}\n`); process.exit(1); }) diff --git a/packages/fork-choice/package.json b/packages/fork-choice/package.json index 728036b365d3..2197ad90a9fd 100644 --- a/packages/fork-choice/package.json +++ b/packages/fork-choice/package.json @@ -29,8 +29,8 @@ "build:release": "yarn clean && yarn run build", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" diff --git a/packages/fork-choice/src/forkChoice/errors.ts b/packages/fork-choice/src/forkChoice/errors.ts index ea0c6305ba42..43d209106eed 100644 --- a/packages/fork-choice/src/forkChoice/errors.ts +++ b/packages/fork-choice/src/forkChoice/errors.ts @@ -95,8 +95,4 @@ export type ForkChoiceErrorType = | {code: ForkChoiceErrorCode.UNABLE_TO_SET_JUSTIFIED_CHECKPOINT; error: Error} | {code: ForkChoiceErrorCode.AFTER_BLOCK_FAILED; error: Error}; -export class ForkChoiceError extends LodestarError { - constructor(type: ForkChoiceErrorType) { - super(type); - } -} +export class ForkChoiceError extends LodestarError {} diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index 6ae3f52e7d3a..828a16725444 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -198,6 +198,7 @@ export class ForkChoice implements IForkChoice { return {head, isHeadTimely, notReorgedReason}; } case UpdateHeadOpt.GetCanonicialHead: + return {head: canonicialHeadBlock}; default: return {head: canonicialHeadBlock}; } @@ -413,7 +414,8 @@ export class ForkChoice implements IForkChoice { }); } - return (this.head = headNode); + this.head = headNode; + return this.head; } /** diff --git a/packages/fork-choice/src/forkChoice/store.ts b/packages/fork-choice/src/forkChoice/store.ts index d16e021529db..2cd4da512870 100644 --- a/packages/fork-choice/src/forkChoice/store.ts +++ b/packages/fork-choice/src/forkChoice/store.ts @@ -55,18 +55,22 @@ export class ForkChoiceStore implements IForkChoiceStore { private _finalizedCheckpoint: CheckpointWithHex; unrealizedFinalizedCheckpoint: CheckpointWithHex; equivocatingIndices = new Set(); + justifiedBalancesGetter: JustifiedBalancesGetter; + currentSlot: Slot; constructor( - public currentSlot: Slot, + currentSlot: Slot, justifiedCheckpoint: phase0.Checkpoint, finalizedCheckpoint: phase0.Checkpoint, justifiedBalances: EffectiveBalanceIncrements, - public justifiedBalancesGetter: JustifiedBalancesGetter, + justifiedBalancesGetter: JustifiedBalancesGetter, private readonly events?: { onJustified: (cp: CheckpointWithHex) => void; onFinalized: (cp: CheckpointWithHex) => void; } ) { + this.justifiedBalancesGetter = justifiedBalancesGetter; + this.currentSlot = currentSlot; const justified = { checkpoint: toCheckpointWithHex(justifiedCheckpoint), balances: justifiedBalances, diff --git a/packages/fork-choice/src/protoArray/errors.ts b/packages/fork-choice/src/protoArray/errors.ts index 2e044de154e1..650fd1c0b244 100644 --- a/packages/fork-choice/src/protoArray/errors.ts +++ b/packages/fork-choice/src/protoArray/errors.ts @@ -56,8 +56,4 @@ export type ProtoArrayErrorType = | {code: ProtoArrayErrorCode.INVALID_JUSTIFIED_EXECUTION_STATUS; root: RootHex} | ({code: ProtoArrayErrorCode.INVALID_LVH_EXECUTION_RESPONSE} & LVHExecError); -export class ProtoArrayError extends LodestarError { - constructor(type: ProtoArrayErrorType) { - super(type); - } -} +export class ProtoArrayError extends LodestarError {} diff --git a/packages/fork-choice/src/protoArray/protoArray.ts b/packages/fork-choice/src/protoArray/protoArray.ts index 0b793d2be099..b8bb63837e36 100644 --- a/packages/fork-choice/src/protoArray/protoArray.ts +++ b/packages/fork-choice/src/protoArray/protoArray.ts @@ -964,7 +964,6 @@ export class ProtoArray { * Returns a common ancestor for nodeA or nodeB or null if there's none */ getCommonAncestor(nodeA: ProtoNode, nodeB: ProtoNode): ProtoNode | null { - // eslint-disable-next-line no-constant-condition while (true) { // If nodeA is higher than nodeB walk up nodeA tree if (nodeA.slot > nodeB.slot) { diff --git a/packages/fork-choice/test/unit/forkChoice/utils.test.ts b/packages/fork-choice/test/unit/forkChoice/utils.test.ts index 3f315d079842..d8793206f4ba 100644 --- a/packages/fork-choice/test/unit/forkChoice/utils.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/utils.test.ts @@ -4,7 +4,6 @@ import {ssz} from "@lodestar/types"; import {assertValidTerminalPowBlock, ExecutionStatus} from "../../../src/index.js"; describe("assertValidTerminalPowBlock", function () { - // eslint-disable-next-line @typescript-eslint/naming-convention const config = createChainForkConfig({TERMINAL_TOTAL_DIFFICULTY: BigInt(10)}); const block = ssz.bellatrix.BeaconBlock.defaultValue(); const executionStatus = ExecutionStatus.Valid; diff --git a/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts b/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts index fdf1a1f3bae4..9c06682ca351 100644 --- a/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts +++ b/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts @@ -77,7 +77,7 @@ describe("getCommonAncestor", () => { for (const {nodeA, nodeB, ancestor} of testCases) { it(`${nodeA} & ${nodeB} -> ${ancestor}`, () => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + // biome-ignore lint/style/noNonNullAssertion: const ancestorNode = fc.getCommonAncestor(fc.getNode(nodeA)!, fc.getNode(nodeB)!); expect(ancestorNode && ancestorNode.blockRoot).toBe(ancestor); }); diff --git a/packages/light-client/package.json b/packages/light-client/package.json index 2eda3a45d455..a503d6bc510e 100644 --- a/packages/light-client/package.json +++ b/packages/light-client/package.json @@ -62,8 +62,8 @@ "check-bundle": "node -e \"(async function() { await import('./dist/lightclient.min.mjs') })()\"", "build:release": "yarn clean && yarn run build && yarn run build:bundle", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "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", diff --git a/packages/light-client/src/events.ts b/packages/light-client/src/events.ts index 5b561718e89e..7c01843d8ad0 100644 --- a/packages/light-client/src/events.ts +++ b/packages/light-client/src/events.ts @@ -15,7 +15,7 @@ export type LightclientEmitterEvents = { export type LightclientEmitter = MittEmitter; -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: export type MittEmitter void>> = { on(type: K, handler: T[K]): void; off(type: K, handler: T[K]): void; diff --git a/packages/light-client/src/index.ts b/packages/light-client/src/index.ts index 5ec0dd73b469..098ea18adc31 100644 --- a/packages/light-client/src/index.ts +++ b/packages/light-client/src/index.ts @@ -224,7 +224,6 @@ export class Lightclient { } private async runLoop(): Promise { - // eslint-disable-next-line no-constant-condition while (true) { const currentPeriod = computeSyncPeriodAtSlot(this.currentSlot); // Check if we have a sync committee for the current clock period diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 408412464606..d80b9bb7d9a1 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -106,7 +106,6 @@ export function upgradeLightClientHeader( // Break if no further upgradation is required else fall through if (ForkSeq[targetFork] <= ForkSeq.bellatrix) break; - // eslint-disable-next-line no-fallthrough case ForkName.capella: (upgradedHeader as LightClientHeader).execution = ssz.capella.LightClientHeader.fields.execution.defaultValue(); @@ -116,7 +115,6 @@ export function upgradeLightClientHeader( // Break if no further upgradation is required else fall through if (ForkSeq[targetFork] <= ForkSeq.capella) break; - // eslint-disable-next-line no-fallthrough case ForkName.deneb: (upgradedHeader as LightClientHeader).execution.blobGasUsed = ssz.deneb.LightClientHeader.fields.execution.fields.blobGasUsed.defaultValue(); @@ -126,7 +124,6 @@ export function upgradeLightClientHeader( // Break if no further upgradation is required else fall through if (ForkSeq[targetFork] <= ForkSeq.deneb) break; - // eslint-disable-next-line no-fallthrough case ForkName.electra: // No changes to LightClientHeader in Electra diff --git a/packages/light-client/src/utils/logger.ts b/packages/light-client/src/utils/logger.ts index afdbf7da7d3d..1f13b98bd6c6 100644 --- a/packages/light-client/src/utils/logger.ts +++ b/packages/light-client/src/utils/logger.ts @@ -1,4 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: export type LogHandler = (message: string, context?: any, error?: Error) => void; export type ILcLogger = { diff --git a/packages/light-client/test/unit/isValidLightClientHeader.test.ts b/packages/light-client/test/unit/isValidLightClientHeader.test.ts index db27a8266103..8181c6a5def4 100644 --- a/packages/light-client/test/unit/isValidLightClientHeader.test.ts +++ b/packages/light-client/test/unit/isValidLightClientHeader.test.ts @@ -5,7 +5,6 @@ import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lo import {isValidLightClientHeader} from "../../src/spec/utils.js"; describe("isValidLightClientHeader", function () { - /* eslint-disable @typescript-eslint/naming-convention */ const chainConfig = createChainForkConfig({ ...defaultChainConfig, ALTAIR_FORK_EPOCH: 0, diff --git a/packages/light-client/test/unit/sync.node.test.ts b/packages/light-client/test/unit/sync.node.test.ts index bcd1d0f25d0b..52afd05760d7 100644 --- a/packages/light-client/test/unit/sync.node.test.ts +++ b/packages/light-client/test/unit/sync.node.test.ts @@ -45,7 +45,6 @@ describe("sync", () => { const targetSlot = firstHeadSlot + slotsIntoPeriod; // Genesis data such that targetSlot is at the current clock slot - // eslint-disable-next-line @typescript-eslint/naming-convention const chainConfig: ChainConfig = {...chainConfigDef, SECONDS_PER_SLOT, ALTAIR_FORK_EPOCH}; const genesisTime = Math.floor(Date.now() / 1000) - chainConfig.SECONDS_PER_SLOT * targetSlot; const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); diff --git a/packages/logger/package.json b/packages/logger/package.json index 196fb306a8b0..3d6ee5a0d874 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -53,8 +53,8 @@ "build:release": "yarn clean && yarn build", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit && yarn test:e2e", "test:unit": "vitest --run --dir test/unit/", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", diff --git a/packages/logger/src/browser.ts b/packages/logger/src/browser.ts index fc91fcfcd2a3..65a0c2a6a64b 100644 --- a/packages/logger/src/browser.ts +++ b/packages/logger/src/browser.ts @@ -70,9 +70,7 @@ class BrowserConsole extends Transport { const message = info[MESSAGE]; if (val <= this.levels[this.level as LogLevel]) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, no-console console[mappedMethod](message); } diff --git a/packages/logger/src/interface.ts b/packages/logger/src/interface.ts index 8f270b0dc4ee..e3ba8483a458 100644 --- a/packages/logger/src/interface.ts +++ b/packages/logger/src/interface.ts @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-extraneous-dependencies import {LEVEL, MESSAGE} from "triple-beam"; import {LogLevel, Logger, LogHandler, LogData} from "@lodestar/utils"; @@ -15,7 +14,6 @@ export const logLevelNum: {[K in LogLevel]: number} = { [LogLevel.trace]: 5, }; -// eslint-disable-next-line @typescript-eslint/naming-convention export const LogLevels = Object.values(LogLevel); export type LogFormat = "human" | "json"; diff --git a/packages/logger/src/utils/consoleTransport.ts b/packages/logger/src/utils/consoleTransport.ts index 41a1084b4b83..6bfd62b2ecd8 100644 --- a/packages/logger/src/utils/consoleTransport.ts +++ b/packages/logger/src/utils/consoleTransport.ts @@ -26,6 +26,7 @@ export class ConsoleDynamicLevel extends transports.Console { return this.levelByModule.delete(module); } + // biome-ignore lint/correctness/noUndeclaredVariables: BufferEncoding is not been identified by the biomejs _write(info: WinstonLogInfo, enc: BufferEncoding, callback: (error?: Error | null | undefined) => void): void { const moduleLevel = this.levelByModule.get(info.module) ?? this.defaultLevel; diff --git a/packages/logger/src/utils/format.ts b/packages/logger/src/utils/format.ts index 651dc56ce687..4e657c0040af 100644 --- a/packages/logger/src/utils/format.ts +++ b/packages/logger/src/utils/format.ts @@ -21,8 +21,8 @@ export function getFormat(opts: LoggerOptions): Format { switch (opts.format) { case "json": return jsonLogFormat(opts); - case "human": + return humanReadableLogFormat(opts); default: return humanReadableLogFormat(opts); } @@ -49,6 +49,7 @@ function formatTimestamp(opts: LoggerOptions): Format { }; case TimestampFormatCode.DateRegular: + return format.timestamp({format: "MMM-DD HH:mm:ss.SSS"}); default: return format.timestamp({format: "MMM-DD HH:mm:ss.SSS"}); } @@ -70,7 +71,8 @@ function jsonLogFormat(opts: LoggerOptions): Format { /** * Winston template function print a human readable string given a log object */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any + +// biome-ignore lint/suspicious/noExplicitAny: function humanReadableTemplateFn(_info: {[key: string]: any; level: string; message: string}): string { const info = _info as WinstonInfoArg; diff --git a/packages/logger/src/utils/json.ts b/packages/logger/src/utils/json.ts index 7408de582dd1..f1919a38da8b 100644 --- a/packages/logger/src/utils/json.ts +++ b/packages/logger/src/utils/json.ts @@ -127,6 +127,7 @@ export function logCtxToString(arg: unknown, depth = 0, fromError = false): stri case "string": case "undefined": case "boolean": + return String(arg); default: return String(arg); } diff --git a/packages/logger/test/e2e/logger/workerLogger.js b/packages/logger/test/e2e/logger/workerLogger.js index 9608336c433f..83d1c857631f 100644 --- a/packages/logger/test/e2e/logger/workerLogger.js +++ b/packages/logger/test/e2e/logger/workerLogger.js @@ -9,7 +9,6 @@ if (!parentPort) throw Error("parentPort must be defined"); const file = fs.createWriteStream(workerData.logFilepath, {flags: "a"}); parentPort.on("message", (data) => { - // eslint-disable-next-line no-console console.log(data); file.write(data); }); diff --git a/packages/logger/test/e2e/logger/workerLogs.test.ts b/packages/logger/test/e2e/logger/workerLogs.test.ts index 3c81cbf92c57..969cd84bc5ff 100644 --- a/packages/logger/test/e2e/logger/workerLogs.test.ts +++ b/packages/logger/test/e2e/logger/workerLogs.test.ts @@ -7,7 +7,6 @@ import {LoggerWorker, getLoggerWorker} from "./workerLoggerHandler.js"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); describe("worker logs", function () { diff --git a/packages/logger/test/unit/node.node.test.ts b/packages/logger/test/unit/node.node.test.ts index 12782fa49af8..da1245fa37f1 100644 --- a/packages/logger/test/unit/node.node.test.ts +++ b/packages/logger/test/unit/node.node.test.ts @@ -6,7 +6,6 @@ import {formatsTestCases} from "../fixtures/loggerFormats.js"; // Node.js maps `process.stdout` to `console._stdout`. // spy does not work on `process.stdout` directly. -// eslint-disable-next-line @typescript-eslint/naming-convention type TestConsole = typeof console & {_stdout: {write: Mock}}; describe("node logger", () => { diff --git a/packages/logger/test/unit/utils/json.test.ts b/packages/logger/test/unit/utils/json.test.ts index 912f15fa958b..4b91fd1995b5 100644 --- a/packages/logger/test/unit/utils/json.test.ts +++ b/packages/logger/test/unit/utils/json.test.ts @@ -113,7 +113,6 @@ describe("Json helper", () => { // Circular references () => { const circularReference: any = {}; - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access circularReference.myself = circularReference; return { id: "circular reference", @@ -161,7 +160,6 @@ describe("Json helper", () => { // Objects {id: "object of basic types", json: {a: 1, b: "a", c: root}, output: `a=1, b=a, c=${rootHex}`}, - // eslint-disable-next-line quotes {id: "object of objects", json: {a: {b: 1}}, output: `a=[object]`}, { id: "error metadata", @@ -175,7 +173,6 @@ describe("Json helper", () => { // Circular references () => { const circularReference: any = {}; - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access circularReference.myself = circularReference; return { id: "circular reference", diff --git a/packages/logger/test/unit/winston.node.test.ts b/packages/logger/test/unit/winston.node.test.ts index 8ef49da4e02d..6763cc667afd 100644 --- a/packages/logger/test/unit/winston.node.test.ts +++ b/packages/logger/test/unit/winston.node.test.ts @@ -8,7 +8,6 @@ import {readFileWhenExists} from "../utils/files.js"; // Node.js maps `process.stdout` to `console._stdout`. // spy does not work on `process.stdout` directly. -// eslint-disable-next-line @typescript-eslint/naming-convention type TestConsole = typeof console & {_stdout: {write: Mock}}; describe("winston logger", () => { diff --git a/packages/params/package.json b/packages/params/package.json index c281f97a41ec..33b8415170f1 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -50,8 +50,8 @@ "build:watch": "yarn run build --watch", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "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", diff --git a/packages/params/src/presets/gnosis.ts b/packages/params/src/presets/gnosis.ts index 412c38a6eb82..5a4a2eac4113 100644 --- a/packages/params/src/presets/gnosis.ts +++ b/packages/params/src/presets/gnosis.ts @@ -4,7 +4,6 @@ import {mainnetPreset} from "./mainnet.js"; // Gnosis preset // https://github.com/gnosischain/specs/tree/master/consensus/preset/gnosis -/* eslint-disable @typescript-eslint/naming-convention */ export const gnosisPreset: BeaconPreset = { ...mainnetPreset, diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index ca599e990df4..a7225739037f 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -3,7 +3,6 @@ import {BeaconPreset} from "../types.js"; // Mainnet preset // https://github.com/ethereum/consensus-specs/tree/dev/presets/mainnet -/* eslint-disable @typescript-eslint/naming-convention */ export const mainnetPreset: BeaconPreset = { // Misc // --------------------------------------------------------------- diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 5dc8fc10d803..d7ab2c27f342 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -3,7 +3,6 @@ import {BeaconPreset} from "../types.js"; // Minimal preset // https://github.com/ethereum/consensus-specs/tree/dev/presets/minimal -/* eslint-disable @typescript-eslint/naming-convention */ export const minimalPreset: BeaconPreset = { // Misc // --------------------------------------------------------------- diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index e867b4a3cf71..2fd88da9fde3 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ - /** * Compile-time chain configuration */ diff --git a/packages/params/test/e2e/ensure-config-is-synced.test.ts b/packages/params/test/e2e/ensure-config-is-synced.test.ts index 38168fa02bae..12e4c2a35e55 100644 --- a/packages/params/test/e2e/ensure-config-is-synced.test.ts +++ b/packages/params/test/e2e/ensure-config-is-synced.test.ts @@ -44,7 +44,6 @@ async function downloadRemoteConfig(preset: "mainnet" | "minimal", commit: strin ); // Merge all the fetched yamls for the different forks - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const beaconPresetRaw: Record = Object.assign( ...(downloadedParams as unknown as [input: Record]) ); diff --git a/packages/params/test/e2e/overridePreset.test.ts b/packages/params/test/e2e/overridePreset.test.ts index 24995cbaa042..12fa1fb095c6 100644 --- a/packages/params/test/e2e/overridePreset.test.ts +++ b/packages/params/test/e2e/overridePreset.test.ts @@ -13,7 +13,6 @@ const exec = util.promisify(child.exec); // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); describe("Override preset", function () { diff --git a/packages/params/test/e2e/overridePresetError.ts b/packages/params/test/e2e/overridePresetError.ts index d5a665bece1f..869f521d33b5 100644 --- a/packages/params/test/e2e/overridePresetError.ts +++ b/packages/params/test/e2e/overridePresetError.ts @@ -5,5 +5,4 @@ import "../../lib/index.js"; import {setActivePreset, PresetName} from "../../lib/setPreset.js"; // This line should throw -// eslint-disable-next-line @typescript-eslint/naming-convention setActivePreset(PresetName.minimal, {SLOTS_PER_EPOCH: 2}); diff --git a/packages/params/test/e2e/overridePresetOk.ts b/packages/params/test/e2e/overridePresetOk.ts index 7373ecee7fff..8887155b5400 100644 --- a/packages/params/test/e2e/overridePresetOk.ts +++ b/packages/params/test/e2e/overridePresetOk.ts @@ -6,7 +6,6 @@ import assert from "node:assert"; // 1. Import from @lodestar/params/setPreset only import {setActivePreset, PresetName} from "../../src/setPreset.js"; -// eslint-disable-next-line @typescript-eslint/naming-convention setActivePreset(PresetName.minimal, {SLOTS_PER_EPOCH: 2}); // 2. Import from any other @lodestar/params paths diff --git a/packages/params/test/e2e/setPreset.test.ts b/packages/params/test/e2e/setPreset.test.ts index 844239d56bab..1e236b8f2d85 100644 --- a/packages/params/test/e2e/setPreset.test.ts +++ b/packages/params/test/e2e/setPreset.test.ts @@ -13,7 +13,6 @@ const exec = util.promisify(child.exec); // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); describe("setPreset", function () { diff --git a/packages/params/test/yaml.ts b/packages/params/test/yaml.ts index 162d48bc4084..d1bc72125923 100644 --- a/packages/params/test/yaml.ts +++ b/packages/params/test/yaml.ts @@ -9,7 +9,6 @@ export const schema = FAILSAFE_SCHEMA.extend({ new Type("tag:yaml.org,2002:str", { kind: "scalar", construct: function (data) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return data !== null ? data : ""; }, }), diff --git a/packages/prover/package.json b/packages/prover/package.json index 6a31b5b1baa0..9bfe7f21e480 100644 --- a/packages/prover/package.json +++ b/packages/prover/package.json @@ -48,8 +48,8 @@ "build:release": "yarn clean && yarn run build", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit && yarn test:e2e", "test:unit": "vitest --run --dir test/unit/", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", diff --git a/packages/prover/scripts/generate_fixtures.ts b/packages/prover/scripts/generate_fixtures.ts index 70ab31fed5c1..b5d1d18d89f1 100644 --- a/packages/prover/scripts/generate_fixtures.ts +++ b/packages/prover/scripts/generate_fixtures.ts @@ -2,9 +2,7 @@ import {writeFile, mkdir} from "node:fs/promises"; import path from "node:path"; import url from "node:url"; -// eslint-disable-next-line import/no-extraneous-dependencies import axios from "axios"; -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); type JSONRequest = {method: string; params: unknown[]}; @@ -95,17 +93,14 @@ async function generateFixture(label: string, generator: Generator, network: NET } const beacon = { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - executionPayload: ((await rawBeacon(network, `eth/v2/beacon/blocks/${slot}`)) as any).data.message.body + executionPayload: ((await rawBeacon(network, `eth/v2/beacon/blocks/${slot}`)) as any).data.message.body .execution_payload, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any - headers: ((await rawBeacon(network, `eth/v1/beacon/headers/${slot}`)) as any).data, + headers: ((await rawBeacon(network, `eth/v1/beacon/headers/${slot}`)) as any).data, }; const payloadBlock = await getBlockByHash( network, - // eslint-disable-next-line @typescript-eslint/naming-convention - (beacon.executionPayload as {block_hash: string}).block_hash, + (beacon.executionPayload as {block_hash: string}).block_hash, true ); diff --git a/packages/prover/src/cli/applyPreset.ts b/packages/prover/src/cli/applyPreset.ts index 158e05243ec7..4a79a1a4417b 100644 --- a/packages/prover/src/cli/applyPreset.ts +++ b/packages/prover/src/cli/applyPreset.ts @@ -1,8 +1,6 @@ // MUST import this file first before anything and not import any Lodestar code. -// eslint-disable-next-line no-restricted-imports, import/no-extraneous-dependencies import {hasher} from "@chainsafe/persistent-merkle-tree/lib/hasher/as-sha256.js"; -// eslint-disable-next-line no-restricted-imports, import/no-extraneous-dependencies import {setHasher} from "@chainsafe/persistent-merkle-tree/lib/hasher/index.js"; // without setting this first, persistent-merkle-tree will use noble instead @@ -45,7 +43,6 @@ else if (network) { if (network === "dev") { process.env.LODESTAR_PRESET = "minimal"; // "c-kzg" has hardcoded the mainnet value, do not use presets - // eslint-disable-next-line @typescript-eslint/naming-convention setActivePreset(PresetName.minimal, {FIELD_ELEMENTS_PER_BLOB: 4096}); } else if (network === "gnosis" || network === "chiado") { process.env.LODESTAR_PRESET = "gnosis"; diff --git a/packages/prover/src/cli/cmds/start/options.ts b/packages/prover/src/cli/cmds/start/options.ts index f63ee974be44..bdf0670771ef 100644 --- a/packages/prover/src/cli/cmds/start/options.ts +++ b/packages/prover/src/cli/cmds/start/options.ts @@ -57,7 +57,9 @@ export const startOptions: CliCommandOptions = { string: true, coerce: (urls: string[]): string[] => // Parse ["url1,url2"] to ["url1", "url2"] - urls.map((item) => item.split(",")).flat(), + urls + .map((item) => item.split(",")) + .flat(), demandOption: true, group: "beacon", }, diff --git a/packages/prover/src/cli/index.ts b/packages/prover/src/cli/index.ts index 845831b32cb0..5bd071642c96 100644 --- a/packages/prover/src/cli/index.ts +++ b/packages/prover/src/cli/index.ts @@ -14,7 +14,7 @@ void prover // Show command help message when no command is provided if (msg.includes("Not enough non-option arguments")) { yarg.showHelp(); - // eslint-disable-next-line no-console + // biome-ignore lint/suspicious/noConsoleLog: This code will run only in browser so console will be available. console.log("\n"); } } @@ -22,7 +22,6 @@ void prover const errorMessage = err !== undefined ? (err instanceof YargsError ? err.message : err.stack) : msg || "Unknown error"; - // eslint-disable-next-line no-console console.error(` ✖ ${errorMessage}\n`); process.exit(1); }) diff --git a/packages/prover/src/interfaces.ts b/packages/prover/src/interfaces.ts index 36222c1476d3..9a67b47ea3b3 100644 --- a/packages/prover/src/interfaces.ts +++ b/packages/prover/src/interfaces.ts @@ -27,7 +27,7 @@ export type ELRequestHandler = ( payload: JsonRpcRequestOrBatch ) => Promise | undefined>; -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: export type ELRequestHandlerAny = ELRequestHandler; /** diff --git a/packages/prover/src/types.ts b/packages/prover/src/types.ts index 781ba1f7b207..d404cd96d4d8 100644 --- a/packages/prover/src/types.ts +++ b/packages/prover/src/types.ts @@ -45,17 +45,17 @@ export interface JsonRpcResponseWithErrorPayload { } // Make the very flexible el response type to match different libraries easily -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: export type JsonRpcResponse = | JsonRpcResponseWithResultPayload | JsonRpcResponseWithErrorPayload; -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: export type JsonRpcBatchResponse = JsonRpcResponse[]; // Response can be a single response or an array of responses in case of batch request // Make the very flexible el response type to match different libraries easily -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: export type JsonRpcResponseOrBatch = JsonRpcResponse | JsonRpcBatchResponse; export type HexString = string; @@ -145,7 +145,6 @@ export interface ELAccessListResponse { 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; diff --git a/packages/prover/src/utils/conversion.ts b/packages/prover/src/utils/conversion.ts index c809de5c4555..77c3141f828a 100644 --- a/packages/prover/src/utils/conversion.ts +++ b/packages/prover/src/utils/conversion.ts @@ -58,7 +58,6 @@ export function headerDataFromELBlock(blockInfo: ELBlock): HeaderData { }; } -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function txDataFromELBlock(txInfo: ELTransaction) { return { ...txInfo, diff --git a/packages/prover/src/utils/evm.ts b/packages/prover/src/utils/evm.ts index 19f43d9584c8..40950647b8f3 100644 --- a/packages/prover/src/utils/evm.ts +++ b/packages/prover/src/utils/evm.ts @@ -20,7 +20,7 @@ export async function createVM({proofProvider}: {proofProvider: ProofProvider}): const blockchain = await Blockchain.create({common}); // Connect blockchain object with existing proof provider for block history - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: (blockchain as any).getBlock = async (blockId: number) => { const payload = await proofProvider.getExecutionPayload(blockId); return { diff --git a/packages/prover/src/utils/file.ts b/packages/prover/src/utils/file.ts index d236d2d5dc95..acc62033010f 100644 --- a/packages/prover/src/utils/file.ts +++ b/packages/prover/src/utils/file.ts @@ -15,7 +15,6 @@ const yamlSchema = FAILSAFE_SCHEMA.extend({ new Type("tag:yaml.org,2002:str", { kind: "scalar", construct: function construct(data) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return data !== null ? data : ""; }, }), diff --git a/packages/prover/src/utils/gitData/gitDataPath.ts b/packages/prover/src/utils/gitData/gitDataPath.ts index e243ca433f2d..1ad3104aafc6 100644 --- a/packages/prover/src/utils/gitData/gitDataPath.ts +++ b/packages/prover/src/utils/gitData/gitDataPath.ts @@ -4,7 +4,6 @@ import {fileURLToPath} from "node:url"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); // Persist git data and distribute through NPM so CLI consumers can know exactly diff --git a/packages/prover/src/utils/gitData/index.ts b/packages/prover/src/utils/gitData/index.ts index 96c5e4bbaef2..0720d39d9e30 100644 --- a/packages/prover/src/utils/gitData/index.ts +++ b/packages/prover/src/utils/gitData/index.ts @@ -11,7 +11,7 @@ export function readAndGetGitData(): GitData { let persistedGitData: Partial; try { persistedGitData = readGitDataFile(); - } catch (e) { + } catch (_e) { persistedGitData = {}; } @@ -23,13 +23,13 @@ export function readAndGetGitData(): GitData { branch: currentGitData.branch && currentGitData.branch.length > 0 ? currentGitData.branch - : persistedGitData.branch ?? "", + : (persistedGitData.branch ?? ""), commit: currentGitData.commit && currentGitData.commit.length > 0 ? currentGitData.commit - : persistedGitData.commit ?? "", + : (persistedGitData.commit ?? ""), }; - } catch (e) { + } catch (_e) { return { branch: "", commit: "", @@ -49,7 +49,7 @@ export function getGitData(): GitData { function getBranch(): string { try { return shellSilent("git rev-parse --abbrev-ref HEAD"); - } catch (e) { + } catch (_e) { return ""; } } @@ -58,7 +58,7 @@ function getBranch(): string { function getCommit(): string { try { return shellSilent("git rev-parse --verify HEAD"); - } catch (e) { + } catch (_e) { return ""; } } diff --git a/packages/prover/src/utils/process.ts b/packages/prover/src/utils/process.ts index 26768ffce1fb..80748544302c 100644 --- a/packages/prover/src/utils/process.ts +++ b/packages/prover/src/utils/process.ts @@ -13,7 +13,7 @@ import {getResponseForRequest, isBatchRequest, isRequest} from "./json_rpc.js"; import {isNullish} from "./validation.js"; import {ELRpcProvider} from "./rpc_provider.js"; -/* eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any */ +// biome-ignore lint/suspicious/noExplicitAny: export const verifiableMethodHandlers: Record> = { eth_getBalance: eth_getBalance, eth_getTransactionCount: eth_getTransactionCount, diff --git a/packages/prover/src/utils/version.ts b/packages/prover/src/utils/version.ts index 4752856e5b1d..624412107603 100644 --- a/packages/prover/src/utils/version.ts +++ b/packages/prover/src/utils/version.ts @@ -6,7 +6,6 @@ import {readAndGetGitData} from "./gitData/index.js"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); type VersionJson = { diff --git a/packages/prover/src/verified_requests/eth_call.ts b/packages/prover/src/verified_requests/eth_call.ts index b28bd222c568..eea7ba146c3f 100644 --- a/packages/prover/src/verified_requests/eth_call.ts +++ b/packages/prover/src/verified_requests/eth_call.ts @@ -8,7 +8,6 @@ import { getVerificationFailedMessage, } from "../utils/json_rpc.js"; -// eslint-disable-next-line @typescript-eslint/naming-convention export const eth_call: ELVerifiedRequestHandler = async ({ rpc, payload, diff --git a/packages/prover/src/verified_requests/eth_estimateGas.ts b/packages/prover/src/verified_requests/eth_estimateGas.ts index fee446aadb5b..4ac4c3ccb6bc 100644 --- a/packages/prover/src/verified_requests/eth_estimateGas.ts +++ b/packages/prover/src/verified_requests/eth_estimateGas.ts @@ -8,7 +8,6 @@ import { getVerificationFailedMessage, } from "../utils/json_rpc.js"; -// eslint-disable-next-line @typescript-eslint/naming-convention export const eth_estimateGas: ELVerifiedRequestHandler< ELApiParams["eth_estimateGas"], ELApiReturn["eth_estimateGas"] diff --git a/packages/prover/src/verified_requests/eth_getBalance.ts b/packages/prover/src/verified_requests/eth_getBalance.ts index b5b7e63dcb64..0c03b23be788 100644 --- a/packages/prover/src/verified_requests/eth_getBalance.ts +++ b/packages/prover/src/verified_requests/eth_getBalance.ts @@ -6,7 +6,6 @@ import { getVerificationFailedMessage, } from "../utils/json_rpc.js"; -// eslint-disable-next-line @typescript-eslint/naming-convention export const eth_getBalance: ELVerifiedRequestHandler<[address: string, block?: number | string], string> = async ({ rpc, payload, diff --git a/packages/prover/src/verified_requests/eth_getBlockByHash.ts b/packages/prover/src/verified_requests/eth_getBlockByHash.ts index cb5fa1711c0f..00a110c01e9a 100644 --- a/packages/prover/src/verified_requests/eth_getBlockByHash.ts +++ b/packages/prover/src/verified_requests/eth_getBlockByHash.ts @@ -7,7 +7,6 @@ import { getVerificationFailedMessage, } from "../utils/json_rpc.js"; -// eslint-disable-next-line @typescript-eslint/naming-convention export const eth_getBlockByHash: ELVerifiedRequestHandler<[block: string, hydrated: boolean], ELBlock> = async ({ rpc, payload, diff --git a/packages/prover/src/verified_requests/eth_getBlockByNumber.ts b/packages/prover/src/verified_requests/eth_getBlockByNumber.ts index a08703881cc0..23e0fa2ca863 100644 --- a/packages/prover/src/verified_requests/eth_getBlockByNumber.ts +++ b/packages/prover/src/verified_requests/eth_getBlockByNumber.ts @@ -7,7 +7,6 @@ import { getVerificationFailedMessage, } from "../utils/json_rpc.js"; -// eslint-disable-next-line @typescript-eslint/naming-convention export const eth_getBlockByNumber: ELVerifiedRequestHandler< [block: string | number, hydrated: boolean], ELBlock diff --git a/packages/prover/src/verified_requests/eth_getCode.ts b/packages/prover/src/verified_requests/eth_getCode.ts index 9cb3362c4e50..f94ae8c1c8bd 100644 --- a/packages/prover/src/verified_requests/eth_getCode.ts +++ b/packages/prover/src/verified_requests/eth_getCode.ts @@ -6,7 +6,6 @@ import { getVerificationFailedMessage, } from "../utils/json_rpc.js"; -// eslint-disable-next-line @typescript-eslint/naming-convention export const eth_getCode: ELVerifiedRequestHandler<[address: string, block?: number | string], string> = async ({ rpc, payload, diff --git a/packages/prover/src/verified_requests/eth_getTransactionCount.ts b/packages/prover/src/verified_requests/eth_getTransactionCount.ts index 4cafd9b2b271..aeef67e96e74 100644 --- a/packages/prover/src/verified_requests/eth_getTransactionCount.ts +++ b/packages/prover/src/verified_requests/eth_getTransactionCount.ts @@ -6,7 +6,6 @@ import { getVerificationFailedMessage, } from "../utils/json_rpc.js"; -// eslint-disable-next-line @typescript-eslint/naming-convention export const eth_getTransactionCount: ELVerifiedRequestHandler< [address: string, block?: number | string], string @@ -15,7 +14,6 @@ export const eth_getTransactionCount: ELVerifiedRequestHandler< params: [address, block], } = payload; const result = await verifyAccount({proofProvider, logger, rpc, address, block}); - if (result.valid) { return getResponseForRequest(payload, result.data.nonce); } diff --git a/packages/prover/test/fixtures/mainnet/eth_call.json b/packages/prover/test/fixtures/mainnet/eth_call.json index 92e9ee557bc2..a3fe44880626 100644 --- a/packages/prover/test/fixtures/mainnet/eth_call.json +++ b/packages/prover/test/fixtures/mainnet/eth_call.json @@ -5226,4 +5226,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/packages/prover/test/fixtures/mainnet/eth_estimateGas_contract_call.json b/packages/prover/test/fixtures/mainnet/eth_estimateGas_contract_call.json index eaae6bc7190d..a8be70662e2b 100644 --- a/packages/prover/test/fixtures/mainnet/eth_estimateGas_contract_call.json +++ b/packages/prover/test/fixtures/mainnet/eth_estimateGas_contract_call.json @@ -5226,4 +5226,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/packages/prover/test/fixtures/mainnet/eth_estimateGas_simple_transfer.json b/packages/prover/test/fixtures/mainnet/eth_estimateGas_simple_transfer.json index f9b654b1a6fa..606e520a441c 100644 --- a/packages/prover/test/fixtures/mainnet/eth_estimateGas_simple_transfer.json +++ b/packages/prover/test/fixtures/mainnet/eth_estimateGas_simple_transfer.json @@ -5227,4 +5227,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/packages/prover/test/fixtures/sepolia/eth_getBalance_contract.json b/packages/prover/test/fixtures/sepolia/eth_getBalance_contract.json index f6e2a31b2b87..660889c259d7 100644 --- a/packages/prover/test/fixtures/sepolia/eth_getBalance_contract.json +++ b/packages/prover/test/fixtures/sepolia/eth_getBalance_contract.json @@ -2704,4 +2704,4 @@ } } ] -} \ No newline at end of file +} diff --git a/packages/prover/test/fixtures/sepolia/eth_getBalance_eoa.json b/packages/prover/test/fixtures/sepolia/eth_getBalance_eoa.json index 03627b534159..a2489403db5b 100644 --- a/packages/prover/test/fixtures/sepolia/eth_getBalance_eoa.json +++ b/packages/prover/test/fixtures/sepolia/eth_getBalance_eoa.json @@ -2703,4 +2703,4 @@ } } ] -} \ No newline at end of file +} diff --git a/packages/prover/test/fixtures/sepolia/eth_getBlock_with_contractCreation.json b/packages/prover/test/fixtures/sepolia/eth_getBlock_with_contractCreation.json index 6b0471a182cf..c61d0e58e35e 100644 --- a/packages/prover/test/fixtures/sepolia/eth_getBlock_with_contractCreation.json +++ b/packages/prover/test/fixtures/sepolia/eth_getBlock_with_contractCreation.json @@ -5,10 +5,7 @@ "id": 809166, "jsonrpc": "2.0", "method": "eth_getBlockByHash", - "params": [ - "0x3a0225b38d5927a37cc95fd48254e83c4e9b70115918a103d9fd7e36464030d4", - true - ] + "params": ["0x3a0225b38d5927a37cc95fd48254e83c4e9b70115918a103d9fd7e36464030d4", true] }, "response": { "jsonrpc": "2.0", @@ -571,4 +568,4 @@ } }, "dependentRequests": [] -} \ No newline at end of file +} diff --git a/packages/prover/test/fixtures/sepolia/eth_getBlock_with_no_accessList.json b/packages/prover/test/fixtures/sepolia/eth_getBlock_with_no_accessList.json index 59bb888450d1..c6c1f9c8d675 100644 --- a/packages/prover/test/fixtures/sepolia/eth_getBlock_with_no_accessList.json +++ b/packages/prover/test/fixtures/sepolia/eth_getBlock_with_no_accessList.json @@ -5,10 +5,7 @@ "id": 809162, "jsonrpc": "2.0", "method": "eth_getBlockByHash", - "params": [ - "0x75b10426177f0f4bd8683999e2c7c597007c6e7c4551d6336c0f880b12c6f3bf", - true - ] + "params": ["0x75b10426177f0f4bd8683999e2c7c597007c6e7c4551d6336c0f880b12c6f3bf", true] }, "response": { "jsonrpc": "2.0", @@ -2381,4 +2378,4 @@ } }, "dependentRequests": [] -} \ No newline at end of file +} diff --git a/packages/prover/test/fixtures/sepolia/eth_getCode.json b/packages/prover/test/fixtures/sepolia/eth_getCode.json index 1787e8cfd2ce..a15c15698420 100644 --- a/packages/prover/test/fixtures/sepolia/eth_getCode.json +++ b/packages/prover/test/fixtures/sepolia/eth_getCode.json @@ -2704,4 +2704,4 @@ } } ] -} \ No newline at end of file +} diff --git a/packages/prover/test/fixtures/sepolia/eth_getTransactionCount.json b/packages/prover/test/fixtures/sepolia/eth_getTransactionCount.json index ff45a5e8a776..486c44698c16 100644 --- a/packages/prover/test/fixtures/sepolia/eth_getTransactionCount.json +++ b/packages/prover/test/fixtures/sepolia/eth_getTransactionCount.json @@ -2703,4 +2703,4 @@ } } ] -} \ No newline at end of file +} diff --git a/packages/prover/test/mocks/request_handler.ts b/packages/prover/test/mocks/request_handler.ts index bbe4f24057de..edde1e59a3fe 100644 --- a/packages/prover/test/mocks/request_handler.ts +++ b/packages/prover/test/mocks/request_handler.ts @@ -116,7 +116,6 @@ export function generateReqHandlerOptionsMock( getExecutionPayload: vi.fn().mockResolvedValue(executionPayload), config: { ...config, - // eslint-disable-next-line @typescript-eslint/naming-convention PRESET_BASE: data.network as unknown as PresetName, }, network: data.network, diff --git a/packages/prover/test/tsconfig.json b/packages/prover/test/tsconfig.json index 7e6bad81b22f..f4241fc1fbcd 100644 --- a/packages/prover/test/tsconfig.json +++ b/packages/prover/test/tsconfig.json @@ -3,4 +3,4 @@ "compilerOptions": { "noEmit": false } -} \ No newline at end of file +} diff --git a/packages/prover/test/unit/verified_requests/eth_getBlockByHash.test.ts b/packages/prover/test/unit/verified_requests/eth_getBlockByHash.test.ts index fca484657c01..3175bdd6d60c 100644 --- a/packages/prover/test/unit/verified_requests/eth_getBlockByHash.test.ts +++ b/packages/prover/test/unit/verified_requests/eth_getBlockByHash.test.ts @@ -3,8 +3,12 @@ import {createForkConfig} from "@lodestar/config"; import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js"; import {eth_getBlockByHash} from "../../../src/verified_requests/eth_getBlockByHash.js"; -import ethGetBlockWithContractCreation from "../../fixtures/sepolia/eth_getBlock_with_contractCreation.json" assert {type: "json"}; -import ethGetBlockWithNoAccessList from "../../fixtures/sepolia/eth_getBlock_with_no_accessList.json" assert {type: "json"}; +import ethGetBlockWithContractCreation from "../../fixtures/sepolia/eth_getBlock_with_contractCreation.json" assert { + type: "json", +}; +import ethGetBlockWithNoAccessList from "../../fixtures/sepolia/eth_getBlock_with_no_accessList.json" assert { + type: "json", +}; import {TestFixture, cloneTestFixture, generateReqHandlerOptionsMock} from "../../mocks/request_handler.js"; import {ELBlock} from "../../../src/types.js"; import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; diff --git a/packages/prover/test/unit/verified_requests/eth_getBlockByNumber.test.ts b/packages/prover/test/unit/verified_requests/eth_getBlockByNumber.test.ts index 81f644a46024..cc1389128ec0 100644 --- a/packages/prover/test/unit/verified_requests/eth_getBlockByNumber.test.ts +++ b/packages/prover/test/unit/verified_requests/eth_getBlockByNumber.test.ts @@ -4,8 +4,12 @@ import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js"; import {ELBlock} from "../../../src/types.js"; import {eth_getBlockByNumber} from "../../../src/verified_requests/eth_getBlockByNumber.js"; -import ethGetBlockWithContractCreation from "../../fixtures/sepolia/eth_getBlock_with_contractCreation.json" assert {type: "json"}; -import ethGetBlockWithNoAccessList from "../../fixtures/sepolia/eth_getBlock_with_no_accessList.json" assert {type: "json"}; +import ethGetBlockWithContractCreation from "../../fixtures/sepolia/eth_getBlock_with_contractCreation.json" assert { + type: "json", +}; +import ethGetBlockWithNoAccessList from "../../fixtures/sepolia/eth_getBlock_with_no_accessList.json" assert { + type: "json", +}; import {TestFixture, cloneTestFixture, generateReqHandlerOptionsMock} from "../../mocks/request_handler.js"; import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; @@ -88,7 +92,6 @@ describe("verified_requests / eth_getBlockByNumber", () => { // Temper the execution payload const testCase = cloneTestFixture(t, { beacon: { - // eslint-disable-next-line @typescript-eslint/naming-convention executionPayload: {parent_hash: "0xbdbd90ab601a073c3d128111eafb12fa7ece4af239abdc8be60184a08c6d7ef4"}, }, }); diff --git a/packages/prover/test/utils/e2e_env.ts b/packages/prover/test/utils/e2e_env.ts index b63d276daa5f..17af3739569a 100644 --- a/packages/prover/test/utils/e2e_env.ts +++ b/packages/prover/test/utils/e2e_env.ts @@ -1,6 +1,5 @@ import {waitForEndpoint} from "@lodestar/test-utils"; -/* eslint-disable @typescript-eslint/naming-convention */ export const rpcUrl = "http://0.0.0.0:8001"; export const beaconUrl = "http://0.0.0.0:5001"; export const proxyPort = 8888; diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index 44dcb8048f99..9bd9775ba2c0 100644 --- a/packages/reqresp/package.json +++ b/packages/reqresp/package.json @@ -45,8 +45,8 @@ "build:release": "yarn clean && yarn run build", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" diff --git a/packages/reqresp/src/encoders/responseDecode.ts b/packages/reqresp/src/encoders/responseDecode.ts index 93ebff674ec6..d55b283df5e6 100644 --- a/packages/reqresp/src/encoders/responseDecode.ts +++ b/packages/reqresp/src/encoders/responseDecode.ts @@ -125,9 +125,8 @@ export async function readErrorMessage(bufferedSource: BufferedSource): Promise< try { return decodeErrorMessage(bytes); - } catch { + } catch (_e) { // Error message is optional and may not be included in the response stream - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call return Buffer.prototype.toString.call(bytes, "hex"); } } diff --git a/packages/reqresp/src/encodingStrategies/sszSnappy/decode.ts b/packages/reqresp/src/encodingStrategies/sszSnappy/decode.ts index 1bf9fc815e28..9ebe52876cfe 100644 --- a/packages/reqresp/src/encodingStrategies/sszSnappy/decode.ts +++ b/packages/reqresp/src/encodingStrategies/sszSnappy/decode.ts @@ -35,7 +35,7 @@ export async function readSszSnappyHeader(bufferedSource: BufferedSource, type: let sszDataLength: number; try { sszDataLength = varintDecode(buffer.subarray()); - } catch (e) { + } catch (_e) { throw new SszSnappyError({code: SszSnappyErrorCode.INVALID_VARINT_BYTES_COUNT, bytes: Infinity}); } diff --git a/packages/reqresp/src/encodingStrategies/sszSnappy/errors.ts b/packages/reqresp/src/encodingStrategies/sszSnappy/errors.ts index 12113ceb42fb..f9d6c4a8e9b5 100644 --- a/packages/reqresp/src/encodingStrategies/sszSnappy/errors.ts +++ b/packages/reqresp/src/encodingStrategies/sszSnappy/errors.ts @@ -28,8 +28,4 @@ type SszSnappyErrorType = | {code: SszSnappyErrorCode.TOO_MANY_BYTES; sszDataLength: number} | {code: SszSnappyErrorCode.SOURCE_ABORTED}; -export class SszSnappyError extends LodestarError { - constructor(type: SszSnappyErrorType) { - super(type); - } -} +export class SszSnappyError extends LodestarError {} diff --git a/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/uncompress.ts b/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/uncompress.ts index e97260989082..69d9ea44d834 100644 --- a/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/uncompress.ts +++ b/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/uncompress.ts @@ -35,7 +35,6 @@ export class SnappyFramesUncompress { } if (type === ChunkType.IDENTIFIER) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call if (!Buffer.prototype.equals.call(data, IDENTIFIER)) { throw "malformed input: bad identifier"; } diff --git a/packages/reqresp/src/metrics.ts b/packages/reqresp/src/metrics.ts index 4af18a782322..faf4b7cf65ae 100644 --- a/packages/reqresp/src/metrics.ts +++ b/packages/reqresp/src/metrics.ts @@ -5,7 +5,6 @@ export type Metrics = ReturnType; /** * A collection of metrics used throughout the Gossipsub behaviour. */ -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function getMetrics(register: MetricsRegister) { // Using function style instead of class to prevent having to re-declare all MetricsPrometheus types. diff --git a/packages/reqresp/src/request/index.ts b/packages/reqresp/src/request/index.ts index 4920a32eb221..b79df24e2adf 100644 --- a/packages/reqresp/src/request/index.ts +++ b/packages/reqresp/src/request/index.ts @@ -98,7 +98,6 @@ export async function* sendRequest( async (timeoutAndParentSignal) => { const protocolIds = Array.from(protocolsMap.keys()); const conn = await libp2p.dialProtocol(peerId, protocolIds, {signal: timeoutAndParentSignal}); - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (!conn) throw Error("dialProtocol timeout"); return conn; }, diff --git a/packages/reqresp/src/response/index.ts b/packages/reqresp/src/response/index.ts index 27758caa3f24..ad13ba8b9359 100644 --- a/packages/reqresp/src/response/index.ts +++ b/packages/reqresp/src/response/index.ts @@ -76,7 +76,7 @@ export async function handleRequest({ signal ).catch((e: unknown) => { if (e instanceof TimeoutError) { - throw e; // Let outter catch {} re-type the error as SERVER_ERROR + throw e; // Let outter catch (_e) {} re-type the error as SERVER_ERROR } else { throw new ResponseError(RespStatus.INVALID_REQUEST, (e as Error).message); } diff --git a/packages/reqresp/src/utils/bufferedSource.ts b/packages/reqresp/src/utils/bufferedSource.ts index ac31a62ba29c..569cc217ea23 100644 --- a/packages/reqresp/src/utils/bufferedSource.ts +++ b/packages/reqresp/src/utils/bufferedSource.ts @@ -18,7 +18,6 @@ export class BufferedSource { } [Symbol.asyncIterator](): AsyncIterator { - // eslint-disable-next-line @typescript-eslint/no-this-alias const that = this; let firstNext = true; @@ -32,7 +31,6 @@ export class BufferedSource { return {done: false, value: that.buffer}; } - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const {done, value: chunk} = await that.source.next(); if (done === true) { that.isDone = true; diff --git a/packages/reqresp/test/fixtures/encodingStrategies.ts b/packages/reqresp/test/fixtures/encodingStrategies.ts index c7705bb9493b..7bf183d8714c 100644 --- a/packages/reqresp/test/fixtures/encodingStrategies.ts +++ b/packages/reqresp/test/fixtures/encodingStrategies.ts @@ -15,7 +15,6 @@ import { // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); type SszSnappyTestBlockData = { diff --git a/packages/reqresp/test/fixtures/messages.ts b/packages/reqresp/test/fixtures/messages.ts index 5558e7c3e13a..a243a05b221b 100644 --- a/packages/reqresp/test/fixtures/messages.ts +++ b/packages/reqresp/test/fixtures/messages.ts @@ -14,7 +14,6 @@ type MessageFixture = { }; const phase0Metadata = ssz.phase0.Metadata.fromJson({ - // eslint-disable-next-line @typescript-eslint/naming-convention seq_number: "9", attnets: "0x0000000000000000", }); @@ -37,7 +36,6 @@ export const sszSnappyPhase0Metadata: MessageFixture = { }; const altairMetadata = ssz.altair.Metadata.fromJson({ - // eslint-disable-next-line @typescript-eslint/naming-convention seq_number: "8", attnets: "0x0000000000000000", syncnets: "0x00", @@ -178,7 +176,6 @@ if (slotBlockAltair - slotBlockPhase0 < SLOTS_PER_EPOCH) { throw Error("phase0 block slot must be an epoch apart from altair block slot"); } const ALTAIR_FORK_EPOCH = Math.floor(slotBlockAltair / SLOTS_PER_EPOCH); -// eslint-disable-next-line @typescript-eslint/naming-convention export const beaconConfig = createBeaconConfig({...chainConfig, ALTAIR_FORK_EPOCH}, ZERO_HASH); export const getEmptyHandler = () => async function* emptyHandler(): AsyncGenerator {}; diff --git a/packages/reqresp/test/fixtures/protocols.ts b/packages/reqresp/test/fixtures/protocols.ts index f20d891781ef..19e8936fc376 100644 --- a/packages/reqresp/test/fixtures/protocols.ts +++ b/packages/reqresp/test/fixtures/protocols.ts @@ -5,7 +5,6 @@ import {ContextBytesType, DialOnlyProtocol, Encoding, ProtocolHandler, Protocol} import {getEmptyHandler} from "./messages.js"; import {beaconConfig} from "./messages.js"; -// eslint-disable-next-line @typescript-eslint/naming-convention const NumToStrReq = new ContainerType( { value: new UintNumberType(4), @@ -15,7 +14,6 @@ const NumToStrReq = new ContainerType( export type NumToStrReqType = ValueOf; -// eslint-disable-next-line @typescript-eslint/naming-convention const NumToStrResp = new ContainerType( { value: new ListBasicType(new UintNumberType(1), 4), diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index b4aabf0140e8..501d13024159 100644 --- a/packages/spec-test-util/package.json +++ b/packages/spec-test-util/package.json @@ -44,8 +44,8 @@ "build:watch": "yarn run build --watch", "check-build": "node -e \"(async function() { await import('./lib/downloadTests.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit && yarn test:e2e", "test:unit": "vitest --run --passWithNoTests --dir test/unit/", "test:e2e": "vitest --run --config vitest.e2e.config.ts --dir test/e2e/", diff --git a/packages/spec-test-util/src/single.ts b/packages/spec-test-util/src/single.ts index 47bf8d0a0742..af77d45f6242 100644 --- a/packages/spec-test-util/src/single.ts +++ b/packages/spec-test-util/src/single.ts @@ -68,6 +68,7 @@ export interface SpecTestOptions { * Optionally pass function to transform loaded values * (values from input files) */ + inputProcessing?: {[K: string]: (value: any) => any}; shouldError?: (testCase: TestCase) => boolean; @@ -86,7 +87,7 @@ const defaultOptions: SpecTestOptions = { getExpected: (testCase) => testCase, shouldError: () => false, shouldSkip: () => false, - expectFunc: (testCase, expected, actual) => expect(actual).to.be.deep.equal(expected), + expectFunc: (_testCase, expected, actual) => expect(actual).to.be.deep.equal(expected), timeout: 10 * 60 * 1000, }; @@ -101,7 +102,7 @@ export function describeDirectorySpecTest throw new Error(`${testCaseDirectoryPath} is not directory`); } - describe(name, function () { + describe(name, () => { if (options.timeout !== undefined) { vi.setConfig({testTimeout: options.timeout ?? 10 * 60 * 1000}); } @@ -114,7 +115,7 @@ export function describeDirectorySpecTest // Use full path here, not just `testSubDirname` to allow usage of `vitest -t` const testName = `${name}/${testSubDirname}`; - it(testName, async function (context) { + it(testName, async (context) => { // some tests require to load meta.yaml first in order to know respective ssz types. const metaFilePath = path.join(testSubDirPath, "meta.yaml"); const meta: TestCase["meta"] = fs.existsSync(metaFilePath) @@ -131,7 +132,7 @@ export function describeDirectorySpecTest if (options.shouldError?.(testCase)) { try { await testFunction(testCase, name); - } catch (e) { + } catch (_e) { return; } } else { diff --git a/packages/spec-test-util/test/e2e/single/index.test.ts b/packages/spec-test-util/test/e2e/single/index.test.ts index 849b0cead30d..2dbefbb9cd22 100644 --- a/packages/spec-test-util/test/e2e/single/index.test.ts +++ b/packages/spec-test-util/test/e2e/single/index.test.ts @@ -8,11 +8,8 @@ import {describeDirectorySpecTest, InputType, loadYamlFile} from "../../../src/s // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); -/* eslint-disable @typescript-eslint/naming-convention */ - export type SimpleStruct = { test: boolean; number: number; diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 6816e5679cf5..e743ece013d9 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -50,8 +50,8 @@ "build:release": "yarn clean && yarn build", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index ee75dff0dfd1..fd671dc5f6f6 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -173,7 +173,7 @@ function isValidDepositSignature( const signature = Signature.fromBytes(depositSignature, true); return verify(signingRoot, publicKey, signature); - } catch (e) { + } catch (_e) { return false; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature } } diff --git a/packages/state-transition/src/util/balance.ts b/packages/state-transition/src/util/balance.ts index e9b7a06e4130..c6b196846ec9 100644 --- a/packages/state-transition/src/util/balance.ts +++ b/packages/state-transition/src/util/balance.ts @@ -2,7 +2,7 @@ import {EFFECTIVE_BALANCE_INCREMENT} from "@lodestar/params"; import {Gwei, ValidatorIndex} from "@lodestar/types"; import {bigIntMax} from "@lodestar/utils"; import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js"; -import {BeaconStateAllForks} from ".."; +import {BeaconStateAllForks} from "../index.js"; import {CachedBeaconStateAllForks} from "../types.js"; /** diff --git a/packages/state-transition/src/util/blindedBlock.ts b/packages/state-transition/src/util/blindedBlock.ts index 2e4e4d590817..ceda91c94bb1 100644 --- a/packages/state-transition/src/util/blindedBlock.ts +++ b/packages/state-transition/src/util/blindedBlock.ts @@ -25,9 +25,13 @@ export function blindedOrFullBlockHashTreeRoot( ): Root { return isBlindedBeaconBlock(blindedOrFull) ? // Blinded - config.getExecutionForkTypes(blindedOrFull.slot).BlindedBeaconBlock.hashTreeRoot(blindedOrFull) + config + .getExecutionForkTypes(blindedOrFull.slot) + .BlindedBeaconBlock.hashTreeRoot(blindedOrFull) : // Full - config.getForkTypes(blindedOrFull.slot).BeaconBlock.hashTreeRoot(blindedOrFull); + config + .getForkTypes(blindedOrFull.slot) + .BeaconBlock.hashTreeRoot(blindedOrFull); } export function blindedOrFullBlockToHeader( @@ -36,9 +40,13 @@ export function blindedOrFullBlockToHeader( ): BeaconBlockHeader { const bodyRoot = isBlindedBeaconBlock(blindedOrFull) ? // Blinded - config.getExecutionForkTypes(blindedOrFull.slot).BlindedBeaconBlockBody.hashTreeRoot(blindedOrFull.body) + config + .getExecutionForkTypes(blindedOrFull.slot) + .BlindedBeaconBlockBody.hashTreeRoot(blindedOrFull.body) : // Full - config.getForkTypes(blindedOrFull.slot).BeaconBlockBody.hashTreeRoot(blindedOrFull.body); + config + .getForkTypes(blindedOrFull.slot) + .BeaconBlockBody.hashTreeRoot(blindedOrFull.body); return { slot: blindedOrFull.slot, diff --git a/packages/state-transition/src/util/seed.ts b/packages/state-transition/src/util/seed.ts index a5a0028d6c17..4131d4d9481f 100644 --- a/packages/state-transition/src/util/seed.ts +++ b/packages/state-transition/src/util/seed.ts @@ -155,7 +155,7 @@ export function computeShuffledIndex(index: number, indexCount: number, seed: By const position = Math.max(permuted, flip); const source = digest(Buffer.concat([_seed, intToBytes(i, 1), intToBytes(Math.floor(position / 256), 4)])); const byte = source[Math.floor((position % 256) / 8)]; - const bit = (byte >> position % 8) % 2; + const bit = (byte >> (position % 8)) % 2; permuted = bit ? flip : permuted; } return permuted; diff --git a/packages/state-transition/src/util/shuffle.ts b/packages/state-transition/src/util/shuffle.ts index 39137bca69d0..a87f22cae43e 100644 --- a/packages/state-transition/src/util/shuffle.ts +++ b/packages/state-transition/src/util/shuffle.ts @@ -108,7 +108,6 @@ function innerShuffleList(input: Shuffleable, seed: Bytes32, dir: boolean): void let source = seed; // just setting it to a Bytes32 let byteV = 0; - // eslint-disable-next-line no-constant-condition while (true) { // spec: pivot = bytes_to_int(hash(seed + int_to_bytes1(round))[0:8]) % list_size // This is the "int_to_bytes1(round)", appended to the seed. diff --git a/packages/state-transition/src/util/weakSubjectivity.ts b/packages/state-transition/src/util/weakSubjectivity.ts index 0e606e66340f..8d7c82842496 100644 --- a/packages/state-transition/src/util/weakSubjectivity.ts +++ b/packages/state-transition/src/util/weakSubjectivity.ts @@ -80,7 +80,6 @@ export function computeWeakSubjectivityPeriodFromConstituents( const t = Math.floor(totalBalanceByIncrement / N); const T = MAX_EFFECTIVE_BALANCE / ETH_TO_GWEI; const delta = churnLimit; - // eslint-disable-next-line @typescript-eslint/naming-convention const Delta = MAX_DEPOSITS * SLOTS_PER_EPOCH; const D = SAFETY_DECAY; diff --git a/packages/state-transition/test/cache.ts b/packages/state-transition/test/cache.ts index 9ca7ea25201c..59ddfe40b7c1 100644 --- a/packages/state-transition/test/cache.ts +++ b/packages/state-transition/test/cache.ts @@ -3,7 +3,6 @@ import {fileURLToPath} from "node:url"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const testCachePath = path.join(__dirname, "../test-cache"); diff --git a/packages/state-transition/test/perf/analyzeEpochs.ts b/packages/state-transition/test/perf/analyzeEpochs.ts index deb0861427bf..9fe04bf7c522 100644 --- a/packages/state-transition/test/perf/analyzeEpochs.ts +++ b/packages/state-transition/test/perf/analyzeEpochs.ts @@ -123,7 +123,6 @@ async function analyzeEpochs(network: NetworkName, fromEpoch?: number): Promise< const {previousEpochAttestations, currentEpochAttestations} = state as phase0.BeaconState; - // eslint-disable-next-line no-console console.log(`Processed epoch ${epoch}`); writeToCsv({ epoch, @@ -182,7 +181,6 @@ if (!network) { } analyzeEpochs(network as NetworkName, fromEpoch).catch((e: Error) => { - // eslint-disable-next-line no-console console.error(e); process.exit(1); }); diff --git a/packages/state-transition/test/perf/dataStructures/arrayish.memory.ts b/packages/state-transition/test/perf/dataStructures/arrayish.memory.ts index 7e10f447181f..f37421ce2a89 100644 --- a/packages/state-transition/test/perf/dataStructures/arrayish.memory.ts +++ b/packages/state-transition/test/perf/dataStructures/arrayish.memory.ts @@ -110,7 +110,6 @@ for (let i = 0; i < 1e8; i++) { const heapUsedM = linearRegression(xs, heapUsed).m; const rssM = linearRegression(xs, rss).m; - // eslint-disable-next-line no-console console.log(i, {arrayBuffersM, externalM, heapTotalM, heapUsedM, rssM}); } } diff --git a/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts b/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts index 2d57de44f8ee..588fe9ec0213 100644 --- a/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts +++ b/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts @@ -78,7 +78,7 @@ type IndicesLengths = { * Create a state that causes `changeRatio` fraction (0,1) of validators to change their effective balance. */ function getRegistryUpdatesTestData( - vc: number, + _vc: number, lengths: IndicesLengths ): { state: CachedBeaconStateAllForks; diff --git a/packages/state-transition/test/perf/misc/arrayCreation.test.ts b/packages/state-transition/test/perf/misc/arrayCreation.test.ts index 8fd52ff99e27..c6a3cf29ed8e 100644 --- a/packages/state-transition/test/perf/misc/arrayCreation.test.ts +++ b/packages/state-transition/test/perf/misc/arrayCreation.test.ts @@ -36,7 +36,6 @@ describe.skip("array creation", function () { } const to = process.hrtime.bigint(); const diffMs = Number(to - from) / 1e6; - // eslint-disable-next-line no-console console.log(`${id}: ${diffMs / opsRun} ms`); }); } diff --git a/packages/state-transition/test/perf/misc/bitopts.test.ts b/packages/state-transition/test/perf/misc/bitopts.test.ts index 93df681bb3e2..38677002a969 100644 --- a/packages/state-transition/test/perf/misc/bitopts.test.ts +++ b/packages/state-transition/test/perf/misc/bitopts.test.ts @@ -14,7 +14,6 @@ describe.skip("bit opts", function () { } const to = process.hrtime.bigint(); const diffMs = Number(to - from) / 1e6; - // eslint-disable-next-line no-console console.log(`Time spent on OR in getAttestationDeltas: ${diffMs * ((orOptsPerRun * validators) / opsRun)} ms`); }); }); diff --git a/packages/state-transition/test/perf/shuffle/shuffle.test.ts b/packages/state-transition/test/perf/shuffle/shuffle.test.ts index ea1a9d606184..55f7875e69dd 100644 --- a/packages/state-transition/test/perf/shuffle/shuffle.test.ts +++ b/packages/state-transition/test/perf/shuffle/shuffle.test.ts @@ -10,7 +10,8 @@ describe("shuffle list", () => { const seed = new Uint8Array([42, 32]); for (const listSize of [ - 16384, 250000, + 16384, + 250000, // Don't run 4_000_000 since it's very slow and not testnet has gotten there yet // 4e6, ]) { diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index c764e2d039f9..7a0bfb29efb3 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -61,7 +61,6 @@ const secretKeyByModIndex = new Map(); const epoch = 23638; export const perfStateEpoch = epoch; -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function getPubkeys(vc = numValidators) { const pubkeysMod = interopPubkeysCached(keypairsMod); const pubkeysModObj = pubkeysMod.map((pk) => PublicKey.fromBytes(pk)); @@ -85,7 +84,6 @@ export function getSecretKeyFromIndexCached(validatorIndex: number): SecretKey { return sk; } -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type function getPubkeyCaches({pubkeysMod, pubkeysModObj}: ReturnType) { // Manually sync pubkeys to prevent doing BLS opts 110_000 times const pubkey2index = new PubkeyIndexMap(); @@ -223,7 +221,6 @@ export function generatePerfTestCachedStateAltair(opts?: { const {pubkeys, pubkeysMod, pubkeysModObj} = getPubkeys(opts?.vc); const {pubkey2index, index2pubkey} = getPubkeyCaches({pubkeys, pubkeysMod, pubkeysModObj}); - // eslint-disable-next-line @typescript-eslint/naming-convention const altairConfig = createChainForkConfig({ALTAIR_FORK_EPOCH: 0}); const origState = generatePerformanceStateAltair(pubkeys); diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index 96c026340143..668f22e13a1e 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -52,7 +52,6 @@ describe("CachedBeaconState", () => { expect(state2.epochCtx.getValidatorIndex(pubkey2)).toBe(index2); }); - /* eslint-disable @typescript-eslint/naming-convention */ it("Clone and mutate cache post-Electra", () => { const stateView = ssz.electra.BeaconState.defaultViewDU(); const state1 = createCachedBeaconStateTest( diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 301cb105dc98..19a7d5c186f8 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -46,7 +46,6 @@ const ZERO_HASH = Buffer.alloc(32, 0); /** default config with ZERO_HASH as genesisValidatorsRoot */ const config = createBeaconConfig(chainConfig, ZERO_HASH); -/* eslint-disable @typescript-eslint/naming-convention */ function getConfig(fork: ForkName, forkEpoch = 0): ChainForkConfig { switch (fork) { case ForkName.phase0: diff --git a/packages/state-transition/test/unit/util/aggregator.test.ts b/packages/state-transition/test/unit/util/aggregator.test.ts index 07fd3172926c..6a9d0a45a2c7 100644 --- a/packages/state-transition/test/unit/util/aggregator.test.ts +++ b/packages/state-transition/test/unit/util/aggregator.test.ts @@ -8,8 +8,6 @@ import { } from "@lodestar/params"; import {isAggregatorFromCommitteeLength, isSyncCommitteeAggregator} from "../../../src/util/aggregator.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - describe("isAttestationAggregator", function () { const committeeLength = 130; diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts index 3cfa4abb3409..a682b4e993ed 100644 --- a/packages/state-transition/test/unit/util/deposit.test.ts +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -29,7 +29,6 @@ describe("getEth1DepositCount", () => { const postElectraState = createCachedBeaconStateTest( stateView, createChainForkConfig({ - /* eslint-disable @typescript-eslint/naming-convention */ ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, @@ -63,7 +62,6 @@ describe("getEth1DepositCount", () => { const postElectraState = createCachedBeaconStateTest( stateView, createChainForkConfig({ - /* eslint-disable @typescript-eslint/naming-convention */ ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, diff --git a/packages/state-transition/test/utils/beforeValue.ts b/packages/state-transition/test/utils/beforeValue.ts index f50520372e17..6a2f5ee86945 100644 --- a/packages/state-transition/test/utils/beforeValue.ts +++ b/packages/state-transition/test/utils/beforeValue.ts @@ -21,7 +21,7 @@ export function beforeValue(fn: () => T | Promise, timeout?: number): Lazy return new Proxy<{value: T}>( {value}, { - get: function (target, prop) { + get: function (_target, prop) { if (prop === "value") { if (value === null) { throw Error("beforeValue has not yet run the before() block"); diff --git a/packages/state-transition/test/utils/beforeValueMocha.ts b/packages/state-transition/test/utils/beforeValueMocha.ts index 0d5f8f77d203..d078357bd3b4 100644 --- a/packages/state-transition/test/utils/beforeValueMocha.ts +++ b/packages/state-transition/test/utils/beforeValueMocha.ts @@ -20,7 +20,7 @@ export function beforeValue(fn: () => T | Promise, timeout?: number): Lazy return new Proxy<{value: T}>( {value}, { - get: function (target, prop) { + get: function (_target, prop) { if (prop === "value") { if (value === null) { throw Error("beforeValue has not yet run the before() block"); diff --git a/packages/state-transition/test/utils/rand.ts b/packages/state-transition/test/utils/rand.ts index 11a0efaffe10..988146ac4bf4 100644 --- a/packages/state-transition/test/utils/rand.ts +++ b/packages/state-transition/test/utils/rand.ts @@ -4,7 +4,8 @@ */ export function mulberry32(a: number) { return function () { - let t = (a += 0x6d2b79f5); + a += 0x6d2b79f5; + let t = a; t = Math.imul(t ^ (t >>> 15), t | 1); t ^= t + Math.imul(t ^ (t >>> 7), t | 61); return ((t ^ (t >>> 14)) >>> 0) / 4294967296; diff --git a/packages/state-transition/test/utils/specTestCases.ts b/packages/state-transition/test/utils/specTestCases.ts index 6c038d202d74..ed3776d868d0 100644 --- a/packages/state-transition/test/utils/specTestCases.ts +++ b/packages/state-transition/test/utils/specTestCases.ts @@ -3,7 +3,6 @@ import {fileURLToPath} from "node:url"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const SPEC_TEST_LOCATION = path.join(__dirname, "../../../../node_modules/@chainsafe/eth2-spec-tests"); diff --git a/packages/state-transition/test/utils/testFileCache.ts b/packages/state-transition/test/utils/testFileCache.ts index b894674f54f6..28741bf932c5 100644 --- a/packages/state-transition/test/utils/testFileCache.ts +++ b/packages/state-transition/test/utils/testFileCache.ts @@ -96,7 +96,6 @@ export async function getNetworkCachedBlock( async function downloadTestFile(fileId: string): Promise { const fileUrl = `${TEST_FILES_BASE_URL}/${fileId}`; - // eslint-disable-next-line no-console console.log(`Downloading file ${fileUrl}`); const res = await got(fileUrl, {responseType: "buffer"}).catch((e: Error) => { diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 5bf61891a9d5..b2a589581055 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -42,8 +42,8 @@ "build:watch": "yarn run build --watch", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/", + "lint:fix": "yarn run lint --write", "check-readme": "typescript-docs-verifier" }, "repository": { diff --git a/packages/test-utils/src/childProcess.ts b/packages/test-utils/src/childProcess.ts index cd6983cca467..d8b86b83ee48 100644 --- a/packages/test-utils/src/childProcess.ts +++ b/packages/test-utils/src/childProcess.ts @@ -86,7 +86,7 @@ export function isPidRunning(pid: number): boolean { // Signal 0 is a special signal that checks if the process exists process.kill(pid, 0); return true; - } catch { + } catch (_e) { return false; } } @@ -304,7 +304,7 @@ export async function spawnChildProcess( }); proc.removeAllListeners("exit"); resolve(proc); - } catch (error) { + } catch (_e) { reject( new Error( `Health check timeout. logPrefix=${logPrefix} pid=${proc.pid} healthTimeout=${prettyMsToTime(healthTimeoutMs ?? 0)}` diff --git a/packages/test-utils/src/cli.ts b/packages/test-utils/src/cli.ts index 8b4a84ec467a..c081a65e03c2 100644 --- a/packages/test-utils/src/cli.ts +++ b/packages/test-utils/src/cli.ts @@ -28,7 +28,6 @@ export async function runCliCommand( opts: CommandRunOptions = {timeoutMs: 1000} ): Promise { return wrapTimeout( - // eslint-disable-next-line no-async-promise-executor new Promise(async (resolve, reject) => { try { await cli diff --git a/packages/test-utils/src/doubles.ts b/packages/test-utils/src/doubles.ts index c61c10ea6099..171c55824996 100644 --- a/packages/test-utils/src/doubles.ts +++ b/packages/test-utils/src/doubles.ts @@ -37,7 +37,6 @@ function wrapLogWriter(...writers: [writer: object, ...keys: string[]][]): { for (const key of keys) { originals[index][key] = writer[key as keyof typeof writer]; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error writer[key as keyof typeof writer] = function mockedWriter(data: string) { // Our fixtures does not include the new line character @@ -51,7 +50,6 @@ function wrapLogWriter(...writers: [writer: object, ...keys: string[]][]): { restore: () => { for (const [index, [writer, ...keys]] of writers.entries()) { for (const key of keys) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error writer[key as keyof typeof writer] = originals[index][key]; } diff --git a/packages/test-utils/src/externalSigner.ts b/packages/test-utils/src/externalSigner.ts index dbcb6bee1dc5..1e48e6af8d40 100644 --- a/packages/test-utils/src/externalSigner.ts +++ b/packages/test-utils/src/externalSigner.ts @@ -69,7 +69,6 @@ export async function startExternalSigner({ stream .on("data", (line) => process.stdout.write(line)) .on("err", (line) => process.stderr.write(line)) - // eslint-disable-next-line no-console .on("end", () => console.log("Stream closed")); return { diff --git a/packages/test-utils/src/http.ts b/packages/test-utils/src/http.ts index b4dd16390483..85b64c110cab 100644 --- a/packages/test-utils/src/http.ts +++ b/packages/test-utils/src/http.ts @@ -42,7 +42,6 @@ export async function matchReqSuccess(url: string, method: Method = "GET"): Prom * Wait for a given endpoint to return a given status code */ export async function waitForEndpoint(url: string, statusCode = 200): Promise { - // eslint-disable-next-line no-constant-condition while (true) { const status = await getReqStatus(url); diff --git a/packages/types/package.json b/packages/types/package.json index f3e034ec1b35..1c020b409071 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -59,8 +59,8 @@ "build:release": "yarn clean && yarn build", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test": "yarn test:unit", "test:constants:minimal": "LODESTAR_PRESET=minimal vitest --run --dir test/constants/", "test:constants:mainnet": "LODESTAR_PRESET=mainnet vitest --run --dir test/constants/", diff --git a/packages/types/src/sszTypes.ts b/packages/types/src/sszTypes.ts index 4399904a94bc..55218574be76 100644 --- a/packages/types/src/sszTypes.ts +++ b/packages/types/src/sszTypes.ts @@ -26,7 +26,8 @@ const typesByFork = { /** * A type of union of forks must accept as any parameter the UNION of all fork types. */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any + +// biome-ignore lint/suspicious/noExplicitAny: type UnionSSZForksTypeOf> = CompositeType< ValueOf, CompositeView, @@ -41,11 +42,9 @@ type SSZTypesByFork = { export type SSZTypesFor = K extends void ? // It compiles fine, need to debug the error - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error {[K2 in keyof SSZTypesByFork[F]]: UnionSSZForksTypeOf} : // It compiles fine, need to debug the error - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error UnionSSZForksTypeOf]>; diff --git a/packages/utils/package.json b/packages/utils/package.json index 0723f5f1815c..6c8218741e30 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -28,8 +28,8 @@ "build:release": "yarn clean && yarn build", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc && vitest --run --typecheck --dir test/types/", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "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", diff --git a/packages/utils/src/assert.ts b/packages/utils/src/assert.ts index 91612b0e6407..7b6af1f00f97 100644 --- a/packages/utils/src/assert.ts +++ b/packages/utils/src/assert.ts @@ -16,7 +16,6 @@ export const assert = { */ equal(actual: T, expected: T, message?: string): void { if (!(actual === expected)) { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions throw new AssertionError(`${message || "Expected values to be equal"}: ${actual} === ${expected}`); } }, diff --git a/packages/utils/src/command.ts b/packages/utils/src/command.ts index 89929a6c41ef..2e62ba5a9648 100644 --- a/packages/utils/src/command.ts +++ b/packages/utils/src/command.ts @@ -6,7 +6,7 @@ export interface CliExample { description?: string; } -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: export interface CliOptionDefinition extends Options { example?: Omit; // Ensure `type` property matches type of `T` @@ -28,7 +28,7 @@ export type CliCommandOptions = Required<{ CliOptionDefinition & (Required> | {demandOption: true}); }>; -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: export interface CliCommand, ParentArgs = Record, R = any> { command: string; describe: string; @@ -41,7 +41,7 @@ export interface CliCommand, ParentArgs = Record< options?: CliCommandOptions; // 1st arg: any = free own sub command options // 2nd arg: subcommand parent options is = to this command options + parent options - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: subcommands?: CliCommand[]; handler?: (args: OwnArgs & ParentArgs) => Promise; } @@ -51,7 +51,8 @@ export interface CliCommand, ParentArgs = Record< * @param yargs * @param cliCommand */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any + +// biome-ignore lint/suspicious/noExplicitAny: export function registerCommandToYargs(yargs: Argv, cliCommand: CliCommand): void { yargs.command({ command: cliCommand.command, diff --git a/packages/utils/src/diff.ts b/packages/utils/src/diff.ts index 204989016b46..4aab18e32779 100644 --- a/packages/utils/src/diff.ts +++ b/packages/utils/src/diff.ts @@ -203,10 +203,12 @@ export function getDiffs(val1: Diffable, val2: Diffable, objectPath: string): Di */ export function diff(val1: unknown, val2: unknown, outputValues = false, filename?: string): void { if (!isDiffable(val1)) { + // biome-ignore lint/suspicious/noConsoleLog: console.log("val1 is not Diffable"); return; } if (!isDiffable(val2)) { + // biome-ignore lint/suspicious/noConsoleLog: console.log("val2 is not Diffable"); return; } @@ -226,6 +228,7 @@ export function diff(val1: unknown, val2: unknown, outputValues = false, filenam if (filename) { fs.writeFileSync(filename, output); } else { + // biome-ignore lint/suspicious/noConsoleLog: console.log(output); } } diff --git a/packages/utils/src/err.ts b/packages/utils/src/err.ts index 81f6f92c0044..7c27a0a067a3 100644 --- a/packages/utils/src/err.ts +++ b/packages/utils/src/err.ts @@ -4,7 +4,6 @@ export type Err = {[symErr]: true; error: T}; export type Result = T | Err; -// eslint-disable-next-line @typescript-eslint/naming-convention export function Err(error: T): Err { return {[symErr]: true, error}; } diff --git a/packages/utils/src/logger.ts b/packages/utils/src/logger.ts index 925a357f4b98..e299e730a81a 100644 --- a/packages/utils/src/logger.ts +++ b/packages/utils/src/logger.ts @@ -12,7 +12,6 @@ export enum LogLevel { trace = "trace", } -// eslint-disable-next-line @typescript-eslint/naming-convention export const LogLevels = Object.values(LogLevel); export type LogHandler = (message: string, context?: LogData, error?: Error) => void; diff --git a/packages/utils/src/objects.ts b/packages/utils/src/objects.ts index ad09d36b0ecc..913bc80275b7 100644 --- a/packages/utils/src/objects.ts +++ b/packages/utils/src/objects.ts @@ -63,7 +63,7 @@ export function isEmptyObject(value: unknown): boolean { * * Inspired on lodash.mapValues, see https://lodash.com/docs/4.17.15#mapValues */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// biome-ignore lint/suspicious/noExplicitAny: export function mapValues( obj: T, iteratee: (value: T[keyof T], key: keyof T) => R diff --git a/packages/utils/src/promise.ts b/packages/utils/src/promise.ts index 2be7467bfff4..894444d46937 100644 --- a/packages/utils/src/promise.ts +++ b/packages/utils/src/promise.ts @@ -109,7 +109,6 @@ export async function resolveOrRacePromises wrapPromise(p)) as ReturnPromiseWithTuple; // We intentionally want an array of promises here - // eslint-disable-next-line @typescript-eslint/no-floating-promises promises = (promiseResults as PromiseResult[]).map((p) => p.promise) as unknown as T; try { diff --git a/packages/utils/src/yaml/int.ts b/packages/utils/src/yaml/int.ts index 64a2c283dd49..bc68895cfd42 100644 --- a/packages/utils/src/yaml/int.ts +++ b/packages/utils/src/yaml/int.ts @@ -162,25 +162,20 @@ export const intType = new Type("tag:yaml.org,2002:int", { construct: constructYamlInteger, predicate: isInteger, instanceOf: BigInt, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore represent: { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore binary: function binary(obj: number) { return obj >= 0 ? "0b" + obj.toString(2) : "-0b" + obj.toString(2).slice(1); }, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore octal: function octal(obj: number) { return obj >= 0 ? "0" + obj.toString(8) : "-0" + obj.toString(8).slice(1); }, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore decimal: function decimal(obj: number) { return obj.toString(10); }, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore hexadecimal: function hexadecimal(obj: number) { return obj >= 0 ? "0x" + obj.toString(16).toUpperCase() : "-0x" + obj.toString(16).toUpperCase().slice(1); diff --git a/packages/utils/src/yaml/schema.ts b/packages/utils/src/yaml/schema.ts index b53fc14a3e86..8db0c67cd943 100644 --- a/packages/utils/src/yaml/schema.ts +++ b/packages/utils/src/yaml/schema.ts @@ -3,9 +3,7 @@ import yml, {FAILSAFE_SCHEMA, Type} from "js-yaml"; import {intType} from "./int.js"; export const schema = FAILSAFE_SCHEMA.extend({ - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access implicit: [yml.types.null as Type, yml.types.bool as Type, intType, yml.types.float as Type], explicit: [], }); diff --git a/packages/utils/test/unit/err.test.ts b/packages/utils/test/unit/err.test.ts index 94cebe3ed1a1..7a08ebbc4319 100644 --- a/packages/utils/test/unit/err.test.ts +++ b/packages/utils/test/unit/err.test.ts @@ -60,7 +60,7 @@ describe("Result Err", () => { try { await mapOkResultsAsync([], async () => [0]); throw Error("did not throw"); - } catch (e) { + } catch (_e) { // Ok } }); diff --git a/packages/utils/test/unit/objects.test.ts b/packages/utils/test/unit/objects.test.ts index 4699a8c6f405..a94ed9213390 100644 --- a/packages/utils/test/unit/objects.test.ts +++ b/packages/utils/test/unit/objects.test.ts @@ -17,8 +17,6 @@ describe("Objects helper", () => { }); }); -/* eslint-disable @typescript-eslint/naming-convention */ - describe("objectToExpectedCase", () => { const testCases: { id: string; diff --git a/packages/validator/package.json b/packages/validator/package.json index 65ed656f010d..932eedac1dba 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -25,8 +25,8 @@ "build:watch": "yarn run build --watch", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", "check-types": "tsc", - "lint": "eslint --color --ext .ts src/ test/", - "lint:fix": "yarn run lint --fix", + "lint": "biome check src/ test/", + "lint:fix": "yarn run lint --write", "test:unit": "vitest --run --dir test/unit/", "test": "yarn test:unit && yarn test:e2e", "test:spec": "vitest --run --config vitest.spec.config.ts --dir test/spec/", diff --git a/packages/validator/src/genesis.ts b/packages/validator/src/genesis.ts index 3156acee689f..7fc3e20673bc 100644 --- a/packages/validator/src/genesis.ts +++ b/packages/validator/src/genesis.ts @@ -6,7 +6,6 @@ import {ApiClient} from "@lodestar/api"; const WAITING_FOR_GENESIS_POLL_MS = 12 * 1000; export async function waitForGenesis(api: ApiClient, logger: Logger, signal?: AbortSignal): Promise { - // eslint-disable-next-line no-constant-condition while (true) { try { return (await api.beacon.getGenesis()).value(); diff --git a/packages/validator/src/metrics.ts b/packages/validator/src/metrics.ts index a437328e8d5f..ca693056fc54 100644 --- a/packages/validator/src/metrics.ts +++ b/packages/validator/src/metrics.ts @@ -25,7 +25,6 @@ export type LodestarGitData = { /** * A collection of metrics used by the validator client */ -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function getMetrics(register: MetricsRegisterExtra, gitData: LodestarGitData) { // Using function style instead of class to prevent having to re-declare all MetricsPrometheus types. diff --git a/packages/validator/src/services/emitter.ts b/packages/validator/src/services/emitter.ts index 19f9ac1de54a..2072acba6219 100644 --- a/packages/validator/src/services/emitter.ts +++ b/packages/validator/src/services/emitter.ts @@ -1,4 +1,4 @@ -import {EventEmitter} from "events"; +import {EventEmitter} from "node:events"; import {StrictEventEmitter} from "strict-event-emitter-types"; import {Slot} from "@lodestar/types"; import {HeadEventData} from "./chainHeaderTracker.js"; diff --git a/packages/validator/src/slashingProtection/attestation/errors.ts b/packages/validator/src/slashingProtection/attestation/errors.ts index 7d4b0978d097..34e11c190c8a 100644 --- a/packages/validator/src/slashingProtection/attestation/errors.ts +++ b/packages/validator/src/slashingProtection/attestation/errors.ts @@ -63,8 +63,4 @@ type InvalidAttestationErrorType = minTargetEpoch: Epoch; }; -export class InvalidAttestationError extends LodestarError { - constructor(type: InvalidAttestationErrorType) { - super(type); - } -} +export class InvalidAttestationError extends LodestarError {} diff --git a/packages/validator/src/slashingProtection/block/errors.ts b/packages/validator/src/slashingProtection/block/errors.ts index be3696bba700..e7868881627b 100644 --- a/packages/validator/src/slashingProtection/block/errors.ts +++ b/packages/validator/src/slashingProtection/block/errors.ts @@ -25,8 +25,4 @@ type InvalidBlockErrorType = minSlot: Slot; }; -export class InvalidBlockError extends LodestarError { - constructor(type: InvalidBlockErrorType) { - super(type); - } -} +export class InvalidBlockError extends LodestarError {} diff --git a/packages/validator/src/slashingProtection/interchange/errors.ts b/packages/validator/src/slashingProtection/interchange/errors.ts index 63771df357c2..d03215f0d930 100644 --- a/packages/validator/src/slashingProtection/interchange/errors.ts +++ b/packages/validator/src/slashingProtection/interchange/errors.ts @@ -12,8 +12,4 @@ type InterchangeErrorErrorType = | {code: InterchangeErrorErrorCode.UNSUPPORTED_VERSION; version: string} | {code: InterchangeErrorErrorCode.GENESIS_VALIDATOR_MISMATCH; root: Root; expectedRoot: Root}; -export class InterchangeError extends LodestarError { - constructor(type: InterchangeErrorErrorType) { - super(type); - } -} +export class InterchangeError extends LodestarError {} diff --git a/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts b/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts index b43ced6c80d3..26210390a272 100644 --- a/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts +++ b/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; import {InterchangeLodestar} from "../types.js"; import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js"; diff --git a/packages/validator/src/slashingProtection/interchange/formats/v5.ts b/packages/validator/src/slashingProtection/interchange/formats/v5.ts index 838ba76c1a57..88e2ce70fe07 100644 --- a/packages/validator/src/slashingProtection/interchange/formats/v5.ts +++ b/packages/validator/src/slashingProtection/interchange/formats/v5.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; import {InterchangeLodestar} from "../types.js"; import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js"; diff --git a/packages/validator/src/slashingProtection/minMaxSurround/errors.ts b/packages/validator/src/slashingProtection/minMaxSurround/errors.ts index fd094df54db3..b6cd31187f57 100644 --- a/packages/validator/src/slashingProtection/minMaxSurround/errors.ts +++ b/packages/validator/src/slashingProtection/minMaxSurround/errors.ts @@ -24,8 +24,4 @@ type SurroundAttestationErrorType = attestation2Target: number; }; -export class SurroundAttestationError extends LodestarError { - constructor(type: SurroundAttestationErrorType) { - super(type); - } -} +export class SurroundAttestationError extends LodestarError {} diff --git a/packages/validator/src/util/externalSignerClient.ts b/packages/validator/src/util/externalSignerClient.ts index 1d9778375b88..64d595452296 100644 --- a/packages/validator/src/util/externalSignerClient.ts +++ b/packages/validator/src/util/externalSignerClient.ts @@ -21,8 +21,6 @@ import {computeEpochAtSlot, blindedOrFullBlockToHeader} from "@lodestar/state-tr import {toHex, toRootHex} from "@lodestar/utils"; import {PubkeyHex} from "../types.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - export enum SignableMessageType { AGGREGATION_SLOT = "AGGREGATION_SLOT", AGGREGATE_AND_PROOF = "AGGREGATE_AND_PROOF", diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 6d6705f512df..f83aa9828633 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -5,8 +5,6 @@ export class NotEqualParamsError extends Error {} type ConfigWithPreset = ChainConfig & BeaconPreset; -/* eslint-disable @typescript-eslint/naming-convention */ - /** * Assert localConfig values match externalSpecJson. externalSpecJson may contain more values than localConfig. * diff --git a/packages/validator/test/spec/params.ts b/packages/validator/test/spec/params.ts index c51a881bfeb3..0f5c707ff1c5 100644 --- a/packages/validator/test/spec/params.ts +++ b/packages/validator/test/spec/params.ts @@ -3,7 +3,6 @@ import {fileURLToPath} from "node:url"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = path.dirname(fileURLToPath(import.meta.url)); // Full link: https://github.com/eth2-clients/slashing-protection-interchange-tests/releases/download/v5.1.0/eip-3076-tests-v5.1.0.tar.gz diff --git a/packages/validator/test/unit/services/attestation.test.ts b/packages/validator/test/unit/services/attestation.test.ts index 66b722273102..b225ab09cdd2 100644 --- a/packages/validator/test/unit/services/attestation.test.ts +++ b/packages/validator/test/unit/services/attestation.test.ts @@ -52,7 +52,6 @@ describe("AttestationService", function () { vi.resetAllMocks(); }); - // eslint-disable-next-line @typescript-eslint/naming-convention const electraConfig: Partial = {ELECTRA_FORK_EPOCH: 0}; const testContexts: [string, AttestationServiceOpts, Partial][] = [ diff --git a/packages/validator/test/unit/services/doppelganger.test.ts b/packages/validator/test/unit/services/doppelganger.test.ts index 9b669b3c9396..943f0c08a9d3 100644 --- a/packages/validator/test/unit/services/doppelganger.test.ts +++ b/packages/validator/test/unit/services/doppelganger.test.ts @@ -213,8 +213,10 @@ function getMockBeaconApi(livenessMap: LivenessMap): ApiClient { } class ClockMockMsToSlot extends ClockMock { - constructor(public currentEpoch: Epoch) { + currentEpoch: Epoch; + constructor(currentEpoch: Epoch) { super(); + this.currentEpoch = currentEpoch; } async tickEpoch(epoch: Epoch, signal: AbortSignal): Promise { diff --git a/packages/validator/test/unit/services/syncCommitteDuties.test.ts b/packages/validator/test/unit/services/syncCommitteDuties.test.ts index dc43502d5b57..87d052b14ae5 100644 --- a/packages/validator/test/unit/services/syncCommitteDuties.test.ts +++ b/packages/validator/test/unit/services/syncCommitteDuties.test.ts @@ -20,8 +20,6 @@ import {ClockMock} from "../../utils/clock.js"; import {initValidatorStore} from "../../utils/validatorStore.js"; import {syncCommitteeIndicesToSubnets} from "../../../src/services/utils.js"; -/* eslint-disable @typescript-eslint/naming-convention */ - describe("SyncCommitteeDutiesService", function () { const api = getApiClientStub(); @@ -210,7 +208,6 @@ describe("SyncCommitteeDutiesService", function () { validatorSyncCommitteeIndices: [7], }; when(api.validator.getSyncCommitteeDuties) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment .calledWith({epoch: expect.any(Number), indices}) .thenResolve(mockApiResponse({data: [duty1, duty2], meta: {executionOptimistic: false}})); diff --git a/packages/validator/test/unit/services/syncCommittee.test.ts b/packages/validator/test/unit/services/syncCommittee.test.ts index 449f826c3806..201bbdc83632 100644 --- a/packages/validator/test/unit/services/syncCommittee.test.ts +++ b/packages/validator/test/unit/services/syncCommittee.test.ts @@ -21,8 +21,6 @@ vi.mock("../../../src/services/emitter.js"); vi.mock("../../../src/services/chainHeaderTracker.js"); vi.mock("../../../src/services/syncingStatusTracker.js"); -/* eslint-disable @typescript-eslint/naming-convention */ - describe("SyncCommitteeService", function () { const api = getApiClientStub(); // @ts-expect-error - Mocked class don't need parameters diff --git a/packages/validator/test/unit/slashingProtection/interchange/index.test.ts b/packages/validator/test/unit/slashingProtection/interchange/index.test.ts index af2694458368..4038c6d1d4c5 100644 --- a/packages/validator/test/unit/slashingProtection/interchange/index.test.ts +++ b/packages/validator/test/unit/slashingProtection/interchange/index.test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import {describe, it, expect} from "vitest"; import {toHexString} from "@chainsafe/ssz"; import {Root, ssz} from "@lodestar/types"; diff --git a/packages/validator/test/unit/slashingProtection/minMaxSurround/utils.ts b/packages/validator/test/unit/slashingProtection/minMaxSurround/utils.ts index e57af53d6837..6d9e4e0f559d 100644 --- a/packages/validator/test/unit/slashingProtection/minMaxSurround/utils.ts +++ b/packages/validator/test/unit/slashingProtection/minMaxSurround/utils.ts @@ -8,11 +8,11 @@ export class DistanceMapStore { this.map = new Map(); } - async get(pubkey: BLSPubkey, epoch: number): Promise { + async get(_pubkey: BLSPubkey, epoch: number): Promise { return this.map.get(epoch) ?? null; } - async setBatch(pubkey: BLSPubkey, values: DistanceEntry[]): Promise { + async setBatch(_pubkey: BLSPubkey, values: DistanceEntry[]): Promise { for (const {source, distance} of values) { this.map.set(source, distance); } diff --git a/packages/validator/test/unit/utils/clock.test.ts b/packages/validator/test/unit/utils/clock.test.ts index d668d753014a..f1c12e2cf66d 100644 --- a/packages/validator/test/unit/utils/clock.test.ts +++ b/packages/validator/test/unit/utils/clock.test.ts @@ -81,7 +81,6 @@ describe("util / Clock", function () { }); describe("getCurrentSlot", function () { - // eslint-disable-next-line @typescript-eslint/naming-convention const testConfig = {SECONDS_PER_SLOT: 12} as BeaconConfig; const genesisTime = Math.floor(new Date("2021-01-01").getTime() / 1000); diff --git a/packages/validator/test/unit/utils/interopConfigs.ts b/packages/validator/test/unit/utils/interopConfigs.ts index d263fa8c1d8f..36fff9051ce8 100644 --- a/packages/validator/test/unit/utils/interopConfigs.ts +++ b/packages/validator/test/unit/utils/interopConfigs.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ - export const lighthouseHoleskyConfig = { CONFIG_NAME: "holesky", PRESET_BASE: "mainnet", diff --git a/packages/validator/test/unit/utils/params.test.ts b/packages/validator/test/unit/utils/params.test.ts index 79701e1f7a6e..13bab507cf13 100644 --- a/packages/validator/test/unit/utils/params.test.ts +++ b/packages/validator/test/unit/utils/params.test.ts @@ -12,8 +12,6 @@ const testCases: {name: string; items: [ChainConfig, Record]}[] {name: "nimbus", items: [networksChainConfig.holesky, nimbusHoleskyConfig]}, ]; -/* eslint-disable @typescript-eslint/naming-convention */ - describe("utils / params / assertEqualParams", () => { it("default == default", () => { const chainConfigJson = chainConfigToJson(chainConfig); diff --git a/packages/validator/test/utils/spec.ts b/packages/validator/test/utils/spec.ts index 91d6a75d1a52..ae0be94b4bfa 100644 --- a/packages/validator/test/utils/spec.ts +++ b/packages/validator/test/utils/spec.ts @@ -1,7 +1,6 @@ import fs from "node:fs"; import path from "node:path"; -/* eslint-disable @typescript-eslint/naming-convention */ export type SlashingProtectionInterchangeTest = { name: string; genesis_validators_root: string; diff --git a/scripts/assert_eslintrc_sorted.mjs b/scripts/assert_eslintrc_sorted.mjs deleted file mode 100755 index 0b298b627340..000000000000 --- a/scripts/assert_eslintrc_sorted.mjs +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env node - -import assert from "node:assert"; -import eslintrc from "../.eslintrc.js"; - -assertSorted(eslintrc.extends, ".extends"); -assertSorted(Object.keys(eslintrc.rules), ".rules"); -for (const overrides of eslintrc.overrides) { - assertSorted(Object.keys(overrides.rules), `.overrides ${overrides.files.join(",")}`); -} - -/** @param {string[]} keys @param {string} id */ -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -function assertSorted(keys, id) { - try { - assert.deepStrictEqual(keys, [...keys].sort()); - } catch (e) { - // eslint-disable-next-line no-console - console.log(`Lint error in ${id}\n\n`, e.message); - process.exit(1); - } -} diff --git a/scripts/release/utils.mjs b/scripts/release/utils.mjs index ee02015f0577..19ae6f3d306b 100644 --- a/scripts/release/utils.mjs +++ b/scripts/release/utils.mjs @@ -50,7 +50,7 @@ export function parseCmdArgs() { // optional arg, defaults to HEAD try { commit = shell(`git log -n 1 --pretty='%h' ${commitArg ?? "HEAD"}`); - } catch (e) { + } catch (_e) { throw Error(`Invalid commit ${commitArg}`); } @@ -62,7 +62,7 @@ export function parseCmdArgs() { try { if (versionObj.includePrerelease) throw Error("Includes pre-release"); if (semver.clean(versionArg) !== versionMMP) throw Error("No clean major.minor.path version"); - } catch (e) { + } catch (_e) { throw Error(`Bad argv[2] semver version '${versionArg}': ${e.message}`); } @@ -82,7 +82,7 @@ export function assertCommitExistsInBranch(commit, branch) { try { // Also, ensure the branch exists first headCommit = shell(`git rev-parse refs/heads/${branch}`); - } catch (e) { + } catch (_e) { throw Error(`Branch ${branch} does not exist: ${e.message}`); } @@ -95,7 +95,7 @@ export function assertCommitExistsInBranch(commit, branch) { try { shell(`git merge-base --is-ancestor ${commit} ${headCommit}`); - } catch (e) { + } catch (_e) { throw Error(`Commit ${commit} does not belong to branch ${branch}`); } } @@ -129,7 +129,7 @@ export async function confirm(message) { export function checkBranchExistsLocal(branch) { try { return shell(`git show-ref refs/heads/${branch}`); - } catch (e) { + } catch (_e) { return null; } } @@ -156,7 +156,7 @@ export function checkBranchExistsRemote(branch) { // Return the first part of the first line return out.split(/\s+/)[0]; - } catch (e) { + } catch (_e) { return null; } } @@ -169,7 +169,7 @@ export function checkBranchExistsRemote(branch) { export function checkTagExistsLocal(tag) { try { return shell(`git show-ref refs/tags/${tag}`); - } catch (e) { + } catch (_e) { return null; } } @@ -195,7 +195,7 @@ export function checkTagExistsRemote(tag) { // Return the first part of the first line return out.split(/\s+/)[0]; - } catch (e) { + } catch (_e) { return null; } } @@ -224,7 +224,7 @@ export function readMainPackageJson() { let jsonStr; try { jsonStr = fs.readFileSync(packageJsonPath, "utf8"); - } catch (e) { + } catch (_e) { if (e.code === "ENOENT") { throw Error(`Must run script from repo root dir, package.json not found at ${packageJsonPath}`); } else { diff --git a/scripts/vitest/setupFiles/dotenv.ts b/scripts/vitest/setupFiles/dotenv.ts index 71364c7426bc..511cefd8eed4 100644 --- a/scripts/vitest/setupFiles/dotenv.ts +++ b/scripts/vitest/setupFiles/dotenv.ts @@ -1,8 +1,6 @@ import path from "node:path"; // It's a dev dependency -// eslint-disable-next-line import/no-extraneous-dependencies import {config} from "dotenv"; -// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = new URL(".", import.meta.url).pathname; config({path: path.join(__dirname, "../../../.env.test")}); diff --git a/types/vitest/index.d.ts b/types/vitest/index.d.ts index 387edcfa5279..297ed11e1904 100644 --- a/types/vitest/index.d.ts +++ b/types/vitest/index.d.ts @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-extraneous-dependencies, @typescript-eslint/no-unused-vars import * as vitest from "vitest"; interface CustomMatchers { @@ -42,7 +41,6 @@ interface CustomAsymmetricMatchers extends CustomMatchers { } declare module "vitest" { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - interface Assertion extends CustomMatchers {} + interface Assertion extends CustomMatchers {} interface AsymmetricMatchersContaining extends CustomAsymmetricMatchers {} } diff --git a/yarn.lock b/yarn.lock index 6d080025630a..9808fee96b84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - "@actions/cache@^1.0.7": version "1.0.7" resolved "https://registry.npmjs.org/@actions/cache/-/cache-1.0.7.tgz" @@ -289,6 +284,60 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@biomejs/biome@^1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-1.9.3.tgz#5362fc390ac00c82e3698824490e3801d012c1b0" + integrity sha512-POjAPz0APAmX33WOQFGQrwLvlu7WLV4CFJMlB12b6ZSg+2q6fYu9kZwLCOA+x83zXfcPd1RpuWOKJW0GbBwLIQ== + optionalDependencies: + "@biomejs/cli-darwin-arm64" "1.9.3" + "@biomejs/cli-darwin-x64" "1.9.3" + "@biomejs/cli-linux-arm64" "1.9.3" + "@biomejs/cli-linux-arm64-musl" "1.9.3" + "@biomejs/cli-linux-x64" "1.9.3" + "@biomejs/cli-linux-x64-musl" "1.9.3" + "@biomejs/cli-win32-arm64" "1.9.3" + "@biomejs/cli-win32-x64" "1.9.3" + +"@biomejs/cli-darwin-arm64@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.3.tgz#3a981835a7a891589b356bbdb4e50157e494aa7d" + integrity sha512-QZzD2XrjJDUyIZK+aR2i5DDxCJfdwiYbUKu9GzkCUJpL78uSelAHAPy7m0GuPMVtF/Uo+OKv97W3P9nuWZangQ== + +"@biomejs/cli-darwin-x64@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.3.tgz#0e33284e5def9cbc17705b6a9acbc22b161accb1" + integrity sha512-vSCoIBJE0BN3SWDFuAY/tRavpUtNoqiceJ5PrU3xDfsLcm/U6N93JSM0M9OAiC/X7mPPfejtr6Yc9vSgWlEgVw== + +"@biomejs/cli-linux-arm64-musl@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.3.tgz#b68e2fe56381cbf71770b6c785215448c47595fd" + integrity sha512-VBzyhaqqqwP3bAkkBrhVq50i3Uj9+RWuj+pYmXrMDgjS5+SKYGE56BwNw4l8hR3SmYbLSbEo15GcV043CDSk+Q== + +"@biomejs/cli-linux-arm64@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.3.tgz#bb8186f000bd7366c3a1822a4a505e374905c462" + integrity sha512-vJkAimD2+sVviNTbaWOGqEBy31cW0ZB52KtpVIbkuma7PlfII3tsLhFa+cwbRAcRBkobBBhqZ06hXoZAN8NODQ== + +"@biomejs/cli-linux-x64-musl@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.3.tgz#01ccee0db2ca2ec9fb51fa69b2fc9e96434b5b32" + integrity sha512-TJmnOG2+NOGM72mlczEsNki9UT+XAsMFAOo8J0me/N47EJ/vkLXxf481evfHLlxMejTY6IN8SdRSiPVLv6AHlA== + +"@biomejs/cli-linux-x64@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.3.tgz#82d6fb824dd2c76142ab8625e202eb63a34e14f1" + integrity sha512-x220V4c+romd26Mu1ptU+EudMXVS4xmzKxPVb9mgnfYlN4Yx9vD5NZraSx/onJnd3Gh/y8iPUdU5CDZJKg9COA== + +"@biomejs/cli-win32-arm64@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.3.tgz#7fac607ade8e204eecae09e127713f000da0ccf2" + integrity sha512-lg/yZis2HdQGsycUvHWSzo9kOvnGgvtrYRgoCEwPBwwAL8/6crOp3+f47tPwI/LI1dZrhSji7PNsGKGHbwyAhw== + +"@biomejs/cli-win32-x64@1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.3.tgz#1cbc269dcd5f29b034cb7f5982353c1cc3629318" + integrity sha512-cQMy2zanBkVLpmmxXdK6YePzmZx0s5Z7KEnwmrW54rcXK3myCNbQa09SwGZ8i/8sLw0H9F3X7K4rxVNGU8/D4Q== + "@bundled-es-modules/cookie@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz#c3b82703969a61cf6a46e959a012b2c257f6b164" @@ -438,19 +487,6 @@ uint8-varint "^2.0.2" uint8arrays "^5.0.1" -"@chainsafe/eslint-plugin-node@^11.2.3": - version "11.2.3" - resolved "https://registry.npmjs.org/@chainsafe/eslint-plugin-node/-/eslint-plugin-node-11.2.3.tgz" - integrity sha512-2iQv5JEaPcJuKP4pdawGd6iOVoUEDwx/PhsLqevwQXXz0WYwazW+p1fTF1bAcQNvZzLz4/wEBPtcVpQKNwY+jw== - dependencies: - eslint-plugin-es "^4.1.0" - eslint-utils "^2.0.0" - ignore "^5.1.1" - is-core-module "^2.3.0" - minimatch "^3.0.4" - resolve "^1.10.1" - semver "^6.1.0" - "@chainsafe/fast-crc32c@^4.1.1": version "4.1.1" resolved "https://registry.yarnpkg.com/@chainsafe/fast-crc32c/-/fast-crc32c-4.1.1.tgz#f551284ecf8325f676a1e26b938bcca51b9c8d93" @@ -814,38 +850,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== -"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== - dependencies: - eslint-visitor-keys "^3.3.0" - -"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.1.tgz#8c4bb756cc2aa7eaf13cfa5e69c83afb3260c20c" - integrity sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ== - -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@eslint/js@8.57.0": - version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== - "@ethereumjs/block@^4.2.2": version "4.2.2" resolved "https://registry.yarnpkg.com/@ethereumjs/block/-/block-4.2.2.tgz#fddecd34ed559f84ab8eb13098a6dee51a1360ae" @@ -1425,25 +1429,6 @@ resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== -"@humanwhocodes/config-array@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== - dependencies: - "@humanwhocodes/object-schema" "^2.0.2" - debug "^4.3.1" - minimatch "^3.0.5" - -"@humanwhocodes/module-importer@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" - integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== - -"@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== - "@hutson/parse-repository-url@^3.0.0": version "3.0.2" resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" @@ -2202,7 +2187,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": +"@nodelib/fs.walk@^1.2.3": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -2657,11 +2642,6 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@pkgr/core@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" - integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== - "@polka/url@^1.0.0-next.24": version "1.0.0-next.24" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.24.tgz#58601079e11784d20f82d0585865bb42305c4df3" @@ -3179,21 +3159,6 @@ resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138" integrity sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA== -"@types/json-schema@^7.0.12": - version "7.0.13" - 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" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - "@types/keyv@^3.1.4": version "3.1.4" resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" @@ -3267,11 +3232,11 @@ undici-types "~5.26.4" "@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== + version "20.16.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.16.7.tgz#0a245bf5805add998a22b8b5adac612ee70190bc" + integrity sha512-QkDQjAY3gkvJNcZOWwzy3BN34RweT0OQ9zJyvLCU0kSK22dO2QYh/NHGfbEAYylPYzRB1/iXcojS79wOg5gFSw== dependencies: - undici-types "~5.26.4" + undici-types "~6.19.2" "@types/node@^20.14.11": version "20.14.11" @@ -3317,16 +3282,6 @@ resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz" integrity sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g== -"@types/semver@^7.5.0": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" - integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw== - -"@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" @@ -3442,145 +3397,6 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz#5a5fcad1a7baed85c10080d71ad901f98c38d5b7" - integrity sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw== - dependencies: - "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "7.2.0" - "@typescript-eslint/type-utils" "7.2.0" - "@typescript-eslint/utils" "7.2.0" - "@typescript-eslint/visitor-keys" "7.2.0" - debug "^4.3.4" - graphemer "^1.4.0" - ignore "^5.2.4" - natural-compare "^1.4.0" - semver "^7.5.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/parser@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.2.0.tgz#44356312aea8852a3a82deebdacd52ba614ec07a" - integrity sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg== - dependencies: - "@typescript-eslint/scope-manager" "7.2.0" - "@typescript-eslint/types" "7.2.0" - "@typescript-eslint/typescript-estree" "7.2.0" - "@typescript-eslint/visitor-keys" "7.2.0" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz#cfb437b09a84f95a0930a76b066e89e35d94e3da" - integrity sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg== - dependencies: - "@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" - integrity sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA== - dependencies: - "@typescript-eslint/typescript-estree" "7.2.0" - "@typescript-eslint/utils" "7.2.0" - debug "^4.3.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/types@7.2.0": - version "7.2.0" - 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" - integrity sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA== - dependencies: - "@typescript-eslint/types" "7.2.0" - "@typescript-eslint/visitor-keys" "7.2.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - minimatch "9.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.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== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.12" - "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "7.2.0" - "@typescript-eslint/types" "7.2.0" - "@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" - integrity sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A== - dependencies: - "@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@^2.0.4": version "2.0.4" resolved "https://registry.yarnpkg.com/@vitest/browser/-/browser-2.0.4.tgz#6569258b4a8085f348007acd5ecf61db4eec4340" @@ -3853,11 +3669,6 @@ abstract-logging@^2.0.1: resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - acorn-walk@^8.1.1: version "8.2.0" resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" @@ -3868,11 +3679,6 @@ acorn@^8.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== -acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== - add-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" @@ -3926,16 +3732,6 @@ ajv-formats@^3.0.1: dependencies: ajv "^8.0.0" -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== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - ajv@^8.0.0, ajv@^8.12.0: version "8.12.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" @@ -3956,6 +3752,16 @@ ajv@^8.6.0: require-from-string "^2.0.2" uri-js "^4.2.2" +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== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ansi-colors@4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" @@ -4142,64 +3948,11 @@ array-ify@^1.0.0: resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== -array-includes@^3.1.7: - version "3.1.7" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - is-string "^1.0.7" - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.filter@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz#423771edeb417ff5914111fff4277ea0624c0d0e" - integrity sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - -array.prototype.findlastindex@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz#d1c50f0b3a9da191981ff8942a0aedd82794404f" - integrity sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ== - dependencies: - call-bind "^1.0.5" - define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.3.0" - es-shim-unscopables "^1.0.2" - -array.prototype.flat@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" - integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - -array.prototype.flatmap@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" - integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - arraybuffer.prototype.slice@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" @@ -5466,7 +5219,7 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -5583,20 +5336,13 @@ de-indent@^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.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: +debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - debug@^4.3.5: version "4.3.5" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" @@ -5649,11 +5395,6 @@ deep-eql@^5.0.1: resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== -deep-is@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - deepmerge-ts@^5.0.0, deepmerge-ts@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/deepmerge-ts/-/deepmerge-ts-5.1.0.tgz#c55206cc4c7be2ded89b9c816cf3608884525d7a" @@ -5690,7 +5431,7 @@ define-lazy-prop@^2.0.0: resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== -define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0, define-properties@^1.2.1: +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== @@ -5865,20 +5606,6 @@ dockerode@^3.3.5: docker-modem "^3.0.0" tar-fs "~2.0.1" -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - dom-accessibility-api@^0.5.9: version "0.5.16" resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" @@ -6011,14 +5738,6 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^5.12.0: - version "5.15.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" - integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - enquirer@~2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" @@ -6058,7 +5777,7 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.18.0-next.2, es-abstract@^1.22.1, es-abstract@^1.22.3: +es-abstract@^1.18.0-next.2, es-abstract@^1.22.1: version "1.22.3" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== @@ -6103,16 +5822,6 @@ es-abstract@^1.18.0-next.2, es-abstract@^1.22.1, es-abstract@^1.22.3: unbox-primitive "^1.0.2" which-typed-array "^1.1.13" -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== - -es-errors@^1.0.0, es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" @@ -6122,20 +5831,6 @@ es-set-tostringtag@^2.0.1: has "^1.0.3" has-tostringtag "^1.0.0" -es-shim-unscopables@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== - dependencies: - has "^1.0.3" - -es-shim-unscopables@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" - integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== - dependencies: - hasown "^2.0.0" - es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -6220,191 +5915,17 @@ escodegen@^2.1.0: optionalDependencies: source-map "~0.6.1" -eslint-import-resolver-node@^0.3.9: - version "0.3.9" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" - integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== - dependencies: - debug "^3.2.7" - is-core-module "^2.13.0" - resolve "^1.22.4" - -eslint-import-resolver-typescript@^3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa" - integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg== - dependencies: - debug "^4.3.4" - enhanced-resolve "^5.12.0" - eslint-module-utils "^2.7.4" - fast-glob "^3.3.1" - get-tsconfig "^4.5.0" - is-core-module "^2.11.0" - is-glob "^4.0.3" - -eslint-module-utils@^2.7.4: - version "2.7.4" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" - integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== - dependencies: - debug "^3.2.7" - -eslint-module-utils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" - integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== - dependencies: - debug "^3.2.7" - -eslint-plugin-es@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz" - integrity sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ== - dependencies: - eslint-utils "^2.0.0" - regexpp "^3.0.0" - -eslint-plugin-import@^2.29.1: - version "2.29.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643" - integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== - dependencies: - array-includes "^3.1.7" - array.prototype.findlastindex "^1.2.3" - array.prototype.flat "^1.3.2" - array.prototype.flatmap "^1.3.2" - debug "^3.2.7" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.9" - eslint-module-utils "^2.8.0" - hasown "^2.0.0" - is-core-module "^2.13.1" - is-glob "^4.0.3" - minimatch "^3.1.2" - object.fromentries "^2.0.7" - object.groupby "^1.0.1" - object.values "^1.1.7" - semver "^6.3.1" - tsconfig-paths "^3.15.0" - -eslint-plugin-prettier@^5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz#17cfade9e732cef32b5f5be53bd4e07afd8e67e1" - integrity sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw== - dependencies: - prettier-linter-helpers "^1.0.0" - synckit "^0.8.6" - -eslint-plugin-vitest@^0.3.26: - version "0.3.26" - resolved "https://registry.yarnpkg.com/eslint-plugin-vitest/-/eslint-plugin-vitest-0.3.26.tgz#0906893c1f8f7094614fc6ff255c0a369cfbf427" - integrity sha512-oxe5JSPgRjco8caVLTh7Ti8PxpwJdhSV0hTQAmkFcNcmy/9DnqLB/oNVRA11RmVRP//2+jIIT6JuBEcpW3obYg== - dependencies: - "@typescript-eslint/utils" "^7.1.1" - -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-utils@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -eslint@^8.57.0: - version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.57.0" - "@humanwhocodes/config-array" "^0.11.14" - "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" - ajv "^6.12.4" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - find-up "^5.0.0" - glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" - ignore "^5.2.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" - esm@^3.2.25: version "3.2.25" resolved "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz" integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== - dependencies: - acorn "^8.9.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" - esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^5.1.0, estraverse@^5.2.0: +estraverse@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== @@ -6608,17 +6129,12 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - fast-fifo@^1.1.0, fast-fifo@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== -fast-glob@^3.2.9, fast-glob@^3.3.1: +fast-glob@^3.2.9: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -6647,11 +6163,6 @@ fast-json-stringify@^6.0.0: json-schema-ref-resolver "^1.0.1" rfdc "^1.2.0" -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - fast-querystring@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/fast-querystring/-/fast-querystring-1.1.1.tgz#f4c56ef56b1a954880cfd8c01b83f9e1a3d3fda2" @@ -6754,13 +6265,6 @@ figures@^5.0.0: escape-string-regexp "^5.0.0" is-unicode-supported "^1.2.0" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - file-stream-rotator@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz#007019e735b262bb6c6f0197e58e5c87cb96cec3" @@ -6834,24 +6338,11 @@ find-up@^6.3.0: locate-path "^7.1.0" path-exists "^5.0.0" -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - flat@^5.0.2: version "5.0.2" resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== -flatted@^3.1.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" - integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== - fn.name@1.x.x: version "1.1.0" resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" @@ -7153,13 +6644,6 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" -get-tsconfig@^4.5.0: - version "4.6.2" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.6.2.tgz#831879a5e6c2aa24fe79b60340e2233a1e0f472e" - integrity sha512-E5XrT4CbbXcXWy+1jChlZmrmCwd5KGx502kDCXJJ7y898TtWW9FwoG5HfOLVRKmlmDGkWN2HM9Ho+/Y8F0sJDg== - dependencies: - resolve-pkg-maps "^1.0.0" - get-uri@^6.0.1: version "6.0.2" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.2.tgz#e019521646f4a8ff6d291fbaea2c46da204bb75b" @@ -7224,13 +6708,6 @@ glob-parent@5.1.2, glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - glob@7.1.4: version "7.1.4" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" @@ -7346,13 +6823,6 @@ global-agent@^3.0.0: semver "^7.3.2" serialize-error "^7.0.1" -globals@^13.19.0: - version "13.20.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== - dependencies: - type-fest "^0.20.2" - globalthis@^1.0.1, globalthis@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" @@ -7360,7 +6830,7 @@ globalthis@^1.0.1, globalthis@^1.0.3: dependencies: define-properties "^1.1.3" -globby@11.1.0, globby@^11.1.0: +globby@11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -7423,11 +6893,6 @@ grapheme-splitter@^1.0.2: resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== -graphemer@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" - integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== - graphql@^16.8.1: version "16.9.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.9.0.tgz#1c310e63f16a49ce1fbb230bd0a000e99f6f115f" @@ -7743,7 +7208,7 @@ ignore-walk@^6.0.0: dependencies: minimatch "^7.4.2" -ignore@^5.0.4, ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4: +ignore@^5.0.4, ignore@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== @@ -7753,7 +7218,7 @@ immutable@^4.3.2: resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.5.tgz#f8b436e66d59f99760dc577f5c99a4fd2a5cc5a0" integrity sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw== -import-fresh@^3.2.1, import-fresh@^3.3.0: +import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -7979,7 +7444,7 @@ is-ci@3.0.1: dependencies: ci-info "^3.2.0" -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: +is-core-module@^2.1.0, is-core-module@^2.13.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== @@ -8018,7 +7483,7 @@ is-generator-function@^1.0.7: resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.8.tgz" integrity sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ== -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: +is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -8101,11 +7566,6 @@ is-observable@^2.1.0: resolved "https://registry.npmjs.org/is-observable/-/is-observable-2.1.0.tgz" integrity sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw== -is-path-inside@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" @@ -8611,23 +8071,11 @@ json-schema-traverse@^1.0.0: resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - json-stringify-safe@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - json5@^2.2.2: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" @@ -8805,14 +8253,6 @@ level@^8.0.0: browser-level "^1.0.1" classic-level "^1.2.0" -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - libnpmaccess@7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-7.0.2.tgz#7f056c8c933dd9c8ba771fa6493556b53c5aac52" @@ -8994,11 +8434,6 @@ lodash.isplainobject@^4.0.6: resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - lodash.some@^4.6.0: version "4.6.0" resolved "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz" @@ -9417,13 +8852,6 @@ minimatch@5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== - dependencies: - brace-expansion "^2.0.1" - minimatch@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" @@ -9431,7 +8859,7 @@ minimatch@^10.0.0: dependencies: brace-expansion "^2.0.1" -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -9459,13 +8887,27 @@ minimatch@^8.0.2: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.3, minimatch@^9.0.4: +minimatch@^9.0.0, minimatch@^9.0.1: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.3: 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@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + 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" @@ -9783,11 +9225,6 @@ native-fetch@^4.0.2: resolved "https://registry.yarnpkg.com/native-fetch/-/native-fetch-4.0.2.tgz#75c8a44c5f3bb021713e5e24f2846750883e49af" integrity sha512-4QcVlKFtv2EYVS5MBgsGX5+NWKtbDbIECdUXDBGDMAZXq3Jkv9zf+y8iS7Ub8fEdga3GpYeazp9gauNqXHJOCg== -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - negotiator@^0.6.2, negotiator@^0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" @@ -10235,35 +9672,6 @@ object.assign@^4.1.4: has-symbols "^1.0.3" object-keys "^1.1.1" -object.fromentries@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" - integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -object.groupby@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.2.tgz#494800ff5bab78fd0eff2835ec859066e00192ec" - integrity sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw== - dependencies: - array.prototype.filter "^1.0.3" - call-bind "^1.0.5" - define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.0.0" - -object.values@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" - integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - obliterator@^2.0.1: version "2.0.4" resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816" @@ -10326,18 +9734,6 @@ openapi-types@^12.1.3: resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-12.1.3.tgz#471995eb26c4b97b7bd356aacf7b91b73e777dd3" integrity sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw== -optionator@^0.9.3: - version "0.9.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== - dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - ora@^5.4.1: version "5.4.1" resolved "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz" @@ -10849,18 +10245,6 @@ postcss@^8.4.39: picocolors "^1.0.1" source-map-js "^1.2.0" -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - prettier@^3.2.5: version "3.2.5" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" @@ -11315,11 +10699,6 @@ regexp.prototype.flags@^1.5.1: define-properties "^1.2.0" set-function-name "^2.0.0" -regexpp@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -11357,12 +10736,7 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve-pkg-maps@^1.0.0: - version "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.22.1: +resolve@^1.10.0, resolve@^1.17.0, 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== @@ -11669,7 +11043,7 @@ semver@7.5.3: dependencies: lru-cache "^6.0.0" -semver@^6.1.0, semver@^6.2.0, semver@^6.3.1: +semver@^6.1.0, semver@^6.2.0: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -12277,7 +11651,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== @@ -12358,25 +11732,12 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -synckit@^0.8.6: - version "0.8.8" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.8.tgz#fe7fe446518e3d3d49f5e429f443cf08b6edfcd7" - integrity sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ== - dependencies: - "@pkgr/core" "^0.1.0" - tslib "^2.6.2" - 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" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - -tar-fs@^3.0.4, tar-fs@^3.0.5, tar-fs@^3.0.6: +tar-fs@^3.0.4, tar-fs@^3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.6.tgz#eaccd3a67d5672f09ca8e8f9c3d2b89fa173f217" integrity sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w== @@ -12387,6 +11748,17 @@ tar-fs@^3.0.4, tar-fs@^3.0.5, tar-fs@^3.0.6: bare-fs "^2.1.1" bare-path "^2.1.0" +tar-fs@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.5.tgz#f954d77767e4e6edf973384e1eb95f8f81d64ed9" + integrity sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg== + dependencies: + pump "^3.0.0" + tar-stream "^3.1.5" + optionalDependencies: + bare-fs "^2.1.1" + bare-path "^2.1.0" + tar-fs@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2" @@ -12492,11 +11864,6 @@ text-hex@1.0.x: resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz" integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - thread-stream@^2.6.0: version "2.7.0" resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-2.7.0.tgz#d8a8e1b3fd538a6cca8ce69dbe5d3d097b601e11" @@ -12648,16 +12015,6 @@ triple-beam@^1.3.0: resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz" integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== -ts-api-utils@^1.0.1: - version "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" @@ -12696,16 +12053,6 @@ ts-node@^10.9.2: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tsconfig-paths@^3.15.0: - version "3.15.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" - integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.2" - minimist "^1.2.6" - strip-bom "^3.0.0" - tsconfig-paths@^4.1.2: version "4.2.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" @@ -12735,7 +12082,7 @@ tslib@^1.10.0: resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.6.1, tslib@^2.6.2: +tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -12769,13 +12116,6 @@ tweetnacl@^0.14.3: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - type-fest@2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.13.0.tgz#d1ecee38af29eb2e863b22299a3d68ef30d2abfb" @@ -12791,11 +12131,6 @@ type-fest@^0.18.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - type-fest@^0.21.3: version "0.21.3" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" @@ -12948,6 +12283,11 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + undici@^5.12.0: version "5.28.4" resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" From 38f54abed47128667d1b7917a442ffb934ff9c7d Mon Sep 17 00:00:00 2001 From: vladmarusyk <149159095+vladmarusyk@users.noreply.github.com> Date: Thu, 10 Oct 2024 20:09:54 +0300 Subject: [PATCH 140/259] feat: allow filtering of validators by top-level validator status (#7143) * Fix ValidatorStatus type issue * refactor: use switch-case and typed general validator status mapping * Update packages/beacon-node/src/api/impl/beacon/state/utils.ts Co-authored-by: Nico Flaig * refactor: deleted unrelated code * refactor: deleted unrelated code * Update packages/beacon-node/src/api/impl/beacon/state/utils.ts Co-authored-by: Nico Flaig --------- Co-authored-by: Nico Flaig --- .../src/api/impl/beacon/state/utils.ts | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index 074fa7928d91..15e8bdf73176 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -83,6 +83,28 @@ export async function getStateResponseWithRegen( return res; } +type GeneralValidatorStatus = "active" | "pending" | "exited" | "withdrawal"; + +function mapToGeneralStatus(subStatus: routes.beacon.ValidatorStatus): GeneralValidatorStatus { + switch (subStatus) { + case "active_ongoing": + case "active_exiting": + case "active_slashed": + return "active"; + case "pending_initialized": + case "pending_queued": + return "pending"; + case "exited_slashed": + case "exited_unslashed": + return "exited"; + case "withdrawal_possible": + case "withdrawal_done": + return "withdrawal"; + default: + throw new Error(`Unknown substatus: ${subStatus}`); + } +} + export function toValidatorResponse( index: ValidatorIndex, validator: phase0.Validator, @@ -109,9 +131,10 @@ export function filterStateValidatorsByStatus( for (const validator of validatorsArr) { const validatorStatus = getValidatorStatus(validator, currentEpoch); + const generalStatus = mapToGeneralStatus(validatorStatus); const resp = getStateValidatorIndex(validator.pubkey, state, pubkey2index); - if (resp.valid && statusSet.has(validatorStatus)) { + if (resp.valid && (statusSet.has(validatorStatus) || statusSet.has(generalStatus))) { responses.push( toValidatorResponse(resp.validatorIndex, validator, state.balances.get(resp.validatorIndex), currentEpoch) ); From 0d87c28aedb2e0556b027fc0714349542ff17542 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 10 Oct 2024 19:39:30 +0100 Subject: [PATCH 141/259] chore: remove 'active' from validator status type (#7146) * chore: remove 'active' from validator status type * Clean up usage --- packages/beacon-node/src/api/impl/validator/index.ts | 1 - packages/types/src/utils/validatorStatus.ts | 4 +++- packages/validator/src/services/indices.ts | 1 - .../validator/test/unit/services/attestationDuties.test.ts | 2 +- .../validator/test/unit/services/syncCommitteDuties.test.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index f6cbc4e98e98..8629bbb1f47c 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -1363,7 +1363,6 @@ export function getValidatorApi( const validator = headState.validators.getReadonly(validatorIndex); const status = getValidatorStatus(validator, currentEpoch); return ( - status === "active" || status === "active_exiting" || status === "active_ongoing" || status === "active_slashed" || diff --git a/packages/types/src/utils/validatorStatus.ts b/packages/types/src/utils/validatorStatus.ts index e14a4b14c412..aa8171fbbbd2 100644 --- a/packages/types/src/utils/validatorStatus.ts +++ b/packages/types/src/utils/validatorStatus.ts @@ -1,8 +1,10 @@ import {FAR_FUTURE_EPOCH} from "@lodestar/params"; import {Epoch, phase0} from "../types.js"; +/** + * [Validator status specification](https://hackmd.io/ofFJ5gOmQpu1jjHilHbdQQ) + */ export type ValidatorStatus = - | "active" | "pending_initialized" | "pending_queued" | "active_ongoing" diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index c3f511669bf1..ff8d1d46ab26 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -20,7 +20,6 @@ type SimpleValidatorStatus = "pending" | "active" | "exited" | "withdrawn"; const statusToSimpleStatusMapping = (status: routes.beacon.ValidatorStatus): SimpleValidatorStatus => { switch (status) { - case "active": case "active_exiting": case "active_slashed": case "active_ongoing": diff --git a/packages/validator/test/unit/services/attestationDuties.test.ts b/packages/validator/test/unit/services/attestationDuties.test.ts index a9d50eaf42c6..f59b00d88c9c 100644 --- a/packages/validator/test/unit/services/attestationDuties.test.ts +++ b/packages/validator/test/unit/services/attestationDuties.test.ts @@ -33,7 +33,7 @@ describe("AttestationDutiesService", function () { const defaultValidator: routes.beacon.ValidatorResponse = { index, balance: 32e9, - status: "active", + status: "active_ongoing", validator: ssz.phase0.Validator.defaultValue(), }; diff --git a/packages/validator/test/unit/services/syncCommitteDuties.test.ts b/packages/validator/test/unit/services/syncCommitteDuties.test.ts index 87d052b14ae5..d94926e9b564 100644 --- a/packages/validator/test/unit/services/syncCommitteDuties.test.ts +++ b/packages/validator/test/unit/services/syncCommitteDuties.test.ts @@ -36,7 +36,7 @@ describe("SyncCommitteeDutiesService", function () { const defaultValidator: routes.beacon.ValidatorResponse = { index: indices[0], balance: 32e9, - status: "active", + status: "active_ongoing", validator: ssz.phase0.Validator.defaultValue(), }; From a570048187f1e729c0be3939239fcfa3aa0a008e Mon Sep 17 00:00:00 2001 From: twoeths Date: Fri, 11 Oct 2024 09:37:29 +0700 Subject: [PATCH 142/259] fix: improve forkchoice (#7142) * fix: reuse deltas in computeDeltas * fix: remodel queuedAttestations * fix: call forkchoice.updateTime() once per clock slot * fix: recomputeForkChoiceHead() at slot boundary * fix: improve computeDeltas() - handle newBalances = oldBalances * fix: do not compute forkchoice head at slot boundary * fix: prepareNextSlot unit test --- .../src/api/impl/validator/index.ts | 12 ----- .../src/chain/blocks/importBlock.ts | 3 +- packages/beacon-node/src/chain/chain.ts | 12 ++--- .../beacon-node/src/chain/forkChoice/index.ts | 5 ++ packages/beacon-node/src/chain/interface.ts | 3 +- .../beacon-node/src/chain/prepareNextSlot.ts | 5 +- .../beacon-node/src/metrics/metrics/beacon.ts | 4 +- .../test/unit/chain/prepareNextSlot.test.ts | 2 +- .../fork-choice/src/forkChoice/forkChoice.ts | 51 ++++++++++++------- .../fork-choice/src/forkChoice/interface.ts | 11 ---- .../src/protoArray/computeDeltas.ts | 11 ++-- 11 files changed, 61 insertions(+), 58 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 8629bbb1f47c..e1ea415443b9 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -389,10 +389,6 @@ export function getValidatorApi( notWhileSyncing(); await waitForSlot(slot); // Must never request for a future slot > currentSlot - // Process the queued attestations in the forkchoice for correct head estimation - // forkChoice.updateTime() might have already been called by the onSlot clock - // handler, in which case this should just return. - chain.forkChoice.updateTime(slot); parentBlockRoot = fromHex(chain.getProposerHead(slot).blockRoot); } else { parentBlockRoot = inParentBlockRoot; @@ -459,10 +455,6 @@ export function getValidatorApi( notWhileSyncing(); await waitForSlot(slot); // Must never request for a future slot > currentSlot - // Process the queued attestations in the forkchoice for correct head estimation - // forkChoice.updateTime() might have already been called by the onSlot clock - // handler, in which case this should just return. - chain.forkChoice.updateTime(slot); parentBlockRoot = fromHex(chain.getProposerHead(slot).blockRoot); } else { parentBlockRoot = inParentBlockRoot; @@ -535,10 +527,6 @@ export function getValidatorApi( notWhileSyncing(); await waitForSlot(slot); // Must never request for a future slot > currentSlot - // Process the queued attestations in the forkchoice for correct head estimation - // forkChoice.updateTime() might have already been called by the onSlot clock - // handler, in which case this should just return. - chain.forkChoice.updateTime(slot); const parentBlockRoot = fromHex(chain.getProposerHead(slot).blockRoot); notOnOutOfRangeData(parentBlockRoot); diff --git a/packages/beacon-node/src/chain/blocks/importBlock.ts b/packages/beacon-node/src/chain/blocks/importBlock.ts index d19d6a60c564..596f01f391a4 100644 --- a/packages/beacon-node/src/chain/blocks/importBlock.ts +++ b/packages/beacon-node/src/chain/blocks/importBlock.ts @@ -19,6 +19,7 @@ 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 {ForkchoiceCaller} from "../forkChoice/index.js"; import {FullyVerifiedBlock, ImportBlockOpts, AttestationImportOpt, BlockInputType} from "./types.js"; import {getCheckpointFromState} from "./utils/checkpoint.js"; import {writeBlockInputToDb} from "./writeBlockInputToDb.js"; @@ -208,7 +209,7 @@ export async function importBlock( // 5. Compute head. If new head, immediately stateCache.setHeadState() const oldHead = this.forkChoice.getHead(); - const newHead = this.recomputeForkChoiceHead(); + const newHead = this.recomputeForkChoiceHead(ForkchoiceCaller.importBlock); const currFinalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch; if (newHead.blockRoot !== oldHead.blockRoot) { diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 371f660abe2e..4bd8cd2bea3d 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -60,7 +60,7 @@ import { } from "./interface.js"; import {IChainOptions} from "./options.js"; import {QueuedStateRegenerator, RegenCaller} from "./regen/index.js"; -import {initializeForkChoice} from "./forkChoice/index.js"; +import {ForkchoiceCaller, initializeForkChoice} from "./forkChoice/index.js"; import {IBlsVerifier, BlsSingleThreadVerifier, BlsMultiThreadWorkerPool} from "./bls/index.js"; import { SeenAttesters, @@ -784,9 +784,9 @@ export class BeaconChain implements IBeaconChain { }; } - recomputeForkChoiceHead(): ProtoBlock { + recomputeForkChoiceHead(caller: ForkchoiceCaller): ProtoBlock { this.metrics?.forkChoice.requests.inc(); - const timer = this.metrics?.forkChoice.findHead.startTimer({entrypoint: FindHeadFnName.recomputeForkChoiceHead}); + const timer = this.metrics?.forkChoice.findHead.startTimer({caller}); try { return this.forkChoice.updateAndGetHead({mode: UpdateHeadOpt.GetCanonicialHead}).head; @@ -800,7 +800,7 @@ export class BeaconChain implements IBeaconChain { predictProposerHead(slot: Slot): ProtoBlock { this.metrics?.forkChoice.requests.inc(); - const timer = this.metrics?.forkChoice.findHead.startTimer({entrypoint: FindHeadFnName.predictProposerHead}); + const timer = this.metrics?.forkChoice.findHead.startTimer({caller: FindHeadFnName.predictProposerHead}); try { return this.forkChoice.updateAndGetHead({mode: UpdateHeadOpt.GetPredictedProposerHead, slot}).head; @@ -814,7 +814,7 @@ export class BeaconChain implements IBeaconChain { getProposerHead(slot: Slot): ProtoBlock { this.metrics?.forkChoice.requests.inc(); - const timer = this.metrics?.forkChoice.findHead.startTimer({entrypoint: FindHeadFnName.getProposerHead}); + const timer = this.metrics?.forkChoice.findHead.startTimer({caller: FindHeadFnName.getProposerHead}); const secFromSlot = this.clock.secFromSlot(slot); try { @@ -1060,8 +1060,8 @@ export class BeaconChain implements IBeaconChain { if (this.forkChoice.irrecoverableError) { this.processShutdownCallback(this.forkChoice.irrecoverableError); } - this.forkChoice.updateTime(slot); + this.forkChoice.updateTime(slot); this.metrics?.clockSlot.set(slot); this.attestationPool.prune(slot); diff --git a/packages/beacon-node/src/chain/forkChoice/index.ts b/packages/beacon-node/src/chain/forkChoice/index.ts index 346a4afe1e7f..839975de4e26 100644 --- a/packages/beacon-node/src/chain/forkChoice/index.ts +++ b/packages/beacon-node/src/chain/forkChoice/index.ts @@ -27,6 +27,11 @@ export type ForkChoiceOpts = RawForkChoiceOpts & { forkchoiceConstructor?: typeof ForkChoice; }; +export enum ForkchoiceCaller { + prepareNextSlot = "prepare_next_slot", + importBlock = "import_block", +} + /** * Fork Choice extended with a ChainEventEmitter */ diff --git a/packages/beacon-node/src/chain/interface.ts b/packages/beacon-node/src/chain/interface.ts index 531f60dc0e63..3b44ffd594ae 100644 --- a/packages/beacon-node/src/chain/interface.ts +++ b/packages/beacon-node/src/chain/interface.ts @@ -58,6 +58,7 @@ import {ShufflingCache} from "./shufflingCache.js"; import {BlockRewards} from "./rewards/blockRewards.js"; import {AttestationsRewards} from "./rewards/attestationsRewards.js"; import {SyncCommitteeRewards} from "./rewards/syncCommitteeRewards.js"; +import {ForkchoiceCaller} from "./forkChoice/index.js"; export {BlockType, type AssembledBlockType}; export {type ProposerPreparationData}; @@ -204,7 +205,7 @@ export interface IBeaconChain { getStatus(): phase0.Status; - recomputeForkChoiceHead(): ProtoBlock; + recomputeForkChoiceHead(caller: ForkchoiceCaller): ProtoBlock; /** When proposerBoostReorg is enabled, this is called at slot n-1 to predict the head block to build on if we are proposing at slot n */ predictProposerHead(slot: Slot): ProtoBlock; diff --git a/packages/beacon-node/src/chain/prepareNextSlot.ts b/packages/beacon-node/src/chain/prepareNextSlot.ts index 48724ab25b0b..bda618758842 100644 --- a/packages/beacon-node/src/chain/prepareNextSlot.ts +++ b/packages/beacon-node/src/chain/prepareNextSlot.ts @@ -18,6 +18,7 @@ import {isQueueErrorAborted} from "../util/queue/index.js"; import {prepareExecutionPayload, getPayloadAttributesForSSE} from "./produceBlock/produceBlockBody.js"; import {IBeaconChain} from "./interface.js"; import {RegenCaller} from "./regen/index.js"; +import {ForkchoiceCaller} from "./forkChoice/index.js"; /* With 12s slot times, this scheduler will run 4s before the start of each slot (`12 / 3 = 4`). */ export const SCHEDULER_LOOKAHEAD_FACTOR = 3; @@ -77,7 +78,9 @@ export class PrepareNextSlotScheduler { await sleep(slotMs - slotMs / SCHEDULER_LOOKAHEAD_FACTOR, this.signal); // calling updateHead() here before we produce a block to reduce reorg possibility - const {slot: headSlot, blockRoot: headRoot} = this.chain.recomputeForkChoiceHead(); + const {slot: headSlot, blockRoot: headRoot} = this.chain.recomputeForkChoiceHead( + ForkchoiceCaller.prepareNextSlot + ); // PS: previously this was comparing slots, but that gave no leway on the skipped // slots on epoch bounday. Making it more fluid. diff --git a/packages/beacon-node/src/metrics/metrics/beacon.ts b/packages/beacon-node/src/metrics/metrics/beacon.ts index 6e86328ee561..1737a5a2468f 100644 --- a/packages/beacon-node/src/metrics/metrics/beacon.ts +++ b/packages/beacon-node/src/metrics/metrics/beacon.ts @@ -58,11 +58,11 @@ export function createBeaconMetrics(register: RegistryMetricCreator) { // Non-spec'ed forkChoice: { - findHead: register.histogram<{entrypoint: string}>({ + findHead: register.histogram<{caller: string}>({ name: "beacon_fork_choice_find_head_seconds", help: "Time taken to find head in seconds", buckets: [0.1, 1, 10], - labelNames: ["entrypoint"], + labelNames: ["caller"], }), requests: register.gauge({ name: "beacon_fork_choice_requests_total", diff --git a/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts b/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts index 9ce121e976d0..c7d0a7801fec 100644 --- a/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts +++ b/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts @@ -98,7 +98,7 @@ describe("PrepareNextSlot scheduler", () => { scheduler.prepareForNextSlot(2 * SLOTS_PER_EPOCH - 1), vi.advanceTimersByTimeAsync((config.SECONDS_PER_SLOT * 1000 * 2) / 3), ]); - expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalledWith(); + expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalledOnce(); expect(regenStub.getBlockSlotState).not.toHaveBeenCalled(); }); diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index 828a16725444..6ca3fd3a183a 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -1,4 +1,4 @@ -import {Logger, fromHex, toRootHex} from "@lodestar/utils"; +import {Logger, MapDef, fromHex, toRootHex} from "@lodestar/utils"; import {SLOTS_PER_HISTORICAL_ROOT, SLOTS_PER_EPOCH, INTERVALS_PER_SLOT} from "@lodestar/params"; import {bellatrix, Slot, ValidatorIndex, phase0, ssz, RootHex, Epoch, Root, BeaconBlock} from "@lodestar/types"; import { @@ -34,7 +34,6 @@ import {ForkChoiceError, ForkChoiceErrorCode, InvalidBlockCode, InvalidAttestati import { IForkChoice, LatestMessage, - QueuedAttestation, PowBlockHex, EpochDifference, AncestorResult, @@ -91,7 +90,9 @@ export class ForkChoice implements IForkChoice { * Attestations that arrived at the current slot and must be queued for later processing. * NOT currently tracked in the protoArray */ - private readonly queuedAttestations = new Set(); + private readonly queuedAttestations: MapDef>> = new MapDef( + () => new MapDef(() => new Set()) + ); // Note: as of Jun 2022 Lodestar metrics show that 100% of the times updateHead() is called, synced = false. // Because we are processing attestations from gossip, recomputing scores is always necessary @@ -128,9 +129,13 @@ export class ForkChoice implements IForkChoice { } getMetrics(): ForkChoiceMetrics { + let numAttestations = 0; + for (const indicesByRoot of this.queuedAttestations.values()) { + numAttestations += Array.from(indicesByRoot.values()).reduce((acc, indices) => acc + indices.size, 0); + } return { votes: this.votes.length, - queuedAttestations: this.queuedAttestations.size, + queuedAttestations: numAttestations, validatedAttestationDatas: this.validatedAttestationDatas.size, balancesLength: this.balances.length, nodes: this.protoArray.nodes.length, @@ -716,12 +721,13 @@ export class ForkChoice implements IForkChoice { // Attestations can only affect the fork choice of subsequent slots. // Delay consideration in the fork choice until their slot is in the past. // ``` - this.queuedAttestations.add({ - slot: slot, - attestingIndices: attestation.attestingIndices, - blockRoot: blockRootHex, - targetEpoch, - }); + const byRoot = this.queuedAttestations.getOrDefault(slot); + const validatorIndices = byRoot.getOrDefault(blockRootHex); + for (const validatorIndex of attestation.attestingIndices) { + if (!this.fcStore.equivocatingIndices.has(validatorIndex)) { + validatorIndices.add(validatorIndex); + } + } } } @@ -751,6 +757,11 @@ export class ForkChoice implements IForkChoice { /** * Call `onTick` for all slots between `fcStore.getCurrentSlot()` and the provided `currentSlot`. + * This should only be called once per slot because: + * - calling this multiple times in the same slot does not update `votes` + * - new attestations in the current slot must stay in the queue + * - new attestations in the old slots are applied to the `votes` already + * - also side effect of this function is `validatedAttestationDatas` reseted */ updateTime(currentSlot: Slot): void { if (this.fcStore.currentSlot >= currentSlot) return; @@ -1352,15 +1363,19 @@ export class ForkChoice implements IForkChoice { */ private processAttestationQueue(): void { const currentSlot = this.fcStore.currentSlot; - for (const attestation of this.queuedAttestations.values()) { - // Delay consideration in the fork choice until their slot is in the past. - if (attestation.slot < currentSlot) { - this.queuedAttestations.delete(attestation); - const {blockRoot, targetEpoch} = attestation; - const blockRootHex = blockRoot; - for (const validatorIndex of attestation.attestingIndices) { - this.addLatestMessage(validatorIndex, targetEpoch, blockRootHex); + for (const [slot, byRoot] of this.queuedAttestations.entries()) { + const targetEpoch = computeEpochAtSlot(slot); + if (slot < currentSlot) { + this.queuedAttestations.delete(slot); + for (const [blockRoot, validatorIndices] of byRoot.entries()) { + const blockRootHex = blockRoot; + for (const validatorIndex of validatorIndices) { + // equivocatingIndices was checked in onAttestation + this.addLatestMessage(validatorIndex, targetEpoch, blockRootHex); + } } + } else { + break; } } } diff --git a/packages/fork-choice/src/forkChoice/interface.ts b/packages/fork-choice/src/forkChoice/interface.ts index 0b6d56a88bf2..9ac8cdfac81b 100644 --- a/packages/fork-choice/src/forkChoice/interface.ts +++ b/packages/fork-choice/src/forkChoice/interface.ts @@ -250,14 +250,3 @@ export type LatestMessage = { epoch: Epoch; root: RootHex; }; - -/** - * Used for queuing attestations from the current slot. Only contains the minimum necessary - * information about the attestation. - */ -export type QueuedAttestation = { - slot: Slot; - attestingIndices: ValidatorIndex[]; - blockRoot: RootHex; - targetEpoch: Epoch; -}; diff --git a/packages/fork-choice/src/protoArray/computeDeltas.ts b/packages/fork-choice/src/protoArray/computeDeltas.ts index 8301c1e77a75..2b87deb098da 100644 --- a/packages/fork-choice/src/protoArray/computeDeltas.ts +++ b/packages/fork-choice/src/protoArray/computeDeltas.ts @@ -3,6 +3,9 @@ import {EffectiveBalanceIncrements} from "@lodestar/state-transition"; import {VoteTracker} from "./interface.js"; import {ProtoArrayError, ProtoArrayErrorCode} from "./errors.js"; +// reuse arrays to avoid memory reallocation and gc +const deltas = new Array(); + /** * Returns a list of `deltas`, where there is one delta for each of the indices in `indices` * @@ -19,10 +22,8 @@ export function computeDeltas( newBalances: EffectiveBalanceIncrements, equivocatingIndices: Set ): number[] { - const deltas = new Array(numProtoNodes); - for (let i = 0; i < numProtoNodes; i++) { - deltas[i] = 0; - } + deltas.length = numProtoNodes; + deltas.fill(0); // avoid creating new variables in the loop to potentially reduce GC pressure let oldBalance, newBalance: number; @@ -47,7 +48,7 @@ export function computeDeltas( // It is possible that there was a vote for an unknown validator if we change our justified // state to a new state with a higher epoch that is on a different fork because that fork may have // on-boarded fewer validators than the prior fork. - newBalance = newBalances[vIndex] ?? 0; + newBalance = newBalances === oldBalances ? oldBalance : newBalances[vIndex] ?? 0; if (equivocatingIndices.size > 0 && equivocatingIndices.has(vIndex)) { // this function could be called multiple times but we only want to process slashing validator for 1 time From 2a0a535646c09ef511a08d1c1975359b545b8c48 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Thu, 10 Oct 2024 20:14:38 -0700 Subject: [PATCH 143/259] feat: process deposit requests at epoch processing (#7131) * initial commit * process deposits on epoch processing * lint * Fix spec test * Remove commented out code * Update packages/state-transition/src/epoch/processPendingDeposits.ts Co-authored-by: twoeths * Address comments * lint --------- Co-authored-by: twoeths --- .../spec/presets/epoch_processing.test.ts | 2 +- .../test/spec/specTestVersioning.ts | 2 +- packages/params/src/index.ts | 3 +- packages/params/src/presets/mainnet.ts | 3 +- packages/params/src/presets/minimal.ts | 3 +- packages/params/src/types.ts | 6 +- .../src/block/processDeposit.ts | 81 ++++++------ .../src/block/processDepositRequest.ts | 13 +- packages/state-transition/src/epoch/index.ts | 10 +- .../epoch/processEffectiveBalanceUpdates.ts | 2 +- .../epoch/processPendingBalanceDeposits.ts | 70 ----------- .../src/epoch/processPendingDeposits.ts | 117 ++++++++++++++++++ .../src/slot/upgradeStateToElectra.ts | 2 - packages/state-transition/src/util/electra.ts | 28 +++-- packages/state-transition/src/util/genesis.ts | 11 +- .../test/perf/analyzeEpochs.ts | 2 +- packages/types/src/electra/sszTypes.ts | 19 +-- packages/types/src/electra/types.ts | 2 +- packages/validator/src/util/params.ts | 3 +- .../test/unit/utils/interopConfigs.ts | 8 +- 20 files changed, 228 insertions(+), 159 deletions(-) delete mode 100644 packages/state-transition/src/epoch/processPendingBalanceDeposits.ts create mode 100644 packages/state-transition/src/epoch/processPendingDeposits.ts diff --git a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts index 604243400aa0..932ad25b481e 100644 --- a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts +++ b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts @@ -46,7 +46,7 @@ const epochTransitionFns: Record = { epochFns.processSyncCommitteeUpdates(fork, state as CachedBeaconStateAltair); }, historical_summaries_update: epochFns.processHistoricalSummariesUpdate as EpochTransitionFn, - pending_balance_deposits: epochFns.processPendingBalanceDeposits as EpochTransitionFn, + pending_deposits: epochFns.processPendingDeposits as EpochTransitionFn, pending_consolidations: epochFns.processPendingConsolidations as EpochTransitionFn, }; diff --git a/packages/beacon-node/test/spec/specTestVersioning.ts b/packages/beacon-node/test/spec/specTestVersioning.ts index d4bc192f6cad..bef42fd1cdfa 100644 --- a/packages/beacon-node/test/spec/specTestVersioning.ts +++ b/packages/beacon-node/test/spec/specTestVersioning.ts @@ -15,7 +15,7 @@ import {DownloadTestsOptions} from "@lodestar/spec-test-util/downloadTests"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const ethereumConsensusSpecsTests: DownloadTestsOptions = { - specVersion: "v1.5.0-alpha.6", + specVersion: "v1.5.0-alpha.7", // Target directory is the host package root: 'packages/*/spec-tests' outputDir: path.join(__dirname, "../../spec-tests"), specTestsRepoUrl: "https://github.com/ethereum/consensus-spec-tests", diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index aa6e97641526..544113e3f8e1 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -96,7 +96,7 @@ export const { MAX_EFFECTIVE_BALANCE_ELECTRA, MIN_ACTIVATION_BALANCE, - PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_DEPOSITS_LIMIT, PENDING_PARTIAL_WITHDRAWALS_LIMIT, PENDING_CONSOLIDATIONS_LIMIT, MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA, @@ -107,6 +107,7 @@ export const { MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_ATTESTATIONS_ELECTRA, MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP, + MAX_PENDING_DEPOSITS_PER_EPOCH, WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA, } = activePreset; diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index ca599e990df4..b488927e77b3 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -125,11 +125,12 @@ export const mainnetPreset: BeaconPreset = { MAX_ATTESTER_SLASHINGS_ELECTRA: 1, MAX_ATTESTATIONS_ELECTRA: 8, MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 8, + MAX_PENDING_DEPOSITS_PER_EPOCH: 16, // 2**11 * 10**9 (= 2,048,000,000,000) Gwei MAX_EFFECTIVE_BALANCE_ELECTRA: 2048000000000, MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: 4096, MIN_ACTIVATION_BALANCE: 32000000000, - PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, + PENDING_DEPOSITS_LIMIT: 134217728, PENDING_PARTIAL_WITHDRAWALS_LIMIT: 134217728, PENDING_CONSOLIDATIONS_LIMIT: 262144, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1, diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index f93e3b1ca2c4..fa061697d2b3 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -126,11 +126,12 @@ export const minimalPreset: BeaconPreset = { MAX_ATTESTER_SLASHINGS_ELECTRA: 1, MAX_ATTESTATIONS_ELECTRA: 8, MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 2, + MAX_PENDING_DEPOSITS_PER_EPOCH: 16, // 2**11 * 10**9 (= 2,048,000,000,000) Gwei MAX_EFFECTIVE_BALANCE_ELECTRA: 2048000000000, MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: 4096, MIN_ACTIVATION_BALANCE: 32000000000, - PENDING_BALANCE_DEPOSITS_LIMIT: 134217728, + PENDING_DEPOSITS_LIMIT: 134217728, PENDING_PARTIAL_WITHDRAWALS_LIMIT: 64, PENDING_CONSOLIDATIONS_LIMIT: 64, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1, diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index e867b4a3cf71..bb32f3690e49 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -89,10 +89,11 @@ export type BeaconPreset = { MAX_ATTESTER_SLASHINGS_ELECTRA: number; MAX_ATTESTATIONS_ELECTRA: number; MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: number; + MAX_PENDING_DEPOSITS_PER_EPOCH: number; MAX_EFFECTIVE_BALANCE_ELECTRA: number; MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: number; MIN_ACTIVATION_BALANCE: number; - PENDING_BALANCE_DEPOSITS_LIMIT: number; + PENDING_DEPOSITS_LIMIT: number; PENDING_PARTIAL_WITHDRAWALS_LIMIT: number; PENDING_CONSOLIDATIONS_LIMIT: number; MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: number; @@ -189,10 +190,11 @@ export const beaconPresetTypes: BeaconPresetTypes = { MAX_ATTESTER_SLASHINGS_ELECTRA: "number", MAX_ATTESTATIONS_ELECTRA: "number", MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: "number", + MAX_PENDING_DEPOSITS_PER_EPOCH: "number", MAX_EFFECTIVE_BALANCE_ELECTRA: "number", MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: "number", MIN_ACTIVATION_BALANCE: "number", - PENDING_BALANCE_DEPOSITS_LIMIT: "number", + PENDING_DEPOSITS_LIMIT: "number", PENDING_PARTIAL_WITHDRAWALS_LIMIT: "number", PENDING_CONSOLIDATIONS_LIMIT: "number", MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: "number", diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index ee75dff0dfd1..f900cdc39bad 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -8,6 +8,7 @@ import { EFFECTIVE_BALANCE_INCREMENT, FAR_FUTURE_EPOCH, ForkSeq, + GENESIS_SLOT, MAX_EFFECTIVE_BALANCE, } from "@lodestar/params"; @@ -15,14 +16,7 @@ import {DepositData} from "@lodestar/types/lib/phase0/types.js"; import {DepositRequest} from "@lodestar/types/lib/electra/types.js"; import {BeaconConfig} from "@lodestar/config"; import {ZERO_HASH} from "../constants/index.js"; -import { - computeDomain, - computeSigningRoot, - hasCompoundingWithdrawalCredential, - hasEth1WithdrawalCredential, - increaseBalance, - switchToCompoundingValidator, -} from "../util/index.js"; +import {computeDomain, computeSigningRoot, getMaxEffectiveBalance, increaseBalance} from "../util/index.js"; import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStateElectra} from "../types.js"; /** @@ -61,38 +55,43 @@ export function applyDeposit( state: CachedBeaconStateAllForks, deposit: DepositData | DepositRequest ): void { - const {config, validators, epochCtx} = state; - const {pubkey, withdrawalCredentials, amount} = deposit; + const {config, epochCtx} = state; + const {pubkey, withdrawalCredentials, amount, signature} = deposit; const cachedIndex = epochCtx.getValidatorIndex(pubkey); - if (cachedIndex === null || !Number.isSafeInteger(cachedIndex) || cachedIndex >= validators.length) { - if (isValidDepositSignature(config, pubkey, withdrawalCredentials, amount, deposit.signature)) { - addValidatorToRegistry(fork, state, pubkey, withdrawalCredentials, amount); - } - } else { - if (fork < ForkSeq.electra) { + const isNewValidator = cachedIndex === null || !Number.isSafeInteger(cachedIndex); + + if (fork < ForkSeq.electra) { + if (isNewValidator) { + if (isValidDepositSignature(config, pubkey, withdrawalCredentials, amount, signature)) { + addValidatorToRegistry(fork, state, pubkey, withdrawalCredentials, amount); + } + } else { // increase balance by deposit amount right away pre-electra increaseBalance(state, cachedIndex, amount); - } else if (fork >= ForkSeq.electra) { - const stateElectra = state as CachedBeaconStateElectra; - const pendingBalanceDeposit = ssz.electra.PendingBalanceDeposit.toViewDU({ - index: cachedIndex, - amount: BigInt(amount), - }); - stateElectra.pendingBalanceDeposits.push(pendingBalanceDeposit); - - if ( - hasCompoundingWithdrawalCredential(withdrawalCredentials) && - hasEth1WithdrawalCredential(validators.getReadonly(cachedIndex).withdrawalCredentials) && - isValidDepositSignature(config, pubkey, withdrawalCredentials, amount, deposit.signature) - ) { - switchToCompoundingValidator(stateElectra, cachedIndex); + } + } else { + const stateElectra = state as CachedBeaconStateElectra; + const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({ + pubkey, + withdrawalCredentials, + amount, + signature, + slot: GENESIS_SLOT, // Use GENESIS_SLOT to distinguish from a pending deposit request + }); + + if (isNewValidator) { + if (isValidDepositSignature(config, pubkey, withdrawalCredentials, amount, deposit.signature)) { + addValidatorToRegistry(fork, state, pubkey, withdrawalCredentials, 0); + stateElectra.pendingDeposits.push(pendingDeposit); } + } else { + stateElectra.pendingDeposits.push(pendingDeposit); } } } -function addValidatorToRegistry( +export function addValidatorToRegistry( fork: ForkSeq, state: CachedBeaconStateAllForks, pubkey: BLSPubkey, @@ -101,8 +100,10 @@ function addValidatorToRegistry( ): void { const {validators, epochCtx} = state; // add validator and balance entries - const effectiveBalance = - fork < ForkSeq.electra ? Math.min(amount - (amount % EFFECTIVE_BALANCE_INCREMENT), MAX_EFFECTIVE_BALANCE) : 0; + const effectiveBalance = Math.min( + amount - (amount % EFFECTIVE_BALANCE_INCREMENT), + fork < ForkSeq.electra ? MAX_EFFECTIVE_BALANCE : getMaxEffectiveBalance(withdrawalCredentials) + ); validators.push( ssz.phase0.Validator.toViewDU({ pubkey, @@ -138,20 +139,10 @@ function addValidatorToRegistry( stateAltair.currentEpochParticipation.push(0); } - if (fork < ForkSeq.electra) { - state.balances.push(amount); - } else if (fork >= ForkSeq.electra) { - state.balances.push(0); - const stateElectra = state as CachedBeaconStateElectra; - const pendingBalanceDeposit = ssz.electra.PendingBalanceDeposit.toViewDU({ - index: validatorIndex, - amount: BigInt(amount), - }); - stateElectra.pendingBalanceDeposits.push(pendingBalanceDeposit); - } + state.balances.push(amount); } -function isValidDepositSignature( +export function isValidDepositSignature( config: BeaconConfig, pubkey: Uint8Array, withdrawalCredentials: Uint8Array, diff --git a/packages/state-transition/src/block/processDepositRequest.ts b/packages/state-transition/src/block/processDepositRequest.ts index e5dd99a40c4e..a349c372d51b 100644 --- a/packages/state-transition/src/block/processDepositRequest.ts +++ b/packages/state-transition/src/block/processDepositRequest.ts @@ -1,8 +1,7 @@ -import {electra} from "@lodestar/types"; +import {electra, ssz} from "@lodestar/types"; import {ForkSeq, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateElectra} from "../types.js"; -import {applyDeposit} from "./processDeposit.js"; export function processDepositRequest( fork: ForkSeq, @@ -13,5 +12,13 @@ export function processDepositRequest( state.depositRequestsStartIndex = BigInt(depositRequest.index); } - applyDeposit(fork, state, depositRequest); + // Create pending deposit + const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({ + pubkey: depositRequest.pubkey, + withdrawalCredentials: depositRequest.withdrawalCredentials, + amount: depositRequest.amount, + signature: depositRequest.signature, + slot: state.slot, + }); + state.pendingDeposits.push(pendingDeposit); } diff --git a/packages/state-transition/src/epoch/index.ts b/packages/state-transition/src/epoch/index.ts index bfb415b9ed6a..b0b1651321d5 100644 --- a/packages/state-transition/src/epoch/index.ts +++ b/packages/state-transition/src/epoch/index.ts @@ -28,7 +28,7 @@ import {processRewardsAndPenalties} from "./processRewardsAndPenalties.js"; import {processSlashings} from "./processSlashings.js"; import {processSlashingsReset} from "./processSlashingsReset.js"; import {processSyncCommitteeUpdates} from "./processSyncCommitteeUpdates.js"; -import {processPendingBalanceDeposits} from "./processPendingBalanceDeposits.js"; +import {processPendingDeposits} from "./processPendingDeposits.js"; import {processPendingConsolidations} from "./processPendingConsolidations.js"; // For spec tests @@ -48,7 +48,7 @@ export { processParticipationFlagUpdates, processSyncCommitteeUpdates, processHistoricalSummariesUpdate, - processPendingBalanceDeposits, + processPendingDeposits, processPendingConsolidations, }; @@ -70,7 +70,7 @@ export enum EpochTransitionStep { processEffectiveBalanceUpdates = "processEffectiveBalanceUpdates", processParticipationFlagUpdates = "processParticipationFlagUpdates", processSyncCommitteeUpdates = "processSyncCommitteeUpdates", - processPendingBalanceDeposits = "processPendingBalanceDeposits", + processPendingDeposits = "processPendingDeposits", processPendingConsolidations = "processPendingConsolidations", } @@ -131,9 +131,9 @@ export function processEpoch( const stateElectra = state as CachedBeaconStateElectra; { const timer = metrics?.epochTransitionStepTime.startTimer({ - step: EpochTransitionStep.processPendingBalanceDeposits, + step: EpochTransitionStep.processPendingDeposits, }); - processPendingBalanceDeposits(stateElectra, cache); + processPendingDeposits(stateElectra, cache); timer?.(); } diff --git a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts index 0ea4b49dddf4..26180d0d9f34 100644 --- a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts +++ b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts @@ -42,7 +42,7 @@ export function processEffectiveBalanceUpdates( // update effective balances with hysteresis // epochTransitionCache.balances is initialized in processRewardsAndPenalties() - // and updated in processPendingBalanceDeposits() and processPendingConsolidations() + // and updated in processPendingDeposits() and processPendingConsolidations() // so it's recycled here for performance. const balances = cache.balances ?? state.balances.getAll(); const currentEpochValidators = cache.validators; diff --git a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts deleted file mode 100644 index bef3ec0b2724..000000000000 --- a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {FAR_FUTURE_EPOCH} from "@lodestar/params"; -import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; -import {increaseBalance} from "../util/balance.js"; -import {getActivationExitChurnLimit} from "../util/validator.js"; - -/** - * Starting from Electra: - * Process pending balance deposits from state subject to churn limit and depsoitBalanceToConsume. - * For each eligible `deposit`, call `increaseBalance()`. - * Remove the processed deposits from `state.pendingBalanceDeposits`. - * Update `state.depositBalanceToConsume` for the next epoch - * - * TODO Electra: Update ssz library to support batch push to `pendingBalanceDeposits` - */ -export function processPendingBalanceDeposits(state: CachedBeaconStateElectra, cache: EpochTransitionCache): void { - const nextEpoch = state.epochCtx.epoch + 1; - const availableForProcessing = state.depositBalanceToConsume + BigInt(getActivationExitChurnLimit(state.epochCtx)); - let processedAmount = 0n; - let nextDepositIndex = 0; - const depositsToPostpone = []; - const validators = state.validators; - const cachedBalances = cache.balances; - - for (const deposit of state.pendingBalanceDeposits.getAllReadonly()) { - const {amount, index: depositIndex} = deposit; - const validator = validators.getReadonly(depositIndex); - - // Validator is exiting, postpone the deposit until after withdrawable epoch - if (validator.exitEpoch < FAR_FUTURE_EPOCH) { - if (nextEpoch <= validator.withdrawableEpoch) { - depositsToPostpone.push(deposit); - } else { - // Deposited balance will never become active. Increase balance but do not consume churn - increaseBalance(state, depositIndex, Number(amount)); - if (cachedBalances) { - cachedBalances[depositIndex] += Number(amount); - } - } - } else { - // Validator is not exiting, attempt to process deposit - if (processedAmount + amount > availableForProcessing) { - // Deposit does not fit in the churn, no more deposit processing in this epoch. - break; - } else { - // Deposit fits in the churn, process it. Increase balance and consume churn. - increaseBalance(state, depositIndex, Number(amount)); - if (cachedBalances) { - cachedBalances[depositIndex] += Number(amount); - } - processedAmount = processedAmount + amount; - } - } - // Regardless of how the deposit was handled, we move on in the queue. - nextDepositIndex++; - } - - const remainingPendingBalanceDeposits = state.pendingBalanceDeposits.sliceFrom(nextDepositIndex); - state.pendingBalanceDeposits = remainingPendingBalanceDeposits; - - if (remainingPendingBalanceDeposits.length === 0) { - state.depositBalanceToConsume = 0n; - } else { - state.depositBalanceToConsume = availableForProcessing - processedAmount; - } - - // TODO Electra: add a function in ListCompositeTreeView to support batch push operation - for (const deposit of depositsToPostpone) { - state.pendingBalanceDeposits.push(deposit); - } -} diff --git a/packages/state-transition/src/epoch/processPendingDeposits.ts b/packages/state-transition/src/epoch/processPendingDeposits.ts new file mode 100644 index 000000000000..53af3ab38763 --- /dev/null +++ b/packages/state-transition/src/epoch/processPendingDeposits.ts @@ -0,0 +1,117 @@ +import {FAR_FUTURE_EPOCH, ForkSeq, GENESIS_SLOT, MAX_PENDING_DEPOSITS_PER_EPOCH} from "@lodestar/params"; +import {PendingDeposit} from "@lodestar/types/lib/electra/types.js"; +import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; +import {increaseBalance} from "../util/balance.js"; +import {getActivationExitChurnLimit} from "../util/validator.js"; +import {computeStartSlotAtEpoch} from "../util/epoch.js"; +import {addValidatorToRegistry, isValidDepositSignature} from "../block/processDeposit.js"; + +/** + * Starting from Electra: + * Process pending balance deposits from state subject to churn limit and depsoitBalanceToConsume. + * For each eligible `deposit`, call `increaseBalance()`. + * Remove the processed deposits from `state.pendingDeposits`. + * Update `state.depositBalanceToConsume` for the next epoch + * + * TODO Electra: Update ssz library to support batch push to `pendingDeposits` + */ +export function processPendingDeposits(state: CachedBeaconStateElectra, cache: EpochTransitionCache): void { + const nextEpoch = state.epochCtx.epoch + 1; + const availableForProcessing = state.depositBalanceToConsume + BigInt(getActivationExitChurnLimit(state.epochCtx)); + let processedAmount = 0; + let nextDepositIndex = 0; + const depositsToPostpone = []; + let isChurnLimitReached = false; + const finalizedSlot = computeStartSlotAtEpoch(state.finalizedCheckpoint.epoch); + + for (const deposit of state.pendingDeposits.getAllReadonly()) { + // Do not process deposit requests if Eth1 bridge deposits are not yet applied. + if ( + // Is deposit request + deposit.slot > GENESIS_SLOT && + // There are pending Eth1 bridge deposits + state.eth1DepositIndex < state.depositRequestsStartIndex + ) { + break; + } + + // Check if deposit has been finalized, otherwise, stop processing. + if (deposit.slot > finalizedSlot) { + break; + } + + // Check if number of processed deposits has not reached the limit, otherwise, stop processing. + if (nextDepositIndex >= MAX_PENDING_DEPOSITS_PER_EPOCH) { + break; + } + + // Read validator state + let isValidatorExited = false; + let isValidatorWithdrawn = false; + + const validatorIndex = state.epochCtx.getValidatorIndex(deposit.pubkey); + if (validatorIndex !== null) { + const validator = state.validators.getReadonly(validatorIndex); + isValidatorExited = validator.exitEpoch < FAR_FUTURE_EPOCH; + isValidatorWithdrawn = validator.withdrawableEpoch < nextEpoch; + } + + if (isValidatorWithdrawn) { + // Deposited balance will never become active. Increase balance but do not consume churn + applyPendingDeposit(state, deposit, cache); + } else if (isValidatorExited) { + // Validator is exiting, postpone the deposit until after withdrawable epoch + depositsToPostpone.push(deposit); + } else { + // Check if deposit fits in the churn, otherwise, do no more deposit processing in this epoch. + isChurnLimitReached = processedAmount + deposit.amount > availableForProcessing; + if (isChurnLimitReached) { + break; + } + // Consume churn and apply deposit. + processedAmount += deposit.amount; + applyPendingDeposit(state, deposit, cache); + } + + // Regardless of how the deposit was handled, we move on in the queue. + nextDepositIndex++; + } + + const remainingPendingDeposits = state.pendingDeposits.sliceFrom(nextDepositIndex); + state.pendingDeposits = remainingPendingDeposits; + + // TODO Electra: add a function in ListCompositeTreeView to support batch push operation + for (const deposit of depositsToPostpone) { + state.pendingDeposits.push(deposit); + } + + // Accumulate churn only if the churn limit has been hit. + if (isChurnLimitReached) { + state.depositBalanceToConsume = availableForProcessing - BigInt(processedAmount); + } else { + state.depositBalanceToConsume = 0n; + } +} + +function applyPendingDeposit( + state: CachedBeaconStateElectra, + deposit: PendingDeposit, + cache: EpochTransitionCache +): void { + const validatorIndex = state.epochCtx.getValidatorIndex(deposit.pubkey); + const {pubkey, withdrawalCredentials, amount, signature} = deposit; + const cachedBalances = cache.balances; + + if (validatorIndex === null) { + // Verify the deposit signature (proof of possession) which is not checked by the deposit contract + if (isValidDepositSignature(state.config, pubkey, withdrawalCredentials, amount, signature)) { + addValidatorToRegistry(ForkSeq.electra, state, pubkey, withdrawalCredentials, amount); + } + } else { + // Increase balance + increaseBalance(state, validatorIndex, amount); + if (cachedBalances) { + cachedBalances[validatorIndex] += amount; + } + } +} diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 0bd36a909b46..b64ac242f83c 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -81,8 +81,6 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache stateElectraView.earliestExitEpoch = Math.max(...exitEpochs) + 1; stateElectraView.consolidationBalanceToConsume = BigInt(0); stateElectraView.earliestConsolidationEpoch = computeActivationExitEpoch(currentEpochPre); - // stateElectraView.pendingBalanceDeposits = ssz.electra.PendingBalanceDeposits.defaultViewDU(); - // pendingBalanceDeposits, pendingPartialWithdrawals, pendingConsolidations are default values // TODO-electra: can we improve this? stateElectraView.commit(); const tmpElectraState = getCachedBeaconState(stateElectraView, stateDeneb); diff --git a/packages/state-transition/src/util/electra.ts b/packages/state-transition/src/util/electra.ts index ac34da6407de..90dd9a3881df 100644 --- a/packages/state-transition/src/util/electra.ts +++ b/packages/state-transition/src/util/electra.ts @@ -1,6 +1,7 @@ -import {COMPOUNDING_WITHDRAWAL_PREFIX, FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE} from "@lodestar/params"; +import {COMPOUNDING_WITHDRAWAL_PREFIX, FAR_FUTURE_EPOCH, GENESIS_SLOT, MIN_ACTIVATION_BALANCE} from "@lodestar/params"; import {ValidatorIndex, ssz} from "@lodestar/types"; import {CachedBeaconStateElectra} from "../types.js"; +import {G2_POINT_AT_INFINITY} from "../constants/constants.js"; import {hasEth1WithdrawalCredential} from "./capella.js"; export function hasCompoundingWithdrawalCredential(withdrawalCredentials: Uint8Array): boolean { @@ -30,14 +31,20 @@ export function switchToCompoundingValidator(state: CachedBeaconStateElectra, in export function queueExcessActiveBalance(state: CachedBeaconStateElectra, index: ValidatorIndex): void { const balance = state.balances.get(index); if (balance > MIN_ACTIVATION_BALANCE) { + const validator = state.validators.getReadonly(index); const excessBalance = balance - MIN_ACTIVATION_BALANCE; state.balances.set(index, MIN_ACTIVATION_BALANCE); - const pendingBalanceDeposit = ssz.electra.PendingBalanceDeposit.toViewDU({ - index, - amount: BigInt(excessBalance), + const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({ + pubkey: validator.pubkey, + withdrawalCredentials: validator.withdrawalCredentials, + amount: excessBalance, + // Use bls.G2_POINT_AT_INFINITY as a signature field placeholder + signature: G2_POINT_AT_INFINITY, + // Use GENESIS_SLOT to distinguish from a pending deposit request + slot: GENESIS_SLOT, }); - state.pendingBalanceDeposits.push(pendingBalanceDeposit); + state.pendingDeposits.push(pendingDeposit); } } @@ -50,9 +57,12 @@ export function queueEntireBalanceAndResetValidator(state: CachedBeaconStateElec state.epochCtx.effectiveBalanceIncrementsSet(index, 0); validator.activationEligibilityEpoch = FAR_FUTURE_EPOCH; - const pendingBalanceDeposit = ssz.electra.PendingBalanceDeposit.toViewDU({ - index, - amount: BigInt(balance), + const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({ + pubkey: validator.pubkey, + withdrawalCredentials: validator.withdrawalCredentials, + amount: balance, + signature: G2_POINT_AT_INFINITY, + slot: GENESIS_SLOT, }); - state.pendingBalanceDeposits.push(pendingBalanceDeposit); + state.pendingDeposits.push(pendingDeposit); } diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 54507d0ef235..aca81258a47a 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -171,10 +171,15 @@ export function applyDeposits( if (fork >= ForkSeq.electra) { const stateElectra = state as CachedBeaconStateElectra; stateElectra.commit(); - for (const {index: validatorIndex, amount} of stateElectra.pendingBalanceDeposits.getAllReadonly()) { - increaseBalance(state, validatorIndex, Number(amount)); + for (const {pubkey, amount} of stateElectra.pendingDeposits.getAllReadonly()) { + const validatorIndex = state.epochCtx.getValidatorIndex(pubkey); + if (validatorIndex === null) { + // Should not happen if the gensis state is correct + continue; + } + increaseBalance(state, validatorIndex, amount); } - stateElectra.pendingBalanceDeposits = ssz.electra.PendingBalanceDeposits.defaultViewDU(); + stateElectra.pendingDeposits = ssz.electra.PendingDeposits.defaultViewDU(); } // Process activations diff --git a/packages/state-transition/test/perf/analyzeEpochs.ts b/packages/state-transition/test/perf/analyzeEpochs.ts index deb0861427bf..2f1485a809b1 100644 --- a/packages/state-transition/test/perf/analyzeEpochs.ts +++ b/packages/state-transition/test/perf/analyzeEpochs.ts @@ -153,7 +153,7 @@ async function analyzeEpochs(network: NetworkName, fromEpoch?: number): Promise< // processSlashingsAllForks: function of process.indicesToSlash // processSlashingsReset: free // -- electra - // processPendingBalanceDeposits: - + // processPendingDeposits: - // processPendingConsolidations: - // -- altair // processInactivityUpdates: - diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 9d995c38efd5..7200af5f4ead 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -17,7 +17,7 @@ import { MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, - PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_DEPOSITS_LIMIT, PENDING_PARTIAL_WITHDRAWALS_LIMIT, PENDING_CONSOLIDATIONS_LIMIT, FINALIZED_ROOT_DEPTH_ELECTRA, @@ -249,15 +249,20 @@ export const SignedBuilderBid = new ContainerType( {typeName: "SignedBuilderBid", jsonCase: "eth2"} ); -export const PendingBalanceDeposit = new ContainerType( +export const PendingDeposit = new ContainerType( { - index: ValidatorIndex, - amount: Gwei, + pubkey: BLSPubkey, + withdrawalCredentials: Bytes32, + // this is actually gwei uintbn64 type, but super unlikely to get a high amount here + // to warrant a bn type + amount: UintNum64, + signature: BLSSignature, + slot: Slot, }, - {typeName: "PendingBalanceDeposit", jsonCase: "eth2"} + {typeName: "PendingDeposit", jsonCase: "eth2"} ); -export const PendingBalanceDeposits = new ListCompositeType(PendingBalanceDeposit, PENDING_BALANCE_DEPOSITS_LIMIT); +export const PendingDeposits = new ListCompositeType(PendingDeposit, PENDING_DEPOSITS_LIMIT); export const PendingPartialWithdrawal = new ContainerType( { @@ -325,7 +330,7 @@ export const BeaconState = new ContainerType( earliestExitEpoch: Epoch, // New in ELECTRA:EIP7251 consolidationBalanceToConsume: Gwei, // New in ELECTRA:EIP7251 earliestConsolidationEpoch: Epoch, // New in ELECTRA:EIP7251 - pendingBalanceDeposits: PendingBalanceDeposits, // New in ELECTRA:EIP7251 + pendingDeposits: PendingDeposits, // New in ELECTRA:EIP7251 pendingPartialWithdrawals: new ListCompositeType(PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT), // New in ELECTRA:EIP7251 pendingConsolidations: new ListCompositeType(PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT), // New in ELECTRA:EIP7251 }, diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index f7996cf336f9..691de409ed91 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -42,7 +42,7 @@ export type LightClientFinalityUpdate = ValueOf; export type LightClientStore = ValueOf; -export type PendingBalanceDeposit = ValueOf; +export type PendingDeposit = ValueOf; export type PendingPartialWithdrawal = ValueOf; export type PendingConsolidation = ValueOf; diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 6d6705f512df..51df32ab4848 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -228,10 +228,11 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Thu, 10 Oct 2024 20:16:05 -0700 Subject: [PATCH 144/259] feat: pass execution requests as bytes to engine API (#7145) * Pass execution requests in bytes * lint --- .../beacon-node/src/execution/engine/types.ts | 114 +++++++----------- 1 file changed, 41 insertions(+), 73 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 32fe4cb79d3d..9545ded1d92e 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -1,4 +1,4 @@ -import {capella, deneb, electra, Wei, bellatrix, Root, ExecutionPayload, ExecutionRequests} from "@lodestar/types"; +import {capella, deneb, electra, Wei, bellatrix, Root, ExecutionPayload, ExecutionRequests, ssz} from "@lodestar/types"; import { BYTES_PER_LOGS_BLOOM, FIELD_ELEMENTS_PER_BLOB, @@ -161,29 +161,17 @@ export type WithdrawalRpc = { amount: QUANTITY; }; -export type ExecutionRequestsRpc = { - deposits: DepositRequestRpc[]; - withdrawals: WithdrawalRequestRpc[]; - consolidations: ConsolidationRequestRpc[]; -}; +/** + * ExecutionRequestsRpc only holds 3 elements in the following order: + * - ssz'ed DepositRequests + * - ssz'ed WithdrawalRequests + * - ssz'ed ConsolidationRequests + */ +export type ExecutionRequestsRpc = [DepositRequestsRpc, WithdrawalRequestsRpc, ConsolidationRequestsRpc]; -export type DepositRequestRpc = { - pubkey: DATA; - withdrawalCredentials: DATA; - amount: QUANTITY; - signature: DATA; - index: QUANTITY; -}; -export type WithdrawalRequestRpc = { - sourceAddress: DATA; - validatorPubkey: DATA; - amount: QUANTITY; -}; -export type ConsolidationRequestRpc = { - sourceAddress: DATA; - sourcePubkey: DATA; - targetPubkey: DATA; -}; +export type DepositRequestsRpc = DATA; +export type WithdrawalRequestsRpc = DATA; +export type ConsolidationRequestsRpc = DATA; export type VersionedHashesRpc = DATA[]; @@ -406,73 +394,53 @@ export function deserializeWithdrawal(serialized: WithdrawalRpc): capella.Withdr } as capella.Withdrawal; } -function serializeDepositRequest(depositRequest: electra.DepositRequest): DepositRequestRpc { - return { - pubkey: bytesToData(depositRequest.pubkey), - withdrawalCredentials: bytesToData(depositRequest.withdrawalCredentials), - amount: numToQuantity(depositRequest.amount), - signature: bytesToData(depositRequest.signature), - index: numToQuantity(depositRequest.index), - }; +function serializeDepositRequests(depositRequests: electra.DepositRequests): DepositRequestsRpc { + return bytesToData(ssz.electra.DepositRequests.serialize(depositRequests)); } -function deserializeDepositRequest(serialized: DepositRequestRpc): electra.DepositRequest { - return { - pubkey: dataToBytes(serialized.pubkey, 48), - withdrawalCredentials: dataToBytes(serialized.withdrawalCredentials, 32), - amount: quantityToNum(serialized.amount), - signature: dataToBytes(serialized.signature, 96), - index: quantityToNum(serialized.index), - } as electra.DepositRequest; +function deserializeDepositRequests(serialized: DepositRequestsRpc): electra.DepositRequests { + return ssz.electra.DepositRequests.deserialize(dataToBytes(serialized, null)); } -function serializeWithdrawalRequest(withdrawalRequest: electra.WithdrawalRequest): WithdrawalRequestRpc { - return { - sourceAddress: bytesToData(withdrawalRequest.sourceAddress), - validatorPubkey: bytesToData(withdrawalRequest.validatorPubkey), - amount: numToQuantity(withdrawalRequest.amount), - }; +function serializeWithdrawalRequests(withdrawalRequests: electra.WithdrawalRequests): WithdrawalRequestsRpc { + return bytesToData(ssz.electra.WithdrawalRequests.serialize(withdrawalRequests)); } -function deserializeWithdrawalRequest(withdrawalRequest: WithdrawalRequestRpc): electra.WithdrawalRequest { - return { - sourceAddress: dataToBytes(withdrawalRequest.sourceAddress, 20), - validatorPubkey: dataToBytes(withdrawalRequest.validatorPubkey, 48), - amount: quantityToBigint(withdrawalRequest.amount), - }; +function deserializeWithdrawalRequest(serialized: WithdrawalRequestsRpc): electra.WithdrawalRequests { + return ssz.electra.WithdrawalRequests.deserialize(dataToBytes(serialized, null)); } -function serializeConsolidationRequest(consolidationRequest: electra.ConsolidationRequest): ConsolidationRequestRpc { - return { - sourceAddress: bytesToData(consolidationRequest.sourceAddress), - sourcePubkey: bytesToData(consolidationRequest.sourcePubkey), - targetPubkey: bytesToData(consolidationRequest.targetPubkey), - }; +function serializeConsolidationRequests( + consolidationRequests: electra.ConsolidationRequests +): ConsolidationRequestsRpc { + return bytesToData(ssz.electra.ConsolidationRequests.serialize(consolidationRequests)); } -function deserializeConsolidationRequest(consolidationRequest: ConsolidationRequestRpc): electra.ConsolidationRequest { - return { - sourceAddress: dataToBytes(consolidationRequest.sourceAddress, 20), - sourcePubkey: dataToBytes(consolidationRequest.sourcePubkey, 48), - targetPubkey: dataToBytes(consolidationRequest.targetPubkey, 48), - }; +function deserializeConsolidationRequests(serialized: ConsolidationRequestsRpc): electra.ConsolidationRequests { + return ssz.electra.ConsolidationRequests.deserialize(dataToBytes(serialized, null)); } +/** + * This is identical to get_execution_requests_list in + * https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/electra/beacon-chain.md#new-get_execution_requests_list + */ export function serializeExecutionRequests(executionRequests: ExecutionRequests): ExecutionRequestsRpc { const {deposits, withdrawals, consolidations} = executionRequests; - return { - deposits: deposits.map(serializeDepositRequest), - withdrawals: withdrawals.map(serializeWithdrawalRequest), - consolidations: consolidations.map(serializeConsolidationRequest), - }; + + return [ + serializeDepositRequests(deposits), + serializeWithdrawalRequests(withdrawals), + serializeConsolidationRequests(consolidations), + ]; } -export function deserializeExecutionRequests(executionRequests: ExecutionRequestsRpc): ExecutionRequests { - const {deposits, withdrawals, consolidations} = executionRequests; +export function deserializeExecutionRequests(serialized: ExecutionRequestsRpc): ExecutionRequests { + const [deposits, withdrawals, consolidations] = serialized; + return { - deposits: deposits.map(deserializeDepositRequest), - withdrawals: withdrawals.map(deserializeWithdrawalRequest), - consolidations: consolidations.map(deserializeConsolidationRequest), + deposits: deserializeDepositRequests(deposits), + withdrawals: deserializeWithdrawalRequest(withdrawals), + consolidations: deserializeConsolidationRequests(consolidations), }; } From 4b7d871ab3387e2af99996c4d4ec8268a95cf41b Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Fri, 11 Oct 2024 14:34:21 +0200 Subject: [PATCH 145/259] chore: fix lint error (#7152) Fix lint error --- packages/fork-choice/src/protoArray/computeDeltas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fork-choice/src/protoArray/computeDeltas.ts b/packages/fork-choice/src/protoArray/computeDeltas.ts index 2b87deb098da..a3366fa738ae 100644 --- a/packages/fork-choice/src/protoArray/computeDeltas.ts +++ b/packages/fork-choice/src/protoArray/computeDeltas.ts @@ -48,7 +48,7 @@ export function computeDeltas( // It is possible that there was a vote for an unknown validator if we change our justified // state to a new state with a higher epoch that is on a different fork because that fork may have // on-boarded fewer validators than the prior fork. - newBalance = newBalances === oldBalances ? oldBalance : newBalances[vIndex] ?? 0; + newBalance = newBalances === oldBalances ? oldBalance : (newBalances[vIndex] ?? 0); if (equivocatingIndices.size > 0 && equivocatingIndices.has(vIndex)) { // this function could be called multiple times but we only want to process slashing validator for 1 time From ac6edd36ee997f8d7a4210337230fbd6a754a8bd Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Fri, 11 Oct 2024 15:08:18 +0200 Subject: [PATCH 146/259] chore: add vscode settings to split prettier and biome (#7149) * Add vscode settings to split prettier and biome * Add whitespace * Fix branch name --- .prettierignore | 4 +++- .vscode/extensions.json | 3 ++- lodestar.code-workspace | 12 ++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 lodestar.code-workspace diff --git a/.prettierignore b/.prettierignore index 7871bd5d3ad7..3934e7720067 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,4 +2,6 @@ **/.nyc_output /packages/*/spec-tests node_modules -**/node_modules \ No newline at end of file +**/node_modules +*.js +*.ts diff --git a/.vscode/extensions.json b/.vscode/extensions.json index de51190cd9f3..d2b074c6eea1 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,5 +1,6 @@ { "recommendations": [ - "biomejs.biome" + "biomejs.biome", + "esbenp.prettier-vscode" ] } diff --git a/lodestar.code-workspace b/lodestar.code-workspace new file mode 100644 index 000000000000..7030ab8d7270 --- /dev/null +++ b/lodestar.code-workspace @@ -0,0 +1,12 @@ +{ + "settings": { + "window.title": "${activeEditorShort}${separator}${rootName}${separator}${profileName}${separator}[${activeRepositoryBranchName}]", + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[javascript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + } +} From cbc7c9018d7b7de648473c45617f2b6789ebe648 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 11 Oct 2024 16:53:42 +0100 Subject: [PATCH 147/259] feat: support fetching historical proposer duties (#7130) * feat: support fetching historical proposer duties * Clone state before creating cached beacon state * Fix error message * Update test cases * Skip syncing pubkeys and sync committe cache * Update proposers tests epoch * Use switch/case instead of if/else * Add comment to clarify when head state can be used * Use loadState instead of creating a separate ViewDU * Clarify not yet initialized error for prev proposer duties * Assert loaded state epoch matches requested --- .../src/api/impl/validator/index.ts | 74 +++++++++++++---- .../test/mocks/mockedBeaconChain.ts | 4 + .../impl/validator/duties/proposer.test.ts | 79 ++++++++++++++----- .../state-transition/src/cache/epochCache.ts | 4 + 4 files changed, 127 insertions(+), 34 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index e1ea415443b9..9c5e6c2987f1 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -1,3 +1,4 @@ +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; import { @@ -10,6 +11,8 @@ import { computeEpochAtSlot, getCurrentSlot, beaconBlockToBlinded, + createCachedBeaconState, + loadState, } from "@lodestar/state-transition"; import { GENESIS_SLOT, @@ -62,6 +65,7 @@ import {validateSyncCommitteeGossipContributionAndProof} from "../../../chain/va import {CommitteeSubscription} from "../../../network/subnets/index.js"; import {ApiModules} from "../types.js"; import {RegenCaller} from "../../../chain/regen/index.js"; +import {getStateResponseWithRegen} from "../beacon/state/utils.js"; import {validateGossipFnRetryUnknownRoot} from "../../../network/processor/gossipHandlers.js"; import {SCHEDULER_LOOKAHEAD_FACTOR} from "../../../chain/prepareNextSlot.js"; import {ChainEvent, CheckpointHex, CommonBlockBody} from "../../../chain/index.js"; @@ -888,15 +892,16 @@ export function getValidatorApi( async getProposerDuties({epoch}) { notWhileSyncing(); - // Early check that epoch is within [current_epoch, current_epoch + 1], or allow for pre-genesis + // Early check that epoch is no more than current_epoch + 1, or allow for pre-genesis const currentEpoch = currentEpochWithDisparity(); const nextEpoch = currentEpoch + 1; - if (currentEpoch >= 0 && epoch !== currentEpoch && epoch !== nextEpoch) { - throw Error(`Requested epoch ${epoch} must equal current ${currentEpoch} or next epoch ${nextEpoch}`); + if (currentEpoch >= 0 && epoch > nextEpoch) { + throw new ApiError(400, `Requested epoch ${epoch} must not be more than one epoch in the future`); } const head = chain.forkChoice.getHead(); let state: CachedBeaconStateAllForks | undefined = undefined; + const startSlot = computeStartSlotAtEpoch(epoch); const slotMs = config.SECONDS_PER_SLOT * 1000; const prepareNextSlotLookAheadMs = slotMs / SCHEDULER_LOOKAHEAD_FACTOR; const toNextEpochMs = msToNextEpoch(); @@ -914,21 +919,63 @@ export function getValidatorApi( } if (!state) { - state = await chain.getHeadStateAtCurrentEpoch(RegenCaller.getDuties); + if (epoch >= currentEpoch - 1) { + // Cached beacon state stores proposers for previous, current and next epoch. The + // requested epoch is within that range, we can use the head state at current epoch + state = await chain.getHeadStateAtCurrentEpoch(RegenCaller.getDuties); + } else { + const res = await getStateResponseWithRegen(chain, startSlot); + + const stateViewDU = + res.state instanceof Uint8Array + ? loadState(config, chain.getHeadState(), res.state).state + : res.state.clone(); + + state = createCachedBeaconState( + stateViewDU, + { + config: chain.config, + // Not required to compute proposers + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], + }, + {skipSyncPubkeys: true, skipSyncCommitteeCache: true} + ); + + if (state.epochCtx.epoch !== epoch) { + throw Error(`Loaded state epoch ${state.epochCtx.epoch} does not match requested epoch ${epoch}`); + } + } } const stateEpoch = state.epochCtx.epoch; let indexes: ValidatorIndex[] = []; - if (epoch === stateEpoch) { - indexes = state.epochCtx.getBeaconProposers(); - } else if (epoch === stateEpoch + 1) { - // Requesting duties for next epoch is allow since they can be predicted with high probabilities. - // @see `epochCtx.getBeaconProposersNextEpoch` JSDocs for rationale. - indexes = state.epochCtx.getBeaconProposersNextEpoch(); - } else { - // Should never happen, epoch is checked to be in bounds above - throw Error(`Proposer duties for epoch ${epoch} not supported, current epoch ${stateEpoch}`); + switch (epoch) { + case stateEpoch: + indexes = state.epochCtx.getBeaconProposers(); + break; + + case stateEpoch + 1: + // Requesting duties for next epoch is allowed since they can be predicted with high probabilities. + // @see `epochCtx.getBeaconProposersNextEpoch` JSDocs for rationale. + indexes = state.epochCtx.getBeaconProposersNextEpoch(); + break; + + case stateEpoch - 1: { + const indexesPrevEpoch = state.epochCtx.getBeaconProposersPrevEpoch(); + if (indexesPrevEpoch === null) { + // Should not happen as previous proposer duties should be initialized for head state + // and if we load state from `Uint8Array` it will always be the state of requested epoch + throw Error(`Proposer duties for previous epoch ${epoch} not yet initialized`); + } + indexes = indexesPrevEpoch; + break; + } + + default: + // Should never happen, epoch is checked to be in bounds above + throw Error(`Proposer duties for epoch ${epoch} not supported, current epoch ${stateEpoch}`); } // NOTE: this is the fastest way of getting compressed pubkeys. @@ -937,7 +984,6 @@ export function getValidatorApi( // TODO: Add a flag to just send 0x00 as pubkeys since the Lodestar validator does not need them. const pubkeys = getPubkeysForIndices(state.validators, indexes); - const startSlot = computeStartSlotAtEpoch(epoch); const duties: routes.validator.ProposerDuty[] = []; for (let i = 0; i < SLOTS_PER_EPOCH; i++) { duties.push({slot: startSlot + i, validatorIndex: indexes[i], pubkey: pubkeys[i]}); diff --git a/packages/beacon-node/test/mocks/mockedBeaconChain.ts b/packages/beacon-node/test/mocks/mockedBeaconChain.ts index 1d597bf4424d..a69efc55836c 100644 --- a/packages/beacon-node/test/mocks/mockedBeaconChain.ts +++ b/packages/beacon-node/test/mocks/mockedBeaconChain.ts @@ -1,4 +1,5 @@ import {vi, Mocked, Mock} from "vitest"; +import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {config as defaultConfig} from "@lodestar/config/default"; import {ChainForkConfig} from "@lodestar/config"; import {ForkChoice, ProtoBlock, EpochDifference} from "@lodestar/fork-choice"; @@ -126,6 +127,8 @@ vi.mock("../../src/chain/chain.js", async (importActual) => { // @ts-expect-error beaconProposerCache: new BeaconProposerCache(), shufflingCache: new ShufflingCache(), + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], produceCommonBlockBody: vi.fn(), getProposerHead: vi.fn(), produceBlock: vi.fn(), @@ -135,6 +138,7 @@ vi.mock("../../src/chain/chain.js", async (importActual) => { predictProposerHead: vi.fn(), getHeadStateAtCurrentEpoch: vi.fn(), getHeadState: vi.fn(), + getStateBySlot: vi.fn(), updateBuilderStatus: vi.fn(), processBlock: vi.fn(), regenStateForAttestationVerification: vi.fn(), diff --git a/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts b/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts index b101382e01a0..49758c9bca58 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts @@ -3,6 +3,7 @@ import {routes} from "@lodestar/api"; import {config} from "@lodestar/config/default"; import {MAX_EFFECTIVE_BALANCE, SLOTS_PER_EPOCH} from "@lodestar/params"; import {BeaconStateAllForks} from "@lodestar/state-transition"; +import {Slot} from "@lodestar/types"; import {ApiTestModules, getApiTestModules} from "../../../../../utils/api.js"; import {FAR_FUTURE_EPOCH} from "../../../../../../src/constants/index.js"; import {SYNC_TOLERANCE_EPOCHS, getValidatorApi} from "../../../../../../src/api/impl/validator/index.js"; @@ -13,6 +14,9 @@ import {SyncState} from "../../../../../../src/sync/interface.js"; import {defaultApiOptions} from "../../../../../../src/api/options.js"; describe("get proposers api impl", function () { + const currentEpoch = 2; + const currentSlot = SLOTS_PER_EPOCH * currentEpoch; + let api: ReturnType; let modules: ApiTestModules; let state: BeaconStateAllForks; @@ -20,12 +24,24 @@ describe("get proposers api impl", function () { beforeEach(function () { vi.useFakeTimers({now: 0}); + vi.advanceTimersByTime(currentSlot * config.SECONDS_PER_SLOT * 1000); modules = getApiTestModules({clock: "real"}); api = getValidatorApi(defaultApiOptions, modules); + initializeState(currentSlot); + + modules.chain.getHeadStateAtCurrentEpoch.mockResolvedValue(cachedState); + modules.forkChoice.getHead.mockReturnValue(zeroProtoBlock); + modules.forkChoice.getFinalizedBlock.mockReturnValue(zeroProtoBlock); + modules.db.block.get.mockResolvedValue({message: {stateRoot: Buffer.alloc(32)}} as any); + + vi.spyOn(modules.sync, "state", "get").mockReturnValue(SyncState.Synced); + }); + + function initializeState(slot: Slot): void { state = generateState( { - slot: 0, + slot, validators: generateValidators(25, { effectiveBalance: MAX_EFFECTIVE_BALANCE, activationEpoch: 0, @@ -37,14 +53,10 @@ describe("get proposers api impl", function () { ); cachedState = createCachedBeaconStateTest(state, config); - modules.chain.getHeadStateAtCurrentEpoch.mockResolvedValue(cachedState); - modules.forkChoice.getHead.mockReturnValue(zeroProtoBlock); - modules.db.block.get.mockResolvedValue({message: {stateRoot: Buffer.alloc(32)}} as any); - - vi.spyOn(modules.sync, "state", "get").mockReturnValue(SyncState.Synced); vi.spyOn(cachedState.epochCtx, "getBeaconProposersNextEpoch"); vi.spyOn(cachedState.epochCtx, "getBeaconProposers"); - }); + vi.spyOn(cachedState.epochCtx, "getBeaconProposersPrevEpoch"); + } afterEach(() => { vi.useRealTimers(); @@ -54,7 +66,7 @@ describe("get proposers api impl", function () { vi.advanceTimersByTime((SYNC_TOLERANCE_EPOCHS * SLOTS_PER_EPOCH + 1) * config.SECONDS_PER_SLOT * 1000); vi.spyOn(modules.sync, "state", "get").mockReturnValue(SyncState.SyncingHead); - await expect(api.getProposerDuties({epoch: 1})).rejects.toThrow("Node is syncing - headSlot 0 currentSlot 9"); + await expect(api.getProposerDuties({epoch: 1})).rejects.toThrow("Node is syncing - headSlot 0 currentSlot 25"); }); it("should raise error if node stalled", async () => { @@ -65,34 +77,61 @@ describe("get proposers api impl", function () { }); it("should get proposers for current epoch", async () => { - const {data: result} = (await api.getProposerDuties({epoch: 0})) as {data: routes.validator.ProposerDutyList}; + const {data: result} = (await api.getProposerDuties({epoch: currentEpoch})) as { + data: routes.validator.ProposerDutyList; + }; expect(result.length).toBe(SLOTS_PER_EPOCH); expect(cachedState.epochCtx.getBeaconProposers).toHaveBeenCalledOnce(); expect(cachedState.epochCtx.getBeaconProposersNextEpoch).not.toHaveBeenCalled(); - expect(result.map((p) => p.slot)).toEqual(Array.from({length: SLOTS_PER_EPOCH}, (_, i) => i)); + expect(cachedState.epochCtx.getBeaconProposersPrevEpoch).not.toHaveBeenCalled(); + expect(result.map((p) => p.slot)).toEqual( + Array.from({length: SLOTS_PER_EPOCH}, (_, i) => currentEpoch * SLOTS_PER_EPOCH + i) + ); }); it("should get proposers for next epoch", async () => { - const {data: result} = (await api.getProposerDuties({epoch: 1})) as {data: routes.validator.ProposerDutyList}; + const nextEpoch = currentEpoch + 1; + const {data: result} = (await api.getProposerDuties({epoch: nextEpoch})) as { + data: routes.validator.ProposerDutyList; + }; expect(result.length).toBe(SLOTS_PER_EPOCH); expect(cachedState.epochCtx.getBeaconProposers).not.toHaveBeenCalled(); expect(cachedState.epochCtx.getBeaconProposersNextEpoch).toHaveBeenCalledOnce(); - expect(result.map((p) => p.slot)).toEqual(Array.from({length: SLOTS_PER_EPOCH}, (_, i) => SLOTS_PER_EPOCH + i)); + expect(cachedState.epochCtx.getBeaconProposersPrevEpoch).not.toHaveBeenCalled(); + expect(result.map((p) => p.slot)).toEqual( + Array.from({length: SLOTS_PER_EPOCH}, (_, i) => nextEpoch * SLOTS_PER_EPOCH + i) + ); + }); + + it("should get proposers for historical epoch", async () => { + const historicalEpoch = currentEpoch - 2; + initializeState(currentSlot - 2 * SLOTS_PER_EPOCH); + modules.chain.getStateBySlot.mockResolvedValue({state, executionOptimistic: false, finalized: true}); + + const {data: result} = (await api.getProposerDuties({epoch: historicalEpoch})) as { + data: routes.validator.ProposerDutyList; + }; + + expect(result.length).toBe(SLOTS_PER_EPOCH); + // Spy won't be called as `getProposerDuties` will create a new cached beacon state + expect(result.map((p) => p.slot)).toEqual( + Array.from({length: SLOTS_PER_EPOCH}, (_, i) => historicalEpoch * SLOTS_PER_EPOCH + i) + ); }); it("should raise error for more than one epoch in the future", async () => { - await expect(api.getProposerDuties({epoch: 2})).rejects.toThrow( - "Requested epoch 2 must equal current 0 or next epoch 1" + await expect(api.getProposerDuties({epoch: currentEpoch + 2})).rejects.toThrow( + "Requested epoch 4 must not be more than one epoch in the future" ); }); it("should have different proposer validator public keys for current and next epoch", async () => { - const {data: currentProposers} = (await api.getProposerDuties({epoch: 0})) as { + const {data: currentProposers} = (await api.getProposerDuties({epoch: currentEpoch})) as { data: routes.validator.ProposerDutyList; }; - const {data: nextProposers} = (await api.getProposerDuties({epoch: 1})) as { + const {data: nextProposers} = (await api.getProposerDuties({epoch: currentEpoch + 1})) as { data: routes.validator.ProposerDutyList; }; @@ -101,10 +140,10 @@ describe("get proposers api impl", function () { }); it("should have different proposer validator indexes for current and next epoch", async () => { - const {data: currentProposers} = (await api.getProposerDuties({epoch: 0})) as { + const {data: currentProposers} = (await api.getProposerDuties({epoch: currentEpoch})) as { data: routes.validator.ProposerDutyList; }; - const {data: nextProposers} = (await api.getProposerDuties({epoch: 1})) as { + const {data: nextProposers} = (await api.getProposerDuties({epoch: currentEpoch + 1})) as { data: routes.validator.ProposerDutyList; }; @@ -112,10 +151,10 @@ describe("get proposers api impl", function () { }); it("should have different proposer slots for current and next epoch", async () => { - const {data: currentProposers} = (await api.getProposerDuties({epoch: 0})) as { + const {data: currentProposers} = (await api.getProposerDuties({epoch: currentEpoch})) as { data: routes.validator.ProposerDutyList; }; - const {data: nextProposers} = (await api.getProposerDuties({epoch: 1})) as { + const {data: nextProposers} = (await api.getProposerDuties({epoch: currentEpoch + 1})) as { data: routes.validator.ProposerDutyList; }; diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 5e901e33d992..4eb16fa49927 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -877,6 +877,10 @@ export class EpochCache { return this.proposers; } + getBeaconProposersPrevEpoch(): ValidatorIndex[] | null { + return this.proposersPrevEpoch; + } + /** * We allow requesting proposal duties 1 epoch in the future as in normal network conditions it's possible to predict * the correct shuffling with high probability. While knowing the proposers in advance is not useful for consensus, From 105a38808f91db1d1a1ecb206496df1c81c49869 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 11 Oct 2024 17:19:13 +0100 Subject: [PATCH 148/259] feat: add ssz support to LC updates by range endpoint (#7119) --- packages/api/src/beacon/routes/lightclient.ts | 62 ++++++++++++++++--- .../api/test/unit/beacon/oapiSpec.test.ts | 2 - .../test/unit/beacon/testData/lightclient.ts | 2 +- 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/packages/api/src/beacon/routes/lightclient.ts b/packages/api/src/beacon/routes/lightclient.ts index decf8982b654..bac73b43ddb2 100644 --- a/packages/api/src/beacon/routes/lightclient.ts +++ b/packages/api/src/beacon/routes/lightclient.ts @@ -7,10 +7,12 @@ import { ssz, SyncPeriod, } from "@lodestar/types"; -import {ForkName} from "@lodestar/params"; -import {ChainForkConfig} from "@lodestar/config"; +import {fromHex} from "@lodestar/utils"; +import {ForkName, ZERO_HASH} from "@lodestar/params"; +import {BeaconConfig, ChainForkConfig, createBeaconConfig} from "@lodestar/config"; +import {genesisData, NetworkName} from "@lodestar/config/networks"; import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; -import {VersionCodec, VersionMeta} from "../../utils/metadata.js"; +import {MetaHeader, VersionCodec, VersionMeta} from "../../utils/metadata.js"; import {getLightClientForkTypes, toForkName} from "../../utils/fork.js"; import { EmptyArgs, @@ -19,7 +21,6 @@ import { EmptyMetaCodec, EmptyRequest, WithVersion, - JsonOnlyResp, } from "../../utils/codecs.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes @@ -90,7 +91,18 @@ export type Endpoints = { >; }; -export function getDefinitions(_config: ChainForkConfig): RouteDefinitions { +export function getDefinitions(config: ChainForkConfig): RouteDefinitions { + // Cache config so fork digests don't need to be recomputed + let beaconConfig: BeaconConfig | undefined; + + const cachedBeaconConfig = (): BeaconConfig => { + if (beaconConfig === undefined) { + const genesisValidatorsRoot = genesisData[config.CONFIG_NAME as NetworkName]?.genesisValidatorsRoot; + beaconConfig = createBeaconConfig(config, genesisValidatorsRoot ? fromHex(genesisValidatorsRoot) : ZERO_HASH); + } + return beaconConfig; + }; + return { getLightClientUpdatesByRange: { url: "/eth/v1/beacon/light_client/updates", @@ -100,7 +112,7 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({startPeriod: query.start_period, count: query.count}), schema: {query: {start_period: Schema.UintRequired, count: Schema.UintRequired}}, }, - resp: JsonOnlyResp({ + resp: { data: { toJson: (data, meta) => { const json: unknown[] = []; @@ -118,12 +130,44 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions { + const chunks: Uint8Array[] = []; + for (const [i, update] of data.entries()) { + const version = meta.versions[i]; + const forkDigest = cachedBeaconConfig().forkName2ForkDigest(version); + const serialized = getLightClientForkTypes(version).LightClientUpdate.serialize(update); + const length = ssz.UintNum64.serialize(4 + serialized.length); + chunks.push(length, forkDigest, serialized); + } + return Buffer.concat(chunks); + }, + deserialize: (data) => { + let offset = 0; + const updates: LightClientUpdate[] = []; + while (offset < data.length) { + const length = ssz.UintNum64.deserialize(data.subarray(offset, offset + 8)); + const forkDigest = ssz.ForkDigest.deserialize(data.subarray(offset + 8, offset + 12)); + const version = cachedBeaconConfig().forkDigest2ForkName(forkDigest); + updates.push( + getLightClientForkTypes(version).LightClientUpdate.deserialize( + data.subarray(offset + 12, offset + 8 + length) + ) + ); + offset += 8 + length; + } + return updates; + }, }, meta: { toJson: (meta) => meta, fromJson: (val) => val as {versions: ForkName[]}, - toHeadersObject: () => ({}), - fromHeaders: () => ({versions: []}), + toHeadersObject: (meta) => ({ + [MetaHeader.Version]: meta.versions.join(","), + }), + fromHeaders: (headers) => { + const versions = headers.getOrDefault(MetaHeader.Version, ""); + return {versions: versions === "" ? [] : (versions.split(",") as ForkName[])}; + }, }, transform: { toResponse: (data, meta) => { @@ -147,7 +191,7 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions = { diff --git a/packages/api/test/unit/beacon/testData/lightclient.ts b/packages/api/test/unit/beacon/testData/lightclient.ts index b86e1f338329..f405d514fc5d 100644 --- a/packages/api/test/unit/beacon/testData/lightclient.ts +++ b/packages/api/test/unit/beacon/testData/lightclient.ts @@ -14,7 +14,7 @@ const signatureSlot = ssz.Slot.defaultValue(); export const testData: GenericServerTestCases = { getLightClientUpdatesByRange: { args: {startPeriod: 1, count: 2}, - res: {data: [lightClientUpdate], meta: {versions: [ForkName.bellatrix]}}, + res: {data: [lightClientUpdate, lightClientUpdate], meta: {versions: [ForkName.altair, ForkName.altair]}}, }, getLightClientOptimisticUpdate: { args: undefined, From fb40cf0340f17283120ccb64e2304007e8e63c4f Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Fri, 11 Oct 2024 12:57:46 -0700 Subject: [PATCH 149/259] feat: add execution requests to builder flow (#7148) * initial commit * Update packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts Co-authored-by: Nico Flaig --------- Co-authored-by: Nico Flaig --- .../src/chain/produceBlock/produceBlockBody.ts | 9 +++++++++ packages/beacon-node/src/execution/builder/http.ts | 5 ++++- packages/beacon-node/src/execution/builder/interface.ts | 2 ++ packages/types/src/electra/sszTypes.ts | 2 ++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index ff8221a326e9..8d90fb6c5b1a 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -220,6 +220,14 @@ export async function produceBlockBody( } else { blobsResult = {type: BlobsResultType.preDeneb}; } + + if (ForkSeq[fork] >= ForkSeq.electra) { + const {executionRequests} = builderRes; + if (executionRequests === undefined) { + throw Error(`Invalid builder getHeader response for fork=${fork}, missing executionRequests`); + } + (blockBody as electra.BlindedBeaconBlockBody).executionRequests = executionRequests; + } } // blockType === BlockType.Full @@ -455,6 +463,7 @@ async function prepareExecutionPayloadHeader( header: ExecutionPayloadHeader; executionPayloadValue: Wei; blobKzgCommitments?: deneb.BlobKzgCommitments; + executionRequests?: electra.ExecutionRequests; }> { if (!chain.executionBuilder) { throw Error("executionBuilder required"); diff --git a/packages/beacon-node/src/execution/builder/http.ts b/packages/beacon-node/src/execution/builder/http.ts index 934b874f5ae3..d7b36a666468 100644 --- a/packages/beacon-node/src/execution/builder/http.ts +++ b/packages/beacon-node/src/execution/builder/http.ts @@ -8,6 +8,7 @@ import { SignedBeaconBlockOrContents, SignedBlindedBeaconBlock, ExecutionPayloadHeader, + electra, } from "@lodestar/types"; import {parseExecutionPayloadAndBlobsBundle, reconstructFullBlockOrContents} from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; @@ -114,6 +115,7 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { header: ExecutionPayloadHeader; executionPayloadValue: Wei; blobKzgCommitments?: deneb.BlobKzgCommitments; + executionRequests?: electra.ExecutionRequests; }> { const signedBuilderBid = (await this.api.getHeader({slot, parentHash, proposerPubkey})).value(); @@ -123,7 +125,8 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { const {header, value: executionPayloadValue} = signedBuilderBid.message; const {blobKzgCommitments} = signedBuilderBid.message as deneb.BuilderBid; - return {header, executionPayloadValue, blobKzgCommitments}; + const {executionRequests} = signedBuilderBid.message as electra.BuilderBid; + return {header, executionPayloadValue, blobKzgCommitments, executionRequests}; } async submitBlindedBlock(signedBlindedBlock: SignedBlindedBeaconBlock): Promise { diff --git a/packages/beacon-node/src/execution/builder/interface.ts b/packages/beacon-node/src/execution/builder/interface.ts index 9a655a68de02..5a6a4eb82f63 100644 --- a/packages/beacon-node/src/execution/builder/interface.ts +++ b/packages/beacon-node/src/execution/builder/interface.ts @@ -8,6 +8,7 @@ import { SignedBeaconBlockOrContents, ExecutionPayloadHeader, SignedBlindedBeaconBlock, + electra, } from "@lodestar/types"; import {ForkExecution} from "@lodestar/params"; @@ -36,6 +37,7 @@ export interface IExecutionBuilder { header: ExecutionPayloadHeader; executionPayloadValue: Wei; blobKzgCommitments?: deneb.BlobKzgCommitments; + executionRequests?: electra.ExecutionRequests; }>; submitBlindedBlock(signedBlock: SignedBlindedBeaconBlock): Promise; } diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 7200af5f4ead..d73c33edd523 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -211,6 +211,7 @@ export const BlindedBeaconBlockBody = new ContainerType( executionPayloadHeader: ExecutionPayloadHeader, blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, + executionRequests: ExecutionRequests, // New in ELECTRA }, {typeName: "BlindedBeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); @@ -235,6 +236,7 @@ export const BuilderBid = new ContainerType( { header: ExecutionPayloadHeader, // Modified in ELECTRA blindedBlobsBundle: denebSsz.BlobKzgCommitments, + executionRequests: ExecutionRequests, // New in ELECTRA value: UintBn256, pubkey: BLSPubkey, }, From 911a3f59f6e47ff8264b88d2b881e90a0f4824e7 Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Sat, 12 Oct 2024 03:26:34 +0700 Subject: [PATCH 150/259] feat: use rust shuffle (#7120) * feat: add temp-deps to test on feat group * feat: add build_temp_deps.sh process * feat: use async for shuffling in epoch transition * feat: use v0.0.1 instead of temp-deps * chore: lint and check-types * fix: log error context * refactor: use toHex * fix: address computeEpochShuffling refactor comments * test: remove perf tests that were moved to swp-or-not-shuffle package * test: add strict equal check for sync/async computeEpochShuffling impls * Revert "refactor: use toHex" This reverts commit 9d64b6735b1358668f8dc6bf4f87d84497206ea5. * fix: EpochShuffling ssz type issue * feat: upgrade swap-or-not to 0.0.2 * refactor: buildCommitteesFromShuffling * docs: add TODO about removing state from shuffling computation * docs: add TODO about removing state from shuffling computation --- .../beacon-node/src/chain/shufflingCache.ts | 21 +- .../test/spec/presets/shuffling.test.ts | 17 +- packages/state-transition/package.json | 1 + .../src/util/epochShuffling.ts | 59 +++-- packages/state-transition/src/util/index.ts | 1 - packages/state-transition/src/util/shuffle.ts | 221 ------------------ .../test/perf/hashing.test.ts | 14 +- .../test/perf/shuffle/numberMath.test.ts | 82 ------- .../test/perf/shuffle/shuffle.test.ts | 29 --- .../test/unit/util/shuffle.test.ts | 29 --- .../test/unit/util/shuffling.test.ts | 32 +++ yarn.lock | 54 +++++ 12 files changed, 161 insertions(+), 399 deletions(-) delete mode 100644 packages/state-transition/src/util/shuffle.ts delete mode 100644 packages/state-transition/test/perf/shuffle/numberMath.test.ts delete mode 100644 packages/state-transition/test/perf/shuffle/shuffle.test.ts delete mode 100644 packages/state-transition/test/unit/util/shuffle.test.ts create mode 100644 packages/state-transition/test/unit/util/shuffling.test.ts diff --git a/packages/beacon-node/src/chain/shufflingCache.ts b/packages/beacon-node/src/chain/shufflingCache.ts index 6c42228b5356..749fea1b82ff 100644 --- a/packages/beacon-node/src/chain/shufflingCache.ts +++ b/packages/beacon-node/src/chain/shufflingCache.ts @@ -4,11 +4,11 @@ import { IShufflingCache, ShufflingBuildProps, computeEpochShuffling, + computeEpochShufflingAsync, } from "@lodestar/state-transition"; import {Epoch, RootHex} from "@lodestar/types"; import {LodestarError, Logger, MapDef, pruneSetToMax} from "@lodestar/utils"; import {Metrics} from "../metrics/metrics.js"; -import {callInNextEventLoop} from "../util/eventLoop.js"; /** * Same value to CheckpointBalancesCache, with the assumption that we don't have to use it for old epochs. In the worse case: @@ -178,14 +178,19 @@ export class ShufflingCache implements IShufflingCache { this.insertPromise(epoch, decisionRoot); /** * TODO: (@matthewkeil) This will get replaced by a proper build queue and a worker to do calculations - * on a NICE thread with a rust implementation + * on a NICE thread */ - callInNextEventLoop(() => { - const timer = this.metrics?.shufflingCache.shufflingCalculationTime.startTimer({source: "build"}); - const shuffling = computeEpochShuffling(state, activeIndices, epoch); - timer?.(); - this.set(shuffling, decisionRoot); - }); + const timer = this.metrics?.shufflingCache.shufflingCalculationTime.startTimer({source: "build"}); + computeEpochShufflingAsync(state, activeIndices, epoch) + .then((shuffling) => { + this.set(shuffling, decisionRoot); + }) + .catch((err) => + this.logger?.error(`error building shuffling for epoch ${epoch} at decisionRoot ${decisionRoot}`, {}, err) + ) + .finally(() => { + timer?.(); + }); } /** diff --git a/packages/beacon-node/test/spec/presets/shuffling.test.ts b/packages/beacon-node/test/spec/presets/shuffling.test.ts index 06e7d4717d06..7b0f38ecf581 100644 --- a/packages/beacon-node/test/spec/presets/shuffling.test.ts +++ b/packages/beacon-node/test/spec/presets/shuffling.test.ts @@ -1,24 +1,27 @@ import path from "node:path"; -import {unshuffleList} from "@lodestar/state-transition"; +import {unshuffleList} from "@chainsafe/swap-or-not-shuffle"; import {InputType} from "@lodestar/spec-test-util"; import {bnToNum, fromHex} from "@lodestar/utils"; -import {ACTIVE_PRESET} from "@lodestar/params"; +import {ACTIVE_PRESET, SHUFFLE_ROUND_COUNT} from "@lodestar/params"; import {RunnerType, TestRunnerFn} from "../utils/types.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; -const shuffling: TestRunnerFn = () => { +const shuffling: TestRunnerFn = () => { return { testFunction: (testcase) => { const seed = fromHex(testcase.mapping.seed); - const output = Array.from({length: bnToNum(testcase.mapping.count)}, (_, i) => i); - unshuffleList(output, seed); - return output; + const output = unshuffleList( + Uint32Array.from(Array.from({length: bnToNum(testcase.mapping.count)}, (_, i) => i)), + seed, + SHUFFLE_ROUND_COUNT + ); + return Buffer.from(output).toString("hex"); }, options: { inputTypes: {mapping: InputType.YAML}, timeout: 10000, - getExpected: (testCase) => testCase.mapping.mapping.map((value) => bnToNum(value)), + getExpected: (testCase) => Buffer.from(testCase.mapping.mapping.map((value) => bnToNum(value))).toString("hex"), // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts }, }; diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index e743ece013d9..a01d835bae95 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -63,6 +63,7 @@ "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/persistent-ts": "^0.19.1", "@chainsafe/ssz": "^0.17.1", + "@chainsafe/swap-or-not-shuffle": "^0.0.2", "@lodestar/config": "^1.22.0", "@lodestar/params": "^1.22.0", "@lodestar/types": "^1.22.0", diff --git a/packages/state-transition/src/util/epochShuffling.ts b/packages/state-transition/src/util/epochShuffling.ts index c26c62fd2079..6f63a2f4f5f8 100644 --- a/packages/state-transition/src/util/epochShuffling.ts +++ b/packages/state-transition/src/util/epochShuffling.ts @@ -1,3 +1,4 @@ +import {asyncUnshuffleList, unshuffleList} from "@chainsafe/swap-or-not-shuffle"; import {Epoch, RootHex, ssz, ValidatorIndex} from "@lodestar/types"; import {GaugeExtra, intDiv, Logger, NoLabels, toRootHex} from "@lodestar/utils"; import { @@ -6,11 +7,11 @@ import { MAX_COMMITTEES_PER_SLOT, SLOTS_PER_EPOCH, TARGET_COMMITTEE_SIZE, + SHUFFLE_ROUND_COUNT, } from "@lodestar/params"; import {BeaconConfig} from "@lodestar/config"; import {BeaconStateAllForks} from "../types.js"; import {getSeed} from "./seed.js"; -import {unshuffleList} from "./shuffle.js"; import {computeStartSlotAtEpoch} from "./epoch.js"; import {getBlockRootAtSlot} from "./blockRoot.js"; import {computeAnchorCheckpoint} from "./computeAnchorCheckpoint.js"; @@ -102,24 +103,15 @@ export function computeCommitteeCount(activeValidatorCount: number): number { return Math.max(1, Math.min(MAX_COMMITTEES_PER_SLOT, committeesPerSlot)); } -export function computeEpochShuffling( - state: BeaconStateAllForks, - activeIndices: Uint32Array, - epoch: Epoch -): EpochShuffling { - const activeValidatorCount = activeIndices.length; - - const shuffling = activeIndices.slice(); - const seed = getSeed(state, epoch, DOMAIN_BEACON_ATTESTER); - unshuffleList(shuffling, seed); - +function buildCommitteesFromShuffling(shuffling: Uint32Array): Uint32Array[][] { + const activeValidatorCount = shuffling.length; const committeesPerSlot = computeCommitteeCount(activeValidatorCount); - const committeeCount = committeesPerSlot * SLOTS_PER_EPOCH; - const committees: Uint32Array[][] = []; + const committees = new Array(SLOTS_PER_EPOCH); for (let slot = 0; slot < SLOTS_PER_EPOCH; slot++) { - const slotCommittees: Uint32Array[] = []; + const slotCommittees = new Array(committeesPerSlot); + for (let committeeIndex = 0; committeeIndex < committeesPerSlot; committeeIndex++) { const index = slot * committeesPerSlot + committeeIndex; const startOffset = Math.floor((activeValidatorCount * index) / committeeCount); @@ -127,17 +119,48 @@ export function computeEpochShuffling( if (!(startOffset <= endOffset)) { throw new Error(`Invalid offsets: start ${startOffset} must be less than or equal end ${endOffset}`); } - slotCommittees.push(shuffling.subarray(startOffset, endOffset)); + slotCommittees[committeeIndex] = shuffling.subarray(startOffset, endOffset); } - committees.push(slotCommittees); + + committees[slot] = slotCommittees; } + return committees; +} + +export function computeEpochShuffling( + // TODO: (@matthewkeil) remove state/epoch and pass in seed to clean this up + state: BeaconStateAllForks, + activeIndices: Uint32Array, + epoch: Epoch +): EpochShuffling { + const seed = getSeed(state, epoch, DOMAIN_BEACON_ATTESTER); + const shuffling = unshuffleList(activeIndices, seed, SHUFFLE_ROUND_COUNT); + const committees = buildCommitteesFromShuffling(shuffling); + return { + epoch, + activeIndices, + shuffling, + committees, + committeesPerSlot: committees[0].length, + }; +} + +export async function computeEpochShufflingAsync( + // TODO: (@matthewkeil) remove state/epoch and pass in seed to clean this up + state: BeaconStateAllForks, + activeIndices: Uint32Array, + epoch: Epoch +): Promise { + const seed = getSeed(state, epoch, DOMAIN_BEACON_ATTESTER); + const shuffling = await asyncUnshuffleList(activeIndices, seed, SHUFFLE_ROUND_COUNT); + const committees = buildCommitteesFromShuffling(shuffling); return { epoch, activeIndices, shuffling, committees, - committeesPerSlot, + committeesPerSlot: committees[0].length, }; } diff --git a/packages/state-transition/src/util/index.ts b/packages/state-transition/src/util/index.ts index 5f8d9e5cdcfc..b88a20719b85 100644 --- a/packages/state-transition/src/util/index.ts +++ b/packages/state-transition/src/util/index.ts @@ -17,7 +17,6 @@ export * from "./genesis.js"; export * from "./interop.js"; export * from "./rootCache.js"; export * from "./seed.js"; -export * from "./shuffle.js"; export * from "./shufflingDecisionRoot.js"; export * from "./signatureSets.js"; export * from "./signingRoot.js"; diff --git a/packages/state-transition/src/util/shuffle.ts b/packages/state-transition/src/util/shuffle.ts deleted file mode 100644 index a87f22cae43e..000000000000 --- a/packages/state-transition/src/util/shuffle.ts +++ /dev/null @@ -1,221 +0,0 @@ -import {digest} from "@chainsafe/as-sha256"; -import {SHUFFLE_ROUND_COUNT} from "@lodestar/params"; -import {Bytes32} from "@lodestar/types"; -import {assert, bytesToBigInt} from "@lodestar/utils"; - -// ArrayLike but with settable indices -type Shuffleable = { - readonly length: number; - [index: number]: number; -}; - -// ShuffleList shuffles a list, using the given seed for randomness. Mutates the input list. -export function shuffleList(input: Shuffleable, seed: Bytes32): void { - innerShuffleList(input, seed, true); -} - -// UnshuffleList undoes a list shuffling using the seed of the shuffling. Mutates the input list. -export function unshuffleList(input: Shuffleable, seed: Bytes32): void { - innerShuffleList(input, seed, false); -} - -const _SHUFFLE_H_SEED_SIZE = 32; -const _SHUFFLE_H_ROUND_SIZE = 1; -const _SHUFFLE_H_POSITION_WINDOW_SIZE = 4; -const _SHUFFLE_H_PIVOT_VIEW_SIZE = _SHUFFLE_H_SEED_SIZE + _SHUFFLE_H_ROUND_SIZE; -const _SHUFFLE_H_TOTAL_SIZE = _SHUFFLE_H_SEED_SIZE + _SHUFFLE_H_ROUND_SIZE + _SHUFFLE_H_POSITION_WINDOW_SIZE; - -/* - -def shuffle(list_size, seed): - indices = list(range(list_size)) - for round in range(90): - hash_bytes = b''.join([ - hash(seed + round.to_bytes(1, 'little') + (i).to_bytes(4, 'little')) - for i in range((list_size + 255) // 256) - ]) - pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'little')), 'little') % list_size - - powers_of_two = [1, 2, 4, 8, 16, 32, 64, 128] - - for i, index in enumerate(indices): - flip = (pivot - index) % list_size - hash_pos = index if index > flip else flip - byte = hash_bytes[hash_pos // 8] - if byte & powers_of_two[hash_pos % 8]: - indices[i] = flip - return indices - -Heavily-optimized version of the set-shuffling algorithm proposed by Vitalik to shuffle all items in a list together. - -Original here: - https://github.com/ethereum/consensus-specs/pull/576 - -Main differences, implemented by @protolambda: - - User can supply input slice to shuffle, simple provide [0,1,2,3,4, ...] to get a list of cleanly shuffled indices. - - Input slice is shuffled (hence no return value), no new array is allocated - - Allocations as minimal as possible: only a very minimal buffer for hashing - (this should be allocated on the stack, compiler will find it with escape analysis). - This is not bigger than what's used for shuffling a single index! - As opposed to larger allocations (size O(n) instead of O(1)) made in the original. - - Replaced pseudocode/python workarounds with bit-logic. - - User can provide their own hash-function (as long as it outputs a 32 len byte slice) - -This Typescript version is an adaption of the Python version, in turn an adaption of the original Go version. -Python: https://github.com/protolambda/eth2fastspec/blob/14e04e9db77ef7c8b7788ffdaa7e142d7318dd7e/eth2fastspec.py#L63 -Go: https://github.com/protolambda/eth2-shuffle -All three implemented by @protolambda, but meant for public use, like the original spec version. -*/ - -function setPositionUint32(value: number, buf: Buffer): void { - // Little endian, optimized version - buf[_SHUFFLE_H_PIVOT_VIEW_SIZE] = (value >> 0) & 0xff; - buf[_SHUFFLE_H_PIVOT_VIEW_SIZE + 1] = (value >> 8) & 0xff; - buf[_SHUFFLE_H_PIVOT_VIEW_SIZE + 2] = (value >> 16) & 0xff; - buf[_SHUFFLE_H_PIVOT_VIEW_SIZE + 3] = (value >> 24) & 0xff; -} - -// Shuffles or unshuffles, depending on the `dir` (true for shuffling, false for unshuffling -function innerShuffleList(input: Shuffleable, seed: Bytes32, dir: boolean): void { - if (input.length <= 1) { - // nothing to (un)shuffle - return; - } - if (SHUFFLE_ROUND_COUNT == 0) { - // no shuffling - return; - } - // uint32 is sufficient, and necessary in JS, - // as we do a lot of bit math on it, which cannot be done as fast on more bits. - 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; - if (!dir) { - // Start at last round. - // Iterating through the rounds in reverse, un-swaps everything, effectively un-shuffling the list. - r = SHUFFLE_ROUND_COUNT - 1; - } - - // Seed is always the first 32 bytes of the hash input, we never have to change this part of the buffer. - 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 - let byteV = 0; - - while (true) { - // spec: pivot = bytes_to_int(hash(seed + int_to_bytes1(round))[0:8]) % list_size - // This is the "int_to_bytes1(round)", appended to the seed. - 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.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) - // 2. Handle the part from pivot (excl) to N (excl). This is mirrored around ((pivot / 2) + (size/2)) - // The pivot defines a split in the array, with each of the splits mirroring their data within the split. - // Print out some example even/odd sized index lists, with some even/odd pivots, - // and you can deduce how the mirroring works exactly. - // Note that the mirror is strict enough to not consider swapping the index @mirror with itself. - let mirror = (pivot + 1) >> 1; - // Since we are iterating through the "positions" in order, we can just repeat the hash every 256th position. - // No need to pre-compute every possible hash for efficiency like in the example code. - // We only need it consecutively (we are going through each in reverse order however, but same thing) - // - // spec: source = hash(seed + int_to_bytes1(round) + int_to_bytes4(position // 256)) - // - seed is still in 0:32 (excl., 32 bytes) - // - round number is still in 32 - // - mix in the position for randomness, except the last byte of it, - // which will be used later to select a bit from the resulting hash. - // We start from the pivot position, and work back to the mirror position (of the part left to the pivot). - // This makes us process each pear exactly once (instead of unnecessarily twice, like in the spec) - setPositionUint32(pivot >> 8, buf); // already using first pivot byte below. - source = digest(buf); - byteV = source[(pivot & 0xff) >> 3]; - - for (let i = 0, j; i < mirror; i++) { - j = pivot - i; - // -- step() fn start - // The pair is i,j. With j being the bigger of the two, hence the "position" identifier of the pair. - // Every 256th bit (aligned to j). - if ((j & 0xff) == 0xff) { - // just overwrite the last part of the buffer, reuse the start (seed, round) - setPositionUint32(j >> 8, buf); - source = digest(buf); - } - - // Same trick with byte retrieval. Only every 8th. - if ((j & 0x7) == 0x7) { - byteV = source[(j & 0xff) >> 3]; - } - - const bitV = (byteV >> (j & 0x7)) & 0x1; - - if (bitV == 1) { - // swap the pair items - const tmp = input[j]; - input[j] = input[i]; - input[i] = tmp; - } - // -- step() fn end - } - - // Now repeat, but for the part after the pivot. - mirror = (pivot + listSize + 1) >> 1; - const end = listSize - 1; - // Again, seed and round input is in place, just update the position. - // We start at the end, and work back to the mirror point. - // This makes us process each pear exactly once (instead of unnecessarily twice, like in the spec) - setPositionUint32(end >> 8, buf); - source = digest(buf); - byteV = source[(end & 0xff) >> 3]; - for (let i = pivot + 1, j; i < mirror; i++) { - j = end - i + pivot + 1; - // -- step() fn start - // The pair is i,j. With j being the bigger of the two, hence the "position" identifier of the pair. - // Every 256th bit (aligned to j). - if ((j & 0xff) == 0xff) { - // just overwrite the last part of the buffer, reuse the start (seed, round) - setPositionUint32(j >> 8, buf); - source = digest(buf); - } - - // Same trick with byte retrieval. Only every 8th. - if ((j & 0x7) == 0x7) { - byteV = source[(j & 0xff) >> 3]; - } - - const bitV = (byteV >> (j & 0x7)) & 0x1; - - if (bitV == 1) { - // swap the pair items - const tmp = input[j]; - input[j] = input[i]; - input[i] = tmp; - } - // -- step() fn end - } - - // go forwards? - if (dir) { - // -> shuffle - r += 1; - if (r == SHUFFLE_ROUND_COUNT) { - break; - } - } else { - if (r == 0) { - break; - } - // -> un-shuffle - r -= 1; - } - } -} diff --git a/packages/state-transition/test/perf/hashing.test.ts b/packages/state-transition/test/perf/hashing.test.ts index b7afc59717bc..26bfd935c08a 100644 --- a/packages/state-transition/test/perf/hashing.test.ts +++ b/packages/state-transition/test/perf/hashing.test.ts @@ -1,13 +1,14 @@ import {itBench} from "@dapplion/benchmark"; +import {unshuffleList} from "@chainsafe/swap-or-not-shuffle"; import {ssz} from "@lodestar/types"; -import {unshuffleList} from "../../src/index.js"; +import {SHUFFLE_ROUND_COUNT} from "@lodestar/params"; import {generatePerfTestCachedStatePhase0, numValidators} from "./util.js"; // Test cost of hashing state after some modifications describe("BeaconState hashTreeRoot", () => { const vc = numValidators; - const indicesShuffled: number[] = []; + let indicesShuffled: Uint32Array; let stateOg: ReturnType; before(function () { @@ -15,8 +16,13 @@ describe("BeaconState hashTreeRoot", () => { stateOg = generatePerfTestCachedStatePhase0(); stateOg.hashTreeRoot(); - for (let i = 0; i < vc; i++) indicesShuffled[i] = i; - unshuffleList(indicesShuffled, new Uint8Array([42, 32])); + const seed = new Uint8Array(32); + seed.set([42, 32], 0); + const preShuffle = new Uint32Array(numValidators); + for (let i = 0; i < vc; i++) { + preShuffle[i] = i; + } + indicesShuffled = unshuffleList(preShuffle, seed, SHUFFLE_ROUND_COUNT); }); const validator = ssz.phase0.Validator.defaultViewDU(); diff --git a/packages/state-transition/test/perf/shuffle/numberMath.test.ts b/packages/state-transition/test/perf/shuffle/numberMath.test.ts deleted file mode 100644 index 08e57b090aa3..000000000000 --- a/packages/state-transition/test/perf/shuffle/numberMath.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import {itBench} from "@dapplion/benchmark"; - -describe.skip("shuffle number math ops", () => { - const forRuns = 100e5; - const j = forRuns / 2; - - const arrSize = forRuns; - const input: number[] = []; - const inputUint32Array = new Uint32Array(arrSize); - for (let i = 0; i < arrSize; i++) { - input[i] = i; - inputUint32Array[i] = i; - } - - itBench("if(i == 1)", () => { - for (let i = 0; i < forRuns; i++) { - if (i === 1) { - // - } - } - }); - - itBench("if(i)", () => { - for (let i = 0; i < forRuns; i++) { - if (i) { - // - } - } - }); - - itBench("i == j", () => { - for (let i = 0; i < forRuns; i++) { - i == j; - } - }); - - itBench("i === j", () => { - for (let i = 0; i < forRuns; i++) { - i === j; - } - }); - - itBench("bit opts", () => { - for (let i = 0; i < forRuns; i++) { - (j & 0x7) == 0x7; - } - }); - - itBench("modulo", () => { - for (let i = 0; i < forRuns; i++) { - j % 8 == 0; - } - }); - - itBench(">> 3", () => { - for (let i = 0; i < forRuns; i++) { - j >> 3; - } - }); - - itBench("/ 8", () => { - for (let i = 0; i < forRuns; i++) { - j / 8; - } - }); - - itBench("swap item in array", () => { - for (let i = 0; i < forRuns; i++) { - const tmp = input[forRuns - i]; - input[forRuns - i] = input[i]; - input[i] = tmp; - } - }); - - itBench("swap item in Uint32Array", () => { - for (let i = 0; i < forRuns; i++) { - const tmp = inputUint32Array[forRuns - i]; - inputUint32Array[forRuns - i] = inputUint32Array[i]; - inputUint32Array[i] = tmp; - } - }); -}); diff --git a/packages/state-transition/test/perf/shuffle/shuffle.test.ts b/packages/state-transition/test/perf/shuffle/shuffle.test.ts deleted file mode 100644 index 55f7875e69dd..000000000000 --- a/packages/state-transition/test/perf/shuffle/shuffle.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {itBench} from "@dapplion/benchmark"; -import {unshuffleList} from "../../../src/index.js"; - -// Lightouse Lodestar -// 512 254.04 us 1.6034 ms (x6) -// 16384 6.2046 ms 18.272 ms (x3) -// 4000000 1.5617 s 4.9690 s (x3) - -describe("shuffle list", () => { - const seed = new Uint8Array([42, 32]); - - for (const listSize of [ - 16384, - 250000, - // Don't run 4_000_000 since it's very slow and not testnet has gotten there yet - // 4e6, - ]) { - itBench({ - id: `shuffle list - ${listSize} els`, - before: () => { - const input: number[] = []; - for (let i = 0; i < listSize; i++) input[i] = i; - return new Uint32Array(input); - }, - beforeEach: (input) => input, - fn: (input) => unshuffleList(input, seed), - }); - } -}); diff --git a/packages/state-transition/test/unit/util/shuffle.test.ts b/packages/state-transition/test/unit/util/shuffle.test.ts deleted file mode 100644 index 9186968674ae..000000000000 --- a/packages/state-transition/test/unit/util/shuffle.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {expect, describe, it} from "vitest"; -import {unshuffleList} from "../../../src/index.js"; - -describe("util / shuffle", () => { - const testCases: { - id: string; - input: number[]; - res: number[]; - }[] = [ - // Values from `unshuffleList()` at commit https://github.com/ChainSafe/lodestar/commit/ec065635ca7da7f3788da018bd68c4900f0427d2 - { - id: "8 elements", - input: [0, 1, 2, 3, 4, 5, 6, 7], - res: [6, 3, 4, 0, 1, 5, 7, 2], - }, - { - id: "16 elements", - input: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - res: [8, 4, 11, 7, 10, 6, 0, 3, 15, 12, 5, 14, 1, 9, 13, 2], - }, - ]; - - const seed = new Uint8Array([42, 32]); - - it.each(testCases)("$id", ({input, res}) => { - unshuffleList(input, seed); - expect(input).toEqual(res); - }); -}); diff --git a/packages/state-transition/test/unit/util/shuffling.test.ts b/packages/state-transition/test/unit/util/shuffling.test.ts new file mode 100644 index 000000000000..f4039b472f5c --- /dev/null +++ b/packages/state-transition/test/unit/util/shuffling.test.ts @@ -0,0 +1,32 @@ +import {describe, it, expect} from "vitest"; +import {ssz} from "@lodestar/types"; +import {generateState} from "../../utils/state.js"; +import {computeEpochShuffling, computeEpochShufflingAsync} from "../../../src/util/epochShuffling.js"; +import {computeEpochAtSlot} from "../../../src/index.js"; + +describe("EpochShuffling", () => { + it("async and sync versions should be identical", async () => { + const numberOfValidators = 1000; + const activeIndices = Uint32Array.from(Array.from({length: numberOfValidators}, (_, i) => i)); + const state = generateState(); + state.slot = 12345; + state.validators = ssz.phase0.Validators.toViewDU( + Array.from({length: numberOfValidators}, () => ({ + activationEligibilityEpoch: 0, + activationEpoch: 0, + exitEpoch: Infinity, + effectiveBalance: 32, + pubkey: Buffer.alloc(48, 0xaa), + slashed: false, + withdrawableEpoch: Infinity, + withdrawalCredentials: Buffer.alloc(8, 0x01), + })) + ); + const epoch = computeEpochAtSlot(state.slot); + + const sync = computeEpochShuffling(state, activeIndices, epoch); + const async = await computeEpochShufflingAsync(state, activeIndices, epoch); + + expect(sync).toStrictEqual(async); + }); +}); diff --git a/yarn.lock b/yarn.lock index 9808fee96b84..3907e9f4e441 100644 --- a/yarn.lock +++ b/yarn.lock @@ -674,6 +674,60 @@ "@chainsafe/as-sha256" "0.5.0" "@chainsafe/persistent-merkle-tree" "0.8.0" +"@chainsafe/swap-or-not-shuffle-darwin-arm64@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@chainsafe/swap-or-not-shuffle-darwin-arm64/-/swap-or-not-shuffle-darwin-arm64-0.0.2.tgz#9c4b02970619b9ec5274f357f3a03ff97e745957" + integrity sha512-e2tmpSgGTHFv1g3oEKP/YElDTmxZwuSwVQ+Cf0gTUA8z4YQsJar61293My6JeA7qC5razWjhvcEk13ZbTCqk0w== + +"@chainsafe/swap-or-not-shuffle-darwin-x64@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@chainsafe/swap-or-not-shuffle-darwin-x64/-/swap-or-not-shuffle-darwin-x64-0.0.2.tgz#d2777b93455a217bf4b5b94b84e76239bc3ce860" + integrity sha512-JrK4psAQz0HzlfnsGRcHnhJSv6OHfjVNkEtERnpAjyeigwCRh09wNBzHEnIk8SOGFk29DabI4FC1wdh2Cs0DAA== + +"@chainsafe/swap-or-not-shuffle-linux-arm64-gnu@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@chainsafe/swap-or-not-shuffle-linux-arm64-gnu/-/swap-or-not-shuffle-linux-arm64-gnu-0.0.2.tgz#a881c6e29704bbbaceb8b75fd9394832087979f3" + integrity sha512-nGTIRUXt1QRNiWQXZnA8IWiHnAw6FNkU7RkngkoDzjD8pEhrtWs8tv/pdOxRKEhw21HBvKi7z8J+a7/MtxDLTg== + +"@chainsafe/swap-or-not-shuffle-linux-arm64-musl@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@chainsafe/swap-or-not-shuffle-linux-arm64-musl/-/swap-or-not-shuffle-linux-arm64-musl-0.0.2.tgz#118f80f7bd7e8f83fb566112a17003f228d86593" + integrity sha512-sumwkxQ0Mky+W66Jf43cHUybgHQ4FENj2iRBRw3jGWiZ79Vv/DZ1dMA6I4/LVWCsvZmFUIvMvKNthGHXefh2DQ== + +"@chainsafe/swap-or-not-shuffle-linux-x64-gnu@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@chainsafe/swap-or-not-shuffle-linux-x64-gnu/-/swap-or-not-shuffle-linux-x64-gnu-0.0.2.tgz#2dca41ba2848f904b5c9bc831cb0428c958261f3" + integrity sha512-do9NH/43eUWxtY+k3fxFltSSfKJpyvAINA/dJ3EHVkqS/oBTwR450CVNV5HFcR5Uvgxuth3/BjVYb4APs8N/MQ== + +"@chainsafe/swap-or-not-shuffle-linux-x64-musl@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@chainsafe/swap-or-not-shuffle-linux-x64-musl/-/swap-or-not-shuffle-linux-x64-musl-0.0.2.tgz#75025eee02e2b34f10852c1de57b8e0050584320" + integrity sha512-ClwDMZd768PIaAUQhbyZpqqip0b6Sgjt8IpP5ACYMJr2AHoiG64POZaiFu+zusT4q3s4/dvqaz86jRQaF4vFkw== + +"@chainsafe/swap-or-not-shuffle-win32-arm64-msvc@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@chainsafe/swap-or-not-shuffle-win32-arm64-msvc/-/swap-or-not-shuffle-win32-arm64-msvc-0.0.2.tgz#f5520df2bf72e823ef225d9f13d317b91b6372e4" + integrity sha512-i9+qj0VSppy2xMChQE38rCmWmmy8SJ0uSaApc0L4KZ+t2aqquYyEUXWGgfdXMZx9MqAUvuigzv34T9qivADFag== + +"@chainsafe/swap-or-not-shuffle-win32-x64-msvc@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@chainsafe/swap-or-not-shuffle-win32-x64-msvc/-/swap-or-not-shuffle-win32-x64-msvc-0.0.2.tgz#7413aa32a4006bf144b66087844aee71bb2a5f42" + integrity sha512-zZ9J0PWzGEgfjjAVMeTvAPdHNs5XCeQqfNQ0E/lQUYhS8Wi84y44R+7M6C/KIcS0GmvCpZXI2sQGeNjqbU5LoA== + +"@chainsafe/swap-or-not-shuffle@^0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@chainsafe/swap-or-not-shuffle/-/swap-or-not-shuffle-0.0.2.tgz#59a148b80bb8e8d4f2f38f7bd00562c7a6b99e62" + integrity sha512-Rbk3p86cX71VAq46+nRcBOHOetK2ls4QrAUf1YOWTYLHmmLvx8j9Q6gQndjtu0OeYGd7Eyj1pQCFDlS9kixk+g== + optionalDependencies: + "@chainsafe/swap-or-not-shuffle-darwin-arm64" "0.0.2" + "@chainsafe/swap-or-not-shuffle-darwin-x64" "0.0.2" + "@chainsafe/swap-or-not-shuffle-linux-arm64-gnu" "0.0.2" + "@chainsafe/swap-or-not-shuffle-linux-arm64-musl" "0.0.2" + "@chainsafe/swap-or-not-shuffle-linux-x64-gnu" "0.0.2" + "@chainsafe/swap-or-not-shuffle-linux-x64-musl" "0.0.2" + "@chainsafe/swap-or-not-shuffle-win32-arm64-msvc" "0.0.2" + "@chainsafe/swap-or-not-shuffle-win32-x64-msvc" "0.0.2" + "@chainsafe/threads@^1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@chainsafe/threads/-/threads-1.11.1.tgz#0b3b8c76f5875043ef6d47aeeb681dc80378f205" From f9d9ae54acc85590ed422836388dc36fcbd8f06c Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:41:17 -0700 Subject: [PATCH 151/259] feat: switch to compounding from consolidation requests (#7122) * New compound switching logic * clean up * fix: remove newCompoundingValidators in EpochTransitionCache * Bump spec version * Address comment * address comment * Lint --------- Co-authored-by: Tuyen Nguyen --- .../src/block/processConsolidationRequest.ts | 80 ++++++++++++++++--- .../src/cache/epochTransitionCache.ts | 8 -- .../epoch/processEffectiveBalanceUpdates.ts | 7 +- .../src/epoch/processPendingConsolidations.ts | 7 -- packages/state-transition/src/util/electra.ts | 16 ++-- 5 files changed, 79 insertions(+), 39 deletions(-) diff --git a/packages/state-transition/src/block/processConsolidationRequest.ts b/packages/state-transition/src/block/processConsolidationRequest.ts index 691ecd5eca0b..c14612579c58 100644 --- a/packages/state-transition/src/block/processConsolidationRequest.ts +++ b/packages/state-transition/src/block/processConsolidationRequest.ts @@ -3,31 +3,38 @@ import {FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} import {CachedBeaconStateElectra} from "../types.js"; import {getConsolidationChurnLimit, isActiveValidator} from "../util/validator.js"; -import {hasExecutionWithdrawalCredential} from "../util/electra.js"; +import {hasExecutionWithdrawalCredential, switchToCompoundingValidator} from "../util/electra.js"; import {computeConsolidationEpochAndUpdateChurn} from "../util/epoch.js"; +import {hasEth1WithdrawalCredential} from "../util/capella.js"; +// TODO Electra: Clean up necessary as there is a lot of overlap with isValidSwitchToCompoundRequest export function processConsolidationRequest( state: CachedBeaconStateElectra, consolidationRequest: electra.ConsolidationRequest ): void { - // If the pending consolidations queue is full, consolidation requests are ignored - if (state.pendingConsolidations.length >= PENDING_CONSOLIDATIONS_LIMIT) { + const {sourcePubkey, targetPubkey, sourceAddress} = consolidationRequest; + const sourceIndex = state.epochCtx.getValidatorIndex(sourcePubkey); + const targetIndex = state.epochCtx.getValidatorIndex(targetPubkey); + + if (sourceIndex === null || targetIndex === null) { return; } - // If there is too little available consolidation churn limit, consolidation requests are ignored - if (getConsolidationChurnLimit(state.epochCtx) <= MIN_ACTIVATION_BALANCE) { + if (isValidSwitchToCompoundRequest(state, consolidationRequest)) { + switchToCompoundingValidator(state, sourceIndex); + // Early return since we have already switched validator to compounding return; } - const {sourcePubkey, targetPubkey} = consolidationRequest; - const sourceIndex = state.epochCtx.getValidatorIndex(sourcePubkey); - const targetIndex = state.epochCtx.getValidatorIndex(targetPubkey); - - if (sourceIndex === null || targetIndex === null) { + // If the pending consolidations queue is full, consolidation requests are ignored + if (state.pendingConsolidations.length >= PENDING_CONSOLIDATIONS_LIMIT) { return; } + // If there is too little available consolidation churn limit, consolidation requests are ignored + if (getConsolidationChurnLimit(state.epochCtx) <= MIN_ACTIVATION_BALANCE) { + return; + } // Verify that source != target, so a consolidation cannot be used as an exit. if (sourceIndex === targetIndex) { return; @@ -46,7 +53,7 @@ export function processConsolidationRequest( return; } - if (Buffer.compare(sourceWithdrawalAddress, consolidationRequest.sourceAddress) !== 0) { + if (Buffer.compare(sourceWithdrawalAddress, sourceAddress) !== 0) { return; } @@ -70,4 +77,55 @@ export function processConsolidationRequest( targetIndex, }); state.pendingConsolidations.push(pendingConsolidation); + + // Churn any target excess active balance of target and raise its max + if (hasEth1WithdrawalCredential(targetValidator.withdrawalCredentials)) { + switchToCompoundingValidator(state, targetIndex); + } +} + +/** + * Determine if we should set consolidation target validator to compounding credential + */ +function isValidSwitchToCompoundRequest( + state: CachedBeaconStateElectra, + consolidationRequest: electra.ConsolidationRequest +): boolean { + const {sourcePubkey, targetPubkey, sourceAddress} = consolidationRequest; + const sourceIndex = state.epochCtx.getValidatorIndex(sourcePubkey); + const targetIndex = state.epochCtx.getValidatorIndex(targetPubkey); + + // Verify pubkey exists + if (sourceIndex === null) { + return false; + } + + // Switch to compounding requires source and target be equal + if (sourceIndex !== targetIndex) { + return false; + } + + const sourceValidator = state.validators.getReadonly(sourceIndex); + const sourceWithdrawalAddress = sourceValidator.withdrawalCredentials.subarray(12); + // Verify request has been authorized + if (Buffer.compare(sourceWithdrawalAddress, sourceAddress) !== 0) { + return false; + } + + // Verify source withdrawal credentials + if (!hasEth1WithdrawalCredential(sourceValidator.withdrawalCredentials)) { + return false; + } + + // Verify the source is active + if (!isActiveValidator(sourceValidator, state.epochCtx.epoch)) { + return false; + } + + // Verify exit for source has not been initiated + if (sourceValidator.exitEpoch !== FAR_FUTURE_EPOCH) { + return false; + } + + return true; } diff --git a/packages/state-transition/src/cache/epochTransitionCache.ts b/packages/state-transition/src/cache/epochTransitionCache.ts index 27b781e8a6a1..2a35317fbc93 100644 --- a/packages/state-transition/src/cache/epochTransitionCache.ts +++ b/packages/state-transition/src/cache/epochTransitionCache.ts @@ -139,12 +139,6 @@ export interface EpochTransitionCache { */ validators: phase0.Validator[]; - /** - * This is for electra only - * Validators that're switched to compounding during processPendingConsolidations(), not available in beforeProcessEpoch() - */ - newCompoundingValidators?: Set; - /** * balances array will be populated by processRewardsAndPenalties() and consumed by processEffectiveBalanceUpdates(). * processRewardsAndPenalties() already has a regular Javascript array of balances. @@ -518,8 +512,6 @@ export function beforeProcessEpoch( inclusionDelays, flags, validators, - // will be assigned in processPendingConsolidations() - newCompoundingValidators: undefined, // Will be assigned in processRewardsAndPenalties() balances: undefined, }; diff --git a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts index 26180d0d9f34..22a46c84f52b 100644 --- a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts +++ b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts @@ -46,7 +46,6 @@ export function processEffectiveBalanceUpdates( // so it's recycled here for performance. const balances = cache.balances ?? state.balances.getAll(); const currentEpochValidators = cache.validators; - const newCompoundingValidators = cache.newCompoundingValidators ?? new Set(); let numUpdate = 0; for (let i = 0, len = balances.length; i < len; i++) { @@ -61,9 +60,9 @@ export function processEffectiveBalanceUpdates( effectiveBalanceLimit = MAX_EFFECTIVE_BALANCE; } else { // from electra, effectiveBalanceLimit is per validator - const isCompoundingValidator = - hasCompoundingWithdrawalCredential(currentEpochValidators[i].withdrawalCredentials) || - newCompoundingValidators.has(i); + const isCompoundingValidator = hasCompoundingWithdrawalCredential( + currentEpochValidators[i].withdrawalCredentials + ); effectiveBalanceLimit = isCompoundingValidator ? MAX_EFFECTIVE_BALANCE_ELECTRA : MIN_ACTIVATION_BALANCE; } diff --git a/packages/state-transition/src/epoch/processPendingConsolidations.ts b/packages/state-transition/src/epoch/processPendingConsolidations.ts index 28178a509bba..0c0d61fd78a9 100644 --- a/packages/state-transition/src/epoch/processPendingConsolidations.ts +++ b/packages/state-transition/src/epoch/processPendingConsolidations.ts @@ -1,8 +1,6 @@ -import {ValidatorIndex} from "@lodestar/types"; import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; import {decreaseBalance, increaseBalance} from "../util/balance.js"; import {getActiveBalance} from "../util/validator.js"; -import {switchToCompoundingValidator} from "../util/electra.js"; /** * Starting from Electra: @@ -22,7 +20,6 @@ export function processPendingConsolidations(state: CachedBeaconStateElectra, ca let nextPendingConsolidation = 0; const validators = state.validators; const cachedBalances = cache.balances; - const newCompoundingValidators = new Set(); for (const pendingConsolidation of state.pendingConsolidations.getAllReadonly()) { const {sourceIndex, targetIndex} = pendingConsolidation; @@ -36,9 +33,6 @@ export function processPendingConsolidations(state: CachedBeaconStateElectra, ca if (sourceValidator.withdrawableEpoch > nextEpoch) { break; } - // Churn any target excess active balance of target and raise its max - switchToCompoundingValidator(state, targetIndex); - newCompoundingValidators.add(targetIndex); // Move active balance to target. Excess balance is withdrawable. const activeBalance = getActiveBalance(state, sourceIndex); decreaseBalance(state, sourceIndex, activeBalance); @@ -51,6 +45,5 @@ export function processPendingConsolidations(state: CachedBeaconStateElectra, ca nextPendingConsolidation++; } - cache.newCompoundingValidators = newCompoundingValidators; state.pendingConsolidations = state.pendingConsolidations.sliceFrom(nextPendingConsolidation); } diff --git a/packages/state-transition/src/util/electra.ts b/packages/state-transition/src/util/electra.ts index 90dd9a3881df..c8522e17e29b 100644 --- a/packages/state-transition/src/util/electra.ts +++ b/packages/state-transition/src/util/electra.ts @@ -17,15 +17,13 @@ export function hasExecutionWithdrawalCredential(withdrawalCredentials: Uint8Arr export function switchToCompoundingValidator(state: CachedBeaconStateElectra, index: ValidatorIndex): void { const validator = state.validators.get(index); - if (hasEth1WithdrawalCredential(validator.withdrawalCredentials)) { - // directly modifying the byte leads to ssz missing the modification resulting into - // wrong root compute, although slicing can be avoided but anyway this is not going - // to be a hot path so its better to clean slice and avoid side effects - const newWithdrawalCredentials = validator.withdrawalCredentials.slice(); - newWithdrawalCredentials[0] = COMPOUNDING_WITHDRAWAL_PREFIX; - validator.withdrawalCredentials = newWithdrawalCredentials; - queueExcessActiveBalance(state, index); - } + // directly modifying the byte leads to ssz missing the modification resulting into + // wrong root compute, although slicing can be avoided but anyway this is not going + // to be a hot path so its better to clean slice and avoid side effects + const newWithdrawalCredentials = validator.withdrawalCredentials.slice(); + newWithdrawalCredentials[0] = COMPOUNDING_WITHDRAWAL_PREFIX; + validator.withdrawalCredentials = newWithdrawalCredentials; + queueExcessActiveBalance(state, index); } export function queueExcessActiveBalance(state: CachedBeaconStateElectra, index: ValidatorIndex): void { From 4f3676a604e6d6293b629726fdd80aadfe488b20 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:46:16 -0700 Subject: [PATCH 152/259] Bump spec version to alpha8 --- packages/beacon-node/test/spec/specTestVersioning.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/test/spec/specTestVersioning.ts b/packages/beacon-node/test/spec/specTestVersioning.ts index bef42fd1cdfa..360fcdeebdfd 100644 --- a/packages/beacon-node/test/spec/specTestVersioning.ts +++ b/packages/beacon-node/test/spec/specTestVersioning.ts @@ -15,7 +15,7 @@ import {DownloadTestsOptions} from "@lodestar/spec-test-util/downloadTests"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const ethereumConsensusSpecsTests: DownloadTestsOptions = { - specVersion: "v1.5.0-alpha.7", + specVersion: "v1.5.0-alpha.8", // Target directory is the host package root: 'packages/*/spec-tests' outputDir: path.join(__dirname, "../../spec-tests"), specTestsRepoUrl: "https://github.com/ethereum/consensus-spec-tests", From d37bdb0eb8a6e8deedd019fd6b7b3413f3fcf6d4 Mon Sep 17 00:00:00 2001 From: Cayman Date: Fri, 11 Oct 2024 17:19:34 -0400 Subject: [PATCH 153/259] chore: upgrade to js-libp2p 2.0 (#7077) * chore: upgrade to js-libp2p 2.0 * chore: bump libp2p versions * chore: fix up yarn lock * chore: fix some tests * chore: fix connection map * feat: gossipsub v1.2 * chore: bump libp2p * chore: tweak idontwantMinDataSize * chore: bump libp2p deps --- package.json | 2 +- packages/beacon-node/package.json | 35 +- .../src/network/core/networkCore.ts | 17 +- .../src/network/core/networkCoreWorker.ts | 8 +- .../network/core/networkCoreWorkerHandler.ts | 10 +- .../beacon-node/src/network/core/types.ts | 2 +- .../beacon-node/src/network/discv5/index.ts | 14 +- .../beacon-node/src/network/discv5/types.ts | 2 +- .../beacon-node/src/network/discv5/worker.ts | 13 +- .../src/network/gossip/gossipsub.ts | 4 + packages/beacon-node/src/network/interface.ts | 4 +- .../beacon-node/src/network/libp2p/index.ts | 21 +- packages/beacon-node/src/network/network.ts | 18 +- .../src/network/peers/datastore.ts | 3 +- .../beacon-node/src/network/peers/discover.ts | 10 +- .../src/network/peers/peerManager.ts | 5 +- .../peers/utils/getConnectedPeerIds.ts | 4 +- packages/beacon-node/src/network/util.ts | 4 +- packages/beacon-node/src/node/nodejs.ts | 8 +- packages/beacon-node/src/util/peerId.ts | 2 +- .../beacon-node/test/e2e/network/mdns.test.ts | 16 +- .../e2e/network/peers/peerManager.test.ts | 12 +- .../test/e2e/network/reqrespEncode.test.ts | 2 +- .../test/perf/network/noise/sendData.test.ts | 17 +- .../peers/util/prioritizePeers.test.ts | 6 +- .../unit/network/peers/priorization.test.ts | 9 +- packages/beacon-node/test/utils/network.ts | 15 +- .../test/utils/networkWithMockDb.ts | 6 +- .../beacon-node/test/utils/node/beacon.ts | 12 +- packages/beacon-node/test/utils/peer.ts | 8 +- packages/cli/package.json | 10 +- packages/cli/src/cmds/beacon/handler.ts | 10 +- .../cli/src/cmds/beacon/initPeerIdAndEnr.ts | 54 +- packages/cli/src/cmds/bootnode/handler.ts | 14 +- packages/cli/src/config/peerId.ts | 67 +- packages/cli/test/unit/cmds/beacon.test.ts | 57 +- .../test/unit/cmds/initPeerIdAndEnr.test.ts | 13 +- packages/cli/test/unit/config/peerId.test.ts | 12 +- packages/reqresp/package.json | 6 +- packages/reqresp/test/utils/peer.ts | 5 +- yarn.lock | 816 ++++++++++-------- 41 files changed, 754 insertions(+), 599 deletions(-) diff --git a/package.json b/package.json index 7399b4ba6c1e..e6de076cf494 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "https-browserify": "^1.0.0", "jsdom": "^23.0.1", "lerna": "^7.3.0", - "libp2p": "1.4.3", + "libp2p": "2.1.7", "mocha": "^10.2.0", "node-gyp": "^9.4.0", "npm-run-all": "^4.1.5", diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 8b46bc0038c7..e3d095b6f1e0 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -96,11 +96,10 @@ "dependencies": { "@chainsafe/as-sha256": "^0.5.0", "@chainsafe/blst": "^2.0.3", - "@chainsafe/discv5": "^9.0.0", - "@chainsafe/enr": "^3.0.0", - "@chainsafe/libp2p-gossipsub": "^13.0.0", - "@chainsafe/libp2p-identify": "^1.0.0", - "@chainsafe/libp2p-noise": "^15.0.0", + "@chainsafe/discv5": "^10.0.1", + "@chainsafe/enr": "^4.0.1", + "@chainsafe/libp2p-gossipsub": "^14.1.0", + "@chainsafe/libp2p-noise": "^16.0.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/prometheus-gc-stats": "^1.0.0", "@chainsafe/ssz": "^0.17.1", @@ -111,15 +110,15 @@ "@fastify/cors": "^10.0.1", "@fastify/swagger": "^9.0.0", "@fastify/swagger-ui": "^5.0.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", + "@libp2p/bootstrap": "^11.0.4", + "@libp2p/crypto": "^5.0.4", + "@libp2p/identify": "^3.0.4", + "@libp2p/interface": "^2.1.2", + "@libp2p/mdns": "^11.0.4", + "@libp2p/mplex": "^11.0.4", + "@libp2p/peer-id": "^5.0.4", + "@libp2p/prometheus-metrics": "^4.1.2", + "@libp2p/tcp": "10.0.4", "@lodestar/api": "^1.22.0", "@lodestar/config": "^1.22.0", "@lodestar/db": "^1.22.0", @@ -134,15 +133,15 @@ "@lodestar/validator": "^1.22.0", "@multiformats/multiaddr": "^12.1.3", "c-kzg": "^2.1.2", - "datastore-core": "^9.1.1", - "datastore-level": "^10.1.1", + "datastore-core": "^10.0.0", + "datastore-level": "^11.0.0", "deepmerge": "^4.3.1", "fastify": "^5.0.0", - "interface-datastore": "^8.2.7", + "interface-datastore": "^8.3.0", "it-all": "^3.0.4", "it-pipe": "^3.0.1", "jwt-simple": "0.5.6", - "libp2p": "1.4.3", + "libp2p": "2.1.7", "multiformats": "^11.0.1", "prom-client": "^15.1.0", "qs": "^6.11.1", diff --git a/packages/beacon-node/src/network/core/networkCore.ts b/packages/beacon-node/src/network/core/networkCore.ts index 1a497925e4fd..9d075c730558 100644 --- a/packages/beacon-node/src/network/core/networkCore.ts +++ b/packages/beacon-node/src/network/core/networkCore.ts @@ -1,4 +1,4 @@ -import {Connection, PeerId} from "@libp2p/interface"; +import {Connection, PrivateKey} from "@libp2p/interface"; import {multiaddr} from "@multiformats/multiaddr"; import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/dist/src/score/peer-score.js"; @@ -55,7 +55,7 @@ type Mods = { export type BaseNetworkInit = { opts: NetworkOptions; config: BeaconConfig; - peerId: PeerId; + privateKey: PrivateKey; peerStoreDir: string | undefined; logger: LoggerNode; metricsRegistry: RegistryMetricCreator | null; @@ -126,7 +126,7 @@ export class NetworkCore implements INetworkCore { static async init({ opts, config, - peerId, + privateKey, peerStoreDir, logger, metricsRegistry, @@ -136,7 +136,7 @@ export class NetworkCore implements INetworkCore { activeValidatorCount, initialStatus, }: BaseNetworkInit): Promise { - const libp2p = await createNodeJsLibp2p(peerId, opts, { + const libp2p = await createNodeJsLibp2p(privateKey, opts, { peerStoreDir, metrics: Boolean(metricsRegistry), metricsRegistry: metricsRegistry ?? undefined, @@ -200,8 +200,9 @@ export class NetworkCore implements INetworkCore { const peerManager = await PeerManager.init( { + privateKey, libp2p, - gossip: gossip, + gossip, reqResp, attnetsService, syncnetsService, @@ -359,7 +360,11 @@ export class NetworkCore implements INetworkCore { } getConnectionsByPeer(): Map { - return getConnectionsMap(this.libp2p); + const m = new Map(); + for (const [k, v] of getConnectionsMap(this.libp2p).entries()) { + m.set(k, v.value); + } + return m; } async getConnectedPeers(): Promise { diff --git a/packages/beacon-node/src/network/core/networkCoreWorker.ts b/packages/beacon-node/src/network/core/networkCoreWorker.ts index 5e4b057402d8..07b6de828b6c 100644 --- a/packages/beacon-node/src/network/core/networkCoreWorker.ts +++ b/packages/beacon-node/src/network/core/networkCoreWorker.ts @@ -3,7 +3,8 @@ import path from "node:path"; import worker from "node:worker_threads"; import type {ModuleThread} from "@chainsafe/threads"; import {expose} from "@chainsafe/threads/worker"; -import {createFromProtobuf} from "@libp2p/peer-id-factory"; +import {privateKeyFromProtobuf} from "@libp2p/crypto/keys"; +import {peerIdFromPrivateKey} from "@libp2p/peer-id"; import {chainConfigFromJson, createBeaconConfig} from "@lodestar/config"; import {getNodeLogger} from "@lodestar/logger/node"; import {RegistryMetricCreator, collectNodeJSMetrics} from "../../metrics/index.js"; @@ -32,7 +33,8 @@ if (!workerData) throw Error("workerData must be defined"); if (!parentPort) throw Error("parentPort must be defined"); const config = createBeaconConfig(chainConfigFromJson(workerData.chainConfigJson), workerData.genesisValidatorsRoot); -const peerId = await createFromProtobuf(workerData.peerIdProto); +const privateKey = privateKeyFromProtobuf(workerData.privateKeyProto); +const peerId = peerIdFromPrivateKey(privateKey); // TODO: Pass options from main thread for logging // TODO: Logging won't be visible in file loggers @@ -92,7 +94,7 @@ if (networkCoreWorkerMetrics) { const core = await NetworkCore.init({ opts: workerData.opts, config, - peerId, + privateKey, peerStoreDir: workerData.peerStoreDir, logger, metricsRegistry: metricsRegister, diff --git a/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts b/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts index bd66a21e726b..e883476b5e65 100644 --- a/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts +++ b/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts @@ -3,8 +3,8 @@ 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, Secp256k1PeerId} from "@libp2p/interface"; -import {exportToProtobuf} from "@libp2p/peer-id-factory"; +import {PrivateKey} from "@libp2p/interface"; +import {privateKeyToProtobuf} from "@libp2p/crypto/keys"; import {routes} from "@lodestar/api"; import {BeaconConfig, chainConfigToJson} from "@lodestar/config"; import type {LoggerNode} from "@lodestar/logger/node"; @@ -44,7 +44,7 @@ export type WorkerNetworkCoreInitModules = { opts: WorkerNetworkCoreOpts; config: BeaconConfig; logger: LoggerNode; - peerId: PeerId; + privateKey: PrivateKey; events: NetworkEventBus; metrics: Metrics | null; getReqRespHandler: GetReqRespHandlerFn; @@ -103,14 +103,14 @@ export class WorkerNetworkCore implements INetworkCore { } static async init(modules: WorkerNetworkCoreInitModules): Promise { - const {opts, config, peerId} = modules; + const {opts, config, privateKey} = modules; const {genesisTime, peerStoreDir, activeValidatorCount, localMultiaddrs, metricsEnabled, initialStatus} = opts; const workerData: NetworkWorkerData = { opts, chainConfigJson: chainConfigToJson(config), genesisValidatorsRoot: config.genesisValidatorsRoot, - peerIdProto: exportToProtobuf(peerId as Secp256k1PeerId), + privateKeyProto: privateKeyToProtobuf(privateKey), localMultiaddrs, metricsEnabled, peerStoreDir, diff --git a/packages/beacon-node/src/network/core/types.ts b/packages/beacon-node/src/network/core/types.ts index 4eeaf96e1903..d2f56c8fa2f1 100644 --- a/packages/beacon-node/src/network/core/types.ts +++ b/packages/beacon-node/src/network/core/types.ts @@ -78,7 +78,7 @@ export type NetworkWorkerData = { genesisTime: number; activeValidatorCount: number; initialStatus: phase0.Status; - peerIdProto: Uint8Array; + privateKeyProto: Uint8Array; localMultiaddrs: string[]; metricsEnabled: boolean; peerStoreDir?: string; diff --git a/packages/beacon-node/src/network/discv5/index.ts b/packages/beacon-node/src/network/discv5/index.ts index 745b3171c38d..34990d404c90 100644 --- a/packages/beacon-node/src/network/discv5/index.ts +++ b/packages/beacon-node/src/network/discv5/index.ts @@ -1,8 +1,8 @@ import EventEmitter from "node:events"; -import {PeerId, Secp256k1PeerId} from "@libp2p/interface"; +import {privateKeyToProtobuf} from "@libp2p/crypto/keys"; +import {PrivateKey} 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"; +import {ENR, ENRData, SignableENR} from "@chainsafe/enr"; import {spawn, Thread, Worker} from "@chainsafe/threads"; import {chainConfigFromJson, chainConfigToJson, BeaconConfig} from "@lodestar/config"; import {LoggerNode} from "@lodestar/logger/node"; @@ -10,7 +10,7 @@ import {NetworkCoreMetrics} from "../core/metrics.js"; import {Discv5WorkerApi, Discv5WorkerData, LodestarDiscv5Opts} from "./types.js"; export type Discv5Opts = { - peerId: PeerId; + privateKey: PrivateKey; discv5: LodestarDiscv5Opts; logger: LoggerNode; config: BeaconConfig; @@ -25,7 +25,6 @@ export type Discv5Events = { * Wrapper class abstracting the details of discv5 worker instantiation and message-passing */ export class Discv5Worker extends (EventEmitter as {new (): StrictEventEmitter}) { - private readonly keypair; private readonly subscription: {unsubscribe: () => void}; private closed = false; @@ -35,14 +34,13 @@ export class Discv5Worker extends (EventEmitter as {new (): StrictEventEmitter this.onDiscovered(enrObj)); } static async init(opts: Discv5Opts): Promise { const workerData: Discv5WorkerData = { enr: opts.discv5.enr, - peerIdProto: exportToProtobuf(opts.peerId as Secp256k1PeerId), + privateKeyProto: privateKeyToProtobuf(opts.privateKey), bindAddrs: opts.discv5.bindAddrs, config: opts.discv5.config ?? {}, bootEnrs: opts.discv5.bootEnrs, @@ -80,7 +78,7 @@ export class Discv5Worker extends (EventEmitter as {new (): StrictEventEmitter { const obj = await this.workerApi.enr(); - return new SignableENR(obj.kvs, obj.seq, this.keypair.privateKey); + return new SignableENR(obj.kvs, obj.seq, this.opts.privateKey.raw); } setEnrValue(key: string, value: Uint8Array): Promise { diff --git a/packages/beacon-node/src/network/discv5/types.ts b/packages/beacon-node/src/network/discv5/types.ts index 63c5cd52b6fe..cbaf2423f87f 100644 --- a/packages/beacon-node/src/network/discv5/types.ts +++ b/packages/beacon-node/src/network/discv5/types.ts @@ -31,7 +31,7 @@ export type LodestarDiscv5Opts = { /** discv5 worker constructor data */ export interface Discv5WorkerData { enr: string; - peerIdProto: Uint8Array; + privateKeyProto: Uint8Array; bindAddrs: BindAddrs; config: Discv5Config; bootEnrs: string[]; diff --git a/packages/beacon-node/src/network/discv5/worker.ts b/packages/beacon-node/src/network/discv5/worker.ts index 8e96751d5fe7..40eb08f7af92 100644 --- a/packages/beacon-node/src/network/discv5/worker.ts +++ b/packages/beacon-node/src/network/discv5/worker.ts @@ -1,12 +1,13 @@ import worker from "node:worker_threads"; import path from "node:path"; import fs from "node:fs"; -import {createFromProtobuf} from "@libp2p/peer-id-factory"; import {Multiaddr, multiaddr} from "@multiformats/multiaddr"; import {expose} from "@chainsafe/threads/worker"; import {Observable, Subject} from "@chainsafe/threads/observable"; import {Discv5} from "@chainsafe/discv5"; -import {createPrivateKeyFromPeerId, ENR, ENRData, SignableENR, SignableENRData} from "@chainsafe/enr"; +import {ENR, ENRData, SignableENR, SignableENRData} from "@chainsafe/enr"; +import {privateKeyFromProtobuf} from "@libp2p/crypto/keys"; +import {peerIdFromPrivateKey} from "@libp2p/peer-id"; import {createBeaconConfig} from "@lodestar/config"; import {getNodeLogger} from "@lodestar/logger/node"; import {Gauge} from "@lodestar/utils"; @@ -42,15 +43,15 @@ if (workerData.metrics) { }); } -const peerId = await createFromProtobuf(workerData.peerIdProto); -const keypair = createPrivateKeyFromPeerId(peerId); +const privateKey = privateKeyFromProtobuf(workerData.privateKeyProto); +const peerId = peerIdFromPrivateKey(privateKey); const config = createBeaconConfig(workerData.chainConfig, workerData.genesisValidatorsRoot); // Initialize discv5 const discv5 = Discv5.create({ - enr: SignableENR.decodeTxt(workerData.enr, keypair.privateKey), - peerId, + enr: SignableENR.decodeTxt(workerData.enr, privateKey.raw), + privateKey, bindAddrs: { ip4: (workerData.bindAddrs.ip4 ? multiaddr(workerData.bindAddrs.ip4) : undefined) as Multiaddr, ip6: workerData.bindAddrs.ip6 ? multiaddr(workerData.bindAddrs.ip6) : undefined, diff --git a/packages/beacon-node/src/network/gossip/gossipsub.ts b/packages/beacon-node/src/network/gossip/gossipsub.ts index 1fc326ba1e58..debcbaf89854 100644 --- a/packages/beacon-node/src/network/gossip/gossipsub.ts +++ b/packages/beacon-node/src/network/gossip/gossipsub.ts @@ -135,6 +135,10 @@ export class Eth2Gossipsub extends GossipSub { // if this is false, only publish to mesh peers. If there is not enough GOSSIP_D mesh peers, // publish to some more topic peers to make sure we always publish to at least GOSSIP_D peers floodPublish: !opts?.disableFloodPublish, + // Only send IDONTWANT messages if the message size is larger than this + // This should be large enough to not send IDONTWANT for "small" messages + // See https://github.com/ChainSafe/lodestar/pull/7077#issuecomment-2383679472 + idontwantMinDataSize: 16829, }); this.scoreParams = scoreParams; this.config = config; diff --git a/packages/beacon-node/src/network/interface.ts b/packages/beacon-node/src/network/interface.ts index 8d73379af221..ccb5ddecb557 100644 --- a/packages/beacon-node/src/network/interface.ts +++ b/packages/beacon-node/src/network/interface.ts @@ -12,10 +12,11 @@ import { PeerRouting, PeerStore, Upgrader, + PrivateKey, } from "@libp2p/interface"; import type {AddressManager, ConnectionManager, Registrar, TransportManager} from "@libp2p/interface-internal"; import type {Datastore} from "interface-datastore"; -import {Identify} from "@chainsafe/libp2p-identify"; +import {Identify} from "@libp2p/identify"; import { LightClientFinalityUpdate, LightClientOptimisticUpdate, @@ -93,6 +94,7 @@ export interface INetwork extends INetworkCorePublic { export type LodestarComponents = { peerId: PeerId; + privateKey: PrivateKey; nodeInfo: NodeInfo; logger: ComponentLogger; events: TypedEventTarget; diff --git a/packages/beacon-node/src/network/libp2p/index.ts b/packages/beacon-node/src/network/libp2p/index.ts index a0d58033cf2f..7697dbcb49a7 100644 --- a/packages/beacon-node/src/network/libp2p/index.ts +++ b/packages/beacon-node/src/network/libp2p/index.ts @@ -1,8 +1,7 @@ -import {PeerId} from "@libp2p/interface"; +import {PrivateKey} from "@libp2p/interface"; import {Registry} from "prom-client"; import {ENR} from "@chainsafe/enr"; -// TODO: We should use this fork until https://github.com/libp2p/js-libp2p/pull/2387 -import {identify} from "@chainsafe/libp2p-identify"; +import {identify} from "@libp2p/identify"; import {bootstrap} from "@libp2p/bootstrap"; import {mdns} from "@libp2p/mdns"; import {createLibp2p} from "libp2p"; @@ -34,7 +33,7 @@ export async function getDiscv5Multiaddrs(bootEnrs: string[]): Promise } export async function createNodeJsLibp2p( - peerId: PeerId, + privateKey: PrivateKey, networkOpts: Partial = {}, nodeJsLibp2pOpts: NodeJsLibp2pOpts = {} ): Promise { @@ -65,12 +64,12 @@ export async function createNodeJsLibp2p( } return createLibp2p({ - peerId, + privateKey, addresses: { listen: localMultiaddrs, announce: [], }, - connectionEncryption: [noise()], + connectionEncrypters: [noise()], // Reject connections when the server's connection count gets high transports: [ tcp({ @@ -99,15 +98,14 @@ export async function createNodeJsLibp2p( maxParallelDials: 100, maxPeerAddrsToDial: 4, dialTimeout: 30_000, - - // Rely entirely on lodestar's peer manager to prune connections - //maxConnections: options.maxConnections, - // DOCS: There is no way to turn off autodial other than setting minConnections to 0 - minConnections: 0, // the maximum number of pending connections libp2p will accept before it starts rejecting incoming connections. // make it the same to backlog option above maxIncomingPendingConnections: 5, }, + // rely on lodestar's peer manager to ping peers + connectionMonitor: { + enabled: false, + }, datastore, services: { identify: identify({ @@ -118,6 +116,7 @@ export async function createNodeJsLibp2p( // and passing it here directly causes problems downstream, not to mention is slowwww components: (components: LodestarComponents) => ({ peerId: components.peerId, + privateKey: components.privateKey, nodeInfo: components.nodeInfo, logger: components.logger, events: components.events, diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 1b3ccaaaf75a..73208f497d66 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -1,6 +1,7 @@ -import {PeerId} from "@libp2p/interface"; +import {PeerId, PrivateKey} from "@libp2p/interface"; import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/score"; +import {peerIdFromPrivateKey} from "@libp2p/peer-id"; import {BeaconConfig} from "@lodestar/config"; import {sleep} from "@lodestar/utils"; import {LoggerNode} from "@lodestar/logger/node"; @@ -50,7 +51,7 @@ import {getActiveForks} from "./forks.js"; type NetworkModules = { opts: NetworkOptions; - peerId: PeerId; + privateKey: PrivateKey; config: BeaconConfig; logger: LoggerNode; chain: IBeaconChain; @@ -63,7 +64,7 @@ type NetworkModules = { export type NetworkInitModules = { opts: NetworkOptions; config: BeaconConfig; - peerId: PeerId; + privateKey: PrivateKey; peerStoreDir?: string; logger: LoggerNode; metrics: Metrics | null; @@ -104,7 +105,7 @@ export class Network implements INetwork { private regossipBlsChangesPromise: Promise | null = null; constructor(modules: NetworkModules) { - this.peerId = modules.peerId; + this.peerId = peerIdFromPrivateKey(modules.privateKey); this.config = modules.config; this.logger = modules.logger; this.chain = modules.chain; @@ -134,7 +135,7 @@ export class Network implements INetwork { chain, db, gossipHandlers, - peerId, + privateKey, peerStoreDir, getReqRespHandler, }: NetworkInitModules): Promise { @@ -159,7 +160,7 @@ export class Network implements INetwork { initialStatus, }, config, - peerId, + privateKey, logger, events, metrics, @@ -168,7 +169,7 @@ export class Network implements INetwork { : await NetworkCore.init({ opts, config, - peerId, + privateKey, peerStoreDir, logger, clock: chain.clock, @@ -185,11 +186,12 @@ export class Network implements INetwork { ); const multiaddresses = opts.localMultiaddrs?.join(","); + const peerId = peerIdFromPrivateKey(privateKey); logger.info(`PeerId ${peerIdToString(peerId)}, Multiaddrs ${multiaddresses}`); return new Network({ opts, - peerId, + privateKey, config, logger, chain, diff --git a/packages/beacon-node/src/network/peers/datastore.ts b/packages/beacon-node/src/network/peers/datastore.ts index 88a7a6f5f2d6..e0f2001c26ee 100644 --- a/packages/beacon-node/src/network/peers/datastore.ts +++ b/packages/beacon-node/src/network/peers/datastore.ts @@ -1,3 +1,4 @@ +import {AbortOptions} from "@libp2p/interface"; import {BaseDatastore} from "datastore-core"; import {LevelDatastore} from "datastore-level"; import {Key, KeyQuery, Query, Pair} from "interface-datastore"; @@ -57,7 +58,7 @@ export class Eth2PeerDataStore extends BaseDatastore { return this._dbDatastore.close(); } - async put(key: Key, val: Uint8Array): Promise { + async put(key: Key, val: Uint8Array, _options?: AbortOptions): Promise { return this._put(key, val, false); } diff --git a/packages/beacon-node/src/network/peers/discover.ts b/packages/beacon-node/src/network/peers/discover.ts index 9e06a39b4fb4..d3bfd2d2aab4 100644 --- a/packages/beacon-node/src/network/peers/discover.ts +++ b/packages/beacon-node/src/network/peers/discover.ts @@ -1,5 +1,5 @@ import {Multiaddr} from "@multiformats/multiaddr"; -import type {PeerId, PeerInfo} from "@libp2p/interface"; +import type {PeerId, PeerInfo, PrivateKey} from "@libp2p/interface"; import {ENR} from "@chainsafe/enr"; import {BeaconConfig} from "@lodestar/config"; import {pruneSetToMax, sleep} from "@lodestar/utils"; @@ -27,6 +27,7 @@ export type PeerDiscoveryOpts = { }; export type PeerDiscoveryModules = { + privateKey: PrivateKey; libp2p: Libp2p; peerRpcScores: IPeerRpcScoreStore; metrics: NetworkCoreMetrics | null; @@ -158,7 +159,7 @@ export class PeerDiscovery { static async init(modules: PeerDiscoveryModules, opts: PeerDiscoveryOpts): Promise { const discv5 = await Discv5Worker.init({ discv5: opts.discv5, - peerId: modules.libp2p.peerId, + privateKey: modules.privateKey, metrics: modules.metrics ?? undefined, logger: modules.logger, config: modules.config, @@ -323,8 +324,7 @@ export class PeerDiscovery { if (this.randomNodeQuery.code === QueryStatusCode.Active) { this.randomNodeQuery.count++; } - // async due to some crypto that's no longer necessary - const peerId = await enr.peerId(); + const peerId = enr.peerId; // tcp multiaddr is known to be be present, checked inside the worker const multiaddrTCP = enr.getLocationMultiaddr(ENRKey.tcp); if (!multiaddrTCP) { @@ -473,7 +473,7 @@ export class PeerDiscovery { /** Check if there is 1+ open connection with this peer */ private isPeerConnected(peerIdStr: PeerIdStr): boolean { const connections = getConnectionsMap(this.libp2p).get(peerIdStr); - return Boolean(connections && connections.some((connection) => connection.status === "open")); + return Boolean(connections && connections.value.some((connection) => connection.status === "open")); } } diff --git a/packages/beacon-node/src/network/peers/peerManager.ts b/packages/beacon-node/src/network/peers/peerManager.ts index 3971e2147707..7894b63e0be2 100644 --- a/packages/beacon-node/src/network/peers/peerManager.ts +++ b/packages/beacon-node/src/network/peers/peerManager.ts @@ -1,4 +1,4 @@ -import {Connection, PeerId} from "@libp2p/interface"; +import {Connection, PeerId, PrivateKey} from "@libp2p/interface"; import {BitArray} from "@chainsafe/ssz"; import {SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {BeaconConfig} from "@lodestar/config"; @@ -94,6 +94,7 @@ export interface IReqRespBeaconNodePeerManager { } export type PeerManagerModules = { + privateKey: PrivateKey; libp2p: Libp2p; logger: LoggerNode; metrics: NetworkCoreMetrics | null; @@ -685,7 +686,7 @@ export class PeerManager { } for (const connections of getConnectionsMap(this.libp2p).values()) { - const openCnx = connections.find((cnx) => cnx.status === "open"); + const openCnx = connections.value.find((cnx) => cnx.status === "open"); if (openCnx) { const direction = openCnx.direction; peersByDirection.set(direction, 1 + (peersByDirection.get(direction) ?? 0)); diff --git a/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts b/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts index 8542df605b06..d001c0d8892a 100644 --- a/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts +++ b/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts @@ -8,7 +8,7 @@ import {getConnectionsMap} from "../../util.js"; export function getConnectedPeerIds(libp2p: Libp2p): PeerId[] { const peerIds: PeerId[] = []; for (const connections of getConnectionsMap(libp2p).values()) { - const openConnection = connections.find(isConnectionOpen); + const openConnection = connections.value.find(isConnectionOpen); if (openConnection) { peerIds.push(openConnection.remotePeer); } @@ -21,7 +21,7 @@ export function getConnectedPeerIds(libp2p: Libp2p): PeerId[] { */ export function hasSomeConnectedPeer(libp2p: Libp2p): boolean { for (const connections of getConnectionsMap(libp2p).values()) { - if (connections.some(isConnectionOpen)) { + if (connections.value.some(isConnectionOpen)) { return true; } } diff --git a/packages/beacon-node/src/network/util.ts b/packages/beacon-node/src/network/util.ts index 835096afbfc8..2be4756fe693 100644 --- a/packages/beacon-node/src/network/util.ts +++ b/packages/beacon-node/src/network/util.ts @@ -14,12 +14,12 @@ export function prettyPrintPeerIdStr(id: PeerIdStr): string { * Get the connections map from a connection manager */ // Compat function for efficiency reasons -export function getConnectionsMap(libp2p: Libp2p): Map { +export function getConnectionsMap(libp2p: Libp2p): Map { return libp2p.services.components.connectionManager.getConnectionsMap()["map"]; } export function getConnection(libp2p: Libp2p, peerIdStr: string): Connection | undefined { - return getConnectionsMap(libp2p).get(peerIdStr)?.[0] ?? undefined; + return getConnectionsMap(libp2p).get(peerIdStr)?.value[0] ?? undefined; } // https://github.com/ChainSafe/js-libp2p-gossipsub/blob/3475242ed254f7647798ab7f36b21909f6cb61da/src/index.ts#L2009 diff --git a/packages/beacon-node/src/node/nodejs.ts b/packages/beacon-node/src/node/nodejs.ts index 088541a6b5d5..7b42f0daceb2 100644 --- a/packages/beacon-node/src/node/nodejs.ts +++ b/packages/beacon-node/src/node/nodejs.ts @@ -1,7 +1,7 @@ import {setMaxListeners} from "node:events"; import {Registry} from "prom-client"; -import {PeerId} from "@libp2p/interface"; +import {PrivateKey} from "@libp2p/interface"; import {BeaconConfig} from "@lodestar/config"; import {phase0} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; @@ -49,7 +49,7 @@ export type BeaconNodeInitModules = { db: IBeaconDb; logger: LoggerNode; processShutdownCallback: ProcessShutdownCallback; - peerId: PeerId; + privateKey: PrivateKey; peerStoreDir?: string; anchorState: BeaconStateAllForks; wsCheckpoint?: phase0.Checkpoint; @@ -146,7 +146,7 @@ export class BeaconNode { db, logger, processShutdownCallback, - peerId, + privateKey, peerStoreDir, anchorState, wsCheckpoint, @@ -243,7 +243,7 @@ export class BeaconNode { metrics, chain, db, - peerId, + privateKey, peerStoreDir, getReqRespHandler: getReqRespHandlers({db, chain}), }); diff --git a/packages/beacon-node/src/util/peerId.ts b/packages/beacon-node/src/util/peerId.ts index 2afb9bed390e..c62f5416cdfe 100644 --- a/packages/beacon-node/src/util/peerId.ts +++ b/packages/beacon-node/src/util/peerId.ts @@ -12,5 +12,5 @@ export type PeerIdStr = string; export {peerIdFromString}; export function peerIdToString(peerId: PeerId): string { - return base58btc.encode(peerId.multihash.bytes).slice(1); + return base58btc.encode(peerId.toMultihash().bytes).slice(1); } diff --git a/packages/beacon-node/test/e2e/network/mdns.test.ts b/packages/beacon-node/test/e2e/network/mdns.test.ts index 4c49ca319a42..5c796df985b9 100644 --- a/packages/beacon-node/test/e2e/network/mdns.test.ts +++ b/packages/beacon-node/test/e2e/network/mdns.test.ts @@ -1,8 +1,8 @@ import {describe, it, afterEach, beforeEach, expect, vi} from "vitest"; -import {PeerId} from "@libp2p/interface"; +import {PrivateKey} from "@libp2p/interface"; import {multiaddr} from "@multiformats/multiaddr"; -import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {SignableENR} from "@chainsafe/enr"; +import {generateKeyPair} from "@libp2p/crypto/keys"; import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; @@ -34,9 +34,9 @@ describe.skip("mdns", function () { }); afterEach(() => controller.abort()); - async function getOpts(peerId: PeerId): Promise { + async function getOpts(privateKey: PrivateKey): Promise { const bindAddrUdp = `/ip4/0.0.0.0/udp/${port++}`; - const enr = SignableENR.createFromPeerId(peerId); + const enr = SignableENR.createFromPrivateKey(privateKey); enr.setLocationMultiaddr(multiaddr(bindAddrUdp)); return { @@ -80,12 +80,12 @@ describe.skip("mdns", function () { const db = getMockedBeaconDb(); const gossipHandlers = {} as GossipHandlers; - const peerId = await createSecp256k1PeerId(); + const privateKey = await generateKeyPair("secp256k1"); const logger = testLogger(nodeName); - const opts = await getOpts(peerId); + const opts = await getOpts(privateKey); - const modules: Omit = { + const modules: Omit = { config, chain, db, @@ -96,7 +96,7 @@ describe.skip("mdns", function () { const network = await Network.init({ ...modules, - ...(await createNetworkModules(mu, peerId, {...opts, mdns: true})), + ...(await createNetworkModules(mu, privateKey, {...opts, mdns: true})), logger, }); diff --git a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts index b690b9ab4988..e872a3882945 100644 --- a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts +++ b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts @@ -1,7 +1,7 @@ import {describe, it, afterEach, expect, vi} from "vitest"; import {Connection} from "@libp2p/interface"; -import {CustomEvent} from "@libp2p/interface"; import {BitArray} from "@chainsafe/ssz"; +import {generateKeyPair} from "@libp2p/crypto/keys"; import {config} from "@lodestar/config/default"; import {altair, phase0, ssz} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; @@ -47,7 +47,8 @@ describe("network / peers / PeerManager", function () { const clock = new Clock({config: beaconConfig, genesisTime: 0, signal: controller.signal}); const status = ssz.phase0.Status.defaultValue(); const statusCache = new LocalStatusCache(status); - const libp2p = await createNode("/ip4/127.0.0.1/tcp/0"); + const privateKey = await generateKeyPair("secp256k1"); + const libp2p = await createNode("/ip4/127.0.0.1/tcp/0", privateKey); afterEachCallbacks.push(async () => { controller.abort(); @@ -68,6 +69,7 @@ describe("network / peers / PeerManager", function () { const peerManager = new PeerManager( { + privateKey, libp2p, reqResp, logger, @@ -158,7 +160,7 @@ describe("network / peers / PeerManager", function () { const {statusCache, libp2p, networkEventBus} = await mockModules(); // Simualate a peer connection, get() should return truthy - getConnectionsMap(libp2p).set(peerId1.toString(), [libp2pConnectionOutboud]); + getConnectionsMap(libp2p).set(peerId1.toString(), {key: peerId1, value: [libp2pConnectionOutboud]}); // Subscribe to `peerConnected` event, which must fire after checking peer relevance const peerConnectedPromise = waitForEvent(networkEventBus, NetworkEvent.peerConnected, 2000); @@ -177,7 +179,7 @@ describe("network / peers / PeerManager", function () { const {statusCache, libp2p, reqResp, peerManager, networkEventBus} = await mockModules(); // Simualate a peer connection, get() should return truthy - getConnectionsMap(libp2p).set(peerId1.toString(), [libp2pConnectionOutboud]); + getConnectionsMap(libp2p).set(peerId1.toString(), {key: peerId1, value: [libp2pConnectionOutboud]}); // Subscribe to `peerConnected` event, which must fire after checking peer relevance const peerConnectedPromise = waitForEvent(networkEventBus, NetworkEvent.peerConnected, 2000); @@ -190,7 +192,7 @@ describe("network / peers / PeerManager", function () { reqResp.sendMetadata.mockResolvedValue(remoteMetadata); // Simualate a peer connection, get() should return truthy - getConnectionsMap(libp2p).set(peerId1.toString(), [libp2pConnectionOutboud]); + getConnectionsMap(libp2p).set(peerId1.toString(), {key: peerId1, value: [libp2pConnectionOutboud]}); libp2p.services.components.events.dispatchEvent( new CustomEvent("connection:open", {detail: libp2pConnectionOutboud}) ); diff --git a/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts b/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts index d8d02c203dd9..123a4da420f0 100644 --- a/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts +++ b/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts @@ -40,7 +40,7 @@ describe("reqresp encoder", () => { const libp2p = await createLibp2p({ transports: [tcp()], streamMuxers: [mplex()], - connectionEncryption: [noise()], + connectionEncrypters: [noise()], addresses: { listen: [listen], }, diff --git a/packages/beacon-node/test/perf/network/noise/sendData.test.ts b/packages/beacon-node/test/perf/network/noise/sendData.test.ts index 35538a417adf..49e37980a598 100644 --- a/packages/beacon-node/test/perf/network/noise/sendData.test.ts +++ b/packages/beacon-node/test/perf/network/noise/sendData.test.ts @@ -1,11 +1,12 @@ import {itBench} from "@dapplion/benchmark"; import {duplexPair} from "it-pair/duplex"; -import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {pipe} from "it-pipe"; import drain from "it-drain"; import {defaultLogger} from "@libp2p/logger"; import {noise} from "@chainsafe/libp2p-noise"; import {Uint8ArrayList} from "uint8arraylist"; +import {generateKeyPair} from "@libp2p/crypto/keys"; +import {peerIdFromPrivateKey} from "@libp2p/peer-id"; describe("network / noise / sendData", () => { const numberOfMessages = 1000; @@ -24,15 +25,17 @@ describe("network / noise / sendData", () => { itBench({ id: `send data - ${numberOfMessages} ${messageLength}B messages`, beforeEach: async () => { - const peerA = await createSecp256k1PeerId(); - const peerB = await createSecp256k1PeerId(); - const noiseA = noise()({logger: defaultLogger()}); - const noiseB = noise()({logger: defaultLogger()}); + const privateKeyA = await generateKeyPair("secp256k1"); + const privateKeyB = await generateKeyPair("secp256k1"); + const peerA = peerIdFromPrivateKey(privateKeyA); + const peerB = peerIdFromPrivateKey(privateKeyB); + const noiseA = noise()({logger: defaultLogger(), privateKey: privateKeyA, peerId: peerA}); + const noiseB = noise()({logger: defaultLogger(), privateKey: privateKeyB, peerId: peerB}); const [inboundConnection, outboundConnection] = duplexPair(); const [outbound, inbound] = await Promise.all([ - noiseA.secureOutbound(peerA, outboundConnection, peerB), - noiseB.secureInbound(peerB, inboundConnection, peerA), + noiseA.secureOutbound(outboundConnection, {remotePeer: peerB}), + noiseB.secureInbound(inboundConnection, {remotePeer: peerA}), ]); return {connA: outbound.conn, connB: inbound.conn, data: new Uint8Array(messageLength)}; diff --git a/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts b/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts index a0d648a161ea..ecc30ebacef9 100644 --- a/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts +++ b/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts @@ -1,6 +1,7 @@ import {itBench} from "@dapplion/benchmark"; import {PeerId} from "@libp2p/interface"; -import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; +import {generateKeyPair} from "@libp2p/crypto/keys"; +import {peerIdFromPrivateKey} from "@libp2p/peer-id"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {altair, phase0} from "@lodestar/types"; import {defaultNetworkOptions} from "../../../../../src/network/options.js"; @@ -12,7 +13,8 @@ describe("prioritizePeers", () => { before(async function () { for (let i = 0; i < defaultNetworkOptions.maxPeers; i++) { - const peer = await createSecp256k1PeerId(); + const pk = await generateKeyPair("secp256k1"); + const peer = peerIdFromPrivateKey(pk); peer.toString = () => `peer-${i}`; seedPeers.push({ id: peer, diff --git a/packages/beacon-node/test/unit/network/peers/priorization.test.ts b/packages/beacon-node/test/unit/network/peers/priorization.test.ts index cc9ef9b7d711..5b318a9b007f 100644 --- a/packages/beacon-node/test/unit/network/peers/priorization.test.ts +++ b/packages/beacon-node/test/unit/network/peers/priorization.test.ts @@ -1,7 +1,8 @@ import {PeerId} from "@libp2p/interface"; -import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {BitArray} from "@chainsafe/ssz"; import {describe, it, expect} from "vitest"; +import {generateKeyPair} from "@libp2p/crypto/keys"; +import {peerIdFromPrivateKey} from "@libp2p/peer-id"; import {ATTESTATION_SUBNET_COUNT} from "@lodestar/params"; import { ExcessPeerDisconnectReason, @@ -17,7 +18,8 @@ type Result = ReturnType; describe("network / peers / priorization", async () => { const peers: PeerId[] = []; for (let i = 0; i < 8; i++) { - const peer = await createSecp256k1PeerId(); + const pk = await generateKeyPair("secp256k1"); + const peer = peerIdFromPrivateKey(pk); peer.toString = () => `peer-${i}`; peers.push(peer); } @@ -266,7 +268,8 @@ describe("network / peers / priorization", async () => { describe("sortPeersToPrune", async function () { const peers: PeerId[] = []; for (let i = 0; i < 8; i++) { - const peer = await createSecp256k1PeerId(); + const pk = await generateKeyPair("secp256k1"); + const peer = peerIdFromPrivateKey(pk); peer.toString = () => `peer-${i}`; peers.push(peer); } diff --git a/packages/beacon-node/test/utils/network.ts b/packages/beacon-node/test/utils/network.ts index 56c831b269f5..71bb0bd255da 100644 --- a/packages/beacon-node/test/utils/network.ts +++ b/packages/beacon-node/test/utils/network.ts @@ -1,6 +1,6 @@ import {BitArray} from "@chainsafe/ssz"; -import {PeerId} from "@libp2p/interface"; -import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; +import {PrivateKey} from "@libp2p/interface"; +import {generateKeyPair} from "@libp2p/crypto/keys"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {INetwork, Network, NetworkEvent} from "../../src/network/index.js"; import {Libp2p} from "../../src/network/interface.js"; @@ -8,18 +8,17 @@ import {createNodeJsLibp2p} from "../../src/network/libp2p/index.js"; import {NetworkOptions, defaultNetworkOptions} from "../../src/network/options.js"; import {PeerIdStr} from "../../src/util/peerId.js"; -export async function createNode(multiaddr: string, inPeerId?: PeerId): Promise { - const peerId = inPeerId || (await createSecp256k1PeerId()); - return createNodeJsLibp2p(peerId, {localMultiaddrs: [multiaddr]}); +export async function createNode(multiaddr: string, privateKey?: PrivateKey): Promise { + return createNodeJsLibp2p(privateKey ?? (await generateKeyPair("secp256k1")), {localMultiaddrs: [multiaddr]}); } export async function createNetworkModules( multiaddr: string, - peerId?: PeerId, + privateKey?: PrivateKey, opts?: Partial -): Promise<{opts: NetworkOptions; peerId: PeerId}> { +): Promise<{opts: NetworkOptions; privateKey: PrivateKey}> { return { - peerId: peerId ?? (await createSecp256k1PeerId()), + privateKey: privateKey ?? (await generateKeyPair("secp256k1")), opts: {...defaultNetworkOptions, ...opts, localMultiaddrs: [multiaddr]}, }; } diff --git a/packages/beacon-node/test/utils/networkWithMockDb.ts b/packages/beacon-node/test/utils/networkWithMockDb.ts index f8a4a6181d2f..b1c4293588d2 100644 --- a/packages/beacon-node/test/utils/networkWithMockDb.ts +++ b/packages/beacon-node/test/utils/networkWithMockDb.ts @@ -1,4 +1,4 @@ -import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; +import {generateKeyPair} from "@libp2p/crypto/keys"; import {ChainForkConfig, createBeaconConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; import {BeaconChain} from "../../src/chain/chain.js"; @@ -70,7 +70,7 @@ export async function getNetworkForTest( } ); - const modules: Omit = { + const modules: Omit = { config: beaconConfig, chain, db, @@ -81,7 +81,7 @@ export async function getNetworkForTest( const network = await Network.init({ ...modules, - peerId: await createSecp256k1PeerId(), + privateKey: await generateKeyPair("secp256k1"), opts: { ...defaultNetworkOptions, maxPeers: 1, diff --git a/packages/beacon-node/test/utils/node/beacon.ts b/packages/beacon-node/test/utils/node/beacon.ts index 0163fa148102..746c2cde5fd4 100644 --- a/packages/beacon-node/test/utils/node/beacon.ts +++ b/packages/beacon-node/test/utils/node/beacon.ts @@ -1,7 +1,7 @@ import deepmerge from "deepmerge"; import tmp from "tmp"; -import {PeerId} from "@libp2p/interface"; -import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; +import {PrivateKey} from "@libp2p/interface"; +import {generateKeyPair} from "@libp2p/crypto/keys"; import {config as minimalConfig} from "@lodestar/config/default"; import {createBeaconConfig, createChainForkConfig, ChainConfig} from "@lodestar/config"; import {RecursivePartial} from "@lodestar/utils"; @@ -26,16 +26,16 @@ export async function getDevBeaconNode( options?: RecursivePartial; validatorCount?: number; logger?: LoggerNode; - peerId?: PeerId; + privateKey?: PrivateKey; peerStoreDir?: string; anchorState?: BeaconStateAllForks; wsCheckpoint?: phase0.Checkpoint; } & InteropStateOpts ): Promise { const {params, validatorCount = 8, peerStoreDir} = opts; - let {options = {}, logger, peerId} = opts; + let {options = {}, logger, privateKey} = opts; - if (!peerId) peerId = await createSecp256k1PeerId(); + if (!privateKey) privateKey = await generateKeyPair("secp256k1"); const tmpDir = tmp.dirSync({unsafeCleanup: true}); const config = createChainForkConfig({...minimalConfig, ...params}); logger = logger ?? testLogger(); @@ -93,7 +93,7 @@ export async function getDevBeaconNode( db, logger, processShutdownCallback: () => {}, - peerId, + privateKey, peerStoreDir, anchorState, wsCheckpoint: opts.wsCheckpoint, diff --git a/packages/beacon-node/test/utils/peer.ts b/packages/beacon-node/test/utils/peer.ts index 8bd5c6c67be8..aeec92bf994e 100644 --- a/packages/beacon-node/test/utils/peer.ts +++ b/packages/beacon-node/test/utils/peer.ts @@ -1,6 +1,6 @@ import {PeerId} from "@libp2p/interface"; -import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; -import {peerIdFromBytes} from "@libp2p/peer-id"; +import {peerIdFromPrivateKey, peerIdFromPublicKey} from "@libp2p/peer-id"; +import {generateKeyPair, publicKeyFromProtobuf} from "@libp2p/crypto/keys"; import {peerIdToString} from "../../src/util/peerId.js"; /** @@ -9,11 +9,11 @@ import {peerIdToString} from "../../src/util/peerId.js"; */ export function getValidPeerId(): PeerId { const id = Buffer.from("002508021221039481269fe831799b1a0f1d521c1395b4831514859e4559c44d155eae46f03819", "hex"); - return peerIdFromBytes(id); + return peerIdFromPublicKey(publicKeyFromProtobuf(id)); } export async function getRandPeerIdStr(): Promise { - return peerIdToString(await createSecp256k1PeerId()); + return peerIdToString(peerIdFromPrivateKey(await generateKeyPair("secp256k1"))); } export const validPeerIdStr = peerIdToString(getValidPeerId()); diff --git a/packages/cli/package.json b/packages/cli/package.json index b4fc206e5a44..67d0dfd332cc 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -54,14 +54,14 @@ "@chainsafe/bls-keygen": "^0.4.0", "@chainsafe/bls-keystore": "^3.1.0", "@chainsafe/blst": "^2.0.3", - "@chainsafe/discv5": "^9.0.0", - "@chainsafe/enr": "^3.0.0", + "@chainsafe/discv5": "^10.0.1", + "@chainsafe/enr": "^4.0.1", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/ssz": "^0.17.1", "@chainsafe/threads": "^1.11.1", - "@libp2p/crypto": "^4.1.0", - "@libp2p/peer-id": "^4.1.0", - "@libp2p/peer-id-factory": "^4.1.0", + "@libp2p/crypto": "^5.0.4", + "@libp2p/interface": "^2.1.2", + "@libp2p/peer-id": "^5.0.4", "@lodestar/api": "^1.22.0", "@lodestar/beacon-node": "^1.22.0", "@lodestar/config": "^1.22.0", diff --git a/packages/cli/src/cmds/beacon/handler.ts b/packages/cli/src/cmds/beacon/handler.ts index ea424e04824a..2a0238fede20 100644 --- a/packages/cli/src/cmds/beacon/handler.ts +++ b/packages/cli/src/cmds/beacon/handler.ts @@ -24,7 +24,7 @@ import {LogArgs} from "../../options/logOptions.js"; import {BeaconArgs} from "./options.js"; import {getBeaconPaths} from "./paths.js"; import {initBeaconState} from "./initBeaconState.js"; -import {initPeerIdAndEnr} from "./initPeerIdAndEnr.js"; +import {initPrivateKeyAndEnr} from "./initPeerIdAndEnr.js"; const DEFAULT_RETENTION_SSZ_OBJECTS_HOURS = 15 * 24; const HOURS_TO_MS = 3600 * 1000; @@ -34,7 +34,7 @@ const EIGHT_GB = 8 * 1024 * 1024 * 1024; * Runs a beacon node. */ export async function beaconHandler(args: BeaconArgs & GlobalArgs): Promise { - const {config, options, beaconPaths, network, version, commit, peerId, logger} = await beaconHandlerInit(args); + const {config, options, beaconPaths, network, version, commit, privateKey, logger} = await beaconHandlerInit(args); const heapSizeLimit = getHeapStatistics().heap_size_limit; if (heapSizeLimit < EIGHT_GB) { @@ -80,7 +80,7 @@ export async function beaconHandler(args: BeaconArgs & GlobalArgs): Promise { +): Promise<{privateKey: PrivateKey; enr: SignableENR}> { const {persistNetworkIdentity} = args; - const newPeerIdAndENR = async (): Promise<{peerId: PeerId; enr: SignableENR}> => { - const peerId = await createSecp256k1PeerId(); - const enr = SignableENR.createV4(createPrivateKeyFromPeerId(peerId).privateKey); - return {peerId, enr}; + const newPrivateKeyAndENR = async (): Promise<{privateKey: PrivateKey; enr: SignableENR}> => { + const privateKey = await generateKeyPair("secp256k1"); + const enr = SignableENR.createFromPrivateKey(privateKey); + return {privateKey, enr}; }; - const readPersistedPeerIdAndENR = async ( + const readPersistedPrivateKeyAndENR = async ( peerIdFile: string, enrFile: string - ): Promise<{peerId: PeerId; enr: SignableENR; newEnr: boolean}> => { - let peerId: PeerId; + ): Promise<{privateKey: PrivateKey; enr: SignableENR; newEnr: boolean}> => { + let privateKey: PrivateKey; let enr: SignableENR; // attempt to read stored peer id try { - peerId = await readPeerId(peerIdFile); + privateKey = readPrivateKey(peerIdFile); } catch (_e) { logger.warn("Unable to read peerIdFile, creating a new peer id"); - return {...(await newPeerIdAndENR()), newEnr: true}; + return {...(await newPrivateKeyAndENR()), newEnr: true}; } // attempt to read stored enr try { - enr = SignableENR.decodeTxt(fs.readFileSync(enrFile, "utf-8"), createPrivateKeyFromPeerId(peerId).privateKey); + enr = SignableENR.decodeTxt(fs.readFileSync(enrFile, "utf-8"), privateKey.raw); } catch (_e) { logger.warn("Unable to decode stored local ENR, creating a new ENR"); - enr = SignableENR.createV4(createPrivateKeyFromPeerId(peerId).privateKey); - return {peerId, enr, newEnr: true}; + enr = SignableENR.createFromPrivateKey(privateKey); + return {privateKey, enr, newEnr: true}; } // check stored peer id against stored enr - if (!peerId.equals(await enr.peerId())) { + if (!privateKey.equals(enr.peerId)) { logger.warn("Stored local ENR doesn't match peerIdFile, creating a new ENR"); - enr = SignableENR.createV4(createPrivateKeyFromPeerId(peerId).privateKey); - return {peerId, enr, newEnr: true}; + enr = SignableENR.createFromPrivateKey(privateKey); + return {privateKey, enr, newEnr: true}; } - return {peerId, enr, newEnr: false}; + return {privateKey, enr, newEnr: false}; }; if (persistNetworkIdentity) { const enrFile = path.join(beaconDir, "enr"); const peerIdFile = path.join(beaconDir, "peer-id.json"); - const {peerId, enr, newEnr} = await readPersistedPeerIdAndENR(peerIdFile, enrFile); + const {privateKey, enr, newEnr} = await readPersistedPrivateKeyAndENR(peerIdFile, enrFile); overwriteEnrWithCliArgs(enr, args, logger, {newEnr, bootnode}); // Re-persist peer-id and enr - writeFile600Perm(peerIdFile, exportToJSON(peerId)); + writeFile600Perm(peerIdFile, exportToJSON(privateKey)); writeFile600Perm(enrFile, enr.encodeTxt()); - return {peerId, enr}; + return {privateKey, enr}; } else { - const {peerId, enr} = await newPeerIdAndENR(); + const {privateKey, enr} = await newPrivateKeyAndENR(); overwriteEnrWithCliArgs(enr, args, logger, {newEnr: true, bootnode}); - return {peerId, enr}; + return {privateKey, enr}; } } diff --git a/packages/cli/src/cmds/bootnode/handler.ts b/packages/cli/src/cmds/bootnode/handler.ts index 8a262d8f12b7..9c093eed1272 100644 --- a/packages/cli/src/cmds/bootnode/handler.ts +++ b/packages/cli/src/cmds/bootnode/handler.ts @@ -10,7 +10,7 @@ import {getBeaconConfigFromArgs} from "../../config/index.js"; import {getNetworkBootnodes, isKnownNetworkName, readBootnodes} from "../../networks/index.js"; import {onGracefulShutdown, mkdir, writeFile600Perm} from "../../util/index.js"; import {getVersionData} from "../../util/version.js"; -import {initPeerIdAndEnr} from "../beacon/initPeerIdAndEnr.js"; +import {initPrivateKeyAndEnr} from "../beacon/initPeerIdAndEnr.js"; import {parseArgs as parseMetricsArgs} from "../../options/beaconNodeOptions/metrics.js"; import {parseArgs as parseNetworkArgs} from "../../options/beaconNodeOptions/network.js"; import {getBeaconPaths} from "../beacon/paths.js"; @@ -22,7 +22,7 @@ import {BootnodeArgs} from "./options.js"; * Runs a bootnode. */ export async function bootnodeHandler(args: BootnodeArgs & GlobalArgs): Promise { - const {discv5Args, metricsArgs, bootnodeDir, network, version, commit, peerId, enr, logger} = + const {discv5Args, metricsArgs, bootnodeDir, network, version, commit, privateKey, enr, logger} = await bootnodeHandlerInit(args); const abortController = new AbortController(); @@ -34,7 +34,7 @@ export async function bootnodeHandler(args: BootnodeArgs & GlobalArgs): Promise< ip4: enr.getLocationMultiaddr("udp4")?.toString(), ip6: enr.getLocationMultiaddr("udp6")?.toString(), }); - logger.info("Identity", {peerId: peerId.toString(), nodeId: enr.nodeId}); + logger.info("Identity", {peerId: enr.peerId.toString(), nodeId: enr.nodeId}); logger.info("ENR", {enr: enr.encodeTxt()}); // bootnode setup @@ -53,7 +53,7 @@ export async function bootnodeHandler(args: BootnodeArgs & GlobalArgs): Promise< const discv5 = Discv5.create({ enr, - peerId, + privateKey, bindAddrs: { ip4: (bindAddrs.ip4 ? multiaddr(bindAddrs.ip4) : undefined) as Multiaddr, ip6: bindAddrs.ip6 ? multiaddr(bindAddrs.ip6) : undefined, @@ -68,7 +68,7 @@ export async function bootnodeHandler(args: BootnodeArgs & GlobalArgs): Promise< logger.info("Adding bootnode", { ip4: bootEnr.getLocationMultiaddr("udp4")?.toString(), ip6: bootEnr.getLocationMultiaddr("udp6")?.toString(), - peerId: (await bootEnr.peerId()).toString(), + peerId: bootEnr.peerId.toString(), nodeId: enr.nodeId, }); discv5.addEnr(bootEnr); @@ -180,7 +180,7 @@ export async function bootnodeHandlerInit(args: BootnodeArgs & GlobalArgs) { ); const logger = initLogger(args, beaconPaths.dataDir, config, "bootnode.log"); - const {peerId, enr} = await initPeerIdAndEnr(args as unknown as BeaconArgs, bootnodeDir, logger, true); + const {privateKey, enr} = await initPrivateKeyAndEnr(args as unknown as BeaconArgs, bootnodeDir, logger, true); - return {discv5Args, metricsArgs, bootnodeDir, network, version, commit, peerId, enr, logger}; + return {discv5Args, metricsArgs, bootnodeDir, network, version, commit, privateKey, enr, logger}; } diff --git a/packages/cli/src/config/peerId.ts b/packages/cli/src/config/peerId.ts index d4906c716ba7..91390696c2f4 100644 --- a/packages/cli/src/config/peerId.ts +++ b/packages/cli/src/config/peerId.ts @@ -1,7 +1,11 @@ -import type {PeerId} from "@libp2p/interface"; -import {peerIdFromBytes} from "@libp2p/peer-id"; -import {createFromPrivKey, createFromPubKey} from "@libp2p/peer-id-factory"; -import {unmarshalPrivateKey, unmarshalPublicKey} from "@libp2p/crypto/keys"; +import type {PrivateKey} from "@libp2p/interface"; +import {peerIdFromPrivateKey, peerIdFromString} from "@libp2p/peer-id"; +import { + privateKeyFromProtobuf, + privateKeyToProtobuf, + publicKeyFromProtobuf, + publicKeyToProtobuf, +} from "@libp2p/crypto/keys"; import {fromString as uint8ArrayFromString} from "uint8arrays/from-string"; import {toString as uint8ArrayToString} from "uint8arrays/to-string"; import {writeFile600Perm, readFile} from "../util/index.js"; @@ -9,45 +13,38 @@ import {writeFile600Perm, readFile} from "../util/index.js"; // Peer id to / from JSON taken from peer-id-factory // See https://github.com/libp2p/js-libp2p-peer-id/pull/9 for more details -async function createFromParts(multihash: Uint8Array, privKey?: Uint8Array, pubKey?: Uint8Array): Promise { - if (privKey != null) { - const key = await unmarshalPrivateKey(privKey); +// after libp2p 2.0, PeerId no longer contains a private key +// but we retain a semi-backwards-compatible on-disk format +// Note: all properties are required +export type PeerIdJSON = {id: string; pubKey: string; privKey: string}; - return createFromPrivKey(key); - } else if (pubKey != null) { - const key = unmarshalPublicKey(pubKey); - - return createFromPubKey(key); - } - - return peerIdFromBytes(multihash); -} - -export type PeerIdJSON = {id: string; pubKey?: string; privKey?: string}; - -export function exportToJSON(peerId: PeerId, excludePrivateKey?: boolean): PeerIdJSON { +export function exportToJSON(privateKey: PrivateKey): PeerIdJSON { + const publicKey = privateKey.publicKey; + const peerId = peerIdFromPrivateKey(privateKey); return { - id: uint8ArrayToString(peerId.toBytes(), "base58btc"), - pubKey: peerId.publicKey != null ? uint8ArrayToString(peerId.publicKey, "base64pad") : undefined, - privKey: - excludePrivateKey === true || peerId.privateKey == null - ? undefined - : uint8ArrayToString(peerId.privateKey, "base64pad"), + id: peerId.toString(), + pubKey: uint8ArrayToString(publicKeyToProtobuf(publicKey), "base64pad"), + privKey: uint8ArrayToString(privateKeyToProtobuf(privateKey), "base64pad"), }; } -export async function createFromJSON(obj: PeerIdJSON): Promise { - return createFromParts( - uint8ArrayFromString(obj.id, "base58btc"), - obj.privKey != null ? uint8ArrayFromString(obj.privKey, "base64pad") : undefined, - obj.pubKey != null ? uint8ArrayFromString(obj.pubKey, "base64pad") : undefined - ); +export function createFromJSON(obj: PeerIdJSON): PrivateKey { + const privateKey = privateKeyFromProtobuf(uint8ArrayFromString(obj.privKey, "base64pad")); + const publicKey = publicKeyFromProtobuf(uint8ArrayFromString(obj.pubKey, "base64pad")); + const peerId = peerIdFromString(obj.id); + if (!publicKey.equals(privateKey.publicKey)) { + throw new Error("Public key does not match private key"); + } + if (!peerId.equals(peerIdFromPrivateKey(privateKey))) { + throw new Error("Peer ID does not match private key"); + } + return privateKey; } -export function writePeerId(filepath: string, peerId: PeerId): void { - writeFile600Perm(filepath, exportToJSON(peerId)); +export function writePrivateKey(filepath: string, privateKey: PrivateKey): void { + writeFile600Perm(filepath, exportToJSON(privateKey)); } -export async function readPeerId(filepath: string): Promise { +export function readPrivateKey(filepath: string): PrivateKey { return createFromJSON(readFile(filepath)); } diff --git a/packages/cli/test/unit/cmds/beacon.test.ts b/packages/cli/test/unit/cmds/beacon.test.ts index 6e7b7f389a29..74cde026b1ad 100644 --- a/packages/cli/test/unit/cmds/beacon.test.ts +++ b/packages/cli/test/unit/cmds/beacon.test.ts @@ -1,15 +1,16 @@ import path from "node:path"; import fs from "node:fs"; import {describe, it, expect} from "vitest"; -import {createFromJSON, createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {multiaddr} from "@multiformats/multiaddr"; -import {createPrivateKeyFromPeerId, ENR, SignableENR} from "@chainsafe/enr"; +import {ENR, SignableENR} from "@chainsafe/enr"; +import {generateKeyPair} from "@libp2p/crypto/keys"; +import {peerIdFromPrivateKey} from "@libp2p/peer-id"; import {chainConfig} from "@lodestar/config/default"; import {chainConfigToJson} from "@lodestar/config"; import {LogLevel} from "@lodestar/utils"; -import {exportToJSON} from "../../../src/config/peerId.js"; +import {createFromJSON, exportToJSON} from "../../../src/config/peerId.js"; import {beaconHandlerInit} from "../../../src/cmds/beacon/handler.js"; -import {initPeerIdAndEnr, isLocalMultiAddr} from "../../../src/cmds/beacon/initPeerIdAndEnr.js"; +import {initPrivateKeyAndEnr, isLocalMultiAddr} from "../../../src/cmds/beacon/initPeerIdAndEnr.js"; import {BeaconArgs} from "../../../src/cmds/beacon/options.js"; import {GlobalArgs} from "../../../src/options/globalOptions.js"; import {testFilesDir, testLogger} from "../../utils.js"; @@ -55,26 +56,26 @@ describe("cmds / beacon / args handler", () => { }); it("Create different PeerId every run", async () => { - const {peerId: peerId1} = await runBeaconHandlerInit({}); - const {peerId: peerId2} = await runBeaconHandlerInit({}); + const {privateKey: pk1} = await runBeaconHandlerInit({}); + const {privateKey: pk2} = await runBeaconHandlerInit({}); - expect(peerId1.toString()).not.toBe(peerId2.toString()); + expect(pk1.equals(pk2)).toBe(false); }); it("Re-use existing peer", async () => { - const prevPeerId = await createSecp256k1PeerId(); + const prevPk = await generateKeyPair("secp256k1"); const peerIdFile = path.join(testFilesDir, "peer-id.json"); - fs.writeFileSync(peerIdFile, JSON.stringify(exportToJSON(prevPeerId))); - const enr = SignableENR.createV4(createPrivateKeyFromPeerId(prevPeerId).privateKey); + fs.writeFileSync(peerIdFile, JSON.stringify(exportToJSON(prevPk))); + const enr = SignableENR.createFromPrivateKey(prevPk); const enrFilePath = path.join(testFilesDir, "enr"); fs.writeFileSync(enrFilePath, enr.encodeTxt()); - const {peerId} = await runBeaconHandlerInit({ + const {privateKey} = await runBeaconHandlerInit({ persistNetworkIdentity: true, }); - expect(peerId.toString()).toBe(prevPeerId.toString()); + expect(privateKey.equals(prevPk)).toBe(true); }); it("Set known deposit contract", async () => { @@ -117,48 +118,48 @@ describe("Test isLocalMultiAddr", () => { describe("initPeerIdAndEnr", () => { it("should not reuse peer id, persistNetworkIdentity=false", async () => { - const {peerId: peerId1} = await initPeerIdAndEnr( + const {privateKey: pk1} = await initPrivateKeyAndEnr( {persistNetworkIdentity: false} as BeaconArgs, testFilesDir, testLogger() ); - const {peerId: peerId2} = await initPeerIdAndEnr( + const {privateKey: pk2} = await initPrivateKeyAndEnr( {persistNetworkIdentity: false} as BeaconArgs, testFilesDir, testLogger() ); - expect(peerId1.toString()).not.toBe(peerId2.toString()); + expect(pk1.equals(pk2)).toBe(false); }); it("should reuse peer id, persistNetworkIdentity=true", async () => { - const {peerId: peerId1} = await initPeerIdAndEnr( + const {privateKey: pk1} = await initPrivateKeyAndEnr( {persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger() ); - const {peerId: peerId2} = await initPeerIdAndEnr( + const {privateKey: pk2} = await initPrivateKeyAndEnr( {persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger() ); - expect(peerId1.toString()).toBe(peerId2.toString()); + expect(pk1.equals(pk2)).toBe(true); }); it("should overwrite invalid peer id", async () => { const peerIdFile = path.join(testFilesDir, "peer-id.json"); - const peerId1Str = "wrong peer id file content"; - fs.writeFileSync(peerIdFile, peerId1Str); - const {peerId: peerId2} = await initPeerIdAndEnr( + const pk1Str = "wrong peer id file content"; + fs.writeFileSync(peerIdFile, pk1Str); + const {privateKey: pk2} = await initPrivateKeyAndEnr( {persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger() ); - const filePeerId = await createFromJSON(JSON.parse(fs.readFileSync(peerIdFile, "utf-8"))); + const filePk = createFromJSON(JSON.parse(fs.readFileSync(peerIdFile, "utf-8"))); - expect(peerId1Str).not.toBe(peerId2.toString()); - expect(filePeerId.toString()).toBe(peerId2.toString()); + expect(pk1Str).not.toBe(peerIdFromPrivateKey(pk2).toString()); + expect(filePk.equals(pk2)).toBe(true); }); it("should overwrite invalid enr", async () => { @@ -166,7 +167,7 @@ describe("initPeerIdAndEnr", () => { const invalidEnr = "wrong enr file content"; fs.writeFileSync(enrFilePath, invalidEnr); - await initPeerIdAndEnr({persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger()); + await initPrivateKeyAndEnr({persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger()); const validEnr = fs.readFileSync(enrFilePath, "utf-8"); @@ -174,13 +175,13 @@ describe("initPeerIdAndEnr", () => { }); it("should overwrite enr that doesn't match peer id", async () => { - const otherPeerId = await createSecp256k1PeerId(); - const otherEnr = SignableENR.createFromPeerId(otherPeerId); + const otherPk = await generateKeyPair("secp256k1"); + const otherEnr = SignableENR.createFromPrivateKey(otherPk); const enrFilePath = path.join(testFilesDir, "enr"); const otherEnrStr = otherEnr.encodeTxt(); fs.writeFileSync(enrFilePath, otherEnrStr); - const {enr} = await initPeerIdAndEnr({persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger()); + const {enr} = await initPrivateKeyAndEnr({persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger()); expect(enr.nodeId).not.toBe(otherEnr); }); diff --git a/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts b/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts index a207e0c0f59d..3dd9b48c298d 100644 --- a/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts +++ b/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts @@ -1,7 +1,8 @@ import fs from "node:fs"; import {describe, it, expect, beforeEach, afterEach} from "vitest"; import tmp from "tmp"; -import {initPeerIdAndEnr} from "../../../src/cmds/beacon/initPeerIdAndEnr.js"; +import {peerIdFromPrivateKey} from "@libp2p/peer-id"; +import {initPrivateKeyAndEnr} from "../../../src/cmds/beacon/initPeerIdAndEnr.js"; import {BeaconArgs} from "../../../src/cmds/beacon/options.js"; import {testLogger} from "../../utils.js"; @@ -17,35 +18,35 @@ describe("initPeerIdAndEnr", () => { }); it("first time should create a new enr and peer id", async () => { - const {enr, peerId} = await initPeerIdAndEnr( + const {enr, privateKey} = await initPrivateKeyAndEnr( {persistNetworkIdentity: true} as unknown as BeaconArgs, tmpDir.name, testLogger(), true ); // "enr peer id doesn't equal the returned peer id" - expect((await enr.peerId()).toString()).toBe(peerId.toString()); + expect(enr.peerId.toString()).toBe(peerIdFromPrivateKey(privateKey).toString()); expect(enr.seq).toBe(BigInt(1)); expect(enr.tcp).toBeUndefined(); expect(enr.tcp6).toBeUndefined(); }); it("second time should use ths existing enr and peer id", async () => { - const run1 = await initPeerIdAndEnr( + const run1 = await initPrivateKeyAndEnr( {persistNetworkIdentity: true} as unknown as BeaconArgs, tmpDir.name, testLogger(), true ); - const run2 = await initPeerIdAndEnr( + const run2 = await initPrivateKeyAndEnr( {persistNetworkIdentity: true} as unknown as BeaconArgs, tmpDir.name, testLogger(), true ); - expect(run1.peerId.toString()).toBe(run2.peerId.toString()); + expect(run1.privateKey.equals(run2.privateKey)).toBe(true); expect(run1.enr.encodeTxt()).toBe(run2.enr.encodeTxt()); }); }); diff --git a/packages/cli/test/unit/config/peerId.test.ts b/packages/cli/test/unit/config/peerId.test.ts index c0cdc8cff1a9..120a5e931749 100644 --- a/packages/cli/test/unit/config/peerId.test.ts +++ b/packages/cli/test/unit/config/peerId.test.ts @@ -1,16 +1,16 @@ import {describe, it, expect} from "vitest"; -import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; +import {generateKeyPair} from "@libp2p/crypto/keys"; import {getTestdirPath} from "../../utils.js"; -import {writePeerId, readPeerId} from "../../../src/config/index.js"; +import {writePrivateKey, readPrivateKey} from "../../../src/config/index.js"; describe("config / peerId", () => { const peerIdFilepath = getTestdirPath("./test-peer-id.json"); it("create, write and read PeerId", async () => { - const peerId = await createSecp256k1PeerId(); - writePeerId(peerIdFilepath, peerId); - const peerIdRead = await readPeerId(peerIdFilepath); + const privateKey = await generateKeyPair("secp256k1"); + writePrivateKey(peerIdFilepath, privateKey); + const pkRead = readPrivateKey(peerIdFilepath); - expect(peerIdRead.toString()).toBe(peerId.toString()); + expect(pkRead.toString()).toBe(privateKey.toString()); }); }); diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index 9bd9775ba2c0..d6d4fbd2b5c2 100644 --- a/packages/reqresp/package.json +++ b/packages/reqresp/package.json @@ -53,7 +53,7 @@ }, "dependencies": { "@chainsafe/fast-crc32c": "^4.1.1", - "@libp2p/interface": "^1.3.0", + "@libp2p/interface": "^2.1.2", "@lodestar/config": "^1.22.0", "@lodestar/params": "^1.22.0", "@lodestar/utils": "^1.22.0", @@ -67,10 +67,10 @@ "devDependencies": { "@lodestar/logger": "^1.22.0", "@lodestar/types": "^1.22.0", - "libp2p": "1.4.3" + "libp2p": "2.1.7" }, "peerDependencies": { - "libp2p": "~1.4.3" + "libp2p": "~2.1.7" }, "keywords": [ "ethereum", diff --git a/packages/reqresp/test/utils/peer.ts b/packages/reqresp/test/utils/peer.ts index 43edaefbafdd..cbc21eca370f 100644 --- a/packages/reqresp/test/utils/peer.ts +++ b/packages/reqresp/test/utils/peer.ts @@ -1,5 +1,6 @@ import {PeerId} from "@libp2p/interface"; -import {peerIdFromBytes} from "@libp2p/peer-id"; +import {peerIdFromPublicKey} from "@libp2p/peer-id"; +import {publicKeyFromProtobuf} from "@libp2p/crypto/keys"; /** * Returns a valid PeerId with opts `bits: 256, keyType: "secp256k1"` @@ -7,5 +8,5 @@ import {peerIdFromBytes} from "@libp2p/peer-id"; */ export function getValidPeerId(): PeerId { const id = Buffer.from("002508021221039481269fe831799b1a0f1d521c1395b4831514859e4559c44d155eae46f03819", "hex"); - return peerIdFromBytes(id); + return peerIdFromPublicKey(publicKeyFromProtobuf(id)); } diff --git a/yarn.lock b/yarn.lock index 3907e9f4e441..32c923a514e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -456,14 +456,14 @@ "@chainsafe/blst-linux-x64-musl" "2.0.3" "@chainsafe/blst-win32-x64-msvc" "2.0.3" -"@chainsafe/discv5@^9.0.0": - version "9.0.0" - resolved "https://registry.yarnpkg.com/@chainsafe/discv5/-/discv5-9.0.0.tgz#05d4d9d671894b41f0fafa8f32c48ae3ed761bd1" - integrity sha512-7s23ziqsHG/KRgkX79qB/w8kuqPrY8aJaF2aRDy9cScJocJ6ZaOnXhEc8Ku1AcSyrvfGp+tY8R4rDABcxRY+Wg== +"@chainsafe/discv5@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@chainsafe/discv5/-/discv5-10.0.1.tgz#1aefe3826b19b1f66e76c737a7a49ae7c77d7664" + integrity sha512-YpvqOMOn/sQMHU97lonvRnbtLZQW1Vqjcwtofd0hOJ6ohtxn+Ne7Cos8qCOFkhRHirGG6irHej4akh/BlBscSA== dependencies: - "@chainsafe/enr" "^3.0.0" - "@libp2p/crypto" "^4.0.1" - "@libp2p/interface" "^1.1.1" + "@chainsafe/enr" "^4.0.1" + "@libp2p/crypto" "^5.0.1" + "@libp2p/interface" "^2.0.1" "@multiformats/multiaddr" "^12.1.10" bcrypto "^5.4.0" bigint-buffer "^1.1.5" @@ -472,17 +472,17 @@ rlp "^2.2.6" strict-event-emitter-types "^2.0.0" -"@chainsafe/enr@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@chainsafe/enr/-/enr-3.0.0.tgz#71c83d4381d703bbcd19245ce733eb7c779a30ed" - integrity sha512-D8M8sqnvOim0jWlTdr2IhLyVe0GSUgpk+QO6UaLY4pQVdW1myJP8REp7xdbv1193ULVEkJQFTJAZexTOtmu3jw== +"@chainsafe/enr@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@chainsafe/enr/-/enr-4.0.1.tgz#9c9ad8cd84aedc1242d7e7ac99d670c0f8ee3c0d" + integrity sha512-eYGZC6Wq9UNtD5AZLO21w9DctRkEAhMZ/kIa+eggT5lVRcVSI06O7PmSXOSRW6z+Td/9MQKGEDtuyYa1esWlSg== dependencies: - "@libp2p/crypto" "^4.0.1" - "@libp2p/interface" "^1.1.1" - "@libp2p/peer-id" "^4.0.4" + "@libp2p/crypto" "^5.0.1" + "@libp2p/interface" "^2.0.1" + "@libp2p/peer-id" "^5.0.1" "@multiformats/multiaddr" "^12.1.10" bigint-buffer "^1.1.5" - ethereum-cryptography "^2.1.3" + ethereum-cryptography "^2.2.0" rlp "^2.2.6" uint8-varint "^2.0.2" uint8arrays "^5.0.1" @@ -528,54 +528,37 @@ resolved "https://registry.yarnpkg.com/@chainsafe/is-ip/-/is-ip-2.0.2.tgz#7311e7403f11d8c5cfa48111f56fcecaac37c9f6" integrity sha512-ndGqEMG1W5WkGagaqOZHpPU172AGdxr+LD15sv3WIUvT5oCFUrG1Y0CW/v2Egwj4JXEvSibaIIIqImsm98y1nA== -"@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== +"@chainsafe/libp2p-gossipsub@^14.1.0": + version "14.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-gossipsub/-/libp2p-gossipsub-14.1.0.tgz#0003a214c2a88b04ab7c256c70ec439717958f09" + integrity sha512-nzFBbHOoRFa/bXUSzmJaXOgHI+EttTldhLJ33yWcM0DxnWhLKychHkCDLoJO3THa1+dnzrDJoxj3N3/V0WoPVw== dependencies: - "@libp2p/crypto" "^4.0.1" - "@libp2p/interface" "^1.1.2" - "@libp2p/interface-internal" "^1.0.7" - "@libp2p/peer-id" "^4.0.5" - "@libp2p/pubsub" "^9.0.8" + "@libp2p/crypto" "^5.0.0" + "@libp2p/interface" "^2.0.0" + "@libp2p/interface-internal" "^2.0.0" + "@libp2p/peer-id" "^5.0.0" + "@libp2p/pubsub" "^10.0.0" "@multiformats/multiaddr" "^12.1.14" denque "^2.1.0" it-length-prefixed "^9.0.4" it-pipe "^3.0.1" it-pushable "^3.2.3" multiformats "^13.0.1" - protons-runtime "5.4.0" + protons-runtime "^5.5.0" uint8arraylist "^2.4.8" uint8arrays "^5.0.1" -"@chainsafe/libp2p-identify@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-identify/-/libp2p-identify-1.0.0.tgz#28191e619715a87c140d8b516ee85cb7d39e41e0" - integrity sha512-X+VWUC0xeCFIulE4BU5M8FmTxZ/OKzku+9/1UaX2EG1LcqQkCDrPi6CCODbE0SraqImG4aVHRbiCFWxKEfE8wQ== - dependencies: - "@libp2p/interface" "^1.1.2" - "@libp2p/interface-internal" "^1.0.7" - "@libp2p/peer-id" "^4.0.5" - "@libp2p/peer-record" "^7.0.7" - "@multiformats/multiaddr" "^12.1.10" - "@multiformats/multiaddr-matcher" "^1.1.0" - it-protobuf-stream "^1.1.1" - protons-runtime "^5.0.0" - uint8arraylist "^2.4.7" - uint8arrays "^5.0.0" - wherearewe "^2.0.1" - -"@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== +"@chainsafe/libp2p-noise@^16.0.0": + version "16.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-noise/-/libp2p-noise-16.0.0.tgz#52bb558490065439b0026950d7d99567da5c2c96" + integrity sha512-8rqr8V1RD2/lVbfL0Bb//N8iPOFof11cUe8v8z8xJT7fUhCAbtCCSM4jbwI4HCnw0MvHLmcpmAfDCFRwcWzoeA== dependencies: "@chainsafe/as-chacha20poly1305" "^0.1.0" "@chainsafe/as-sha256" "^0.4.1" - "@libp2p/crypto" "^4.0.0" - "@libp2p/interface" "^1.0.0" - "@libp2p/peer-id" "^4.0.0" - "@noble/ciphers" "^0.4.0" + "@libp2p/crypto" "^5.0.0" + "@libp2p/interface" "^2.0.0" + "@libp2p/peer-id" "^5.0.0" + "@noble/ciphers" "^0.6.0" "@noble/curves" "^1.1.0" "@noble/hashes" "^1.3.1" it-length-prefixed "^9.0.1" @@ -583,7 +566,7 @@ it-pair "^2.0.6" it-pipe "^3.0.1" it-stream-types "^2.0.1" - protons-runtime "^5.0.0" + protons-runtime "^5.5.0" uint8arraylist "^2.4.3" uint8arrays "^5.0.0" wherearewe "^2.0.1" @@ -1686,247 +1669,277 @@ yargs "16.2.0" yargs-parser "20.2.4" -"@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== +"@libp2p/bootstrap@^11.0.4": + version "11.0.7" + resolved "https://registry.yarnpkg.com/@libp2p/bootstrap/-/bootstrap-11.0.7.tgz#ecb14834fff03a184a3a7fd211d2ef85b3002fc6" + integrity sha512-PRDMVXf67+ASYTco6APqPy4HF03mQ8UX+BbBZcMAMpnlPsetYfWgQg3YiBe56J+PVQLs0FPsGpfLmAg7PUguQA== dependencies: - "@libp2p/interface" "^1.3.0" - "@libp2p/peer-id" "^4.1.0" + "@libp2p/interface" "^2.1.2" + "@libp2p/interface-internal" "^2.0.7" + "@libp2p/peer-id" "^5.0.4" "@multiformats/mafmt" "^12.1.6" - "@multiformats/multiaddr" "^12.2.1" + "@multiformats/multiaddr" "^12.2.3" -"@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== +"@libp2p/crypto@^5.0.0", "@libp2p/crypto@^5.0.1", "@libp2p/crypto@^5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@libp2p/crypto/-/crypto-5.0.4.tgz#26f24025f3dd2be959360c6b58c94ccadb04ed63" + integrity sha512-v5xsngOlDu8JP3GQDvK+2YYzTELl7/aPfXPbIzKEcy7ON2hu79t1BZMuavjPsr+WWIPNg5yKst6IJfRilzwXRQ== dependencies: - "@libp2p/interface" "^1.3.0" + "@libp2p/interface" "^2.1.2" "@noble/curves" "^1.4.0" "@noble/hashes" "^1.4.0" asn1js "^3.0.5" 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" + uint8arrays "^5.1.0" + +"@libp2p/identify@^3.0.4": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@libp2p/identify/-/identify-3.0.7.tgz#a7541d6775cf652314bf2209b281b402e8dedc35" + integrity sha512-4Ns/0HN9lvQAox8eaJruKXakOtikduk6kPlz+KYmFMgVE5/kRBRf7h0aK/8cyU9sQPbSZLCaJ3gBWoDrfMIu2w== + dependencies: + "@libp2p/crypto" "^5.0.4" + "@libp2p/interface" "^2.1.2" + "@libp2p/interface-internal" "^2.0.7" + "@libp2p/peer-id" "^5.0.4" + "@libp2p/peer-record" "^8.0.7" + "@libp2p/utils" "^6.1.0" + "@multiformats/multiaddr" "^12.2.3" + "@multiformats/multiaddr-matcher" "^1.2.1" + it-drain "^3.0.7" + it-parallel "^3.0.7" + it-protobuf-stream "^1.1.3" protons-runtime "^5.4.0" uint8arraylist "^2.4.8" - uint8arrays "^5.0.3" + uint8arrays "^5.1.0" wherearewe "^2.0.1" -"@libp2p/interface-internal@^1.0.7", "@libp2p/interface-internal@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@libp2p/interface-internal/-/interface-internal-1.1.1.tgz#ff16b4fee4a3d3e39121e26eeeab42e9257f5f49" - integrity sha512-lLPd7yysXqpb1oiPZAn57w3CQdD33C+mu6pfUuPYI5yWMgwWq8V3XE4IMG1IyHUGEYZAuGglghAH9YQNbtticw== +"@libp2p/interface-internal@^2.0.0", "@libp2p/interface-internal@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@libp2p/interface-internal/-/interface-internal-2.0.7.tgz#ceefa71553ce5aec9be793fcc646680f7d289806" + integrity sha512-numJBYHajL7W1BuURkQ4tlZ4sUGNGI3GWkhTmL2fS+LxYS2hUVTxcemHtUZGpcJQ17GiCqq+j4GE3bkBagOb0g== dependencies: - "@libp2p/interface" "^1.3.0" - "@libp2p/peer-collections" "^5.1.11" - "@multiformats/multiaddr" "^12.2.1" + "@libp2p/interface" "^2.1.2" + "@libp2p/peer-collections" "^6.0.7" + "@multiformats/multiaddr" "^12.2.3" + progress-events "^1.0.0" uint8arraylist "^2.4.8" -"@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== +"@libp2p/interface@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@libp2p/interface/-/interface-1.7.0.tgz#b75b6032a6b0d0d5a13e551dcf4d481a8ca9a88f" + integrity sha512-/zFyaIaIGW0aihhsH7/93vQdpWInUzFocxF11RO/029Y6h0SVjs24HHbils+DqaFDTqN+L7oNlBx2rM2MnmTjA== dependencies: - "@multiformats/multiaddr" "^12.2.1" + "@multiformats/multiaddr" "^12.2.3" it-pushable "^3.2.3" it-stream-types "^2.0.1" multiformats "^13.1.0" progress-events "^1.0.0" uint8arraylist "^2.4.8" -"@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== +"@libp2p/interface@^2.0.0", "@libp2p/interface@^2.0.1", "@libp2p/interface@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@libp2p/interface/-/interface-2.1.2.tgz#7b38047a7d2d35a6a4e0f0f22fbdeeec98b85321" + integrity sha512-uD4NapC+1qGX7RmgC1aehQm3pMs1MpO1DwuhUlAo1M6CyNxfs1Ha9jhg2T+G4u4CAJM6wffZTyPGnKnrR+M8Fw== dependencies: - "@libp2p/interface" "^1.3.0" - "@multiformats/multiaddr" "^12.2.1" - debug "^4.3.4" + "@multiformats/multiaddr" "^12.2.3" + it-pushable "^3.2.3" + it-stream-types "^2.0.1" + multiformats "^13.1.0" + progress-events "^1.0.0" + uint8arraylist "^2.4.8" + +"@libp2p/logger@^4.0.6": + version "4.0.20" + resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-4.0.20.tgz#bcb7fa83f3803d8ec37926747a18108728589c13" + integrity sha512-TTh2dhHsOTAlMPxSa9ncFPHa/0jTt+0AQxwHdlxg/OGLAgc9VRhnrhHUbJZp07Crcw4T/MOfS4KhjlxgqYgJRw== + dependencies: + "@libp2p/interface" "^1.7.0" + "@multiformats/multiaddr" "^12.2.3" interface-datastore "^8.2.11" multiformats "^13.1.0" + weald "^1.0.2" -"@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== +"@libp2p/logger@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-5.1.0.tgz#d580e2ee89e3f4224129cc12d727b45494aad6e5" + integrity sha512-hmkk1TONYRe+kKs5QTxkayIfj9qicp8hcrJ1Ac9QfTW/jdaUlnqd1uop4QcOD5GV6qNMq+v1qaMFWFYSN9RcPA== 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" + "@libp2p/interface" "^2.1.2" + "@multiformats/multiaddr" "^12.2.3" + interface-datastore "^8.3.0" + multiformats "^13.1.0" + weald "^1.0.2" + +"@libp2p/mdns@^11.0.4": + version "11.0.7" + resolved "https://registry.yarnpkg.com/@libp2p/mdns/-/mdns-11.0.7.tgz#ab968f952085a59d3ea829727e79f631fa049376" + integrity sha512-CW0MbN2bQvSVsZmYT8Ul5a2TOiwhU3aBKyHyCuf5WA70Nu6Lc72YSc+vRT2EIw5Ihb+dbxC/mXrhY1xKdXaWCg== + dependencies: + "@libp2p/interface" "^2.1.2" + "@libp2p/interface-internal" "^2.0.7" + "@libp2p/peer-id" "^5.0.4" + "@libp2p/utils" "^6.1.0" + "@multiformats/multiaddr" "^12.2.3" "@types/multicast-dns" "^7.2.4" dns-packet "^5.6.1" multicast-dns "^7.2.5" -"@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== +"@libp2p/mplex@^11.0.4": + version "11.0.7" + resolved "https://registry.yarnpkg.com/@libp2p/mplex/-/mplex-11.0.7.tgz#18f5af4d59bbd9bdf64c9ddda30020c6b674010d" + integrity sha512-q13aTXf6+kEQk67bnlDnXBy8TAU19zxrNrxzwTTW3m9HEyPEKoA1YJuSqZuDjxfP31BbMshs3xxnlXgph5SpUw== dependencies: - "@libp2p/interface" "^1.3.0" - "@libp2p/utils" "^5.3.2" + "@libp2p/interface" "^2.1.2" + "@libp2p/utils" "^6.1.0" it-pipe "^3.0.1" it-pushable "^3.2.3" it-stream-types "^2.0.1" uint8-varint "^2.0.4" uint8arraylist "^2.4.8" - uint8arrays "^5.0.3" + uint8arrays "^5.1.0" -"@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== +"@libp2p/multistream-select@^6.0.5": + version "6.0.5" + resolved "https://registry.yarnpkg.com/@libp2p/multistream-select/-/multistream-select-6.0.5.tgz#919c923ac13573a44de6945695f1d1882ba35da4" + integrity sha512-iOMHcF/NzeShmnRLf9KI39bgfxptklbf6Tv9NvBbICfYO/IJB6KDI6bOif5eXXqUqZjHrQJ3jrRppOEwk2HV4g== dependencies: - "@libp2p/interface" "^1.3.0" + "@libp2p/interface" "^2.1.2" it-length-prefixed "^9.0.4" - it-length-prefixed-stream "^1.1.6" + it-length-prefixed-stream "^1.1.7" it-stream-types "^2.0.1" p-defer "^4.0.1" race-signal "^1.0.2" uint8-varint "^2.0.4" uint8arraylist "^2.4.8" - uint8arrays "^5.0.3" + uint8arrays "^5.1.0" -"@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== +"@libp2p/peer-collections@^6.0.7": + version "6.0.7" + resolved "https://registry.yarnpkg.com/@libp2p/peer-collections/-/peer-collections-6.0.7.tgz#8347e08aebbdf4a39962bb87e5ae86cc0aadfcb4" + integrity sha512-e3o994iEUvPR58x8Y5iE6lvrkv48oJXp/A1XIxMB4D/kA4OlY5BjDpHpR4nE4+EkzhIbslbMLAfip2FStyjtHg== dependencies: - "@libp2p/interface" "^1.3.0" - "@libp2p/peer-id" "^4.1.0" - -"@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.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/interface" "^2.1.2" + "@libp2p/peer-id" "^5.0.4" + "@libp2p/utils" "^6.1.0" + multiformats "^13.2.2" -"@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== +"@libp2p/peer-id@^5.0.0", "@libp2p/peer-id@^5.0.1", "@libp2p/peer-id@^5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@libp2p/peer-id/-/peer-id-5.0.4.tgz#5a71f449b97098a5b12631b6be898a016a82c6bb" + integrity sha512-CHNbQ4Odlc+YDTtv6BzWdGSaJ1I3Wb6iHNV7YB59v0ivSsd0NzlR31qWpK/ByUAMT+hfzQzR1dK9s3e7zS4/zQ== dependencies: - "@libp2p/interface" "^1.3.0" + "@libp2p/crypto" "^5.0.4" + "@libp2p/interface" "^2.1.2" 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" + uint8arrays "^5.1.0" + +"@libp2p/peer-record@^8.0.7": + version "8.0.7" + resolved "https://registry.yarnpkg.com/@libp2p/peer-record/-/peer-record-8.0.7.tgz#a092b2405e1130b8211f8ef15748b453096029d8" + integrity sha512-YsN8R+5O0MQwYQ0UGqERJJVRx7hAU4/nxiby91wzbgdfuL4qVPXHG4k0OAAtxVGLYa0q7KeXBpBG8qoaKhOXMQ== + dependencies: + "@libp2p/crypto" "^5.0.4" + "@libp2p/interface" "^2.1.2" + "@libp2p/peer-id" "^5.0.4" + "@libp2p/utils" "^6.1.0" + "@multiformats/multiaddr" "^12.2.3" + multiformats "^13.2.2" 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" + uint8arrays "^5.1.0" + +"@libp2p/peer-store@^11.0.7": + version "11.0.7" + resolved "https://registry.yarnpkg.com/@libp2p/peer-store/-/peer-store-11.0.7.tgz#e9a57d8a0ce1b3d0559a11b7e6633620f4297276" + integrity sha512-h8W/XVYfKTmJhhnh2Mdub23CzPv24l5g1RRwFsEKCkWAe95M/fvDMPTM2ahRUB64qfnFT5X4XNFFyJFMsVtjLA== + dependencies: + "@libp2p/crypto" "^5.0.4" + "@libp2p/interface" "^2.1.2" + "@libp2p/peer-collections" "^6.0.7" + "@libp2p/peer-id" "^5.0.4" + "@libp2p/peer-record" "^8.0.7" + "@multiformats/multiaddr" "^12.2.3" + interface-datastore "^8.3.0" + it-all "^3.0.6" mortice "^3.0.4" multiformats "^13.1.0" protons-runtime "^5.4.0" uint8arraylist "^2.4.8" - uint8arrays "^5.0.3" + uint8arrays "^5.1.0" -"@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== +"@libp2p/prometheus-metrics@^4.1.2": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@libp2p/prometheus-metrics/-/prometheus-metrics-4.2.1.tgz#a563e05cac1f67a161824301cacdfd659bc3052c" + integrity sha512-Mt93FWjP1Jz5G/FsG7cf0J4Y1nYs4eQvx1RjtuEghoQcSzD8nSupeMt67YRQG87R/qrs0jdiGtYxmoCoagsIDw== dependencies: - "@libp2p/interface" "^1.3.0" - it-foreach "^2.0.6" + "@libp2p/interface" "^2.1.2" + it-foreach "^2.1.0" it-stream-types "^2.0.1" - prom-client "^15.1.1" + prom-client "^15.1.2" uint8arraylist "^2.4.8" -"@libp2p/pubsub@^9.0.8": - 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" +"@libp2p/pubsub@^10.0.0": + version "10.0.7" + resolved "https://registry.yarnpkg.com/@libp2p/pubsub/-/pubsub-10.0.7.tgz#1b7e0b7e96b75a8a1f557171ef4d72c17879e5c0" + integrity sha512-XYAYaASilesqxonjhiEENF/jXoT3jcftNYySkiyajrw3rZnLVkfJMRese3lkFqkIZqy7K/7aAtYEDJLeSrJDiQ== + dependencies: + "@libp2p/crypto" "^5.0.4" + "@libp2p/interface" "^2.1.2" + "@libp2p/interface-internal" "^2.0.7" + "@libp2p/peer-collections" "^6.0.7" + "@libp2p/peer-id" "^5.0.4" + "@libp2p/utils" "^6.1.0" it-length-prefixed "^9.0.4" it-pipe "^3.0.1" it-pushable "^3.2.3" multiformats "^13.1.0" p-queue "^8.0.1" uint8arraylist "^2.4.8" - uint8arrays "^5.0.3" + uint8arrays "^5.1.0" -"@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== +"@libp2p/tcp@10.0.4": + version "10.0.4" + resolved "https://registry.yarnpkg.com/@libp2p/tcp/-/tcp-10.0.4.tgz#9fdcd4ef5940816d366ee29e7e8150a5a4bd2f11" + integrity sha512-53WIxkKNMHJphTK/VUJvL5jPrkEitZpZqUSA8zN7e02OXwwOC/X3U03xvVFdrjGL32rW524+7I+SrvS+hVdNCw== dependencies: - "@libp2p/interface" "^1.3.0" - "@libp2p/utils" "^5.3.2" + "@libp2p/interface" "^2.1.2" + "@libp2p/utils" "^6.0.4" "@multiformats/mafmt" "^12.1.6" - "@multiformats/multiaddr" "^12.2.1" + "@multiformats/multiaddr" "^12.2.3" "@types/sinon" "^17.0.3" - stream-to-it "^1.0.0" + progress-events "^1.0.0" + stream-to-it "^1.0.1" -"@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== +"@libp2p/utils@^6.0.4", "@libp2p/utils@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@libp2p/utils/-/utils-6.1.0.tgz#5ccece78a38bec2c2d759136ccc78494838c2b87" + integrity sha512-pxuUI8QgeS06bMZRpy0JnACPhrrCJS5/rVNTcnQK8lV1ag2bjwkGG/359AwjeEolzYQeLrmmqnZyawd1Y74wpw== dependencies: "@chainsafe/is-ip" "^2.0.2" - "@libp2p/interface" "^1.3.0" - "@libp2p/logger" "^4.0.11" - "@multiformats/multiaddr" "^12.2.1" - "@multiformats/multiaddr-matcher" "^1.2.0" + "@libp2p/crypto" "^5.0.4" + "@libp2p/interface" "^2.1.2" + "@libp2p/logger" "^5.1.0" + "@multiformats/multiaddr" "^12.2.3" + "@sindresorhus/fnv1a" "^3.1.0" + "@types/murmurhash3js-revisited" "^3.0.3" + any-signal "^4.1.1" delay "^6.0.0" get-iterator "^2.0.1" is-loopback-addr "^2.0.2" + it-foreach "^2.1.1" + it-pipe "^3.0.1" it-pushable "^3.2.3" it-stream-types "^2.0.1" + murmurhash3js-revisited "^3.0.0" netmask "^2.0.2" p-defer "^4.0.1" - race-event "^1.2.0" + race-event "^1.3.0" race-signal "^1.0.2" uint8arraylist "^2.4.8" + uint8arrays "^5.1.0" "@lukeed/ms@^2.0.2": version "2.0.2" @@ -1993,7 +2006,7 @@ outvariant "^1.2.1" strict-event-emitter "^0.5.1" -"@multiformats/dns@^1.0.3", "@multiformats/dns@^1.0.5": +"@multiformats/dns@^1.0.3", "@multiformats/dns@^1.0.6": version "1.0.6" resolved "https://registry.yarnpkg.com/@multiformats/dns/-/dns-1.0.6.tgz#b8c7de11459a02a5f4e609d35d3cdb95cb6ad152" integrity sha512-nt/5UqjMPtyvkG9BQYdJ4GfLK3nMqGpFZOzf4hAmIa0sJh2LlS9YKXZ4FgwBDsaHvzZqR/rUFIywIc7pkHNNuw== @@ -2013,23 +2026,22 @@ dependencies: "@multiformats/multiaddr" "^12.0.0" -"@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== +"@multiformats/multiaddr-matcher@^1.2.1": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@multiformats/multiaddr-matcher/-/multiaddr-matcher-1.2.4.tgz#affb3c63b5cd83b44156be19583981651373ec2e" + integrity sha512-GgpqzQFL4Mj8t7cLNHC5nuYUuSm0kTtSUyYswiyWwTSUY3XwRAMx0UiFWQg+ETk0u+/IvFaHxfnyEoH3tasvwg== dependencies: "@chainsafe/is-ip" "^2.0.1" "@multiformats/multiaddr" "^12.0.0" multiformats "^13.0.0" -"@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== +"@multiformats/multiaddr@^12.0.0", "@multiformats/multiaddr@^12.1.10", "@multiformats/multiaddr@^12.1.14", "@multiformats/multiaddr@^12.1.3", "@multiformats/multiaddr@^12.2.3": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@multiformats/multiaddr/-/multiaddr-12.3.1.tgz#953ceb4ae3b39125b7b2c721230ea7b398cf49fe" + integrity sha512-yoGODQY4nIj41ENJClucS8FtBoe8w682bzbKldEQr9lSlfdHqAsRC+vpJAOBpiMwPps1tHua4kxrDmvprdhoDQ== dependencies: "@chainsafe/is-ip" "^2.0.1" "@chainsafe/netmask" "^2.0.0" - "@libp2p/interface" "^1.0.0" "@multiformats/dns" "^1.0.3" multiformats "^13.0.0" uint8-varint "^2.0.1" @@ -2100,12 +2112,19 @@ resolved "https://registry.yarnpkg.com/@napi-rs/snappy-win32-x64-msvc/-/snappy-win32-x64-msvc-7.2.2.tgz#4f598d3a5d50904d9f72433819f68b21eaec4f7d" integrity sha512-a43cyx1nK0daw6BZxVcvDEXxKMFLSBSDTAhsFD0VqSKcC7MGUBMaqyoWUcMiI7LBSz4bxUmxDWKfCYzpEmeb3w== -"@noble/ciphers@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.4.0.tgz#e3f69e3ce935683dd8dadb636652a5cb5cd5958c" - integrity sha512-xaUaUUDWbHIFSxaQ/pIe+33VG2mfJp6N/KxKLmZr5biWdNznCAmfu24QRhX10BbVAuqOahAoyp0S4M9md6GPDw== +"@noble/ciphers@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.6.0.tgz#a3d82c72ce71ba43128e7eb71757b5ecb75b1273" + integrity sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ== -"@noble/curves@1.3.0", "@noble/curves@^1.1.0", "@noble/curves@~1.3.0": +"@noble/curves@1.4.2", "@noble/curves@~1.4.0": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.2.tgz#40309198c76ed71bc6dbf7ba24e81ceb4d0d1fe9" + integrity sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/curves@^1.1.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== @@ -2124,12 +2143,12 @@ 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.2": +"@noble/hashes@1.3.3", "@noble/hashes@^1.0.0", "@noble/hashes@^1.3.0", "@noble/hashes@^1.3.1": 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": +"@noble/hashes@1.4.0", "@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== @@ -2702,11 +2721,11 @@ integrity sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ== "@puppeteer/browsers@1.4.6", "@puppeteer/browsers@^1.6.0", "@puppeteer/browsers@^2.1.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.3.0.tgz#791ea7d80450fea24eb19fb1d70c367ad4e08cae" - integrity sha512-ioXoq9gPxkss4MYhD+SFaU9p1IHFUX0ILAWFPyjGaBdjLsYAlZw6j1iLA0N/m12uVHLFDfSYNF7EQccjinIMDA== + version "2.4.0" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.4.0.tgz#a0dd0f4e381e53f509109ae83b891db5972750f5" + integrity sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g== dependencies: - debug "^4.3.5" + debug "^4.3.6" extract-zip "^2.0.1" progress "^2.0.3" proxy-agent "^6.4.0" @@ -2870,27 +2889,27 @@ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.0.0.tgz#109fb595021de285f05a7db6806f2f48296fcee7" integrity sha512-gIVaYhUsy+9s58m/ETjSJVKHhKTBMmcRb9cEV5/5dwvfDlfORjKrFsDeDHWRrm6RjcPvCLZFwGJjAjLj1gg4HA== -"@scure/base@~1.1.4": - version "1.1.5" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.5.tgz#1d85d17269fe97694b9c592552dd9e5e33552157" - integrity sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ== +"@scure/base@~1.1.6": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.8.tgz#8f23646c352f020c83bca750a82789e246d42b50" + integrity sha512-6CyAclxj3Nb0XT7GHK6K4zK6k2xJm6E4Ft0Ohjt4WgegiFUHEtFb2CGzmPmGBwoIhrLsqNLYfLr04Y1GePrzZg== -"@scure/bip32@1.3.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.3.tgz#a9624991dc8767087c57999a5d79488f48eae6c8" - integrity sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ== +"@scure/bip32@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.4.0.tgz#4e1f1e196abedcef395b33b9674a042524e20d67" + integrity sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg== dependencies: - "@noble/curves" "~1.3.0" - "@noble/hashes" "~1.3.2" - "@scure/base" "~1.1.4" + "@noble/curves" "~1.4.0" + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" -"@scure/bip39@1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.2.tgz#f3426813f4ced11a47489cbcf7294aa963966527" - integrity sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA== +"@scure/bip39@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.3.0.tgz#0f258c16823ddd00739461ac31398b4e7d6a18c3" + integrity sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== dependencies: - "@noble/hashes" "~1.3.2" - "@scure/base" "~1.1.4" + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" "@scure/bip39@^1.0.0": version "1.0.0" @@ -2934,6 +2953,11 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== +"@sindresorhus/fnv1a@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/fnv1a/-/fnv1a-3.1.0.tgz#f8e46597298f6fd4c12dc901cdd4e73beb4d24fa" + integrity sha512-KV321z5m/0nuAg83W1dPLy85HpHDk7Sdi4fJbwvacWsEhAh+rZUW4ZfGcXmUIvjZg4ss2bcwNlRhJ7GBEUG08w== + "@sindresorhus/is@^4.0.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" @@ -3248,6 +3272,11 @@ "@types/dns-packet" "*" "@types/node" "*" +"@types/murmurhash3js-revisited@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.3.tgz#94e247168a18342477639126da8f01353437e8d0" + integrity sha512-QvlqvYtGBYIDeO8dFdY4djkRubcrc+yTJtBc7n8VZPlJDUS/00A+PssbvERM8f9bYRmcaSEHPZgZojeQj7kzAA== + "@types/mute-stream@^0.0.4": version "0.0.4" resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478" @@ -3336,6 +3365,11 @@ resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz" integrity sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g== +"@types/retry@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.2.tgz#ed279a64fa438bb69f2480eda44937912bb7480a" + integrity sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow== + "@types/sinon@^17.0.3": version "17.0.3" resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-17.0.3.tgz#9aa7e62f0a323b9ead177ed23a36ea757141a5fa" @@ -3718,6 +3752,19 @@ 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-level@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.4.tgz#3ad8d684c51cc9cbc9cf9612a7100b716c414b57" + integrity sha512-eUP/6pbXBkMbXFdx4IH2fVgvB7M0JvR7/lIL33zcs0IBcwjdzSSl31TOJsaCzmKSSDF9h8QYSOJux4Nd4YJqFg== + dependencies: + buffer "^6.0.3" + catering "^2.1.0" + is-buffer "^2.0.5" + level-supports "^4.0.0" + level-transcoder "^1.0.1" + module-error "^1.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" @@ -5349,15 +5396,14 @@ data-urls@^5.0.0: whatwg-mimetype "^4.0.0" whatwg-url "^14.0.0" -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== +datastore-core@10.0.0, datastore-core@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/datastore-core/-/datastore-core-10.0.0.tgz#86abe346338e88c3326fb7aeb90eff3613cf542f" + integrity sha512-/b5KDmSAIFizS/ZzTTU+ZdfOcQc6mRmbc4/EK/WOzbEO5c0KWyjRLsZ3DWwh9wiPu93V7pX1oC+Or61k8UPPsg== dependencies: "@libp2p/logger" "^4.0.6" - err-code "^3.0.1" interface-datastore "^8.0.0" - interface-store "^5.0.0" + interface-store "6.0.0" it-drain "^3.0.5" it-filter "^3.0.4" it-map "^3.0.5" @@ -5367,18 +5413,19 @@ datastore-core@^9.0.0, datastore-core@^9.1.1, datastore-core@^9.2.9: it-sort "^3.0.4" it-take "^3.0.4" -datastore-level@*, datastore-level@^10.1.1: - version "10.1.1" - resolved "https://registry.yarnpkg.com/datastore-level/-/datastore-level-10.1.1.tgz#390dc6ca17dc691947a3e81c984b4b6064812e81" - integrity sha512-4fQPf/6fIXdcC0XZPGMiNuoOmF82Vhdz+LPTmbzR+CbbnCri6eOcFdzBPnDsAAuPOCV6Zld1EhgM2cRArw1+sQ== +datastore-level@*, datastore-level@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/datastore-level/-/datastore-level-11.0.0.tgz#c0f7324bd74e15bec01f2911f5740fbf59c344f7" + integrity sha512-ATSEfGoWTAHgDeZaYukeHu0FgyhjW3FKUw3XtcIpfBl4UF2kLNnYRBfzCeH+3RA0QaZvbSWpgYk6Gwf7m1oCtg== dependencies: - datastore-core "^9.0.0" + datastore-core "10.0.0" interface-datastore "^8.0.0" - it-filter "^3.0.0" - it-map "^3.0.1" - it-sort "^3.0.1" - it-take "^3.0.1" - level "^8.0.0" + interface-store "6.0.0" + it-filter "^3.0.4" + it-map "^3.0.5" + it-sort "^3.0.4" + it-take "^3.0.4" + level "^8.0.1" dateformat@^3.0.3: version "3.0.3" @@ -5404,6 +5451,13 @@ debug@^4.3.5: dependencies: ms "2.1.2" +debug@^4.3.6: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" @@ -6001,15 +6055,15 @@ esutils@^2.0.2: resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz#1352270ed3b339fe25af5ceeadcf1b9c8e30768a" - integrity sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA== +ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz#58f2810f8e020aecb97de8c8c76147600b0b8ccf" + integrity sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg== dependencies: - "@noble/curves" "1.3.0" - "@noble/hashes" "1.3.3" - "@scure/bip32" "1.3.3" - "@scure/bip39" "1.2.2" + "@noble/curves" "1.4.2" + "@noble/hashes" "1.4.0" + "@scure/bip32" "1.4.0" + "@scure/bip39" "1.3.0" ethers@^5.7.1: version "5.7.2" @@ -7396,18 +7450,18 @@ inquirer@^9.1.5: through "^2.3.6" wrap-ansi "^8.1.0" -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== +interface-datastore@^8.0.0, interface-datastore@^8.2.11, interface-datastore@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/interface-datastore/-/interface-datastore-8.3.0.tgz#0ce9a2f0f61f9fbe1c1734c6d10a0265193689f7" + integrity sha512-RM/rTSmRcnoCwGZIHrPm+nlGYVoT4R0lcFvNnDyhdFT4R6BuHHhfFP47UldVEjs98SfxLuMhaNMsyjI918saHw== dependencies: - interface-store "^5.0.0" + interface-store "6.0.0" uint8arrays "^5.0.2" -interface-store@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/interface-store/-/interface-store-5.1.0.tgz#1735cead844fe452d62c307fafbaaa1d261e6ff3" - integrity sha512-mjUwX3XSoreoxCS3sXS3pSRsGnUjl9T06KBqt/T7AgE9Sgp4diH64ZyURJKnj2T5WmCvTbC0Dm+mwQV5hfLSBQ== +interface-store@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/interface-store/-/interface-store-6.0.0.tgz#8d8277a582f69d819134e125b686e147099a4728" + integrity sha512-HkjsDPsjA7SKkCr+TH1elUQApAAM3X3JPwrz3vFzaf614wI+ZD6GVvwKGZCHYcbSRqeZP/uzVPqezzeISeo5kA== internal-slot@^1.0.5: version "1.0.5" @@ -7593,6 +7647,11 @@ is-negative-zero@^2.0.2: resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-network-error@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-network-error/-/is-network-error-1.1.0.tgz#d26a760e3770226d11c169052f266a4803d9c997" + integrity sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g== + is-node-process@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134" @@ -7817,6 +7876,11 @@ it-all@^3.0.0, it-all@^3.0.4: resolved "https://registry.yarnpkg.com/it-all/-/it-all-3.0.4.tgz#08f2e3eb3df04fa4525a343dcacfbdf91ffee162" integrity sha512-UMiy0i9DqCHBdWvMbzdYvVGa5/w4t1cc4nchpbnjdLhklglv8mQeEYnii0gvKESJuL1zV32Cqdb33R6/GPfxpQ== +it-all@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/it-all/-/it-all-3.0.6.tgz#30a4f922ae9ca0945b0f720d3478ae6f5b6707ab" + integrity sha512-HXZWbxCgQZJfrv5rXvaVeaayXED8nTKx9tj9fpBhmcUJcedVZshMMMqTj0RG2+scGypb9Ut1zd1ifbf3lA8L+Q== + it-byte-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/it-byte-stream/-/it-byte-stream-1.0.0.tgz#07645e1c94444760bc7abecebf187b83777b0351" @@ -7826,29 +7890,38 @@ it-byte-stream@^1.0.0: it-stream-types "^2.0.1" uint8arraylist "^2.4.1" -it-drain@^3.0.3, it-drain@^3.0.5: +it-byte-stream@^1.0.12: + version "1.1.0" + resolved "https://registry.yarnpkg.com/it-byte-stream/-/it-byte-stream-1.1.0.tgz#f5b80b713fb71a34cbff2390b7232b103cf625bb" + integrity sha512-WWponBWdKEa6o2U3NX+wGMY8X1EkWXcQvpC+3CUqKb4ZzK30q3EPqiTjFxLf9tNVgdF/MNAtx/XclpVfgaz9KQ== + dependencies: + it-queueless-pushable "^1.0.0" + it-stream-types "^2.0.1" + uint8arraylist "^2.4.8" + +it-drain@^3.0.3, it-drain@^3.0.5, it-drain@^3.0.7: 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, it-filter@^3.0.4: +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.6: - version "2.1.0" - resolved "https://registry.yarnpkg.com/it-foreach/-/it-foreach-2.1.0.tgz#37dd606d92d93ac82ee3fdeffeec7f9f8dd76cf8" - integrity sha512-nobWUecq9E2ED1kcXz2o27yN6KePauSdmxJNMwCduWByrF4WNB2UgBHjr9QV2jPXpEWPDuzxZas9fVhQj1Vovg== +it-foreach@^2.1.0, it-foreach@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/it-foreach/-/it-foreach-2.1.1.tgz#93e311a1057dd0ff7631f914dc9c2c963f27a4b8" + integrity sha512-ID4Gxnavk/LVQLQESAQ9hR6dR63Ih6X+8VdxEktX8rpz2dCGAbZpey/eljTNbMfV2UKXHiu6UsneoNBZuac97g== dependencies: it-peekable "^3.0.0" -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== +it-length-prefixed-stream@^1.0.0, it-length-prefixed-stream@^1.1.7: + version "1.2.0" + resolved "https://registry.yarnpkg.com/it-length-prefixed-stream/-/it-length-prefixed-stream-1.2.0.tgz#1f6ad78c60dea3b16364f86a0b78058f4d66a04e" + integrity sha512-vX7dzSl/2UMYYsAr0FQdPNVR5xYEETaeboZ+eXxNBjgARuvxnWA6OedW8lC5/J3ebMTC98JhA3eH76eTijUOsA== dependencies: it-byte-stream "^1.0.0" it-stream-types "^2.0.1" @@ -7867,14 +7940,14 @@ it-length-prefixed@^9.0.1, it-length-prefixed@^9.0.4: uint8arraylist "^2.0.0" uint8arrays "^5.0.1" -it-map@^3.0.1, it-map@^3.0.5: +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.3: +it-merge@^3.0.0, it-merge@^3.0.3, it-merge@^3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/it-merge/-/it-merge-3.0.5.tgz#2b0d1d07c825b9d20c4c2889aab8e07322fd803e" integrity sha512-2l7+mPf85pyRF5pqi0dKcA54E5Jm/2FyY5GsOaN51Ta0ipC7YZ3szuAsH8wOoB6eKY4XsU4k2X+mzPmFBMayEA== @@ -7889,12 +7962,12 @@ it-pair@^2.0.6: it-stream-types "^2.0.1" p-defer "^4.0.0" -it-parallel@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/it-parallel/-/it-parallel-3.0.6.tgz#d8f9efa56dac5f960545b3a148d2ca171694d228" - integrity sha512-i7UM7I9LTkDJw3YIqXHFAPZX6CWYzGc+X3irdNrVExI4vPazrJdI7t5OqrSVN8CONXLAunCiqaSV/zZRbQR56A== +it-parallel@^3.0.7: + version "3.0.8" + resolved "https://registry.yarnpkg.com/it-parallel/-/it-parallel-3.0.8.tgz#fb4a5344732ddae9eff7c7b21908aa1f223638d4" + integrity sha512-URLhs6eG4Hdr4OdvgBBPDzOjBeSSmI+Kqex2rv/aAyYClME26RYHirLVhZsZP5M+ZP6M34iRlXk8Wlqtezuqpg== dependencies: - p-defer "^4.0.0" + p-defer "^4.0.1" it-peekable@^3.0.0: version "3.0.1" @@ -7910,10 +7983,10 @@ it-pipe@^3.0.1: it-pushable "^3.1.2" it-stream-types "^2.0.1" -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== +it-protobuf-stream@^1.1.3: + version "1.1.5" + resolved "https://registry.yarnpkg.com/it-protobuf-stream/-/it-protobuf-stream-1.1.5.tgz#70da43abfb6beaaf7c53262d8cfd176d463b08f0" + integrity sha512-H70idW45As3cEbU4uSoZ9IYHUIV3YM69/2mmXYR7gOlPabWjuyNi3/abK11geiiq3la27Sos/mXr68JljjKtEQ== dependencies: it-length-prefixed-stream "^1.0.0" it-stream-types "^2.0.1" @@ -7926,6 +7999,14 @@ it-pushable@^3.1.2, it-pushable@^3.2.0, it-pushable@^3.2.3: dependencies: p-defer "^4.0.0" +it-queueless-pushable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/it-queueless-pushable/-/it-queueless-pushable-1.0.0.tgz#917b52964cd6465d6436f923552c407c5ee3d11c" + integrity sha512-HbcAbcuQj7a9EBxiRCZ+77FxWutgs/pY5ZvEyQnylWPGNFojCLAUwhcZjf5OuEQ9+y+vSa7w1GQBe8xJdmIn5A== + dependencies: + p-defer "^4.0.1" + race-signal "^1.0.2" + it-reader@^6.0.1: version "6.0.4" resolved "https://registry.yarnpkg.com/it-reader/-/it-reader-6.0.4.tgz#439cb88225dcd15116be0ffde9e846a928c3871a" @@ -7934,7 +8015,7 @@ it-reader@^6.0.1: it-stream-types "^2.0.1" uint8arraylist "^2.0.0" -it-sort@^3.0.1, it-sort@^3.0.4: +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== @@ -7946,7 +8027,7 @@ 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, it-take@^3.0.4: +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== @@ -8307,6 +8388,15 @@ level@^8.0.0: browser-level "^1.0.1" classic-level "^1.2.0" +level@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/level/-/level-8.0.1.tgz#737161db1bc317193aca4e7b6f436e7e1df64379" + integrity sha512-oPBGkheysuw7DmzFQYyFe8NAia5jFLAgEnkgWnK3OXAuJr8qFT+xBQIwokAZPME2bhPFzS8hlYcL16m8UZrtwQ== + dependencies: + abstract-level "^1.0.4" + browser-level "^1.0.1" + classic-level "^1.2.0" + libnpmaccess@7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-7.0.2.tgz#7f056c8c933dd9c8ba771fa6493556b53c5aac52" @@ -8329,32 +8419,37 @@ libnpmpublish@7.3.0: sigstore "^1.4.0" ssri "^10.0.1" -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" +libp2p@2.1.7: + version "2.1.7" + resolved "https://registry.yarnpkg.com/libp2p/-/libp2p-2.1.7.tgz#e0d921cba459c78c63d783aafea6ead98a75e57f" + integrity sha512-nUxws8eHeI4jREZJFNdif20c8jYnqPkmvioI3y/hICgXchkhcKzgT1E3jEd2CVT+isskr5LnJ1n70aw6bt0m6w== + dependencies: + "@libp2p/crypto" "^5.0.4" + "@libp2p/interface" "^2.1.2" + "@libp2p/interface-internal" "^2.0.7" + "@libp2p/logger" "^5.1.0" + "@libp2p/multistream-select" "^6.0.5" + "@libp2p/peer-collections" "^6.0.7" + "@libp2p/peer-id" "^5.0.4" + "@libp2p/peer-store" "^11.0.7" + "@libp2p/utils" "^6.1.0" + "@multiformats/dns" "^1.0.6" + "@multiformats/multiaddr" "^12.2.3" + "@multiformats/multiaddr-matcher" "^1.2.1" any-signal "^4.1.1" - datastore-core "^9.2.9" - interface-datastore "^8.2.11" - it-merge "^3.0.3" - it-parallel "^3.0.6" + datastore-core "^10.0.0" + interface-datastore "^8.3.0" + it-byte-stream "^1.0.12" + it-merge "^3.0.5" + it-parallel "^3.0.7" merge-options "^3.0.4" multiformats "^13.1.0" - uint8arrays "^5.0.3" + p-defer "^4.0.1" + p-retry "^6.2.0" + progress-events "^1.0.0" + race-event "^1.3.0" + race-signal "^1.0.2" + uint8arrays "^5.1.0" light-my-request@^6.0.0: version "6.0.0" @@ -9177,11 +9272,16 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +ms@^3.0.0-canary.1: + version "3.0.0-canary.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-3.0.0-canary.1.tgz#c7b34fbce381492fd0b345d1cf56e14d67b77b80" + integrity sha512-kh8ARjh8rMN7Du2igDRO9QJnqCb2xYTJxyQYK7vJJS4TvLLmsbyhiKpSW+t+y26gyOyMd0riphX0GeWKU3ky5g== + msw@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/msw/-/msw-2.3.2.tgz#ea4f45b51f833fa3b2215c4093bcda28dbe25a83" @@ -9223,10 +9323,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@^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== +multiformats@^13.0.0, multiformats@^13.0.1, multiformats@^13.1.0, multiformats@^13.2.2: + version "13.2.2" + resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-13.2.2.tgz#16da153ee8b68d8c9da31b52176e90b3cd8b43ef" + integrity sha512-RWI+nyf0q64vyOxL8LbKtjJMki0sogRL/8axvklNtiTM0iFCVtHwME9w6+0P1/v4dQvsIg8A45oT3ka1t/M/+A== multimatch@5.0.0: version "5.0.0" @@ -9239,6 +9339,11 @@ multimatch@5.0.0: arrify "^2.0.1" minimatch "^3.0.4" +murmurhash3js-revisited@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz#6bd36e25de8f73394222adc6e41fa3fac08a5869" + integrity sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g== + mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -9947,6 +10052,15 @@ p-reduce@2.1.0, p-reduce@^2.0.0, p-reduce@^2.1.0: resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== +p-retry@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-6.2.0.tgz#8d6df01af298750009691ce2f9b3ad2d5968f3bd" + integrity sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA== + dependencies: + "@types/retry" "0.12.2" + is-network-error "^1.0.0" + retry "^0.13.1" + p-timeout@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" @@ -10357,10 +10471,10 @@ progress@^2.0.3: resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -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== +prom-client@^15.1.0, prom-client@^15.1.2: + version "15.1.3" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-15.1.3.tgz#69fa8de93a88bc9783173db5f758dc1c69fa8fc2" + integrity sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g== dependencies: "@opentelemetry/api" "^1.4.0" tdigest "^0.1.1" @@ -10406,10 +10520,10 @@ protocols@^2.0.0, protocols@^2.0.1: resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== -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== +protons-runtime@^5.4.0, protons-runtime@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/protons-runtime/-/protons-runtime-5.5.0.tgz#ea06d9ef843aad77ea5de3e1ebafa81b58c24570" + integrity sha512-EsALjF9QsrEk6gbCx3lmfHxVN0ah7nG3cY7GySD4xf4g8cr7g543zB88Foh897Sr1RQJ9yDCUsoT1i1H/cVUFA== dependencies: uint8-varint "^2.0.2" uint8arraylist "^2.4.3" @@ -10558,7 +10672,7 @@ 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.2.0: +race-event@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/race-event/-/race-event-1.3.0.tgz#854f34118c31addf877898bd9f8e4dcfac9de7a2" integrity sha512-kaLm7axfOnahIqD3jQ4l1e471FIFcEGebXEnhxyLscuUzV8C94xVHtWEqDDXxll7+yu/6lW0w1Ff4HbtvHvOHg== @@ -10854,6 +10968,11 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -11540,7 +11659,7 @@ stream-http@^3.2.0: readable-stream "^3.6.0" xtend "^4.0.2" -stream-to-it@^1.0.0: +stream-to-it@^1.0.1: 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== @@ -11776,6 +11895,11 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^9.4.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.4.0.tgz#17bfcf686288f531db3dea3215510621ccb55954" + integrity sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw== + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -12307,10 +12431,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, 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== +uint8arrays@^5.0.0, uint8arrays@^5.0.1, uint8arrays@^5.0.2, uint8arrays@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-5.1.0.tgz#14047c9bdf825d025b7391299436e5e50e7270f1" + integrity sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww== dependencies: multiformats "^13.0.0" @@ -12675,6 +12799,14 @@ wcwidth@^1.0.0, wcwidth@^1.0.1: dependencies: defaults "^1.0.3" +weald@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/weald/-/weald-1.0.2.tgz#a51fb3a8dbf5fa2b71ef09f9a267c86a46742238" + integrity sha512-iG5cIuBwsPe1ZcoGGd4X6QYlepU1vLr4l4oWpzQWqeJPSo9B8bxxyE6xlnj3TCmThtha7gyVL+uuZgUFkPyfDg== + dependencies: + ms "^3.0.0-canary.1" + supports-color "^9.4.0" + web-streams-polyfill@^3.0.3: version "3.2.1" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" From 1c84d360074a3849426c29148993c2522c56f183 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Fri, 11 Oct 2024 22:42:38 -0700 Subject: [PATCH 154/259] chore: clean up single-used functions in Electra (#7132) * chore: clean up single-used function * Remove Uint8Array * Present state-transition constants in Uint8Array --- .../src/constants/constants.ts | 16 +++-- .../epoch/processEffectiveBalanceUpdates.ts | 9 +-- .../src/epoch/processPendingConsolidations.ts | 13 ++-- .../src/slot/upgradeStateToElectra.ts | 69 ++++++------------- packages/state-transition/src/util/electra.ts | 21 +----- .../state-transition/src/util/validator.ts | 8 --- 6 files changed, 39 insertions(+), 97 deletions(-) diff --git a/packages/state-transition/src/constants/constants.ts b/packages/state-transition/src/constants/constants.ts index c3ff3f9ac79e..3afb4e687508 100644 --- a/packages/state-transition/src/constants/constants.ts +++ b/packages/state-transition/src/constants/constants.ts @@ -1,10 +1,12 @@ -export const ZERO_HASH = Buffer.alloc(32, 0); -export const EMPTY_SIGNATURE = Buffer.alloc(96, 0); +export const ZERO_HASH = new Uint8Array(32).fill(0); +export const EMPTY_SIGNATURE = new Uint8Array(96).fill(0); export const SECONDS_PER_DAY = 86400; export const BASE_REWARDS_PER_EPOCH = 4; -export const G2_POINT_AT_INFINITY = Buffer.from( - "c000000000000000000000000000000000000000000000000000000000000000" + - "0000000000000000000000000000000000000000000000000000000000000000" + - "0000000000000000000000000000000000000000000000000000000000000000", - "hex" +export const G2_POINT_AT_INFINITY = new Uint8Array( + Buffer.from( + "c000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000", + "hex" + ) ); diff --git a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts index 22a46c84f52b..1fe5c92eea1a 100644 --- a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts +++ b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts @@ -5,12 +5,10 @@ import { HYSTERESIS_QUOTIENT, HYSTERESIS_UPWARD_MULTIPLIER, MAX_EFFECTIVE_BALANCE, - MAX_EFFECTIVE_BALANCE_ELECTRA, - MIN_ACTIVATION_BALANCE, TIMELY_TARGET_FLAG_INDEX, } from "@lodestar/params"; import {EpochTransitionCache, CachedBeaconStateAllForks, BeaconStateAltair} from "../types.js"; -import {hasCompoundingWithdrawalCredential} from "../util/electra.js"; +import {getMaxEffectiveBalance} from "../util/validator.js"; /** Same to https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/beacon-chain.md#has_flag */ const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX; @@ -60,10 +58,7 @@ export function processEffectiveBalanceUpdates( effectiveBalanceLimit = MAX_EFFECTIVE_BALANCE; } else { // from electra, effectiveBalanceLimit is per validator - const isCompoundingValidator = hasCompoundingWithdrawalCredential( - currentEpochValidators[i].withdrawalCredentials - ); - effectiveBalanceLimit = isCompoundingValidator ? MAX_EFFECTIVE_BALANCE_ELECTRA : MIN_ACTIVATION_BALANCE; + effectiveBalanceLimit = getMaxEffectiveBalance(currentEpochValidators[i].withdrawalCredentials); } if ( diff --git a/packages/state-transition/src/epoch/processPendingConsolidations.ts b/packages/state-transition/src/epoch/processPendingConsolidations.ts index 0c0d61fd78a9..0ec39409f8a7 100644 --- a/packages/state-transition/src/epoch/processPendingConsolidations.ts +++ b/packages/state-transition/src/epoch/processPendingConsolidations.ts @@ -1,6 +1,6 @@ import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; import {decreaseBalance, increaseBalance} from "../util/balance.js"; -import {getActiveBalance} from "../util/validator.js"; +import {getMaxEffectiveBalance} from "../util/validator.js"; /** * Starting from Electra: @@ -34,12 +34,13 @@ export function processPendingConsolidations(state: CachedBeaconStateElectra, ca break; } // Move active balance to target. Excess balance is withdrawable. - const activeBalance = getActiveBalance(state, sourceIndex); - decreaseBalance(state, sourceIndex, activeBalance); - increaseBalance(state, targetIndex, activeBalance); + const maxEffectiveBalance = getMaxEffectiveBalance(state.validators.getReadonly(sourceIndex).withdrawalCredentials); + const sourceEffectiveBalance = Math.min(state.balances.get(sourceIndex), maxEffectiveBalance); + decreaseBalance(state, sourceIndex, sourceEffectiveBalance); + increaseBalance(state, targetIndex, sourceEffectiveBalance); if (cachedBalances) { - cachedBalances[sourceIndex] -= activeBalance; - cachedBalances[targetIndex] += activeBalance; + cachedBalances[sourceIndex] -= sourceEffectiveBalance; + cachedBalances[targetIndex] += sourceEffectiveBalance; } nextPendingConsolidation++; diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index b64ac242f83c..3c29436c2e5d 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -1,14 +1,11 @@ import {Epoch, ValidatorIndex, ssz} from "@lodestar/types"; -import {FAR_FUTURE_EPOCH, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; +import {FAR_FUTURE_EPOCH, GENESIS_SLOT, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateDeneb} from "../types.js"; import {CachedBeaconStateElectra, getCachedBeaconState} from "../cache/stateCache.js"; -import { - hasCompoundingWithdrawalCredential, - queueEntireBalanceAndResetValidator, - queueExcessActiveBalance, -} from "../util/electra.js"; +import {hasCompoundingWithdrawalCredential, queueExcessActiveBalance} from "../util/electra.js"; import {computeActivationExitEpoch} from "../util/epoch.js"; import {getActivationExitChurnLimit, getConsolidationChurnLimit} from "../util/validator.js"; +import {G2_POINT_AT_INFINITY} from "../constants/constants.js"; /** * Upgrade a state from Deneb to Electra. @@ -93,7 +90,23 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache }); for (const validatorIndex of preActivation) { - queueEntireBalanceAndResetValidator(stateElectraView as CachedBeaconStateElectra, validatorIndex); + const stateElectra = stateElectraView as CachedBeaconStateElectra; + const balance = stateElectra.balances.get(validatorIndex); + stateElectra.balances.set(validatorIndex, 0); + + const validator = stateElectra.validators.get(validatorIndex); + validator.effectiveBalance = 0; + stateElectra.epochCtx.effectiveBalanceIncrementsSet(validatorIndex, 0); + validator.activationEligibilityEpoch = FAR_FUTURE_EPOCH; + + const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({ + pubkey: validator.pubkey, + withdrawalCredentials: validator.withdrawalCredentials, + amount: balance, + signature: G2_POINT_AT_INFINITY, + slot: GENESIS_SLOT, + }); + stateElectra.pendingDeposits.push(pendingDeposit); } for (let i = 0; i < validatorsArr.length; i++) { @@ -114,45 +127,3 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache return stateElectra; } - -export function upgradeStateToElectraOriginal(stateDeneb: CachedBeaconStateDeneb): CachedBeaconStateElectra { - const {config} = stateDeneb; - - const stateElectraNode = ssz.deneb.BeaconState.commitViewDU(stateDeneb); - const stateElectraView = ssz.electra.BeaconState.getViewDU(stateElectraNode); - - const stateElectra = getCachedBeaconState(stateElectraView, stateDeneb); - - stateElectra.fork = ssz.phase0.Fork.toViewDU({ - previousVersion: stateDeneb.fork.currentVersion, - currentVersion: config.ELECTRA_FORK_VERSION, - epoch: stateDeneb.epochCtx.epoch, - }); - - // default value of depositRequestsStartIndex is UNSET_DEPOSIT_REQUESTS_START_INDEX - stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_REQUESTS_START_INDEX; - - const validatorsArr = stateElectra.validators.getAllReadonly(); - - for (let i = 0; i < validatorsArr.length; i++) { - const validator = validatorsArr[i]; - - // [EIP-7251]: add validators that are not yet active to pending balance deposits - if (validator.activationEligibilityEpoch === FAR_FUTURE_EPOCH) { - queueEntireBalanceAndResetValidator(stateElectra, i); - } - - // [EIP-7251]: Ensure early adopters of compounding credentials go through the activation churn - const withdrawalCredential = validator.withdrawalCredentials; - if (hasCompoundingWithdrawalCredential(withdrawalCredential)) { - queueExcessActiveBalance(stateElectra, i); - } - } - - // Commit new added fields ViewDU to the root node - stateElectra.commit(); - // Clear cache to ensure the cache of deneb fields is not used by new ELECTRA fields - stateElectra["clearCache"](); - - return stateElectra; -} diff --git a/packages/state-transition/src/util/electra.ts b/packages/state-transition/src/util/electra.ts index c8522e17e29b..f1082c6d4603 100644 --- a/packages/state-transition/src/util/electra.ts +++ b/packages/state-transition/src/util/electra.ts @@ -1,4 +1,4 @@ -import {COMPOUNDING_WITHDRAWAL_PREFIX, FAR_FUTURE_EPOCH, GENESIS_SLOT, MIN_ACTIVATION_BALANCE} from "@lodestar/params"; +import {COMPOUNDING_WITHDRAWAL_PREFIX, GENESIS_SLOT, MIN_ACTIVATION_BALANCE} from "@lodestar/params"; import {ValidatorIndex, ssz} from "@lodestar/types"; import {CachedBeaconStateElectra} from "../types.js"; import {G2_POINT_AT_INFINITY} from "../constants/constants.js"; @@ -45,22 +45,3 @@ export function queueExcessActiveBalance(state: CachedBeaconStateElectra, index: state.pendingDeposits.push(pendingDeposit); } } - -export function queueEntireBalanceAndResetValidator(state: CachedBeaconStateElectra, index: ValidatorIndex): void { - const balance = state.balances.get(index); - state.balances.set(index, 0); - - const validator = state.validators.get(index); - validator.effectiveBalance = 0; - state.epochCtx.effectiveBalanceIncrementsSet(index, 0); - validator.activationEligibilityEpoch = FAR_FUTURE_EPOCH; - - const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({ - pubkey: validator.pubkey, - withdrawalCredentials: validator.withdrawalCredentials, - amount: balance, - signature: G2_POINT_AT_INFINITY, - slot: GENESIS_SLOT, - }); - state.pendingDeposits.push(pendingDeposit); -} diff --git a/packages/state-transition/src/util/validator.ts b/packages/state-transition/src/util/validator.ts index ebad21d9d25c..083b1ce1a572 100644 --- a/packages/state-transition/src/util/validator.ts +++ b/packages/state-transition/src/util/validator.ts @@ -84,14 +84,6 @@ export function getMaxEffectiveBalance(withdrawalCredentials: Uint8Array): numbe } } -export function getActiveBalance(state: CachedBeaconStateElectra, validatorIndex: ValidatorIndex): number { - const validatorMaxEffectiveBalance = getMaxEffectiveBalance( - state.validators.getReadonly(validatorIndex).withdrawalCredentials - ); - - return Math.min(state.balances.get(validatorIndex), validatorMaxEffectiveBalance); -} - export function getPendingBalanceToWithdraw(state: CachedBeaconStateElectra, validatorIndex: ValidatorIndex): number { return state.pendingPartialWithdrawals .getAllReadonly() From 2a7f7e6afd51137960b6d540be5354b3ad85bbed Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Mon, 14 Oct 2024 19:27:04 +0700 Subject: [PATCH 155/259] fix: make sure shuffling is calculated when querying next epoch proposers (#7156) * feat: make getBeaconProposersNextEpoch async to await for shuffling calculation * fix: build error in getBeaconProposersNextEpoch * fix: failed unit test * refactor: use tuyen suggestion to await for shuffling keeping state-transition sync --- packages/beacon-node/src/api/impl/validator/index.ts | 2 ++ packages/state-transition/src/cache/epochCache.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 9c5e6c2987f1..1fccf083070c 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -957,6 +957,8 @@ export function getValidatorApi( break; case stateEpoch + 1: + // make sure shuffling is calculated and ready for next call to calculate nextProposers + await chain.shufflingCache.get(state.epochCtx.nextEpoch, state.epochCtx.nextDecisionRoot); // Requesting duties for next epoch is allowed since they can be predicted with high probabilities. // @see `epochCtx.getBeaconProposersNextEpoch` JSDocs for rationale. indexes = state.epochCtx.getBeaconProposersNextEpoch(); diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 4eb16fa49927..5601162b2c2a 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -921,7 +921,7 @@ export class EpochCache { getBeaconProposersNextEpoch(): ValidatorIndex[] { if (!this.proposersNextEpoch.computed) { const indexes = computeProposers( - this.config.getForkSeqAtEpoch(this.epoch + 1), + this.config.getForkSeqAtEpoch(this.nextEpoch), this.proposersNextEpoch.seed, this.getShufflingAtEpoch(this.nextEpoch), this.effectiveBalanceIncrements From b5c6043202aae1e7662ac7678cdf2572af4ed686 Mon Sep 17 00:00:00 2001 From: twoeths Date: Mon, 14 Oct 2024 20:05:40 +0700 Subject: [PATCH 156/259] fix: queued attestations metric (#7158) --- .../beacon-node/src/metrics/metrics/beacon.ts | 2 +- .../fork-choice/src/forkChoice/forkChoice.ts | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/src/metrics/metrics/beacon.ts b/packages/beacon-node/src/metrics/metrics/beacon.ts index 1737a5a2468f..685fd56674ad 100644 --- a/packages/beacon-node/src/metrics/metrics/beacon.ts +++ b/packages/beacon-node/src/metrics/metrics/beacon.ts @@ -94,7 +94,7 @@ export function createBeaconMetrics(register: RegistryMetricCreator) { }), queuedAttestations: register.gauge({ name: "beacon_fork_choice_queued_attestations_count", - help: "Current count of queued_attestations in fork choice data structures", + help: "Count of queued_attestations in fork choice per slot", }), validatedAttestationDatas: register.gauge({ name: "beacon_fork_choice_validated_attestation_datas_count", diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index 6ca3fd3a183a..1084ec8b8e00 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -94,6 +94,12 @@ export class ForkChoice implements IForkChoice { () => new MapDef(() => new Set()) ); + /** + * It's inconsistent to count number of queued attestations at different intervals of slot. + * Instead of that, we count number of queued attestations at the previous slot. + */ + private queuedAttestationsPreviousSlot = 0; + // Note: as of Jun 2022 Lodestar metrics show that 100% of the times updateHead() is called, synced = false. // Because we are processing attestations from gossip, recomputing scores is always necessary // /** Avoid having to compute deltas all the times. */ @@ -129,13 +135,9 @@ export class ForkChoice implements IForkChoice { } getMetrics(): ForkChoiceMetrics { - let numAttestations = 0; - for (const indicesByRoot of this.queuedAttestations.values()) { - numAttestations += Array.from(indicesByRoot.values()).reduce((acc, indices) => acc + indices.size, 0); - } return { votes: this.votes.length, - queuedAttestations: numAttestations, + queuedAttestations: this.queuedAttestationsPreviousSlot, validatedAttestationDatas: this.validatedAttestationDatas.size, balancesLength: this.balances.length, nodes: this.protoArray.nodes.length, @@ -771,6 +773,7 @@ export class ForkChoice implements IForkChoice { this.onTick(previousSlot + 1); } + this.queuedAttestationsPreviousSlot = 0; // Process any attestations that might now be eligible. this.processAttestationQueue(); this.validatedAttestationDatas = new Set(); @@ -1373,6 +1376,10 @@ export class ForkChoice implements IForkChoice { // equivocatingIndices was checked in onAttestation this.addLatestMessage(validatorIndex, targetEpoch, blockRootHex); } + + if (slot === currentSlot - 1) { + this.queuedAttestationsPreviousSlot += validatorIndices.size; + } } } else { break; From 4e853d65c9950400fadc311c1584813a9cea3c4f Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Mon, 14 Oct 2024 20:55:14 +0200 Subject: [PATCH 157/259] style: enable all biomejs recommended rules (#7153) * Enable recomended correctness/noVoidTypeReturn * Enable recomended rule correctness/useYield * Enable recomended rule performance/noAccumulatingSpread * Enable recomended rule performance/noDelete * Enable recomended rule suspicious/noAsyncPromiseExecutor * Enable recommended rule suspicious/noDoubleEquals * Enable recommended rule suspicious/noDuplicateTestHooks * Enable recommended rule suspicious/noExportsInTest * Enable recommended rule suspicious/noFallthroughSwitchClause * Enable recommended rule suspicious/noGlobalIsFinite * Enable recommended rule suspicious/noGlobalIsNan * Enable recommended rule suspicious/noPrototypeBuiltins * Enable recommended rule suspicious/noShadowRestrictedNames * Enable recommended rule suspicious/useDefaultSwitchClauseLast * Enable recommended rule suspicious/useGetterReturn * Enable recommended rule style/noUnusedTemplateLiteral * Convert default case to unreachable code * Enable recommended rule complexity/noForEach * Enable recommended rule complexity/noThisInStatic * Enable recommended rule complexity/useFlatMap * Enable recommended rule complexity/useOptionalChain * Enable recommended rule complexity/useRegexLiterals * Reorganize the config structure * Fix few typos * Revert "Enable recomended rule performance/noDelete" This reverts commit 6cc060b03c487c632b6719349a9206378e953409. * Fix formatting * Enable recommended rule style/noUselessElse * Enable recommended rule complexity/useLiteralKeys * Enable recommended rule complexity/useArrowFunction * Fix few types * Fix a test file * Fix formatting * Enable recommended rule suspicious/noImplicitAnyLet * Enable recommended rule complexity/noUselessEmptyExport * Fix types * Fix unti tests * Fix unit test * Fix lint error * Fix a unit test pattern * Fix formatting --- biome.jsonc | 88 +++----- packages/api/src/beacon/server/events.ts | 4 +- packages/api/src/utils/client/eventSource.ts | 3 +- packages/api/src/utils/client/httpClient.ts | 36 ++-- packages/api/src/utils/client/response.ts | 6 +- packages/api/src/utils/codecs.ts | 6 +- packages/api/src/utils/headers.ts | 2 +- packages/api/src/utils/httpStatusCode.ts | 2 - packages/api/src/utils/serdes.ts | 5 +- packages/api/test/unit/client/fetch.test.ts | 6 +- .../unit/client/httpClientFallback.test.ts | 8 +- packages/api/test/utils/checkAgainstSpec.ts | 10 +- packages/api/test/utils/parseOpenApiSpec.ts | 2 +- packages/api/test/utils/utils.ts | 4 +- .../src/api/impl/beacon/blocks/index.ts | 28 ++- .../src/api/impl/beacon/blocks/utils.ts | 2 +- .../src/api/impl/beacon/state/index.ts | 4 +- .../src/api/impl/beacon/state/utils.ts | 2 +- .../src/api/impl/lodestar/index.ts | 5 +- .../beacon-node/src/api/impl/node/index.ts | 5 +- .../src/api/impl/validator/index.ts | 94 +++++---- .../beacon-node/src/chain/balancesCache.ts | 2 +- .../beacon-node/src/chain/blocks/index.ts | 12 +- .../blocks/verifyBlocksDataAvailability.ts | 1 + .../chain/blocks/verifyBlocksSanityChecks.ts | 15 +- .../src/chain/blocks/writeBlockInputToDb.ts | 2 +- .../src/chain/bls/multithread/index.ts | 3 +- packages/beacon-node/src/chain/chain.ts | 69 ++++--- .../beacon-node/src/chain/genesis/genesis.ts | 12 +- .../src/chain/lightClient/index.ts | 10 +- .../opPools/aggregatedAttestationPool.ts | 82 ++++---- .../src/chain/opPools/attestationPool.ts | 7 +- .../beacon-node/src/chain/opPools/opPool.ts | 5 +- .../chain/opPools/syncCommitteeMessagePool.ts | 8 +- .../opPools/syncContributionAndProofPool.ts | 5 +- .../chain/produceBlock/produceBlockBody.ts | 40 ++-- .../beacon-node/src/chain/regen/queued.ts | 2 +- .../src/chain/rewards/attestationsRewards.ts | 2 +- .../src/chain/rewards/blockRewards.ts | 4 +- .../src/chain/rewards/syncCommitteeRewards.ts | 4 +- .../chain/seenCache/seenGossipBlockInput.ts | 66 +++--- .../beacon-node/src/chain/shufflingCache.ts | 5 +- .../src/chain/stateCache/datastore/file.ts | 2 +- .../src/chain/validation/aggregateAndProof.ts | 2 +- .../src/chain/validation/attestation.ts | 55 +++-- .../validation/lightClientFinalityUpdate.ts | 6 +- .../validation/lightClientOptimisticUpdate.ts | 6 +- packages/beacon-node/src/db/buckets.ts | 7 +- .../src/db/repositories/blockArchive.ts | 2 +- .../src/db/repositories/blockArchiveIndex.ts | 2 +- .../src/db/repositories/depositDataRoot.ts | 4 +- .../beacon-node/src/eth1/eth1DataCache.ts | 2 +- .../src/eth1/eth1DepositDataTracker.ts | 30 ++- .../beacon-node/src/eth1/eth1DepositsCache.ts | 4 +- .../src/eth1/eth1MergeBlockTracker.ts | 91 ++++----- packages/beacon-node/src/eth1/index.ts | 10 +- .../src/eth1/provider/jsonRpcHttpClient.ts | 14 +- .../beacon-node/src/eth1/provider/utils.ts | 2 +- .../beacon-node/src/eth1/utils/deposits.ts | 4 +- .../beacon-node/src/eth1/utils/eth1Vote.ts | 10 +- .../utils/optimizeNextBlockDiffForGenesis.ts | 3 +- .../beacon-node/src/execution/engine/http.ts | 6 +- .../beacon-node/src/execution/engine/mock.ts | 22 +- .../src/metrics/validatorMonitor.ts | 90 ++++----- .../beacon-node/src/monitoring/properties.ts | 6 +- .../beacon-node/src/monitoring/service.ts | 6 +- .../src/network/core/networkCore.ts | 6 + .../src/network/gossip/encoding.ts | 3 +- .../src/network/gossip/gossipsub.ts | 12 +- .../beacon-node/src/network/gossip/topic.ts | 2 +- .../beacon-node/src/network/peers/discover.ts | 19 +- .../src/network/peers/peerManager.ts | 9 +- .../network/processor/gossipQueues/index.ts | 3 +- .../network/processor/gossipQueues/indexed.ts | 3 +- .../network/processor/gossipQueues/linear.ts | 12 +- .../reqresp/beaconBlocksMaybeBlobsByRange.ts | 6 +- .../reqresp/beaconBlocksMaybeBlobsByRoot.ts | 8 +- .../reqresp/handlers/lightClientBootstrap.ts | 3 +- .../handlers/lightClientFinalityUpdate.ts | 14 +- .../handlers/lightClientOptimisticUpdate.ts | 14 +- .../handlers/lightClientUpdatesByRange.ts | 3 +- .../beacon-node/src/network/reqresp/types.ts | 9 +- packages/beacon-node/src/network/util.ts | 1 + packages/beacon-node/src/node/nodejs.ts | 2 +- packages/beacon-node/src/node/notifier.ts | 51 +++-- .../beacon-node/src/sync/backfill/backfill.ts | 5 +- packages/beacon-node/src/sync/range/range.ts | 6 +- .../src/sync/range/utils/batches.ts | 4 +- packages/beacon-node/src/sync/sync.ts | 52 ++--- packages/beacon-node/src/sync/unknownBlock.ts | 21 +- .../src/sync/utils/remoteSyncType.ts | 57 +++--- packages/beacon-node/src/util/binarySearch.ts | 2 +- packages/beacon-node/src/util/bitArray.ts | 2 +- packages/beacon-node/src/util/kzg.ts | 5 +- .../api/impl/beacon/block/endpoint.test.ts | 2 +- .../api/impl/beacon/node/endpoints.test.ts | 2 +- .../api/impl/beacon/state/endpoint.test.ts | 2 +- .../test/e2e/api/impl/config.test.ts | 2 +- .../e2e/api/impl/lightclient/endpoint.test.ts | 10 +- .../test/e2e/api/lodestar/lodestar.test.ts | 8 +- .../test/e2e/chain/bls/multithread.test.ts | 27 +-- .../test/e2e/chain/lightclient.test.ts | 8 +- .../test/e2e/chain/proposerBoostReorg.test.ts | 2 +- .../stateCache/nHistoricalStates.test.ts | 4 +- .../beacon/repositories/blockArchive.test.ts | 2 +- .../e2e/doppelganger/doppelganger.test.ts | 14 +- .../e2e/eth1/eth1ForBlockProduction.test.ts | 4 +- .../e2e/eth1/eth1MergeBlockTracker.test.ts | 2 +- .../test/e2e/eth1/eth1Provider.test.ts | 18 +- .../test/e2e/eth1/jsonRpcHttpClient.test.ts | 22 +- .../beacon-node/test/e2e/eth1/stream.test.ts | 6 +- .../test/e2e/network/gossipsub.test.ts | 16 +- .../beacon-node/test/e2e/network/mdns.test.ts | 17 +- .../test/e2e/network/network.test.ts | 12 +- .../onWorker/dataSerialization.test.ts | 2 +- .../e2e/network/peers/peerManager.test.ts | 6 +- .../test/e2e/network/reqresp.test.ts | 28 +-- .../test/e2e/network/reqrespEncode.test.ts | 1 + .../test/e2e/sync/finalizedSync.test.ts | 4 +- .../test/e2e/sync/unknownBlockSync.test.ts | 4 +- .../test/memory/unfinalizedPubkey2Index.ts | 1 + .../beacon-node/test/perf/bls/bls.test.ts | 2 +- .../seenCache/seenAggregateAndProof.test.ts | 2 +- .../inMemoryCheckpointsCache.test.ts | 2 +- .../updateUnfinalizedPubkeys.test.ts | 2 +- .../perf/chain/verifyImportBlocks.test.ts | 20 +- .../test/perf/network/gossip/encoding.test.ts | 2 +- .../peers/util/prioritizePeers.test.ts | 2 +- .../beacon-node/test/perf/util/bytes.test.ts | 2 +- .../test/perf/util/dataview.test.ts | 2 +- .../test/perf/util/transferBytes.test.ts | 2 +- .../test/sim/electra-interop.test.ts | 18 +- .../beacon-node/test/sim/mergemock.test.ts | 8 +- .../beacon-node/test/spec/bls/index.test.ts | 2 +- packages/beacon-node/test/spec/general/bls.ts | 3 +- .../test/spec/general/ssz_generic_types.ts | 4 +- .../spec/presets/epoch_processing.test.ts | 2 +- .../test/spec/presets/light_client/sync.ts | 2 +- .../test/spec/presets/ssz_static.test.ts | 4 +- .../test/spec/presets/transition.test.ts | 2 +- .../test/spec/utils/runValidSszTest.ts | 4 +- .../network/gossip/scoringParameters.test.ts | 2 +- .../test/unit/api/impl/beacon/beacon.test.ts | 8 +- .../beacon/blocks/getBlockHeaders.test.ts | 20 +- .../unit/api/impl/beacon/state/utils.test.ts | 2 +- .../test/unit/api/impl/config/config.test.ts | 16 +- .../test/unit/api/impl/events/events.test.ts | 14 +- .../impl/validator/duties/proposer.test.ts | 4 +- .../validator/produceAttestationData.test.ts | 8 +- .../api/impl/validator/produceBlockV2.test.ts | 4 +- .../api/impl/validator/produceBlockV3.test.ts | 188 +++++++++--------- .../unit/chain/archive/blockArchiver.test.ts | 6 +- .../test/unit/chain/beaconProposerCache.ts | 12 +- .../blocks/verifyBlocksSanityChecks.test.ts | 2 +- .../test/unit/chain/bls/bls.test.ts | 2 +- .../unit/chain/forkChoice/forkChoice.test.ts | 4 +- .../test/unit/chain/genesis/genesis.test.ts | 2 +- .../upgradeLightClientHeader.test.ts | 8 +- .../opPools/aggregatedAttestationPool.test.ts | 12 +- .../chain/opPools/attestationPool.test.ts | 4 +- .../unit/chain/opPools/syncCommittee.test.ts | 4 +- .../opPools/syncCommitteeContribution.test.ts | 6 +- .../test/unit/chain/reprocess.test.ts | 2 +- .../chain/seenCache/aggregateAndProof.test.ts | 4 +- .../chain/seenCache/syncCommittee.test.ts | 2 +- .../test/unit/chain/shufflingCache.test.ts | 10 +- .../stateCache/blockStateCacheImpl.test.ts | 8 +- .../stateCache/fifoBlockStateCache.test.ts | 4 +- .../inMemoryCheckpointsCache.test.ts | 2 +- .../persistentCheckpointsCache.test.ts | 20 +- ...hufflingForAttestationVerification.test.ts | 18 +- .../test/unit/chain/validation/block.test.ts | 26 +-- .../lightClientFinalityUpdate.test.ts | 2 +- .../lightClientOptimisticUpdate.test.ts | 2 +- .../chain/validation/syncCommittee.test.ts | 26 +-- .../db/api/repositories/blockArchive.test.ts | 20 +- .../test/unit/db/api/repository.test.ts | 30 +-- .../beacon-node/test/unit/db/buckets.test.ts | 2 +- .../unit/eth1/eth1DepositDataTracker.test.ts | 6 +- .../unit/eth1/eth1MergeBlockTracker.test.ts | 9 +- .../unit/eth1/utils/depositContract.test.ts | 2 +- .../test/unit/eth1/utils/deposits.test.ts | 8 +- .../test/unit/eth1/utils/eth1Data.test.ts | 12 +- .../unit/eth1/utils/eth1DepositEvent.test.ts | 2 +- .../test/unit/eth1/utils/eth1Vote.test.ts | 10 +- .../utils/groupDepositEventsByBlock.test.ts | 2 +- .../optimizeNextBlockDiffForGenesis.test.ts | 5 +- .../unit/executionEngine/httpRetry.test.ts | 12 +- .../test/unit/monitoring/remoteService.ts | 12 +- .../test/unit/monitoring/service.test.ts | 4 +- .../beaconBlocksMaybeBlobsByRange.test.ts | 2 +- .../test/unit/network/gossip/topic.test.ts | 2 +- .../test/unit/network/metadata.test.ts | 2 +- .../unit/network/peers/priorization.test.ts | 2 +- .../test/unit/network/peers/score.test.ts | 8 +- .../test/unit/network/processorQueues.test.ts | 6 +- .../network/subnets/attnetsService.test.ts | 2 +- .../test/unit/network/util.test.ts | 6 +- .../test/unit/sync/backfill/verify.test.ts | 8 +- .../test/unit/sync/unknownBlock.test.ts | 2 +- .../beacon-node/test/unit/util/array.test.ts | 6 +- .../beacon-node/test/unit/util/clock.test.ts | 6 +- .../test/unit/util/dependentRoot.test.ts | 6 +- .../beacon-node/test/unit/util/file.test.ts | 6 +- .../beacon-node/test/unit/util/kzg.test.ts | 6 +- .../test/unit/util/wrapError.test.ts | 6 +- packages/beacon-node/test/utils/cache.ts | 2 +- packages/beacon-node/test/utils/errors.ts | 8 +- packages/beacon-node/test/utils/runEl.ts | 4 +- packages/cli/src/applyPreset.ts | 3 - .../cli/src/cmds/beacon/initBeaconState.ts | 38 ++-- .../cli/src/cmds/beacon/initPeerIdAndEnr.ts | 8 +- packages/cli/src/cmds/bootnode/options.ts | 2 +- packages/cli/src/cmds/dev/options.ts | 4 +- packages/cli/src/cmds/validator/handler.ts | 8 +- .../cli/src/cmds/validator/keymanager/impl.ts | 3 +- .../src/cmds/validator/keymanager/server.ts | 3 +- packages/cli/src/cmds/validator/options.ts | 7 +- .../signers/importExternalKeystores.ts | 20 +- .../cli/src/cmds/validator/signers/index.ts | 77 ++++--- .../src/cmds/validator/signers/logSigners.ts | 6 +- .../validator/slashingProtection/export.ts | 3 +- .../cli/src/cmds/validator/voluntaryExit.ts | 11 +- packages/cli/src/networks/dev.ts | 3 +- packages/cli/src/networks/index.ts | 2 +- .../cli/src/options/beaconNodeOptions/api.ts | 4 +- .../src/options/beaconNodeOptions/builder.ts | 2 +- .../src/options/beaconNodeOptions/chain.ts | 6 +- .../cli/src/options/beaconNodeOptions/eth1.ts | 12 +- .../options/beaconNodeOptions/execution.ts | 10 +- .../src/options/beaconNodeOptions/metrics.ts | 2 +- .../src/options/beaconNodeOptions/network.ts | 18 +- packages/cli/src/options/logOptions.ts | 2 +- packages/cli/src/options/paramsOptions.ts | 10 +- packages/cli/src/util/file.ts | 6 +- packages/cli/src/util/format.ts | 4 +- packages/cli/src/util/fs.ts | 6 +- packages/cli/src/util/jwt.ts | 2 +- packages/cli/src/util/logger.ts | 6 +- .../cli/test/e2e/blsToExecutionchange.test.ts | 2 +- .../cli/test/e2e/importFromFsDirect.test.ts | 16 +- .../cli/test/e2e/importFromFsPreStep.test.ts | 6 +- .../test/e2e/importKeystoresFromApi.test.ts | 8 +- .../test/e2e/importRemoteKeysFromApi.test.ts | 6 +- .../e2e/propserConfigfromKeymanager.test.ts | 2 +- packages/cli/test/e2e/runDevCmd.test.ts | 2 +- packages/cli/test/e2e/validatorList.test.ts | 4 +- packages/cli/test/e2e/voluntaryExit.test.ts | 5 +- .../cli/test/e2e/voluntaryExitFromApi.test.ts | 5 +- .../e2e/voluntaryExitRemoteSigner.test.ts | 5 +- packages/cli/test/unit/util/gitData.test.ts | 2 +- packages/cli/test/unit/util/logger.test.ts | 2 +- packages/cli/test/unit/validator/keys.test.ts | 2 +- .../defaults/attestationCountAssertion.ts | 2 +- .../crucible/assertions/nodeAssertion.ts | 4 +- .../utils/crucible/clients/beacon/lodestar.ts | 4 +- .../utils/crucible/clients/execution/geth.ts | 2 +- .../cli/test/utils/crucible/tableReporter.ts | 19 +- .../cli/test/utils/crucible/utils/network.ts | 3 +- .../cli/test/utils/crucible/utils/paths.ts | 11 +- .../cli/test/utils/crucible/utils/syncing.ts | 3 +- packages/db/src/controller/level.ts | 10 +- packages/db/src/util.ts | 2 +- packages/flare/src/cmds/selfSlashAttester.ts | 2 +- packages/flare/src/cmds/selfSlashProposer.ts | 2 +- packages/flare/src/util/format.ts | 4 +- .../fork-choice/src/forkChoice/forkChoice.ts | 8 +- .../src/protoArray/computeDeltas.ts | 4 +- .../fork-choice/src/protoArray/protoArray.ts | 13 +- .../test/unit/forkChoice/forkChoice.test.ts | 22 +- .../unit/forkChoice/getProposerHead.test.ts | 4 +- .../test/unit/forkChoice/utils.test.ts | 12 +- .../unit/protoArray/getCommonAncestor.test.ts | 6 +- packages/fork-choice/test/utils/index.ts | 19 ++ .../light-client/src/spec/isBetterUpdate.ts | 22 +- packages/light-client/src/spec/utils.ts | 4 + packages/light-client/src/utils/clock.ts | 4 +- .../unit/isValidLightClientHeader.test.ts | 8 +- .../test/unit/syncInMemory.test.ts | 4 +- .../light-client/test/unit/validation.test.ts | 4 +- packages/logger/src/browser.ts | 2 +- packages/logger/src/env.ts | 12 +- packages/logger/src/node.ts | 2 +- packages/logger/src/utils/json.ts | 10 +- packages/logger/src/winston.ts | 2 +- .../logger/test/e2e/logger/workerLogs.test.ts | 2 +- packages/logger/test/unit/utils/json.test.ts | 4 +- packages/params/src/json.ts | 2 +- .../test/e2e/ensure-config-is-synced.test.ts | 6 +- .../params/test/e2e/overridePreset.test.ts | 2 +- packages/params/test/e2e/setPreset.test.ts | 2 +- packages/params/test/yaml.ts | 4 +- packages/prover/src/cli/applyPreset.ts | 3 - packages/prover/src/cli/cmds/start/options.ts | 4 +- .../src/proof_provider/payload_store.ts | 2 +- packages/prover/src/utils/process.ts | 3 +- .../prover/src/web3_provider_inspector.ts | 2 +- .../prover/test/e2e/cli/cmds/start.test.ts | 2 +- .../test/e2e/web3_batch_request.test.ts | 2 +- .../prover/test/e2e/web3_provider.test.ts | 2 +- .../unit/proof_provider/payload_store.test.ts | 2 +- .../reqresp/src/encoders/responseDecode.ts | 3 +- .../sszSnappy/snappyFrames/uncompress.ts | 3 +- .../src/rate_limiter/ReqRespRateLimiter.ts | 4 +- packages/reqresp/src/request/index.ts | 9 +- packages/reqresp/src/response/index.ts | 8 +- packages/reqresp/src/utils/abortableSource.ts | 4 +- packages/reqresp/src/utils/bufferedSource.ts | 8 +- .../sszSnappy/snappyFrames/uncompress.test.ts | 10 +- packages/reqresp/test/utils/errors.ts | 7 +- packages/spec-test-util/src/downloadTests.ts | 3 +- packages/spec-test-util/src/single.ts | 54 ++--- .../src/block/isValidIndexedAttestation.ts | 6 +- .../src/block/processAttestationPhase0.ts | 17 +- .../src/block/processEth1Data.ts | 3 +- .../src/block/processSyncCommittee.ts | 3 +- .../state-transition/src/cache/epochCache.ts | 33 ++- .../state-transition/src/cache/stateCache.ts | 2 + .../epoch/processPendingBalanceDeposits.ts | 13 +- packages/state-transition/src/metrics.ts | 2 + .../src/signatureSets/attesterSlashings.ts | 6 +- .../src/signatureSets/proposerSlashings.ts | 6 +- .../src/slot/upgradeStateToAltair.ts | 1 + .../src/slot/upgradeStateToCapella.ts | 1 + .../src/slot/upgradeStateToDeneb.ts | 1 + .../src/slot/upgradeStateToElectra.ts | 2 + .../state-transition/src/util/blindedBlock.ts | 12 +- .../src/util/computeAnchorCheckpoint.ts | 4 +- packages/state-transition/src/util/deposit.ts | 6 +- .../state-transition/src/util/execution.ts | 20 +- .../src/util/loadState/loadValidator.ts | 3 +- .../src/util/shufflingDecisionRoot.ts | 13 +- .../state-transition/src/util/validator.ts | 6 +- .../state-transition/test/perf/block/util.ts | 2 + packages/state-transition/test/perf/csv.ts | 2 +- .../test/perf/dataStructures/arrayish.test.ts | 2 +- .../test/perf/misc/aggregationBits.test.ts | 2 +- .../test/perf/misc/arrayCreation.test.ts | 2 +- .../test/perf/misc/proxy.test.ts | 3 +- packages/state-transition/test/perf/util.ts | 4 +- .../test/perf/util/signingRoot.test.ts | 2 +- .../test/unit/util/aggregator.test.ts | 12 +- .../test/unit/util/validator.test.ts | 2 +- .../test/unit/util/weakSubjectivity.test.ts | 2 +- .../test/utils/beforeValue.ts | 10 +- .../test/utils/beforeValueMocha.ts | 9 +- packages/state-transition/test/utils/rand.ts | 2 +- .../test/utils/testFileCache.ts | 62 +++--- packages/test-utils/src/cli.ts | 3 +- packages/types/src/phase0/validator.ts | 1 + packages/types/src/primitive/sszTypes.ts | 1 + packages/types/src/utils/validatorStatus.ts | 8 +- packages/types/test/unit/blinded.test.ts | 2 +- .../types/test/unit/phase0/sszTypes.test.ts | 2 +- packages/types/test/unit/ssz.test.ts | 8 +- .../types/test/unit/validatorStatus.test.ts | 22 +- packages/utils/src/bytes.ts | 6 +- packages/utils/src/bytes/nodejs.ts | 6 +- packages/utils/src/diff.ts | 4 +- packages/utils/src/objects.ts | 6 +- packages/utils/src/retry.ts | 8 +- packages/utils/src/sleep.ts | 2 +- packages/utils/src/url.ts | 2 +- packages/utils/src/yaml/int.ts | 4 +- packages/utils/test/perf/bytes.test.ts | 2 +- packages/utils/test/unit/math.test.ts | 2 +- packages/utils/test/unit/promise.node.test.ts | 2 +- packages/utils/test/unit/promiserace.test.ts | 3 +- packages/utils/test/unit/retry.test.ts | 3 +- packages/utils/test/unit/sleep.test.ts | 8 +- packages/utils/test/unit/timeout.test.ts | 14 +- packages/validator/src/buckets.ts | 8 +- packages/validator/src/services/block.ts | 63 +++--- .../src/services/doppelgangerService.ts | 9 +- .../validator/src/services/validatorStore.ts | 41 ++-- .../slashingProtection/attestation/index.ts | 13 +- .../src/slashingProtection/block/index.ts | 14 +- packages/validator/src/util/clock.ts | 15 +- .../src/util/externalSignerClient.ts | 14 +- packages/validator/src/validator.ts | 2 +- .../validator/test/e2e/web3signer.test.ts | 4 +- .../test/unit/services/attestation.test.ts | 2 +- .../unit/services/attestationDuties.test.ts | 8 +- .../test/unit/services/block.test.ts | 6 +- .../test/unit/services/blockDuties.test.ts | 6 +- .../test/unit/services/indicesService.test.ts | 4 +- .../unit/services/syncCommitteDuties.test.ts | 10 +- .../test/unit/services/syncCommittee.test.ts | 2 +- .../services/syncingStatusTracker.test.ts | 8 +- .../validator/test/unit/utils/batch.test.ts | 2 +- .../validator/test/unit/utils/clock.test.ts | 6 +- .../test/unit/validatorStore.test.ts | 4 +- 392 files changed, 1852 insertions(+), 1919 deletions(-) create mode 100644 packages/fork-choice/test/utils/index.ts diff --git a/biome.jsonc b/biome.jsonc index b49fc601600c..62d67fb7575f 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -24,27 +24,8 @@ "enabled": true, "rules": { "recommended": true, - "complexity": { - "noForEach": "off", - "noStaticOnlyClass": "off", - "noThisInStatic": "off", - "noUselessEmptyExport": "off", - "noUselessTypeConstraint": "error", - "useArrowFunction": "off", - "useFlatMap": "off", - "useLiteralKeys": "off", - "useOptionalChain": "off", - "useRegexLiterals": "off", - "noBannedTypes": "error", - "noUselessThisAlias": "error" - }, "correctness": { - "noInvalidConstructorSuper": "off", - "noInvalidUseBeforeDeclaration": "off", - "noPrecisionLoss": "error", "noUnusedVariables": "error", - "noVoidTypeReturn": "off", - "useYield": "off", "useImportExtensions": { "level": "error", "options": { @@ -57,17 +38,16 @@ } }, "useArrayLiterals": "error", - "noUndeclaredDependencies": "off", // TODO: Need to see why this rule is not detecting monorepo packages "noUndeclaredVariables": "error" }, "performance": { - "noAccumulatingSpread": "off", + // This rule should be enabled but with considerations and careful review "noDelete": "off" }, "style": { + // The code usage looks suspicious so it should be enabled in a separate PR "noCommaOperator": "off", - "noInferrableTypes": "off", - "noNonNullAssertion": "error", + // There are a lot of places we mutate params, should be fixed in an independent PR. "noParameterAssign": "off", "noRestrictedGlobals": { "level": "error", @@ -75,15 +55,24 @@ "deniedGlobals": ["fetch"] } }, - "noUnusedTemplateLiteral": "off", - "noUselessElse": "off", - "noVar": "error", - "useConst": "error", - "useEnumInitializers": "off", + // We prefer to use `Math.pow` over `**` operator "useExponentiationOperator": "off", + // In some cases the enums are initialized with values of other enums + "useLiteralEnumMembers": "off", + // We prefer to have multiple declarations lines + "useSingleVarDeclarator": "off", + // We use `+` operator for string concatenation a lot + "useTemplate": "off", + // We use to export types and object without differentiating "useExportType": "off", + // We use to import types and object without differentiating "useImportType": "off", - "useLiteralEnumMembers": "off", + // It's nice to use `Number` namespace but should be done in a separate PR + "useNumberNamespace": "off", + // We prefer to auto-initialize enums + "useEnumInitializers": "off", + "noVar": "error", + "useConst": "error", "useNamingConvention": { "level": "error", "options": { @@ -194,34 +183,14 @@ ] } }, - "useNumberNamespace": "off", - "useSingleVarDeclarator": "off", - "useTemplate": "off", - "noNamespace": "error", - "useAsConstAssertion": "error" + "noNamespace": "error" }, "suspicious": { - "noAssignInExpressions": "error", - "noAsyncPromiseExecutor": "off", + // `void` as type is useful in our case when used as generic constraint e.g. K extends number | void "noConfusingVoidType": "off", - "noConsoleLog": "error", - "noDoubleEquals": "off", - "noDuplicateTestHooks": "off", - "noExplicitAny": "error", - "noExportsInTest": "off", - "noFallthroughSwitchClause": "off", - "noGlobalIsFinite": "off", - "noGlobalIsNan": "off", - "noImplicitAnyLet": "off", - "noPrototypeBuiltins": "off", - "noRedundantUseStrict": "off", - "noShadowRestrictedNames": "off", - "useDefaultSwitchClauseLast": "off", - "useGetterReturn": "off", - "noExtraNonNullAssertion": "error", - "noMisleadingInstantiator": "error", - "noUnsafeDeclarationMerging": "error", - "noEmptyBlockStatements": "off" // There is a lot of empty code blocks, should be enabled and clean up separately. + // There is a lot of empty code blocks, should be enabled and clean up separately. + "noEmptyBlockStatements": "off", + "noConsoleLog": "error" }, "nursery": { "useConsistentMemberAccessibility": { @@ -369,7 +338,16 @@ { "include": ["**/test/**/*.test.ts"], "linter": { - "rules": {} + "rules": { + "complexity": { + // During tests we often need to use private/protected attributes, which is only possible with literal keys + "useLiteralKeys": "off" + }, + "suspicious": { + // During tests it's quicker to define variables with `let` without specifying types + "noImplicitAnyLet": "off" + } + } } } ] diff --git a/packages/api/src/beacon/server/events.ts b/packages/api/src/beacon/server/events.ts index 96212f006d8f..b9027ab1879d 100644 --- a/packages/api/src/beacon/server/events.ts +++ b/packages/api/src/beacon/server/events.ts @@ -23,9 +23,9 @@ export function getRoutes(config: ChainForkConfig, methods: ApplicationMethods { + for (const [key, value] of Object.entries(res.getHeaders())) { if (value !== undefined) res.raw.setHeader(key, value); - }); + } res.raw.setHeader("Content-Type", "text/event-stream"); res.raw.setHeader("Cache-Control", "no-cache,no-transform"); diff --git a/packages/api/src/utils/client/eventSource.ts b/packages/api/src/utils/client/eventSource.ts index 2e2cf0076068..f023a0ec5f0b 100644 --- a/packages/api/src/utils/client/eventSource.ts +++ b/packages/api/src/utils/client/eventSource.ts @@ -2,7 +2,6 @@ export async function getEventSource(): Promise { if (globalThis.EventSource) { return EventSource; - } else { - return (await import("eventsource")).default as unknown as typeof EventSource; } + return (await import("eventsource")).default as unknown as typeof EventSource; } diff --git a/packages/api/src/utils/client/httpClient.ts b/packages/api/src/utils/client/httpClient.ts index eec86725fcaa..721a150f7fcd 100644 --- a/packages/api/src/utils/client/httpClient.ts +++ b/packages/api/src/utils/client/httpClient.ts @@ -155,12 +155,10 @@ export class HttpClient implements IHttpClient { if (init.retries > 0) { return this.requestWithRetries(definition, args, init); - } else { - return this.getRequestMethod(init)(definition, args, init); } - } else { - return this.requestWithFallbacks(definition, args, localInit); + return this.getRequestMethod(init)(definition, args, init); } + return this.requestWithFallbacks(definition, args, localInit); } /** @@ -252,19 +250,16 @@ export class HttpClient implements IHttpClient { }); if (res.ok) { return res; - } else { - if (i >= this.urlsInits.length - 1) { - return res; - } else { - this.logger?.debug("Request error, retrying", {}, res.error() as Error); - } } + if (i >= this.urlsInits.length - 1) { + return res; + } + this.logger?.debug("Request error, retrying", {}, res.error() as Error); } catch (e) { if (i >= this.urlsInits.length - 1) { throw e; - } else { - this.logger?.debug("Request error, retrying", {}, e as Error); } + this.logger?.debug("Request error, retrying", {}, e as Error); } } @@ -352,7 +347,9 @@ export class HttpClient implements IHttpClient { // Attach global/local signal to this request's controller const onSignalAbort = (): void => controller.abort(); - abortSignals.forEach((s) => s?.addEventListener("abort", onSignalAbort)); + for (const s of abortSignals) { + s?.addEventListener("abort", onSignalAbort); + } const routeId = definition.operationId; const {printableUrl, requestWireFormat, responseWireFormat} = init; @@ -389,19 +386,20 @@ export class HttpClient implements IHttpClient { if (isAbortedError(e)) { if (abortSignals.some((s) => s?.aborted)) { throw new ErrorAborted(`${routeId} request`); - } else if (controller.signal.aborted) { + } + if (controller.signal.aborted) { throw new TimeoutError(`${routeId} request`); - } else { - throw Error("Unknown aborted error"); } - } else { - throw e; + throw Error("Unknown aborted error"); } + throw e; } finally { timer?.(); clearTimeout(timeout); - abortSignals.forEach((s) => s?.removeEventListener("abort", onSignalAbort)); + for (const s of abortSignals) { + s?.removeEventListener("abort", onSignalAbort); + } } } diff --git a/packages/api/src/utils/client/response.ts b/packages/api/src/utils/client/response.ts index 7a4c4fb98ce4..626252b9aaca 100644 --- a/packages/api/src/utils/client/response.ts +++ b/packages/api/src/utils/client/response.ts @@ -35,9 +35,8 @@ export class ApiResponse extends Response { if (this.status === HttpStatusCode.NO_CONTENT) { this._wireFormat = null; return this._wireFormat; - } else { - throw Error("Content-Type header is required in response"); } + throw Error("Content-Type header is required in response"); } const mediaType = parseContentTypeHeader(contentType); @@ -197,9 +196,8 @@ export class ApiResponse extends Response { return `${errJson.message}\n` + errJson.failures.map((e) => e.message).join("\n"); } return errJson.message; - } else { - return errBody; } + return errBody; } catch (_e) { return errBody || this.statusText; } diff --git a/packages/api/src/utils/codecs.ts b/packages/api/src/utils/codecs.ts index 54214740f435..db96daf0ce50 100644 --- a/packages/api/src/utils/codecs.ts +++ b/packages/api/src/utils/codecs.ts @@ -68,11 +68,11 @@ export const EmptyResponseCodec: ResponseCodec = { export function ArrayOf(elementType: Type, limit = Infinity): ArrayType, unknown, unknown> { if (isCompositeType(elementType)) { return new ListCompositeType(elementType, limit) as unknown as ArrayType, unknown, unknown>; - } else if (isBasicType(elementType)) { + } + if (isBasicType(elementType)) { return new ListBasicType(elementType, limit) as unknown as ArrayType, unknown, unknown>; - } else { - throw Error(`Unknown type ${elementType.typeName}`); } + throw Error(`Unknown type ${elementType.typeName}`); } export function WithMeta(getType: (m: M) => Type): ResponseDataCodec { diff --git a/packages/api/src/utils/headers.ts b/packages/api/src/utils/headers.ts index 5f3c6e3e1dfc..7547ac022a7a 100644 --- a/packages/api/src/utils/headers.ts +++ b/packages/api/src/utils/headers.ts @@ -70,7 +70,7 @@ export function parseAcceptHeader(accept?: string, supported = SUPPORTED_MEDIA_T } const qvalue = +weight.replace("q=", ""); - if (isNaN(qvalue) || qvalue > 1 || qvalue <= 0) { + if (Number.isNaN(qvalue) || qvalue > 1 || qvalue <= 0) { // If we can't convert the qvalue to a valid number, move on return best; } diff --git a/packages/api/src/utils/httpStatusCode.ts b/packages/api/src/utils/httpStatusCode.ts index 572562e7da3d..2316f3d1db87 100644 --- a/packages/api/src/utils/httpStatusCode.ts +++ b/packages/api/src/utils/httpStatusCode.ts @@ -1,5 +1,3 @@ -"use strict"; - /** * Hypertext Transfer Protocol (HTTP) response status codes. * @see {@link https://www.rfc-editor.org/rfc/rfc7231#section-6} diff --git a/packages/api/src/utils/serdes.ts b/packages/api/src/utils/serdes.ts index c2080ad2d020..9fb772a0bc63 100644 --- a/packages/api/src/utils/serdes.ts +++ b/packages/api/src/utils/serdes.ts @@ -18,9 +18,8 @@ export function querySerializeProofPathsArr(paths: JsonPath[]): string[] { export function queryParseProofPathsArr(pathStrs: string | string[]): JsonPath[] { if (Array.isArray(pathStrs)) { return pathStrs.map((pathStr) => queryParseProofPaths(pathStr)); - } else { - return [queryParseProofPaths(pathStrs)]; } + return [queryParseProofPaths(pathStrs)]; } /** @@ -50,7 +49,7 @@ export type U64Str = string; export function fromU64Str(u64Str: U64Str): number { const u64 = parseInt(u64Str, 10); - if (!isFinite(u64)) { + if (!Number.isFinite(u64)) { throw Error(`Invalid uin64 ${u64Str}`); } return u64; diff --git a/packages/api/test/unit/client/fetch.test.ts b/packages/api/test/unit/client/fetch.test.ts index 0c08c5bbf5a3..1faf7d979a02 100644 --- a/packages/api/test/unit/client/fetch.test.ts +++ b/packages/api/test/unit/client/fetch.test.ts @@ -3,7 +3,7 @@ import http from "node:http"; import {describe, it, expect, afterEach} from "vitest"; import {FetchError, FetchErrorType, fetch} from "../../../src/utils/client/fetch.js"; -describe("FetchError", function () { +describe("FetchError", () => { const port = 37421; const randomHex = crypto.randomBytes(32).toString("hex"); @@ -87,7 +87,7 @@ describe("FetchError", function () { const afterHooks: (() => Promise)[] = []; - afterEach(async function () { + afterEach(async () => { while (afterHooks.length) { const afterHook = afterHooks.pop(); if (afterHook) @@ -100,7 +100,7 @@ describe("FetchError", function () { for (const testCase of testCases) { const {id, url = `http://localhost:${port}`, requestListener, signalHandler} = testCase; - it(id, async function () { + it(id, async () => { if (requestListener) { const server = http.createServer(requestListener); await new Promise((resolve) => server.listen(port, resolve)); diff --git a/packages/api/test/unit/client/httpClientFallback.test.ts b/packages/api/test/unit/client/httpClientFallback.test.ts index 244fcbe5bf23..9fcde27de072 100644 --- a/packages/api/test/unit/client/httpClientFallback.test.ts +++ b/packages/api/test/unit/client/httpClientFallback.test.ts @@ -56,12 +56,12 @@ describe("httpClient fallback", () => { // which is handled separately from network errors // but the fallback logic should be the same return new Response(null, {status: 500}); - } else { - throw Error(`test_error_server_${i}`); } - } else { - return new Response(null, {status: 200}); + + throw Error(`test_error_server_${i}`); } + + return new Response(null, {status: 200}); }); }); diff --git a/packages/api/test/utils/checkAgainstSpec.ts b/packages/api/test/utils/checkAgainstSpec.ts index 85e9711ae601..a3f943ad4816 100644 --- a/packages/api/test/utils/checkAgainstSpec.ts +++ b/packages/api/test/utils/checkAgainstSpec.ts @@ -93,13 +93,13 @@ export function runTestCheckAgainstSpec>( } }); - it(`${operationId}_route`, function () { + it(`${operationId}_route`, () => { expect(routeDef.method.toLowerCase()).toBe(routeSpec.method.toLowerCase()); expect(routeDef.url).toBe(routeSpec.url); }); if (requestSchema != null) { - it(`${operationId}_request`, function () { + it(`${operationId}_request`, () => { const reqJson = isRequestWithoutBody(routeDef) ? routeDef.req.writeReq(testData.args) : (routeDef.req as RequestWithBodyCodec).writeReqJson(testData.args); @@ -135,7 +135,7 @@ export function runTestCheckAgainstSpec>( } if (responseOkSchema) { - it(`${operationId}_response`, function () { + it(`${operationId}_response`, () => { const data = routeDef.resp.data.toJson(testData.res?.data, testData.res?.meta); const metaJson = routeDef.resp.meta.toJson(testData.res?.meta); const headers = parseHeaders(routeDef.resp.meta.toHeadersObject(testData.res?.meta)); @@ -218,7 +218,9 @@ type StringifiedProperty = string | StringifiedProperty[]; function stringifyProperty(value: unknown): StringifiedProperty { if (typeof value === "number") { return value.toString(10); - } else if (Array.isArray(value)) { + } + + if (Array.isArray(value)) { return value.map(stringifyProperty); } return String(value); diff --git a/packages/api/test/utils/parseOpenApiSpec.ts b/packages/api/test/utils/parseOpenApiSpec.ts index e6e75014312b..d04827fd2011 100644 --- a/packages/api/test/utils/parseOpenApiSpec.ts +++ b/packages/api/test/utils/parseOpenApiSpec.ts @@ -151,7 +151,7 @@ function preprocessSchema(schema: JsonSchema): void { // Remove non-intersecting allOf enum applyRecursively(schema, (obj) => { - if (obj.allOf && obj.allOf.every((s) => s.enum)) { + if (obj.allOf?.every((s) => s.enum)) { obj.allOf = [obj.allOf[0]]; } }); diff --git a/packages/api/test/utils/utils.ts b/packages/api/test/utils/utils.ts index 32a4db6162c6..d3ecbc964435 100644 --- a/packages/api/test/utils/utils.ts +++ b/packages/api/test/utils/utils.ts @@ -20,8 +20,8 @@ export function getTestServer(): {server: FastifyInstance; start: () => Promise< const start = (): Promise => new Promise((resolve, reject) => { - server.listen({port: 0}, function (err, address) { - if (err !== null && err != undefined) { + server.listen({port: 0}, (err, address) => { + if (err != null) { reject(err); } else { resolve(address); 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 240f391027a9..b54e8752a437 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -176,9 +176,8 @@ export function getBeaconBlockApi({ const message = `Equivocation checks not yet implemented for broadcastValidation=${broadcastValidation}`; if (chain.opts.broadcastValidationStrictness === "error") { throw Error(message); - } else { - chain.logger.warn(message, valLogMeta); } + chain.logger.warn(message, valLogMeta); } break; } @@ -193,9 +192,8 @@ export function getBeaconBlockApi({ const message = `Broadcast validation of ${broadcastValidation} type not implemented yet`; if (chain.opts.broadcastValidationStrictness === "error") { throw Error(message); - } else { - chain.logger.warn(message, valLogMeta); } + chain.logger.warn(message, valLogMeta); } } @@ -266,19 +264,19 @@ export function getBeaconBlockApi({ chain.logger.info("Publishing assembled block", {slot, blockRoot, source}); return publishBlock({signedBlockOrContents}, {...context, sszBytes: null}, opts); - } else { - const source = ProducedBlockSource.builder; - chain.logger.debug("Reconstructing signedBlockOrContents", {slot, blockRoot, source}); + } - const signedBlockOrContents = await reconstructBuilderBlockOrContents(chain, signedBlindedBlock); + const source = ProducedBlockSource.builder; + chain.logger.debug("Reconstructing signedBlockOrContents", {slot, blockRoot, source}); - // the full block is published by relay and it's possible that the block is already known to us - // by gossip - // - // see: https://github.com/ChainSafe/lodestar/issues/5404 - chain.logger.info("Publishing assembled block", {slot, blockRoot, source}); - return publishBlock({signedBlockOrContents}, {...context, sszBytes: null}, {...opts, ignoreIfKnown: true}); - } + const signedBlockOrContents = await reconstructBuilderBlockOrContents(chain, signedBlindedBlock); + + // the full block is published by relay and it's possible that the block is already known to us + // by gossip + // + // see: https://github.com/ChainSafe/lodestar/issues/5404 + chain.logger.info("Publishing assembled block", {slot, blockRoot, source}); + return publishBlock({signedBlockOrContents}, {...context, sszBytes: null}, {...opts, ignoreIfKnown: true}); }; return { diff --git a/packages/beacon-node/src/api/impl/beacon/blocks/utils.ts b/packages/beacon-node/src/api/impl/beacon/blocks/utils.ts index fe4fc5ca3dc0..44152ff4b8a9 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/utils.ts @@ -50,7 +50,7 @@ export function resolveBlockId(forkChoice: IForkChoice, blockId: routes.beacon.B // block id must be slot const blockSlot = parseInt(blockId, 10); - if (isNaN(blockSlot) && isNaN(blockSlot - 0)) { + if (Number.isNaN(blockSlot) && Number.isNaN(blockSlot - 0)) { throw new ValidationError(`Invalid block id '${blockId}'`, "blockId"); } return blockSlot; diff --git a/packages/beacon-node/src/api/impl/beacon/state/index.ts b/packages/beacon-node/src/api/impl/beacon/state/index.ts index 2bf758a8e286..8cce896e1087 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/index.ts @@ -103,7 +103,9 @@ export function getBeaconStateApi({ data: validatorResponses, meta: {executionOptimistic, finalized}, }; - } else if (statuses.length) { + } + + if (statuses.length) { const validatorsByStatus = filterStateValidatorsByStatus(statuses, state, pubkey2index, currentEpoch); return { data: validatorsByStatus, diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index 15e8bdf73176..392262a563be 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -34,7 +34,7 @@ export function resolveStateId( // id must be slot const blockSlot = parseInt(String(stateId), 10); - if (isNaN(blockSlot) && isNaN(blockSlot - 0)) { + if (Number.isNaN(blockSlot) && Number.isNaN(blockSlot - 0)) { throw new ValidationError(`Invalid block id '${stateId}'`, "blockId"); } diff --git a/packages/beacon-node/src/api/impl/lodestar/index.ts b/packages/beacon-node/src/api/impl/lodestar/index.ts index 0e8d2b1fa94b..f89959ad9da6 100644 --- a/packages/beacon-node/src/api/impl/lodestar/index.ts +++ b/packages/beacon-node/src/api/impl/lodestar/index.ts @@ -109,6 +109,7 @@ export function getLodestarApi({ async getBlockProcessorQueueItems() { return { + // biome-ignore lint/complexity/useLiteralKeys: The `blockProcessor` is a protected attribute data: (chain as BeaconChain)["blockProcessor"].jobQueue.getItems().map((item) => { const [blockInputs, opts] = item.args; return { @@ -173,6 +174,7 @@ export function getLodestarApi({ async dumpDbBucketKeys({bucket}) { for (const repo of Object.values(db) as IBeaconDb[keyof IBeaconDb][]) { if (repo instanceof Repository) { + // biome-ignore lint/complexity/useLiteralKeys: `bucket` is protected and `bucketId` is private if (String(repo["bucket"]) === bucket || repo["bucketId"] === bucket) { return {data: stringifyKeys(await repo.keys())}; } @@ -218,8 +220,7 @@ function stringifyKeys(keys: (Uint8Array | number | string)[]): string[] { return keys.map((key) => { if (key instanceof Uint8Array) { return toHex(key); - } else { - return `${key}`; } + return `${key}`; }); } diff --git a/packages/beacon-node/src/api/impl/node/index.ts b/packages/beacon-node/src/api/impl/node/index.ts index 370bba9b3c79..bd1fb85522de 100644 --- a/packages/beacon-node/src/api/impl/node/index.ts +++ b/packages/beacon-node/src/api/impl/node/index.ts @@ -76,10 +76,9 @@ export function getNodeApi( if (isSyncing || isOptimistic || elOffline) { // 206: Node is syncing but can serve incomplete data return {status: syncingStatus ?? routes.node.NodeHealth.SYNCING}; - } else { - // 200: Node is ready - return {status: routes.node.NodeHealth.READY}; } + // 200: Node is ready + return {status: routes.node.NodeHealth.READY}; // else { // 503: Node not initialized or having issues // NOTE: Lodestar does not start its API until fully initialized, so this status can never be served diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 1fccf083070c..6be825b5eb07 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -168,7 +168,9 @@ export function getValidatorApi( if (msToSlot > MAX_API_CLOCK_DISPARITY_MS) { throw Error(`Requested slot ${slot} is in the future`); - } else if (msToSlot > 0) { + } + + if (msToSlot > 0) { await chain.clock.waitForSlot(slot); } @@ -215,19 +217,19 @@ export function getValidatorApi( consensusBlockValue: prettyWeiToEth(consensusValue), blockTotalValue: prettyWeiToEth(totalValue), }; - } else if (source === ProducedBlockSource.builder) { + } + if (source === ProducedBlockSource.builder) { return { builderExecutionPayloadValue: prettyWeiToEth(executionValue), builderConsensusBlockValue: prettyWeiToEth(consensusValue), builderBlockTotalValue: prettyWeiToEth(totalValue), }; - } else { - return { - engineExecutionPayloadValue: prettyWeiToEth(executionValue), - engineConsensusBlockValue: prettyWeiToEth(consensusValue), - engineBlockTotalValue: prettyWeiToEth(totalValue), - }; } + return { + engineExecutionPayloadValue: prettyWeiToEth(executionValue), + engineConsensusBlockValue: prettyWeiToEth(consensusValue), + engineBlockTotalValue: prettyWeiToEth(totalValue), + }; } /** @@ -294,9 +296,9 @@ export function getValidatorApi( const headSlot = chain.forkChoice.getHead().slot; if (currentSlot - headSlot > SYNC_TOLERANCE_EPOCHS * SLOTS_PER_EPOCH) { throw new NodeIsSyncing(`headSlot ${headSlot} currentSlot ${currentSlot}`); - } else { - return; } + + return; } case SyncState.Synced: @@ -399,7 +401,7 @@ export function getValidatorApi( } notOnOutOfRangeData(parentBlockRoot); - let timer; + let timer: undefined | ((opts: {source: ProducedBlockSource}) => number); try { timer = metrics?.blockProductionTime.startTimer(); const {block, executionPayloadValue, consensusBlockValue} = await chain.produceBlindedBlock({ @@ -465,7 +467,7 @@ export function getValidatorApi( } notOnOutOfRangeData(parentBlockRoot); - let timer; + let timer: undefined | ((opts: {source: ProducedBlockSource}) => number); try { timer = metrics?.blockProductionTime.startTimer(); const {block, executionPayloadValue, consensusBlockValue, shouldOverrideBuilder} = await chain.produceBlock({ @@ -511,9 +513,9 @@ export function getValidatorApi( consensusBlockValue, shouldOverrideBuilder, }; - } else { - return {data: block, version, executionPayloadValue, consensusBlockValue, shouldOverrideBuilder}; } + + return {data: block, version, executionPayloadValue, consensusBlockValue, shouldOverrideBuilder}; } finally { if (timer) timer({source}); } @@ -726,13 +728,13 @@ export function getValidatorApi( executionPayloadBlinded: false, executionPayloadSource, }; - } else { - return { - ...builder.value, - executionPayloadBlinded: true, - executionPayloadSource, - }; } + + return { + ...builder.value, + executionPayloadBlinded: true, + executionPayloadSource, + }; } throw Error("Unreachable error occurred during the builder and execution block production"); @@ -757,25 +759,25 @@ export function getValidatorApi( if (opts.blindedLocal === true && ForkSeq[meta.version] >= ForkSeq.bellatrix) { if (meta.executionPayloadBlinded) { return {data, meta}; - } else { - if (isBlockContents(data)) { - const {block} = data; - const blindedBlock = beaconBlockToBlinded(config, block as BeaconBlock); - return { - data: blindedBlock, - meta: {...meta, executionPayloadBlinded: true}, - }; - } else { - const blindedBlock = beaconBlockToBlinded(config, data as BeaconBlock); - return { - data: blindedBlock, - meta: {...meta, executionPayloadBlinded: true}, - }; - } } - } else { - return {data, meta}; + + if (isBlockContents(data)) { + const {block} = data; + const blindedBlock = beaconBlockToBlinded(config, block as BeaconBlock); + return { + data: blindedBlock, + meta: {...meta, executionPayloadBlinded: true}, + }; + } + + const blindedBlock = beaconBlockToBlinded(config, data as BeaconBlock); + return { + data: blindedBlock, + meta: {...meta, executionPayloadBlinded: true}, + }; } + + return {data, meta}; }, async produceBlindedBlock({slot, randaoReveal, graffiti}) { @@ -788,12 +790,14 @@ export function getValidatorApi( const {block} = data; const blindedBlock = beaconBlockToBlinded(config, block as BeaconBlock); return {data: blindedBlock, meta: {version}}; - } else if (isBlindedBeaconBlock(data)) { + } + + if (isBlindedBeaconBlock(data)) { return {data, meta: {version}}; - } else { - const blindedBlock = beaconBlockToBlinded(config, data as BeaconBlock); - return {data: blindedBlock, meta: {version}}; } + + const blindedBlock = beaconBlockToBlinded(config, data as BeaconBlock); + return {data: blindedBlock, meta: {version}}; }, async produceAttestationData({committeeIndex, slot}) { @@ -1226,7 +1230,9 @@ export function getValidatorApi( if (errors.length > 1) { throw Error("Multiple errors on publishAggregateAndProofs\n" + errors.map((e) => e.message).join("\n")); - } else if (errors.length === 1) { + } + + if (errors.length === 1) { throw errors[0]; } }, @@ -1282,7 +1288,9 @@ export function getValidatorApi( if (errors.length > 1) { throw Error("Multiple errors on publishContributionAndProofs\n" + errors.map((e) => e.message).join("\n")); - } else if (errors.length === 1) { + } + + if (errors.length === 1) { throw errors[0]; } }, diff --git a/packages/beacon-node/src/chain/balancesCache.ts b/packages/beacon-node/src/chain/balancesCache.ts index 50a86b31b6c8..d29a6998f600 100644 --- a/packages/beacon-node/src/chain/balancesCache.ts +++ b/packages/beacon-node/src/chain/balancesCache.ts @@ -35,7 +35,7 @@ export class CheckpointBalancesCache { const epochBoundaryRoot = epochBoundarySlot === state.slot ? blockRootHex : toRootHex(getBlockRootAtSlot(state, epochBoundarySlot)); - const index = this.items.findIndex((item) => item.epoch === epoch && item.rootHex == epochBoundaryRoot); + const index = this.items.findIndex((item) => item.epoch === epoch && item.rootHex === epochBoundaryRoot); if (index === -1) { if (this.items.length === MAX_BALANCE_CACHE_SIZE) { this.items.shift(); diff --git a/packages/beacon-node/src/chain/blocks/index.ts b/packages/beacon-node/src/chain/blocks/index.ts index a7a2ced2ad7a..f64e4b1f3813 100644 --- a/packages/beacon-node/src/chain/blocks/index.ts +++ b/packages/beacon-node/src/chain/blocks/index.ts @@ -53,7 +53,9 @@ export async function processBlocks( ): Promise { if (blocks.length === 0) { return; // TODO: or throw? - } else if (blocks.length > 1) { + } + + if (blocks.length > 1) { assertLinearChainSegment(this.config, blocks); } @@ -161,11 +163,13 @@ export async function processBlocks( function getBlockError(e: unknown, block: SignedBeaconBlock): BlockError { if (e instanceof BlockError) { return e; - } else if (e instanceof Error) { + } + + if (e instanceof Error) { const blockError = new BlockError(block, {code: BlockErrorCode.BEACON_CHAIN_ERROR, error: e}); blockError.stack = e.stack; return blockError; - } else { - return new BlockError(block, {code: BlockErrorCode.BEACON_CHAIN_ERROR, error: e as Error}); } + + return new BlockError(block, {code: BlockErrorCode.BEACON_CHAIN_ERROR, error: e as Error}); } diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts index accd3df31ab0..98bfae2c1ce3 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts @@ -78,6 +78,7 @@ async function maybeValidateBlobs( case BlockInputType.outOfRangeData: return {dataAvailabilityStatus: DataAvailabilityStatus.OutOfRange, availableBlockInput: blockInput}; + // biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here case BlockInputType.availableData: if (opts.validBlobSidecars === BlobSidecarValidation.Full) { return {dataAvailabilityStatus: DataAvailabilityStatus.Available, availableBlockInput: blockInput}; diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts index 573dfa52ce8b..22b20a55fb67 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts @@ -45,9 +45,8 @@ export function verifyBlocksSanityChecks( if (blockSlot === 0) { if (opts.ignoreIfKnown) { continue; - } else { - throw new BlockError(block, {code: BlockErrorCode.GENESIS_BLOCK}); } + throw new BlockError(block, {code: BlockErrorCode.GENESIS_BLOCK}); } // Not finalized slot @@ -56,9 +55,8 @@ export function verifyBlocksSanityChecks( if (blockSlot <= finalizedSlot) { if (opts.ignoreIfFinalized) { continue; - } else { - throw new BlockError(block, {code: BlockErrorCode.WOULD_REVERT_FINALIZED_SLOT, blockSlot, finalizedSlot}); } + throw new BlockError(block, {code: BlockErrorCode.WOULD_REVERT_FINALIZED_SLOT, blockSlot, finalizedSlot}); } let parentBlockSlot: Slot; @@ -71,10 +69,9 @@ export function verifyBlocksSanityChecks( parentBlock = chain.forkChoice.getBlockHex(parentRoot); if (!parentBlock) { throw new BlockError(block, {code: BlockErrorCode.PARENT_UNKNOWN, parentRoot}); - } else { - // Parent is known to the fork-choice - parentBlockSlot = parentBlock.slot; } + // Parent is known to the fork-choice + parentBlockSlot = parentBlock.slot; } // Block not in the future, also checks for infinity @@ -89,9 +86,9 @@ export function verifyBlocksSanityChecks( if (chain.forkChoice.hasBlockHex(blockHash)) { if (opts.ignoreIfKnown) { continue; - } else { - throw new BlockError(block, {code: BlockErrorCode.ALREADY_KNOWN, root: blockHash}); } + + throw new BlockError(block, {code: BlockErrorCode.ALREADY_KNOWN, root: blockHash}); } // Block is relevant diff --git a/packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts b/packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts index 89cf7ddc7556..010c6a1fabc1 100644 --- a/packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts +++ b/packages/beacon-node/src/chain/blocks/writeBlockInputToDb.ts @@ -31,7 +31,7 @@ export async function writeBlockInputToDb(this: BeaconChain, blocksInput: BlockI if (blockInput.type === BlockInputType.availableData || blockInput.type === BlockInputType.dataPromise) { const blobSidecars = - blockInput.type == BlockInputType.availableData + blockInput.type === BlockInputType.availableData ? blockInput.blockData.blobs : // At this point of import blobs are available and can be safely awaited (await blockInput.cachedData.availabilityPromise).blobs; diff --git a/packages/beacon-node/src/chain/bls/multithread/index.ts b/packages/beacon-node/src/chain/bls/multithread/index.ts index ce9b726c7693..cb18ca86e42f 100644 --- a/packages/beacon-node/src/chain/bls/multithread/index.ts +++ b/packages/beacon-node/src/chain/bls/multithread/index.ts @@ -313,7 +313,8 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier { this.workers[0].status.code === WorkerStatusCode.initializationError && this.workers.every((worker) => worker.status.code === WorkerStatusCode.initializationError) ) { - return job.reject(this.workers[0].status.error); + job.reject(this.workers[0].status.error); + return; } // Append batchable sets to `bufferedJobs`, starting a timeout to push them into `jobs`. diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 4bd8cd2bea3d..195b8736b2c3 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -464,23 +464,23 @@ export class BeaconChain implements IBeaconChain { executionOptimistic: isOptimisticBlock(block), finalized: slot === finalizedBlock.slot && finalizedBlock.slot !== GENESIS_SLOT, }; - } else { - // Just check if state is already in the cache. If it's not dialed to the correct slot, - // do not bother in advancing the state. restApiCanTriggerRegen == false means do no work - const block = this.forkChoice.getCanonicalBlockAtSlot(slot); - if (!block) { - return null; - } + } - const state = this.regen.getStateSync(block.stateRoot); - return ( - state && { - state, - executionOptimistic: isOptimisticBlock(block), - finalized: slot === finalizedBlock.slot && finalizedBlock.slot !== GENESIS_SLOT, - } - ); + // Just check if state is already in the cache. If it's not dialed to the correct slot, + // do not bother in advancing the state. restApiCanTriggerRegen == false means do no work + const block = this.forkChoice.getCanonicalBlockAtSlot(slot); + if (!block) { + return null; } + + const state = this.regen.getStateSync(block.stateRoot); + return ( + state && { + state, + executionOptimistic: isOptimisticBlock(block), + finalized: slot === finalizedBlock.slot && finalizedBlock.slot !== GENESIS_SLOT, + } + ); } async getHistoricalStateBySlot( @@ -931,28 +931,27 @@ export class BeaconChain implements IBeaconChain { const effectiveBalances = this.checkpointBalancesCache.get(checkpoint); if (effectiveBalances) { return effectiveBalances; - } else { - // not expected, need metrics - this.metrics?.balancesCache.misses.inc(); - this.logger.debug("checkpointBalances cache miss", { - epoch: checkpoint.epoch, - root: checkpoint.rootHex, - }); - - const {state, stateId, shouldWarn} = this.closestJustifiedBalancesStateToCheckpoint(checkpoint, blockState); - this.metrics?.balancesCache.closestStateResult.inc({stateId}); - if (shouldWarn) { - this.logger.warn("currentJustifiedCheckpoint state not avail, using closest state", { - checkpointEpoch: checkpoint.epoch, - checkpointRoot: checkpoint.rootHex, - stateId, - stateSlot: state.slot, - stateRoot: toRootHex(state.hashTreeRoot()), - }); - } + } + // not expected, need metrics + this.metrics?.balancesCache.misses.inc(); + this.logger.debug("checkpointBalances cache miss", { + epoch: checkpoint.epoch, + root: checkpoint.rootHex, + }); - return getEffectiveBalanceIncrementsZeroInactive(state); + const {state, stateId, shouldWarn} = this.closestJustifiedBalancesStateToCheckpoint(checkpoint, blockState); + this.metrics?.balancesCache.closestStateResult.inc({stateId}); + if (shouldWarn) { + this.logger.warn("currentJustifiedCheckpoint state not avail, using closest state", { + checkpointEpoch: checkpoint.epoch, + checkpointRoot: checkpoint.rootHex, + stateId, + stateSlot: state.slot, + stateRoot: toRootHex(state.hashTreeRoot()), + }); } + + return getEffectiveBalanceIncrementsZeroInactive(state); } /** diff --git a/packages/beacon-node/src/chain/genesis/genesis.ts b/packages/beacon-node/src/chain/genesis/genesis.ts index 979476c69530..0c46f920d614 100644 --- a/packages/beacon-node/src/chain/genesis/genesis.ts +++ b/packages/beacon-node/src/chain/genesis/genesis.ts @@ -124,9 +124,9 @@ export class GenesisBuilder implements IGenesisBuilder { depositTree: this.depositTree, block, }; - } else { - this.throttledLog(`Waiting for min genesis time ${block.timestamp} / ${this.config.MIN_GENESIS_TIME}`); } + + this.throttledLog(`Waiting for min genesis time ${block.timestamp} / ${this.config.MIN_GENESIS_TIME}`); } throw Error("depositsStream stopped without a valid genesis state"); @@ -147,11 +147,11 @@ export class GenesisBuilder implements IGenesisBuilder { if (this.activatedValidatorCount >= this.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT) { this.logger.info("Found enough genesis validators", {blockNumber}); return blockNumber; - } else { - this.throttledLog( - `Found ${this.state.validators.length} / ${this.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT} validators to genesis` - ); } + + this.throttledLog( + `Found ${this.state.validators.length} / ${this.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT} validators to genesis` + ); } throw Error("depositsStream stopped without a valid genesis state"); diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index 30567b5d79b8..0a41ea059e73 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -225,7 +225,7 @@ export class LightClientServer { this.zero = { // Assign the hightest fork's default value because it can always be typecasted down to correct fork finalizedHeader: sszTypesFor(highestFork(forkLightClient)).LightClientHeader.defaultValue(), - finalityBranch: ssz.altair.LightClientUpdate.fields["finalityBranch"].defaultValue(), + finalityBranch: ssz.altair.LightClientUpdate.fields.finalityBranch.defaultValue(), }; if (metrics) { @@ -630,12 +630,12 @@ export class LightClientServer { ? await this.getFinalizedHeader(attestedData.finalizedCheckpoint.root) : null; - let isFinalized, finalityBranch, finalizedHeader; + let isFinalized: boolean, finalityBranch: Uint8Array[], finalizedHeader: LightClientHeader; if ( attestedData.isFinalized && finalizedHeaderAttested && - computeSyncPeriodAtSlot(finalizedHeaderAttested.beacon.slot) == syncPeriod + computeSyncPeriodAtSlot(finalizedHeaderAttested.beacon.slot) === syncPeriod ) { isFinalized = true; finalityBranch = attestedData.finalityBranch; @@ -741,7 +741,7 @@ export function blockToLightClientHeader(fork: ForkName, block: BeaconBlock b.notSeenAttesterCount - a.notSeenAttesterCount).slice(0, maxAttestation); } + + return attestations.sort((a, b) => b.notSeenAttesterCount - a.notSeenAttesterCount).slice(0, maxAttestation); } /** Get attestations for API. */ @@ -636,45 +636,43 @@ export function getNotSeenValidatorsFn(state: CachedBeaconStateAllForks): GetNot } // altair and future forks - else { - // Get attestations to be included in an altair block. - // Attestations are sorted by inclusion distance then number of attesters. - // Attestations should pass the validation when processing attestations in state-transition. - // check for altair block already - const altairState = state as CachedBeaconStateAltair; - const previousParticipation = altairState.previousEpochParticipation.getAll(); - const currentParticipation = altairState.currentEpochParticipation.getAll(); - const stateEpoch = computeEpochAtSlot(state.slot); - // this function could be called multiple times with same slot + committeeIndex - const cachedNotSeenValidators = new Map>(); - - return (epoch: Epoch, slot: Slot, committeeIndex: number) => { - const participationStatus = - epoch === stateEpoch ? currentParticipation : epoch === stateEpoch - 1 ? previousParticipation : null; - - if (participationStatus === null) { - return null; - } - const cacheKey = slot + "_" + committeeIndex; - let notSeenAttestingIndices = cachedNotSeenValidators.get(cacheKey); - if (notSeenAttestingIndices != null) { - // if all validators are seen then return null, we don't need to check for any attestations of same committee again - return notSeenAttestingIndices.size === 0 ? null : notSeenAttestingIndices; - } - - const committee = state.epochCtx.getBeaconCommittee(slot, committeeIndex); - notSeenAttestingIndices = new Set(); - for (const [i, validatorIndex] of committee.entries()) { - // no need to check flagIsTimelySource as if validator is not seen, it's participation status is 0 - if (participationStatus[validatorIndex] === 0) { - notSeenAttestingIndices.add(i); - } - } - cachedNotSeenValidators.set(cacheKey, notSeenAttestingIndices); + // Get attestations to be included in an altair block. + // Attestations are sorted by inclusion distance then number of attesters. + // Attestations should pass the validation when processing attestations in state-transition. + // check for altair block already + const altairState = state as CachedBeaconStateAltair; + const previousParticipation = altairState.previousEpochParticipation.getAll(); + const currentParticipation = altairState.currentEpochParticipation.getAll(); + const stateEpoch = computeEpochAtSlot(state.slot); + // this function could be called multiple times with same slot + committeeIndex + const cachedNotSeenValidators = new Map>(); + + return (epoch: Epoch, slot: Slot, committeeIndex: number) => { + const participationStatus = + epoch === stateEpoch ? currentParticipation : epoch === stateEpoch - 1 ? previousParticipation : null; + + if (participationStatus === null) { + return null; + } + const cacheKey = slot + "_" + committeeIndex; + let notSeenAttestingIndices = cachedNotSeenValidators.get(cacheKey); + if (notSeenAttestingIndices != null) { // if all validators are seen then return null, we don't need to check for any attestations of same committee again return notSeenAttestingIndices.size === 0 ? null : notSeenAttestingIndices; - }; - } + } + + const committee = state.epochCtx.getBeaconCommittee(slot, committeeIndex); + notSeenAttestingIndices = new Set(); + for (const [i, validatorIndex] of committee.entries()) { + // no need to check flagIsTimelySource as if validator is not seen, it's participation status is 0 + if (participationStatus[validatorIndex] === 0) { + notSeenAttestingIndices.add(i); + } + } + cachedNotSeenValidators.set(cacheKey, notSeenAttestingIndices); + // if all validators are seen then return null, we don't need to check for any attestations of same committee again + return notSeenAttestingIndices.size === 0 ? null : notSeenAttestingIndices; + }; } export function extractParticipationPhase0( @@ -716,7 +714,7 @@ export function getValidateAttestationDataFn( const stateEpoch = state.epochCtx.epoch; return (attData: phase0.AttestationData) => { const targetEpoch = attData.target.epoch; - let justifiedCheckpoint; + let justifiedCheckpoint: phase0.Checkpoint; // simple check first if (targetEpoch === stateEpoch) { justifiedCheckpoint = currentJustifiedCheckpoint; @@ -761,7 +759,7 @@ export function isValidAttestationData( data: phase0.AttestationData ): boolean { const {previousJustifiedCheckpoint, currentJustifiedCheckpoint} = state; - let justifiedCheckpoint; + let justifiedCheckpoint: phase0.Checkpoint; const stateEpoch = state.epochCtx.epoch; const targetEpoch = data.target.epoch; diff --git a/packages/beacon-node/src/chain/opPools/attestationPool.ts b/packages/beacon-node/src/chain/opPools/attestationPool.ts index 887448b1e553..8d8fbb92c0f1 100644 --- a/packages/beacon-node/src/chain/opPools/attestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/attestationPool.ts @@ -145,11 +145,10 @@ export class AttestationPool { if (aggregate) { // Aggregate mutating return aggregateAttestationInto(aggregate, attestation); - } else { - // Create new aggregate - aggregateByIndex.set(committeeIndex, attestationToAggregate(attestation)); - return InsertOutcome.NewData; } + // Create new aggregate + aggregateByIndex.set(committeeIndex, attestationToAggregate(attestation)); + return InsertOutcome.NewData; } /** diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index ee66591e9aef..f71186c06d35 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -410,10 +410,9 @@ function isVoluntaryExitSignatureIncludable(stateFork: ForkSeq, voluntaryExitFor if (stateFork >= ForkSeq.deneb) { // Exists are perpetually valid https://eips.ethereum.org/EIPS/eip-7044 return true; - } else { - // Can only include exits from the current and previous fork - return voluntaryExitFork === stateFork || voluntaryExitFork === stateFork - 1; } + // Can only include exits from the current and previous fork + return voluntaryExitFork === stateFork || voluntaryExitFork === stateFork - 1; } function isSlashableAtEpoch(validator: phase0.Validator, epoch: Epoch): boolean { diff --git a/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts b/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts index bbaba1835dce..4de11e447231 100644 --- a/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts +++ b/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts @@ -88,11 +88,11 @@ export class SyncCommitteeMessagePool { if (contribution) { // Aggregate mutating return aggregateSignatureInto(contribution, signature, indexInSubcommittee); - } else { - // Create new aggregate - contributionsByRoot.set(rootHex, signatureToAggregate(subnet, signature, indexInSubcommittee)); - return InsertOutcome.NewData; } + + // Create new aggregate + contributionsByRoot.set(rootHex, signatureToAggregate(subnet, signature, indexInSubcommittee)); + return InsertOutcome.NewData; } /** diff --git a/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts b/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts index ff0feea891e1..81363be218d8 100644 --- a/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts +++ b/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts @@ -90,10 +90,9 @@ export class SyncContributionAndProofPool { const bestContribution = bestContributionBySubnet.get(subnet); if (bestContribution) { return replaceIfBetter(bestContribution, contribution, syncCommitteeParticipants); - } else { - bestContributionBySubnet.set(subnet, contributionToFast(contribution, syncCommitteeParticipants)); - return InsertOutcome.NewData; } + bestContributionBySubnet.set(subnet, contributionToFast(contribution, syncCommitteeParticipants)); + return InsertOutcome.NewData; } /** diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index ff8221a326e9..37670e4b8f82 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -481,26 +481,26 @@ export async function getExecutionPayloadParentHash( if (isMergeTransitionComplete(state)) { // Post-merge, normal payload return {isPremerge: false, parentHash: state.latestExecutionPayloadHeader.blockHash}; - } else { - if ( - !ssz.Root.equals(chain.config.TERMINAL_BLOCK_HASH, ZERO_HASH) && - getCurrentEpoch(state) < chain.config.TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH - ) - throw new Error( - `InvalidMergeTBH epoch: expected >= ${ - chain.config.TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH - }, actual: ${getCurrentEpoch(state)}` - ); + } - const terminalPowBlockHash = await chain.eth1.getTerminalPowBlock(); - if (terminalPowBlockHash === null) { - // Pre-merge, no prepare payload call is needed - return {isPremerge: true}; - } else { - // Signify merge via producing on top of the last PoW block - return {isPremerge: false, parentHash: terminalPowBlockHash}; - } + if ( + !ssz.Root.equals(chain.config.TERMINAL_BLOCK_HASH, ZERO_HASH) && + getCurrentEpoch(state) < chain.config.TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH + ) { + throw new Error( + `InvalidMergeTBH epoch: expected >= ${ + chain.config.TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH + }, actual: ${getCurrentEpoch(state)}` + ); } + + const terminalPowBlockHash = await chain.eth1.getTerminalPowBlock(); + if (terminalPowBlockHash === null) { + // Pre-merge, no prepare payload call is needed + return {isPremerge: true}; + } + // Signify merge via producing on top of the last PoW block + return {isPremerge: false, parentHash: terminalPowBlockHash}; } export async function getPayloadAttributesForSSE( @@ -536,9 +536,9 @@ export async function getPayloadAttributesForSSE( payloadAttributes, }; return ssePayloadAttributes; - } else { - throw Error("The execution is still pre-merge"); } + + throw Error("The execution is still pre-merge"); } function preparePayloadAttributes( diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index 57e64bd364ea..694e8635a3b7 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -336,7 +336,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { caller: regenRequest.args[regenRequest.args.length - 1] as RegenCaller, entrypoint: regenRequest.key as RegenFnName, }; - let timer; + let timer: (() => number) | undefined; try { timer = this.metrics?.regenFnCallDuration.startTimer(metricsLabels); switch (regenRequest.key) { diff --git a/packages/beacon-node/src/chain/rewards/attestationsRewards.ts b/packages/beacon-node/src/chain/rewards/attestationsRewards.ts index 0c74b8610f93..588b310f87ea 100644 --- a/packages/beacon-node/src/chain/rewards/attestationsRewards.ts +++ b/packages/beacon-node/src/chain/rewards/attestationsRewards.ts @@ -85,7 +85,7 @@ function computeIdealAttestationsRewardsAndPenaltiesAltair( for (let i = 0; i < PARTICIPATION_FLAG_WEIGHTS.length; i++) { const weight = PARTICIPATION_FLAG_WEIGHTS[i]; - let unslashedStakeByIncrement; + let unslashedStakeByIncrement: number; let flagName: keyof IdealAttestationsReward; switch (i) { diff --git a/packages/beacon-node/src/chain/rewards/blockRewards.ts b/packages/beacon-node/src/chain/rewards/blockRewards.ts index 65dc23496070..19a59aaa028e 100644 --- a/packages/beacon-node/src/chain/rewards/blockRewards.ts +++ b/packages/beacon-node/src/chain/rewards/blockRewards.ts @@ -90,9 +90,9 @@ function computeSyncAggregateReward(block: altair.BeaconBlock, preState: CachedB const {syncProposerReward} = preState.epochCtx; return syncCommitteeBits.getTrueBitIndexes().length * Math.floor(syncProposerReward); // syncProposerReward should already be integer - } else { - return 0; // phase0 block does not have syncAggregate } + + return 0; // phase0 block does not have syncAggregate } /** diff --git a/packages/beacon-node/src/chain/rewards/syncCommitteeRewards.ts b/packages/beacon-node/src/chain/rewards/syncCommitteeRewards.ts index 89ef84af43a2..71d345e32811 100644 --- a/packages/beacon-node/src/chain/rewards/syncCommitteeRewards.ts +++ b/packages/beacon-node/src/chain/rewards/syncCommitteeRewards.ts @@ -51,7 +51,7 @@ export async function computeSyncCommitteeRewards( return rewards.filter( (reward) => filtersSet.has(reward.validatorIndex) || filtersSet.has(index2pubkey[reward.validatorIndex].toHex()) ); - } else { - return rewards; } + + return rewards; } diff --git a/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts b/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts index 3806668436d8..1c03979b7d77 100644 --- a/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts +++ b/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts @@ -72,9 +72,9 @@ export class SeenGossipBlockInput { blockInput: NullBlockInput; blockInputMeta: {pending: GossipedInputType.block; haveBlobs: number; expectedBlobs: null}; } { - let blockHex; - let blockCache; - let fork; + let blockHex: RootHex; + let blockCache: BlockInputCacheType; + let fork: ForkName; if (gossipedInput.type === GossipedInputType.block) { const {signedBlock, blockBytes} = gossipedInput; @@ -149,42 +149,42 @@ export class SeenGossipBlockInput { blockInput, blockInputMeta: {pending: null, haveBlobs: allBlobs.blobs.length, expectedBlobs: blobKzgCommitments.length}, }; - } else { - const blockInput = getBlockInput.dataPromise( - config, - signedBlock, - BlockSource.gossip, - blockBytes ?? null, - cachedData - ); - - resolveBlockInput(blockInput); - return { - blockInput, - blockInputMeta: { - pending: GossipedInputType.blob, - haveBlobs: blobsCache.size, - expectedBlobs: blobKzgCommitments.length, - }, - }; - } - } else { - // will need to wait for the block to showup - if (cachedData === undefined) { - throw Error("Missing cachedData for deneb+ blobs"); } - const {blobsCache} = cachedData; + const blockInput = getBlockInput.dataPromise( + config, + signedBlock, + BlockSource.gossip, + blockBytes ?? null, + cachedData + ); + + resolveBlockInput(blockInput); return { - blockInput: { - block: null, - blockRootHex: blockHex, - cachedData, - blockInputPromise, + blockInput, + blockInputMeta: { + pending: GossipedInputType.blob, + haveBlobs: blobsCache.size, + expectedBlobs: blobKzgCommitments.length, }, - blockInputMeta: {pending: GossipedInputType.block, haveBlobs: blobsCache.size, expectedBlobs: null}, }; } + + // will need to wait for the block to showup + if (cachedData === undefined) { + throw Error("Missing cachedData for deneb+ blobs"); + } + const {blobsCache} = cachedData; + + return { + blockInput: { + block: null, + blockRootHex: blockHex, + cachedData, + blockInputPromise, + }, + blockInputMeta: {pending: GossipedInputType.block, haveBlobs: blobsCache.size, expectedBlobs: null}, + }; } } diff --git a/packages/beacon-node/src/chain/shufflingCache.ts b/packages/beacon-node/src/chain/shufflingCache.ts index 749fea1b82ff..bdedddacf6db 100644 --- a/packages/beacon-node/src/chain/shufflingCache.ts +++ b/packages/beacon-node/src/chain/shufflingCache.ts @@ -130,10 +130,9 @@ export class ShufflingCache implements IShufflingCache { if (isShufflingCacheItem(cacheItem)) { this.metrics?.shufflingCache.hit.inc(); return cacheItem.shuffling; - } else { - this.metrics?.shufflingCache.shufflingPromiseNotResolved.inc(); - return cacheItem.promise; } + this.metrics?.shufflingCache.shufflingPromiseNotResolved.inc(); + return cacheItem.promise; } /** diff --git a/packages/beacon-node/src/chain/stateCache/datastore/file.ts b/packages/beacon-node/src/chain/stateCache/datastore/file.ts index f487079ae443..3c978c2355d6 100644 --- a/packages/beacon-node/src/chain/stateCache/datastore/file.ts +++ b/packages/beacon-node/src/chain/stateCache/datastore/file.ts @@ -13,7 +13,7 @@ const CHECKPOINT_FILE_NAME_LENGTH = 82; export class FileCPStateDatastore implements CPStateDatastore { private readonly folderPath: string; - constructor(parentDir: string = ".") { + constructor(parentDir = ".") { // by default use the beacon folder `/beacon/checkpoint_states` this.folderPath = path.join(parentDir, CHECKPOINT_STATES_FOLDER); } diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index de5f40372c9f..6d6eab6ec15a 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -74,7 +74,7 @@ async function validateAggregateAndProof( const seenAttDataKey = serializedData ? getSeenAttDataKeyFromSignedAggregateAndProof(fork, serializedData) : null; const cachedAttData = seenAttDataKey ? chain.seenAttestationDatas.get(attSlot, seenAttDataKey) : null; - let attIndex; + let attIndex: number | null; if (ForkSeq[fork] >= ForkSeq.electra) { attIndex = (aggregate as electra.Attestation).committeeBits.getSingleTrueBit(); // [REJECT] len(committee_indices) == 1, where committee_indices = get_committee_indices(aggregate) diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index 119a8ee1a899..0b3f490e4129 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -208,19 +208,18 @@ export async function validateApiAttestation( const targetEpoch = attestation.data.target.epoch; chain.seenAttesters.add(targetEpoch, validatorIndex); return step0Result; - } else { - throw new AttestationError(GossipAction.IGNORE, { - code: AttestationErrorCode.INVALID_SIGNATURE, - }); } + + throw new AttestationError(GossipAction.IGNORE, { + code: AttestationErrorCode.INVALID_SIGNATURE, + }); } catch (err) { if (err instanceof EpochCacheError && err.type.code === EpochCacheErrorCode.COMMITTEE_INDEX_OUT_OF_RANGE) { throw new AttestationError(GossipAction.IGNORE, { code: AttestationErrorCode.BAD_TARGET_EPOCH, }); - } else { - throw err; } + throw err; } } @@ -274,7 +273,7 @@ async function validateAttestationNoSignatureCheck( const attEpoch = computeEpochAtSlot(attSlot); const attTarget = attData.target; const targetEpoch = attTarget.epoch; - let committeeIndex; + let committeeIndex: number | null; if (attestationOrCache.attestation) { if (isElectraAttestation(attestationOrCache.attestation)) { // api or first time validation of a gossip attestation @@ -715,27 +714,27 @@ function verifyAttestationTargetRoot(headBlock: ProtoBlock, targetRoot: Root, at targetRoot: toRootHex(targetRoot), expected: null, }); - } else { - const expectedTargetRoot = - headBlockEpoch === attestationEpoch - ? // If the block is in the same epoch as the attestation, then use the target root - // from the block. - headBlock.targetRoot - : // If the head block is from a previous epoch then skip slots will cause the head block - // root to become the target block root. - // - // We know the head block is from a previous epoch due to a previous check. - headBlock.blockRoot; - - // TODO: Do a fast comparision to convert and compare byte by byte - if (expectedTargetRoot !== toRootHex(targetRoot)) { - // Reject any attestation with an invalid target root. - throw new AttestationError(GossipAction.REJECT, { - code: AttestationErrorCode.INVALID_TARGET_ROOT, - targetRoot: toRootHex(targetRoot), - expected: expectedTargetRoot, - }); - } + } + + const expectedTargetRoot = + headBlockEpoch === attestationEpoch + ? // If the block is in the same epoch as the attestation, then use the target root + // from the block. + headBlock.targetRoot + : // If the head block is from a previous epoch then skip slots will cause the head block + // root to become the target block root. + // + // We know the head block is from a previous epoch due to a previous check. + headBlock.blockRoot; + + // TODO: Do a fast comparision to convert and compare byte by byte + if (expectedTargetRoot !== toRootHex(targetRoot)) { + // Reject any attestation with an invalid target root. + throw new AttestationError(GossipAction.REJECT, { + code: AttestationErrorCode.INVALID_TARGET_ROOT, + targetRoot: toRootHex(targetRoot), + expected: expectedTargetRoot, + }); } } diff --git a/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts b/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts index f4865c73f8e4..0b19495abde6 100644 --- a/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts +++ b/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts @@ -34,9 +34,9 @@ export function validateLightClientFinalityUpdate( } // [IGNORE] The received finality_update matches the locally computed one exactly - const sszType = config.getLightClientForkTypes(gossipedFinalityUpdate.attestedHeader.beacon.slot)[ - "LightClientFinalityUpdate" - ]; + const sszType = config.getLightClientForkTypes( + gossipedFinalityUpdate.attestedHeader.beacon.slot + ).LightClientFinalityUpdate; if (localFinalityUpdate === null || !sszType.equals(gossipedFinalityUpdate, localFinalityUpdate)) { throw new LightClientError(GossipAction.IGNORE, { code: LightClientErrorCode.FINALITY_UPDATE_NOT_MATCHING_LOCAL, diff --git a/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts b/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts index 182321984af5..7a7dd7f34a91 100644 --- a/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts +++ b/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts @@ -35,9 +35,9 @@ export function validateLightClientOptimisticUpdate( } // [IGNORE] The received optimistic_update matches the locally computed one exactly - const sszType = config.getLightClientForkTypes(gossipedOptimisticUpdate.attestedHeader.beacon.slot)[ - "LightClientOptimisticUpdate" - ]; + const sszType = config.getLightClientForkTypes( + gossipedOptimisticUpdate.attestedHeader.beacon.slot + ).LightClientOptimisticUpdate; if (localOptimisticUpdate === null || !sszType.equals(gossipedOptimisticUpdate, localOptimisticUpdate)) { throw new LightClientError(GossipAction.IGNORE, { code: LightClientErrorCode.OPTIMISTIC_UPDATE_NOT_MATCHING_LOCAL, diff --git a/packages/beacon-node/src/db/buckets.ts b/packages/beacon-node/src/db/buckets.ts index eff123879037..c35a5a18edf5 100644 --- a/packages/beacon-node/src/db/buckets.ts +++ b/packages/beacon-node/src/db/buckets.ts @@ -65,11 +65,10 @@ export enum Bucket { export function getBucketNameByValue(enumValue: T): keyof typeof Bucket { const keys = Object.keys(Bucket).filter((x) => { - if (isNaN(parseInt(x))) { - return Bucket[x as keyof typeof Bucket] == enumValue; - } else { - return false; + if (Number.isNaN(parseInt(x))) { + return Bucket[x as keyof typeof Bucket] === enumValue; } + return false; }) as (keyof typeof Bucket)[]; if (keys.length > 0) { return keys[0]; diff --git a/packages/beacon-node/src/db/repositories/blockArchive.ts b/packages/beacon-node/src/db/repositories/blockArchive.ts index 15c07f552b21..427650a37bc3 100644 --- a/packages/beacon-node/src/db/repositories/blockArchive.ts +++ b/packages/beacon-node/src/db/repositories/blockArchive.ts @@ -105,7 +105,7 @@ export class BlockArchiveRepository extends Repository async *valuesStream(opts?: BlockFilterOptions): AsyncIterable { const firstSlot = this.getFirstSlot(opts); const valuesStream = super.valuesStream(opts); - const step = (opts && opts.step) ?? 1; + const step = opts?.step ?? 1; for await (const value of valuesStream) { if ((value.message.slot - firstSlot) % step === 0) { diff --git a/packages/beacon-node/src/db/repositories/blockArchiveIndex.ts b/packages/beacon-node/src/db/repositories/blockArchiveIndex.ts index 797142d09db7..8c2785dbe67c 100644 --- a/packages/beacon-node/src/db/repositories/blockArchiveIndex.ts +++ b/packages/beacon-node/src/db/repositories/blockArchiveIndex.ts @@ -17,7 +17,7 @@ export async function deleteRootIndex( signedBeaconBlockType: SSZTypesFor, block: SignedBeaconBlock ): Promise { - const beaconBlockType = (signedBeaconBlockType as typeof ssz.phase0.SignedBeaconBlock).fields["message"]; + const beaconBlockType = (signedBeaconBlockType as typeof ssz.phase0.SignedBeaconBlock).fields.message; return db.delete(getRootIndexKey(beaconBlockType.hashTreeRoot(block.message))); } diff --git a/packages/beacon-node/src/db/repositories/depositDataRoot.ts b/packages/beacon-node/src/db/repositories/depositDataRoot.ts index 9b872c91bce4..97200ccd0f92 100644 --- a/packages/beacon-node/src/db/repositories/depositDataRoot.ts +++ b/packages/beacon-node/src/db/repositories/depositDataRoot.ts @@ -69,7 +69,9 @@ export class DepositDataRootRepository extends Repository { // TODO: Review and fix properly if (index > depositRootTree.length) { throw Error(`Error setting depositRootTree index ${index} > length ${depositRootTree.length}`); - } else if (index === depositRootTree.length) { + } + + if (index === depositRootTree.length) { depositRootTree.push(value); } else { depositRootTree.set(index, value); diff --git a/packages/beacon-node/src/eth1/eth1DataCache.ts b/packages/beacon-node/src/eth1/eth1DataCache.ts index 91b8537d1cc4..7f9bb99a2f16 100644 --- a/packages/beacon-node/src/eth1/eth1DataCache.ts +++ b/packages/beacon-node/src/eth1/eth1DataCache.ts @@ -21,6 +21,6 @@ export class Eth1DataCache { async getHighestCachedBlockNumber(): Promise { const highestEth1Data = await this.db.eth1Data.lastValue(); - return highestEth1Data && highestEth1Data.blockNumber; + return highestEth1Data?.blockNumber ?? null; } } diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index a38b3f9987d9..674b6b600f31 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -14,7 +14,7 @@ import {Eth1DepositsCache} from "./eth1DepositsCache.js"; import {Eth1DataCache} from "./eth1DataCache.js"; import {getEth1VotesToConsider, pickEth1Vote} from "./utils/eth1Vote.js"; import {getDeposits} from "./utils/deposits.js"; -import {Eth1DataAndDeposits, IEth1Provider} from "./interface.js"; +import {Eth1DataAndDeposits, EthJsonRpcBlockRaw, IEth1Provider} from "./interface.js"; import {Eth1Options} from "./options.js"; import {HttpRpcError} from "./provider/jsonRpcHttpClient.js"; import {parseEth1Block} from "./provider/eth1Provider.js"; @@ -243,7 +243,7 @@ export class Eth1DepositDataTracker { const fromBlock = Math.min(remoteFollowBlock, this.getFromBlockToFetch(lastProcessedDepositBlockNumber)); const toBlock = Math.min(remoteFollowBlock, fromBlock + this.eth1GetLogsBatchSizeDynamic - 1); - let depositEvents; + let depositEvents: phase0.DepositEvent[]; try { depositEvents = await this.eth1Provider.getDepositEvents(fromBlock, toBlock); // Increase the batch size linearly even if we scale down exponentially (half each time) @@ -313,7 +313,7 @@ export class Eth1DepositDataTracker { lastProcessedDepositBlockNumber ); - let blocksRaw; + let blocksRaw: EthJsonRpcBlockRaw[]; try { blocksRaw = await this.eth1Provider.getBlocksByNumber(fromBlock, toBlock); // Increase the batch size linearly even if we scale down exponentially (half each time) @@ -380,26 +380,24 @@ export class Eth1DepositDataTracker { this.eth1FollowDistance = Math.min(this.eth1FollowDistance + delta, this.config.ETH1_FOLLOW_DISTANCE); return true; - } else { - // Blocks are slower than expected, reduce eth1FollowDistance. Limit min CATCHUP_MIN_FOLLOW_DISTANCE - const delta = - this.eth1FollowDistance - - Math.max(this.eth1FollowDistance - ETH1_FOLLOW_DISTANCE_DELTA_IF_SLOW, ETH_MIN_FOLLOW_DISTANCE); - this.eth1FollowDistance = this.eth1FollowDistance - delta; - - // Even if the blocks are slow, when we are all caught up as there is no - // further possibility to reduce follow distance, we need to call it quits - // for now, else it leads to an incessant poll on the EL - return delta === 0; } + // Blocks are slower than expected, reduce eth1FollowDistance. Limit min CATCHUP_MIN_FOLLOW_DISTANCE + const delta = + this.eth1FollowDistance - + Math.max(this.eth1FollowDistance - ETH1_FOLLOW_DISTANCE_DELTA_IF_SLOW, ETH_MIN_FOLLOW_DISTANCE); + this.eth1FollowDistance = this.eth1FollowDistance - delta; + + // Even if the blocks are slow, when we are all caught up as there is no + // further possibility to reduce follow distance, we need to call it quits + // for now, else it leads to an incessant poll on the EL + return delta === 0; } private getFromBlockToFetch(lastCachedBlock: number | null): number { if (lastCachedBlock === null) { return this.eth1Provider.deployBlock ?? 0; - } else { - return lastCachedBlock + 1; } + return lastCachedBlock + 1; } private async getLastProcessedDepositBlockNumber(): Promise { diff --git a/packages/beacon-node/src/eth1/eth1DepositsCache.ts b/packages/beacon-node/src/eth1/eth1DepositsCache.ts index 2fb187d02cf7..13dd29013124 100644 --- a/packages/beacon-node/src/eth1/eth1DepositsCache.ts +++ b/packages/beacon-node/src/eth1/eth1DepositsCache.ts @@ -129,7 +129,7 @@ export class Eth1DepositsCache { */ async getHighestDepositEventBlockNumber(): Promise { const latestEvent = await this.db.depositEvent.lastValue(); - return latestEvent && latestEvent.blockNumber; + return latestEvent?.blockNumber || null; } /** @@ -137,6 +137,6 @@ export class Eth1DepositsCache { */ async getLowestDepositEventBlockNumber(): Promise { const firstEvent = await this.db.depositEvent.firstValue(); - return firstEvent && firstEvent.blockNumber; + return firstEvent?.blockNumber || null; } } diff --git a/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts b/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts index f2ce0a8bb2f5..5bf76625dfe8 100644 --- a/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts +++ b/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts @@ -126,11 +126,10 @@ export class Eth1MergeBlockTracker { td: this.latestEth1Block.totalDifficulty, timestamp: this.latestEth1Block.timestamp, }; - } else { - return { - ttdHit: true, - }; } + return { + ttdHit: true, + }; } /** @@ -193,7 +192,7 @@ export class Eth1MergeBlockTracker { // Persist found merge block here to affect both caller paths: // - internal searcher // - external caller if STOPPED - if (mergeBlock && this.status.code != StatusCode.FOUND) { + if (mergeBlock && this.status.code !== StatusCode.FOUND) { if (this.status.code === StatusCode.SEARCHING) { this.close(); } @@ -242,60 +241,56 @@ export class Eth1MergeBlockTracker { const block = await this.getPowBlock(terminalBlockHash); if (block) { return block; - } else { - // if a TERMINAL_BLOCK_HASH other than ZERO_HASH is configured and we can't find it, return NONE - return null; } + // if a TERMINAL_BLOCK_HASH other than ZERO_HASH is configured and we can't find it, return NONE + return null; } // Search merge block by TTD - else { - const latestBlockRaw = await this.eth1Provider.getBlockByNumber("latest"); - if (!latestBlockRaw) { - throw Error("getBlockByNumber('latest') returned null"); - } - - let block = toPowBlock(latestBlockRaw); - this.latestEth1Block = {...block, timestamp: quantityToNum(latestBlockRaw.timestamp)}; - this.cacheBlock(block); + const latestBlockRaw = await this.eth1Provider.getBlockByNumber("latest"); + if (!latestBlockRaw) { + throw Error("getBlockByNumber('latest') returned null"); + } - // This code path to look backwards for the merge block is only necessary if: - // - The network has not yet found the merge block - // - There are descendants of the merge block in the eth1 chain - // For the search below to require more than a few hops, multiple block proposers in a row must fail to detect - // an existing merge block. Such situation is extremely unlikely, so this search is left un-optimized. Since - // this class can start eagerly looking for the merge block when not necessary, startPollingMergeBlock() should - // only be called when there is certainty that a mergeBlock search is necessary. - - while (true) { - if (block.totalDifficulty < this.config.TERMINAL_TOTAL_DIFFICULTY) { - // TTD not reached yet - return null; - } + let block = toPowBlock(latestBlockRaw); + this.latestEth1Block = {...block, timestamp: quantityToNum(latestBlockRaw.timestamp)}; + this.cacheBlock(block); + + // This code path to look backwards for the merge block is only necessary if: + // - The network has not yet found the merge block + // - There are descendants of the merge block in the eth1 chain + // For the search below to require more than a few hops, multiple block proposers in a row must fail to detect + // an existing merge block. Such situation is extremely unlikely, so this search is left un-optimized. Since + // this class can start eagerly looking for the merge block when not necessary, startPollingMergeBlock() should + // only be called when there is certainty that a mergeBlock search is necessary. + + while (true) { + if (block.totalDifficulty < this.config.TERMINAL_TOTAL_DIFFICULTY) { + // TTD not reached yet + return null; + } - // else block.totalDifficulty >= this.config.TERMINAL_TOTAL_DIFFICULTY - // Potential mergeBlock! Must find the first block that passes TTD + // else block.totalDifficulty >= this.config.TERMINAL_TOTAL_DIFFICULTY + // Potential mergeBlock! Must find the first block that passes TTD - // Allow genesis block to reach TTD https://github.com/ethereum/consensus-specs/pull/2719 - if (block.parentHash === ZERO_HASH_HEX) { - return block; - } + // Allow genesis block to reach TTD https://github.com/ethereum/consensus-specs/pull/2719 + if (block.parentHash === ZERO_HASH_HEX) { + return block; + } - const parent = await this.getPowBlock(block.parentHash); - if (!parent) { - throw Error(`Unknown parent of block with TD>TTD ${block.parentHash}`); - } + const parent = await this.getPowBlock(block.parentHash); + if (!parent) { + throw Error(`Unknown parent of block with TD>TTD ${block.parentHash}`); + } - this.metrics?.eth1.eth1ParentBlocksFetched.inc(); + this.metrics?.eth1.eth1ParentBlocksFetched.inc(); - // block.td > TTD && parent.td < TTD => block is mergeBlock - if (parent.totalDifficulty < this.config.TERMINAL_TOTAL_DIFFICULTY) { - // Is terminal total difficulty block AND has verified block -> parent relationship - return block; - } else { - block = parent; - } + // block.td > TTD && parent.td < TTD => block is mergeBlock + if (parent.totalDifficulty < this.config.TERMINAL_TOTAL_DIFFICULTY) { + // Is terminal total difficulty block AND has verified block -> parent relationship + return block; } + block = parent; } } diff --git a/packages/beacon-node/src/eth1/index.ts b/packages/beacon-node/src/eth1/index.ts index 7b2ec17496d3..42b82d03a848 100644 --- a/packages/beacon-node/src/eth1/index.ts +++ b/packages/beacon-node/src/eth1/index.ts @@ -53,9 +53,8 @@ export function initializeEth1ForBlockProduction( logger: modules.logger, signal: modules.signal, }); - } else { - return new Eth1ForBlockProductionDisabled(); } + return new Eth1ForBlockProductionDisabled(); } export class Eth1ForBlockProduction implements IEth1ForBlockProduction { @@ -85,9 +84,8 @@ export class Eth1ForBlockProduction implements IEth1ForBlockProduction { async getEth1DataAndDeposits(state: CachedBeaconStateAllForks): Promise { if (this.eth1DepositDataTracker === null) { return {eth1Data: state.eth1Data, deposits: []}; - } else { - return this.eth1DepositDataTracker.getEth1DataAndDeposits(state); } + return this.eth1DepositDataTracker.getEth1DataAndDeposits(state); } async getTerminalPowBlock(): Promise { @@ -104,11 +102,11 @@ export class Eth1ForBlockProduction implements IEth1ForBlockProduction { } startPollingMergeBlock(): void { - return this.eth1MergeBlockTracker.startPollingMergeBlock(); + this.eth1MergeBlockTracker.startPollingMergeBlock(); } stopPollingEth1Data(): void { - return this.eth1DepositDataTracker?.stopPollingEth1Data(); + this.eth1DepositDataTracker?.stopPollingEth1Data(); } } diff --git a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts index e1a2a001c278..f2ceae0d8c19 100644 --- a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts +++ b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts @@ -268,7 +268,7 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { }; const token = encodeJwtToken(jwtClaim, this.jwtSecret); - headers["Authorization"] = `Bearer ${token}`; + headers.Authorization = `Bearer ${token}`; } const res = await fetch(url, { @@ -296,12 +296,10 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { // controller will abort on both parent signal abort + timeout of this specific request if (this.opts?.signal?.aborted) { throw new ErrorAborted("request"); - } else { - throw new TimeoutError("request"); } - } else { - throw e; + throw new TimeoutError("request"); } + throw e; } finally { timer?.(); this.metrics?.activeRequests.dec({routeId}, 1); @@ -315,11 +313,11 @@ export class JsonRpcHttpClient implements IJsonRpcHttpClient { function parseRpcResponse(res: RpcResponse, payload: RpcPayload

): R { if (res.result !== undefined) { return res.result; - } else if (res.error !== undefined) { + } + if (res.error !== undefined) { throw new ErrorJsonRpcResponse(res, payload.method); - } else { - throw Error(`Invalid JSON RPC response, no result or error property: ${jsonSerializeTry(res)}`); } + throw Error(`Invalid JSON RPC response, no result or error property: ${jsonSerializeTry(res)}`); } /** diff --git a/packages/beacon-node/src/eth1/provider/utils.ts b/packages/beacon-node/src/eth1/provider/utils.ts index 096f1d7233c8..7010e1377ca6 100644 --- a/packages/beacon-node/src/eth1/provider/utils.ts +++ b/packages/beacon-node/src/eth1/provider/utils.ts @@ -53,7 +53,7 @@ export function numToQuantity(num: number | bigint): QUANTITY { */ export function quantityToNum(hex: QUANTITY, id = ""): number { const num = parseInt(hex, 16); - if (isNaN(num) || num < 0) throw Error(`Invalid hex decimal ${id} '${hex}'`); + if (Number.isNaN(num) || num < 0) throw Error(`Invalid hex decimal ${id} '${hex}'`); return num; } diff --git a/packages/beacon-node/src/eth1/utils/deposits.ts b/packages/beacon-node/src/eth1/utils/deposits.ts index 8d0331fc01d6..36f8c331ebc9 100644 --- a/packages/beacon-node/src/eth1/utils/deposits.ts +++ b/packages/beacon-node/src/eth1/utils/deposits.ts @@ -33,7 +33,9 @@ export async function getDeposits( if (deposits.length < depositsLen) { throw new Eth1Error({code: Eth1ErrorCode.NOT_ENOUGH_DEPOSITS, len: deposits.length, expectedLen: depositsLen}); - } else if (deposits.length > depositsLen) { + } + + if (deposits.length > depositsLen) { throw new Eth1Error({code: Eth1ErrorCode.TOO_MANY_DEPOSITS, len: deposits.length, expectedLen: depositsLen}); } diff --git a/packages/beacon-node/src/eth1/utils/eth1Vote.ts b/packages/beacon-node/src/eth1/utils/eth1Vote.ts index 7a4e3ddca9b6..84d35ae7d434 100644 --- a/packages/beacon-node/src/eth1/utils/eth1Vote.ts +++ b/packages/beacon-node/src/eth1/utils/eth1Vote.ts @@ -72,16 +72,14 @@ export function pickEth1Vote(state: BeaconStateAllForks, votesToConsider: phase0 } // If there's a single winning vote with a majority vote that one - else if (eth1DataRootsMaxVotes.length === 1) { + if (eth1DataRootsMaxVotes.length === 1) { return eth1DataHashToEth1Data.get(eth1DataRootsMaxVotes[0]) ?? state.eth1Data; } // If there are multiple winning votes, vote for the latest one - else { - const latestMostVotedRoot = - eth1DataVotesOrder[Math.max(...eth1DataRootsMaxVotes.map((root) => eth1DataVotesOrder.indexOf(root)))]; - return eth1DataHashToEth1Data.get(latestMostVotedRoot) ?? state.eth1Data; - } + const latestMostVotedRoot = + eth1DataVotesOrder[Math.max(...eth1DataRootsMaxVotes.map((root) => eth1DataVotesOrder.indexOf(root)))]; + return eth1DataHashToEth1Data.get(latestMostVotedRoot) ?? state.eth1Data; } /** diff --git a/packages/beacon-node/src/eth1/utils/optimizeNextBlockDiffForGenesis.ts b/packages/beacon-node/src/eth1/utils/optimizeNextBlockDiffForGenesis.ts index 4dc633693580..961d58680e47 100644 --- a/packages/beacon-node/src/eth1/utils/optimizeNextBlockDiffForGenesis.ts +++ b/packages/beacon-node/src/eth1/utils/optimizeNextBlockDiffForGenesis.ts @@ -13,7 +13,6 @@ export function optimizeNextBlockDiffForGenesis( const numBlocksToGenesis = Math.floor(timeToGenesis / params.SECONDS_PER_ETH1_BLOCK); if (numBlocksToGenesis <= 2) { return 1; - } else { - return Math.max(1, Math.floor(numBlocksToGenesis / 2)); } + return Math.max(1, Math.floor(numBlocksToGenesis / 2)); } diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index a8206a89250d..e5e65746d90f 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -258,9 +258,8 @@ export class ExecutionEngineHttp implements IExecutionEngine { ).catch((e: Error) => { if (e instanceof HttpRpcError || e instanceof ErrorJsonRpcResponse) { return {status: ExecutionPayloadStatus.ELERROR, latestValidHash: null, validationError: e.message}; - } else { - return {status: ExecutionPayloadStatus.UNAVAILABLE, latestValidHash: null, validationError: e.message}; } + return {status: ExecutionPayloadStatus.UNAVAILABLE, latestValidHash: null, validationError: e.message}; }); this.updateEngineState(getExecutionEngineState({payloadStatus: status, oldState: this.state})); @@ -379,9 +378,8 @@ export class ExecutionEngineHttp implements IExecutionEngine { // Throw error on syncing if requested to produce a block, else silently ignore if (payloadAttributes) { throw Error("Execution Layer Syncing"); - } else { - return null; } + return null; case ExecutionPayloadStatus.INVALID: throw Error( diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index bc3a130e604e..8062b68bf572 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -149,7 +149,9 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { const predefinedResponse = this.predefinedPayloadStatuses.get(blockHash); if (predefinedResponse) { return predefinedResponse; - } else if (this.opts.onlyPredefinedResponses) { + } + + if (this.opts.onlyPredefinedResponses) { throw Error(`No predefined response for blockHash ${blockHash}`); } @@ -212,7 +214,9 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { payloadStatus: predefinedResponse, payloadId: null, }; - } else if (this.opts.onlyPredefinedResponses) { + } + + if (this.opts.onlyPredefinedResponses) { throw Error(`No predefined response for headBlockHash ${headBlockHash}`); } @@ -344,14 +348,12 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { } // Don't start build process - else { - // IF the payload is deemed VALID and a build process hasn't been started - // {payloadStatus: {status: VALID, latestValidHash: forkchoiceState.headBlockHash, validationError: null}, payloadId: null} - return { - payloadStatus: {status: ExecutionPayloadStatus.VALID, latestValidHash: null, validationError: null}, - payloadId: null, - }; - } + // IF the payload is deemed VALID and a build process hasn't been started + // {payloadStatus: {status: VALID, latestValidHash: forkchoiceState.headBlockHash, validationError: null}, payloadId: null} + return { + payloadStatus: {status: ExecutionPayloadStatus.VALID, latestValidHash: null, validationError: null}, + payloadId: null, + }; } /** diff --git a/packages/beacon-node/src/metrics/validatorMonitor.ts b/packages/beacon-node/src/metrics/validatorMonitor.ts index 34dfa6b72e03..14a210f62997 100644 --- a/packages/beacon-node/src/metrics/validatorMonitor.ts +++ b/packages/beacon-node/src/metrics/validatorMonitor.ts @@ -814,7 +814,7 @@ function renderAttestationSummary( } // - else if (flags.timelyTarget) { + if (flags.timelyTarget) { // timelyHead == false, means at least one is true // - attestation voted incorrect head // - attestation was included late @@ -870,57 +870,55 @@ function renderAttestationSummary( } // - else if (flags.timelySource) { + if (flags.timelySource) { // timelyTarget == false && timelySource == true means that // - attestation voted the wrong target but distance is <= integer_squareroot(SLOTS_PER_EPOCH) return "wrong_target_timely_source"; } // - else { - // timelySource == false, either: - // - attestation was not included in the block - // - included in block with wrong target (very unlikely) - // - included in block with distance > SLOTS_PER_EPOCH (very unlikely) - - // Validator failed to submit an attestation for this epoch, validator client is probably offline - if (!summary || summary.poolSubmitDelayMinSec === null) { - return "no_submission"; - } + // timelySource == false, either: + // - attestation was not included in the block + // - included in block with wrong target (very unlikely) + // - included in block with distance > SLOTS_PER_EPOCH (very unlikely) + + // Validator failed to submit an attestation for this epoch, validator client is probably offline + if (!summary || summary.poolSubmitDelayMinSec === null) { + return "no_submission"; + } - const canonicalBlockInclusion = summary.blockInclusions.find((block) => isCanonical(rootCache, block)); - if (canonicalBlockInclusion) { - // Canonical block inclusion with no participation flags set means wrong target + late source - return "wrong_target_late_source"; - } + const canonicalBlockInclusion = summary.blockInclusions.find((block) => isCanonical(rootCache, block)); + if (canonicalBlockInclusion) { + // Canonical block inclusion with no participation flags set means wrong target + late source + return "wrong_target_late_source"; + } - const submittedLate = - summary.poolSubmitDelayMinSec > - (INTERVALS_LATE_ATTESTATION_SUBMISSION * config.SECONDS_PER_SLOT) / INTERVALS_PER_SLOT; - - const aggregateInclusion = summary.aggregateInclusionDelaysSec.length > 0; - - if (submittedLate && aggregateInclusion) { - return "late_submit"; - } else if (submittedLate && !aggregateInclusion) { - return "late_submit_no_aggregate_inclusion"; - } else if (!submittedLate && aggregateInclusion) { - // TODO: Why was it missed then? - if (summary.blockInclusions.length) { - return "block_inclusion_but_orphan"; - } else { - return "aggregate_inclusion_but_missed"; - } - // } else if (!submittedLate && !aggregateInclusion) { - } else { - // Did the node had enough peers? - if (summary.poolSubmitSentPeers === 0) { - return "sent_to_zero_peers"; - } else { - return "no_aggregate_inclusion"; - } + const submittedLate = + summary.poolSubmitDelayMinSec > + (INTERVALS_LATE_ATTESTATION_SUBMISSION * config.SECONDS_PER_SLOT) / INTERVALS_PER_SLOT; + + const aggregateInclusion = summary.aggregateInclusionDelaysSec.length > 0; + + if (submittedLate && aggregateInclusion) { + return "late_submit"; + } + if (submittedLate && !aggregateInclusion) { + return "late_submit_no_aggregate_inclusion"; + } + + if (!submittedLate && aggregateInclusion) { + // TODO: Why was it missed then? + if (summary.blockInclusions.length) { + return "block_inclusion_but_orphan"; } + return "aggregate_inclusion_but_missed"; + // } else if (!submittedLate && !aggregateInclusion) { } + // Did the node had enough peers? + if (summary.poolSubmitSentPeers === 0) { + return "sent_to_zero_peers"; + } + return "no_aggregate_inclusion"; } function whyIsHeadVoteWrong(rootCache: RootHexCache, canonicalBlockInclusion: AttestationBlockInclusion): string { @@ -968,9 +966,7 @@ function whyIsHeadVoteWrong(rootCache: RootHexCache, canonicalBlockInclusion: At // \_(A)_(A) // // Vote for different heads on skipped slot - else { - return "wrong_head_vote"; - } + return "wrong_head_vote"; } function whyIsDistanceNotOk( @@ -989,9 +985,7 @@ function whyIsDistanceNotOk( } // - else { - return "late_unknown"; - } + return "late_unknown"; } /** Returns true if the state's root record includes `block` */ diff --git a/packages/beacon-node/src/monitoring/properties.ts b/packages/beacon-node/src/monitoring/properties.ts index 55b94dd159b7..2ab819179863 100644 --- a/packages/beacon-node/src/monitoring/properties.ts +++ b/packages/beacon-node/src/monitoring/properties.ts @@ -140,11 +140,11 @@ export class MetricProperty implements ClientStatsPropert case JsonType.Boolean: if (this.definition.rangeValue != null) { return value === this.definition.rangeValue; - } else if (this.definition.threshold != null) { + } + if (this.definition.threshold != null) { return value >= this.definition.threshold; - } else { - return value > 0; } + return value > 0; } } return value; diff --git a/packages/beacon-node/src/monitoring/service.ts b/packages/beacon-node/src/monitoring/service.ts index bd2388738d1f..f6a6a2352e02 100644 --- a/packages/beacon-node/src/monitoring/service.ts +++ b/packages/beacon-node/src/monitoring/service.ts @@ -191,11 +191,11 @@ export class MonitoringService { // error was thrown by abort signal if (signal.reason === FetchAbortReason.Close) { throw new ErrorAborted("request"); - } else if (signal.reason === FetchAbortReason.Timeout) { + } + if (signal.reason === FetchAbortReason.Timeout) { throw new TimeoutError("request"); - } else { - throw e; } + throw e; } finally { timer({status: res?.ok ? SendDataStatus.Success : SendDataStatus.Error}); clearTimeout(timeout); diff --git a/packages/beacon-node/src/network/core/networkCore.ts b/packages/beacon-node/src/network/core/networkCore.ts index 9d075c730558..b000d184e0eb 100644 --- a/packages/beacon-node/src/network/core/networkCore.ts +++ b/packages/beacon-node/src/network/core/networkCore.ts @@ -224,6 +224,7 @@ export class NetworkCore implements INetworkCore { reqResp.registerProtocolsAtFork(forkCurrentSlot); // Bind discv5's ENR to local metadata + // biome-ignore lint/complexity/useLiteralKeys: `discovery` is a private attribute discv5 = peerManager["discovery"]?.discv5; // Initialize ENR with clock's fork @@ -277,6 +278,7 @@ export class NetworkCore implements INetworkCore { async scrapeMetrics(): Promise { return [ (await this.metrics?.register.metrics()) ?? "", + // biome-ignore lint/complexity/useLiteralKeys: `discovery` is a private attribute (await this.peerManager["discovery"]?.discv5.scrapeMetrics()) ?? "", ] .filter((str) => str.length > 0) @@ -344,6 +346,7 @@ export class NetworkCore implements INetworkCore { // REST API queries async getNetworkIdentity(): Promise { + // biome-ignore lint/complexity/useLiteralKeys: `discovery` is a private attribute const enr = await this.peerManager["discovery"]?.discv5.enr(); const discoveryAddresses = [ enr?.getLocationMultiaddr("tcp")?.toString() ?? null, @@ -410,6 +413,7 @@ export class NetworkCore implements INetworkCore { } async dumpDiscv5KadValues(): Promise { + // biome-ignore lint/complexity/useLiteralKeys: `discovery` is a private attribute return (await this.peerManager["discovery"]?.discv5?.kadValues())?.map((enr) => enr.encodeTxt()) ?? []; } @@ -426,6 +430,7 @@ export class NetworkCore implements INetworkCore { } async writeDiscv5Profile(durationMs: number, dirpath: string): Promise { + // biome-ignore lint/complexity/useLiteralKeys: `discovery` is a private attribute return this.peerManager["discovery"]?.discv5.writeProfile(durationMs, dirpath) ?? "no discv5"; } @@ -434,6 +439,7 @@ export class NetworkCore implements INetworkCore { } writeDiscv5HeapSnapshot(prefix: string, dirpath: string): Promise { + // biome-ignore lint/complexity/useLiteralKeys: `discovery` is a private attribute return this.peerManager["discovery"]?.discv5.writeHeapSnapshot(prefix, dirpath) ?? Promise.resolve("no discv5"); } diff --git a/packages/beacon-node/src/network/gossip/encoding.ts b/packages/beacon-node/src/network/gossip/encoding.ts index 02c0df07b2f1..f7f733fcd915 100644 --- a/packages/beacon-node/src/network/gossip/encoding.ts +++ b/packages/beacon-node/src/network/gossip/encoding.ts @@ -25,9 +25,8 @@ const sharedMsgIdBuf = Buffer.alloc(20); export function fastMsgIdFn(rpcMsg: RPC.Message): string { if (rpcMsg.data) { return xxhash.h64Raw(rpcMsg.data, h64Seed).toString(16); - } else { - return "0000000000000000"; } + return "0000000000000000"; } export function msgIdToStrFn(msgId: Uint8Array): string { diff --git a/packages/beacon-node/src/network/gossip/gossipsub.ts b/packages/beacon-node/src/network/gossip/gossipsub.ts index debcbaf89854..83bb913325bf 100644 --- a/packages/beacon-node/src/network/gossip/gossipsub.ts +++ b/packages/beacon-node/src/network/gossip/gossipsub.ts @@ -121,7 +121,7 @@ export class Eth2Gossipsub extends GossipSub { // TODO: figure out a way to dynamically transition to the size dataTransform: new DataTransformSnappy( gossipTopicCache, - isFinite(config.BELLATRIX_FORK_EPOCH) ? GOSSIP_MAX_SIZE_BELLATRIX : GOSSIP_MAX_SIZE + Number.isFinite(config.BELLATRIX_FORK_EPOCH) ? GOSSIP_MAX_SIZE_BELLATRIX : GOSSIP_MAX_SIZE ), metricsRegister: metricsRegister as MetricsRegister | null, metricsTopicStrToLabel: metricsRegister @@ -184,10 +184,11 @@ export class Eth2Gossipsub extends GossipSub { } private onScrapeLodestarMetrics(metrics: Eth2GossipsubMetrics): void { - const mesh = this["mesh"]; + const mesh = this.mesh; + // biome-ignore lint/complexity/useLiteralKeys: `topics` is a private attribute const topics = this["topics"] as Map>; - const peers = this["peers"]; - const score = this["score"]; + const peers = this.peers; + const score = this.score; const meshPeersByClient = new Map(); const meshPeerIdStrs = new Set(); @@ -324,7 +325,8 @@ export class Eth2Gossipsub extends GossipSub { */ function attSubnetLabel(subnet: number): string { if (subnet > 9) return String(subnet); - else return `0${subnet}`; + + return `0${subnet}`; } function getMetricsTopicStrToLabel(config: BeaconConfig, opts: {disableLightClientServer: boolean}): TopicStrToLabel { diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index c44e29274bca..ed44c8314425 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -137,7 +137,7 @@ export function sszDeserializeAttestation(fork: ForkName, serializedData: Uint8A // Parsing -const gossipTopicRegex = new RegExp("^/eth2/(\\w+)/(\\w+)/(\\w+)"); +const gossipTopicRegex = /^\/eth2\/(\w+)\/(\w+)\/(\w+)/; /** * Parse a `GossipTopic` object from its stringified form. diff --git a/packages/beacon-node/src/network/peers/discover.ts b/packages/beacon-node/src/network/peers/discover.ts index d3bfd2d2aab4..0ca67caf74fa 100644 --- a/packages/beacon-node/src/network/peers/discover.ts +++ b/packages/beacon-node/src/network/peers/discover.ts @@ -278,9 +278,8 @@ export class PeerDiscovery { if (this.randomNodeQuery.code === QueryStatusCode.Active) { this.metrics?.discovery.findNodeQueryRequests.inc({action: "ignore"}); return; - } else { - this.metrics?.discovery.findNodeQueryRequests.inc({action: "start"}); } + this.metrics?.discovery.findNodeQueryRequests.inc({action: "start"}); // Use async version to prevent blocking the event loop // Time to completion of this function is not critical, in case this async call add extra lag @@ -372,7 +371,7 @@ export class PeerDiscovery { if ( this.libp2p.services.components.connectionManager .getDialQueue() - .find((pendingDial) => pendingDial.peerId && pendingDial.peerId.equals(peerId)) + .find((pendingDial) => pendingDial.peerId?.equals(peerId)) ) { return DiscoveredPeerStatus.already_dialing; } @@ -389,13 +388,13 @@ export class PeerDiscovery { if (this.shouldDialPeer(cachedPeer)) { void this.dialPeer(cachedPeer); return DiscoveredPeerStatus.attempt_dial; - } else { - // Add to pending good peers with a last seen time - this.cachedENRs.set(peerId.toString(), cachedPeer); - const dropped = pruneSetToMax(this.cachedENRs, MAX_CACHED_ENRS); - // If the cache was already full, count the peer as dropped - return dropped > 0 ? DiscoveredPeerStatus.dropped : DiscoveredPeerStatus.cached; } + + // Add to pending good peers with a last seen time + this.cachedENRs.set(peerId.toString(), cachedPeer); + const dropped = pruneSetToMax(this.cachedENRs, MAX_CACHED_ENRS); + // If the cache was already full, count the peer as dropped + return dropped > 0 ? DiscoveredPeerStatus.dropped : DiscoveredPeerStatus.cached; } catch (e) { this.logger.error("Error onDiscovered", {}, e as Error); return DiscoveredPeerStatus.error; @@ -473,7 +472,7 @@ export class PeerDiscovery { /** Check if there is 1+ open connection with this peer */ private isPeerConnected(peerIdStr: PeerIdStr): boolean { const connections = getConnectionsMap(this.libp2p).get(peerIdStr); - return Boolean(connections && connections.value.some((connection) => connection.status === "open")); + return Boolean(connections?.value.some((connection) => connection.status === "open")); } } diff --git a/packages/beacon-node/src/network/peers/peerManager.ts b/packages/beacon-node/src/network/peers/peerManager.ts index 7894b63e0be2..b076285b0d21 100644 --- a/packages/beacon-node/src/network/peers/peerManager.ts +++ b/packages/beacon-node/src/network/peers/peerManager.ts @@ -277,11 +277,14 @@ export class PeerManager { switch (request.method) { case ReqRespMethod.Ping: - return this.onPing(peer, request.body); + this.onPing(peer, request.body); + return; case ReqRespMethod.Goodbye: - return this.onGoodbye(peer, request.body); + this.onGoodbye(peer, request.body); + return; case ReqRespMethod.Status: - return this.onStatus(peer, request.body); + this.onStatus(peer, request.body); + return; } } catch (e) { this.logger.error("Error onRequest handler", {}, e as Error); diff --git a/packages/beacon-node/src/network/processor/gossipQueues/index.ts b/packages/beacon-node/src/network/processor/gossipQueues/index.ts index 12596a42b7a1..dfa5b0dd1973 100644 --- a/packages/beacon-node/src/network/processor/gossipQueues/index.ts +++ b/packages/beacon-node/src/network/processor/gossipQueues/index.ts @@ -104,8 +104,7 @@ export function createGossipQueues(): { return mapValues(gossipQueueOpts, (opts) => { if (isIndexedGossipQueueMinSizeOpts(opts)) { return new IndexedGossipQueueMinSize(opts); - } else { - return new LinearGossipQueue(opts); } + return new LinearGossipQueue(opts); }); } diff --git a/packages/beacon-node/src/network/processor/gossipQueues/indexed.ts b/packages/beacon-node/src/network/processor/gossipQueues/indexed.ts index 8edba7dfaadb..a7b23b2ac929 100644 --- a/packages/beacon-node/src/network/processor/gossipQueues/indexed.ts +++ b/packages/beacon-node/src/network/processor/gossipQueues/indexed.ts @@ -123,9 +123,8 @@ export class IndexedGossipQueueMinSize implements GossipQueue { // overload, need to drop more items if (this.opts.dropOpts.type === DropType.count) { return this.dropByCount(this.opts.dropOpts.count); - } else { - this.recentDrop = true; - const droppedCount = this.dropByRatio(this._dropRatio); - // increase drop ratio the next time queue is full - this._dropRatio = Math.min(MAX_DROP_RATIO, this._dropRatio + this.opts.dropOpts.step); - return droppedCount; } + + this.recentDrop = true; + const droppedCount = this.dropByRatio(this._dropRatio); + // increase drop ratio the next time queue is full + this._dropRatio = Math.min(MAX_DROP_RATIO, this._dropRatio + this.opts.dropOpts.step); + return droppedCount; } next(): T | null { diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts index 74b6d8f13b2e..8c69c21679ba 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts @@ -37,7 +37,7 @@ export async function beaconBlocksMaybeBlobsByRange( } // Only request blobs if they are recent enough - else if (computeEpochAtSlot(startSlot) >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) { + if (computeEpochAtSlot(startSlot) >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) { const [allBlocks, allBlobSidecars] = await Promise.all([ network.sendBeaconBlocksByRange(peerId, request), network.sendBlobSidecarsByRange(peerId, request), @@ -47,9 +47,7 @@ export async function beaconBlocksMaybeBlobsByRange( } // Post Deneb but old blobs - else { - throw Error("Cannot sync blobs outside of blobs prune window"); - } + throw Error("Cannot sync blobs outside of blobs prune window"); } // Assumes that the blobs are in the same sequence as blocks, doesn't require block to be sorted diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts index b53addab9b43..3d121156d8e6 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts @@ -1,5 +1,5 @@ import {ChainForkConfig} from "@lodestar/config"; -import {phase0, deneb} from "@lodestar/types"; +import {phase0, deneb, SignedBeaconBlock} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import {fromHex} from "@lodestar/utils"; import { @@ -64,7 +64,11 @@ export async function unavailableBeaconBlobsByRoot( } // resolve the block if thats unavailable - let block, blobsCache, blockBytes, resolveAvailability, cachedData; + let block: SignedBeaconBlock, + blobsCache: NullBlockInput["cachedData"]["blobsCache"], + blockBytes: Uint8Array | null, + resolveAvailability: NullBlockInput["cachedData"]["resolveAvailability"], + cachedData: NullBlockInput["cachedData"]; if (unavailableBlockInput.block === null) { const allBlocks = await network.sendBeaconBlocksByRoot(peerId, [fromHex(unavailableBlockInput.blockRootHex)]); block = allBlocks[0].data; diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts index d14e0945e977..3b50304eb50c 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts @@ -24,8 +24,7 @@ export async function* onLightClientBootstrap(requestBody: Root, chain: IBeaconC } catch (e) { if ((e as LightClientServerError).type?.code === LightClientServerErrorCode.RESOURCE_UNAVAILABLE) { throw new ResponseError(RespStatus.RESOURCE_UNAVAILABLE, (e as Error).message); - } else { - throw new ResponseError(RespStatus.SERVER_ERROR, (e as Error).message); } + throw new ResponseError(RespStatus.SERVER_ERROR, (e as Error).message); } } diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts index 2468b0b64f4b..4764c6f198f7 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts @@ -9,12 +9,12 @@ export async function* onLightClientFinalityUpdate(chain: IBeaconChain): AsyncIt const update = chain.lightClientServer.getFinalityUpdate(); if (update === null) { throw new ResponseError(RespStatus.RESOURCE_UNAVAILABLE, "No latest finality update available"); - } else { - const fork = chain.config.getForkName(update.signatureSlot); - const type = responseSszTypeByMethod[ReqRespMethod.LightClientFinalityUpdate](fork, 0); - yield { - data: type.serialize(update), - fork, - }; } + + const fork = chain.config.getForkName(update.signatureSlot); + const type = responseSszTypeByMethod[ReqRespMethod.LightClientFinalityUpdate](fork, 0); + yield { + data: type.serialize(update), + fork, + }; } diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts index ba8371910c02..4c030a8e4174 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts @@ -9,12 +9,12 @@ export async function* onLightClientOptimisticUpdate(chain: IBeaconChain): Async const update = chain.lightClientServer.getOptimisticUpdate(); if (update === null) { throw new ResponseError(RespStatus.RESOURCE_UNAVAILABLE, "No latest optimistic update available"); - } else { - const fork = chain.config.getForkName(update.signatureSlot); - const type = responseSszTypeByMethod[ReqRespMethod.LightClientOptimisticUpdate](fork, 0); - yield { - data: type.serialize(update), - fork, - }; } + + const fork = chain.config.getForkName(update.signatureSlot); + const type = responseSszTypeByMethod[ReqRespMethod.LightClientOptimisticUpdate](fork, 0); + yield { + data: type.serialize(update), + fork, + }; } diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts index eb0e3c3d3f4e..89466eca6c21 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts @@ -31,9 +31,8 @@ export async function* onLightClientUpdatesByRange( } catch (e) { if ((e as LightClientServerError).type?.code === LightClientServerErrorCode.RESOURCE_UNAVAILABLE) { throw new ResponseError(RespStatus.RESOURCE_UNAVAILABLE, (e as Error).message); - } else { - throw new ResponseError(RespStatus.SERVER_ERROR, (e as Error).message); } + throw new ResponseError(RespStatus.SERVER_ERROR, (e as Error).message); } } } diff --git a/packages/beacon-node/src/network/reqresp/types.ts b/packages/beacon-node/src/network/reqresp/types.ts index 02d99dd86933..96ae1558ec07 100644 --- a/packages/beacon-node/src/network/reqresp/types.ts +++ b/packages/beacon-node/src/network/reqresp/types.ts @@ -90,16 +90,16 @@ export type ResponseTypeGetter = (fork: ForkName, version: number) => Type const blocksResponseType: ResponseTypeGetter = (fork, version) => { if (version === Version.V1) { return ssz.phase0.SignedBeaconBlock; - } else { - return ssz[fork].SignedBeaconBlock; } + + return ssz[fork].SignedBeaconBlock; }; export const responseSszTypeByMethod: {[K in ReqRespMethod]: ResponseTypeGetter} = { [ReqRespMethod.Status]: () => ssz.phase0.Status, [ReqRespMethod.Goodbye]: () => ssz.phase0.Goodbye, [ReqRespMethod.Ping]: () => ssz.phase0.Ping, - [ReqRespMethod.Metadata]: (_, version) => (version == Version.V1 ? ssz.phase0.Metadata : ssz.altair.Metadata), + [ReqRespMethod.Metadata]: (_, version) => (version === Version.V1 ? ssz.phase0.Metadata : ssz.altair.Metadata), [ReqRespMethod.BeaconBlocksByRange]: blocksResponseType, [ReqRespMethod.BeaconBlocksByRoot]: blocksResponseType, [ReqRespMethod.BlobSidecarsByRange]: () => ssz.deneb.BlobSidecar, @@ -114,9 +114,8 @@ export const responseSszTypeByMethod: {[K in ReqRespMethod]: ResponseTypeGetter< function onlyLightclientFork(fork: ForkName): ForkLightClient { if (isForkLightClient(fork)) { return fork; - } else { - throw Error(`Not a lightclient fork ${fork}`); } + throw Error(`Not a lightclient fork ${fork}`); } export type RequestTypedContainer = { diff --git a/packages/beacon-node/src/network/util.ts b/packages/beacon-node/src/network/util.ts index 2be4756fe693..f1d6b917b5e4 100644 --- a/packages/beacon-node/src/network/util.ts +++ b/packages/beacon-node/src/network/util.ts @@ -15,6 +15,7 @@ export function prettyPrintPeerIdStr(id: PeerIdStr): string { */ // Compat function for efficiency reasons export function getConnectionsMap(libp2p: Libp2p): Map { + // biome-ignore lint/complexity/useLiteralKeys: `map` is a private attribute return libp2p.services.components.connectionManager.getConnectionsMap()["map"]; } diff --git a/packages/beacon-node/src/node/nodejs.ts b/packages/beacon-node/src/node/nodejs.ts index 7b42f0daceb2..0e51b15e514b 100644 --- a/packages/beacon-node/src/node/nodejs.ts +++ b/packages/beacon-node/src/node/nodejs.ts @@ -305,7 +305,7 @@ export class BeaconNode { void runNodeNotifier({network, chain, sync, config, logger, signal}); - return new this({ + return new BeaconNode({ opts, config, db, diff --git a/packages/beacon-node/src/node/notifier.ts b/packages/beacon-node/src/node/notifier.ts index 6b9a29817158..20a359a45c49 100644 --- a/packages/beacon-node/src/node/notifier.ts +++ b/packages/beacon-node/src/node/notifier.ts @@ -92,7 +92,7 @@ export async function runNodeNotifier(modules: NodeNotifierModules): Promise msPerHalfSlot ? msToNextSlot - msPerHalfSlot : msToNextSlot + msPerHalfSlot; - } else { - // after the 1st time always wait until middle of next clock slot - return msToNextSlot + msPerHalfSlot; } + // after the 1st time always wait until middle of next clock slot + return msToNextSlot + msPerHalfSlot; } function getHeadExecutionInfo( @@ -181,26 +179,25 @@ function getHeadExecutionInfo( ): string[] { if (clockEpoch < config.BELLATRIX_FORK_EPOCH) { return []; - } else { - const executionStatusStr = headInfo.executionStatus.toLowerCase(); - - // Add execution status to notifier only if head is on/post bellatrix - if (isExecutionCachedStateType(headState)) { - if (isMergeTransitionComplete(headState)) { - const executionPayloadHashInfo = - headInfo.executionStatus !== ExecutionStatus.PreMerge ? headInfo.executionPayloadBlockHash : "empty"; - const executionPayloadNumberInfo = - headInfo.executionStatus !== ExecutionStatus.PreMerge ? headInfo.executionPayloadNumber : NaN; - return [ - `exec-block: ${executionStatusStr}(${executionPayloadNumberInfo} ${prettyBytesShort( - executionPayloadHashInfo - )})`, - ]; - } else { - return [`exec-block: ${executionStatusStr}`]; - } - } else { - return []; + } + + const executionStatusStr = headInfo.executionStatus.toLowerCase(); + + // Add execution status to notifier only if head is on/post bellatrix + if (isExecutionCachedStateType(headState)) { + if (isMergeTransitionComplete(headState)) { + const executionPayloadHashInfo = + headInfo.executionStatus !== ExecutionStatus.PreMerge ? headInfo.executionPayloadBlockHash : "empty"; + const executionPayloadNumberInfo = + headInfo.executionStatus !== ExecutionStatus.PreMerge ? headInfo.executionPayloadNumber : NaN; + return [ + `exec-block: ${executionStatusStr}(${executionPayloadNumberInfo} ${prettyBytesShort( + executionPayloadHashInfo + )})`, + ]; } + return [`exec-block: ${executionStatusStr}`]; } + + return []; } diff --git a/packages/beacon-node/src/sync/backfill/backfill.ts b/packages/beacon-node/src/sync/backfill/backfill.ts index f60e28a19e1d..9612cf23b615 100644 --- a/packages/beacon-node/src/sync/backfill/backfill.ts +++ b/packages/beacon-node/src/sync/backfill/backfill.ts @@ -262,7 +262,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} // Load a previous finalized or wsCheckpoint slot from DB below anchorSlot const prevFinalizedCheckpointBlock = await extractPreviousFinOrWsCheckpoint(config, db, anchorSlot, logger); - return new this(opts, { + return new BackfillSync(opts, { syncAnchor, backfillStartFromSlot, backfillRangeWrittenSlot, @@ -457,6 +457,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} this.status = BackfillSyncStatus.aborted; break; case BackfillSyncErrorCode.NOT_ANCHORED: + // biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here case BackfillSyncErrorCode.NOT_LINEAR: // Lets try to jump directly to the parent of this anchorBlock as previous // (segment) of blocks could be orphaned/missed @@ -674,7 +675,7 @@ export class BackfillSync extends (EventEmitter as {new (): BackfillSyncEmitter} ); // If possible, read back till anchorBlock > this.prevFinalizedCheckpointBlock - let parentBlock, + let parentBlock: SignedBeaconBlock | null, backCount = 1; let isPrevFinWsConfirmedAnchorParent = false; diff --git a/packages/beacon-node/src/sync/range/range.ts b/packages/beacon-node/src/sync/range/range.ts index efdf84cf7af1..51e3a5d0f182 100644 --- a/packages/beacon-node/src/sync/range/range.ts +++ b/packages/beacon-node/src/sync/range/range.ts @@ -150,17 +150,15 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) { if (chain.isSyncing) { if (chain.syncType === RangeSyncType.Finalized) { return {status: RangeSyncStatus.Finalized, target: chain.target}; - } else { - syncingHeadTargets.push(chain.target); } + syncingHeadTargets.push(chain.target); } } if (syncingHeadTargets.length > 0) { return {status: RangeSyncStatus.Head, targets: syncingHeadTargets}; - } else { - return {status: RangeSyncStatus.Idle}; } + return {status: RangeSyncStatus.Idle}; } /** Full debug state for lodestar API */ diff --git a/packages/beacon-node/src/sync/range/utils/batches.ts b/packages/beacon-node/src/sync/range/utils/batches.ts index 734c84800b69..c8490ade6317 100644 --- a/packages/beacon-node/src/sync/range/utils/batches.ts +++ b/packages/beacon-node/src/sync/range/utils/batches.ts @@ -113,7 +113,7 @@ export function isSyncChainDone(batches: Batch[], lastEpochWithProcessBlocks: Ep if (lastAwaitingValidation) { return batchStartEpochIsAfterSlot(lastAwaitingValidation.startEpoch + EPOCHS_PER_BATCH, targetSlot); - } else { - return batchStartEpochIsAfterSlot(lastEpochWithProcessBlocks, targetSlot); } + + return batchStartEpochIsAfterSlot(lastEpochWithProcessBlocks, targetSlot); } diff --git a/packages/beacon-node/src/sync/sync.ts b/packages/beacon-node/src/sync/sync.ts index cc8ddc6eb499..1e03431adbbb 100644 --- a/packages/beacon-node/src/sync/sync.ts +++ b/packages/beacon-node/src/sync/sync.ts @@ -99,31 +99,31 @@ export class BeaconSync implements IBeaconSync { isOptimistic: false, elOffline, }; - } else { - const head = this.chain.forkChoice.getHead(); - - switch (this.state) { - case SyncState.SyncingFinalized: - case SyncState.SyncingHead: - case SyncState.Stalled: - return { - headSlot: head.slot, - syncDistance: currentSlot - head.slot, - isSyncing: true, - isOptimistic: isOptimisticBlock(head), - elOffline, - }; - case SyncState.Synced: - return { - headSlot: head.slot, - syncDistance: 0, - isSyncing: false, - isOptimistic: isOptimisticBlock(head), - elOffline, - }; - default: - throw new Error("Node is stopped, cannot get sync status"); - } + } + + const head = this.chain.forkChoice.getHead(); + + switch (this.state) { + case SyncState.SyncingFinalized: + case SyncState.SyncingHead: + case SyncState.Stalled: + return { + headSlot: head.slot, + syncDistance: currentSlot - head.slot, + isSyncing: true, + isOptimistic: isOptimisticBlock(head), + elOffline, + }; + case SyncState.Synced: + return { + headSlot: head.slot, + syncDistance: 0, + isSyncing: false, + isOptimistic: isOptimisticBlock(head), + elOffline, + }; + default: + throw new Error("Node is stopped, cannot get sync status"); } } @@ -163,6 +163,8 @@ export class BeaconSync implements IBeaconSync { return SyncState.SyncingHead; case RangeSyncStatus.Idle: return SyncState.Stalled; + default: + throw new Error("Unreachable code"); } } diff --git a/packages/beacon-node/src/sync/unknownBlock.ts b/packages/beacon-node/src/sync/unknownBlock.ts index a172b5d723db..003b035a898d 100644 --- a/packages/beacon-node/src/sync/unknownBlock.ts +++ b/packages/beacon-node/src/sync/unknownBlock.ts @@ -15,7 +15,7 @@ import { beaconBlocksMaybeBlobsByRoot, unavailableBeaconBlobsByRoot, } from "../network/reqresp/beaconBlocksMaybeBlobsByRoot.js"; -import {wrapError} from "../util/wrapError.js"; +import {Result, wrapError} from "../util/wrapError.js"; import {PendingBlock, PendingBlockStatus, PendingBlockType} from "./interface.js"; import {getDescendantBlocks, getAllDescendantBlocks, getUnknownAndAncestorBlocks} from "./utils/pendingBlocksTree.js"; import {SyncOptions} from "./options.js"; @@ -168,7 +168,7 @@ export class UnknownBlockSync { blockInputOrRootHex: RootHex | BlockInput | NullBlockInput, peerIdStr?: string ): Exclude { - let blockRootHex; + let blockRootHex: RootHex; let blockInput: BlockInput | NullBlockInput | null; let unknownBlockType: Exclude; @@ -285,7 +285,7 @@ export class UnknownBlockSync { block.status = PendingBlockStatus.fetching; - let res; + let res: Result<{blockInput: BlockInput; peerIdStr: string}>; if (block.blockInput === null) { res = await wrapError(this.fetchUnknownBlockRoot(fromHex(block.blockRootHex), connectedPeers)); } else { @@ -493,9 +493,8 @@ export class UnknownBlockSync { if (lastError) { lastError.message = `Error fetching UnknownBlockRoot after ${MAX_ATTEMPTS_PER_BLOCK} attempts: ${lastError.message}`; throw lastError; - } else { - throw Error(`Error fetching UnknownBlockRoot after ${MAX_ATTEMPTS_PER_BLOCK}: unknown error`); } + throw Error(`Error fetching UnknownBlockRoot after ${MAX_ATTEMPTS_PER_BLOCK}: unknown error`); } /** @@ -511,10 +510,10 @@ export class UnknownBlockSync { } const shuffledPeers = shuffle(connectedPeers); - let blockRootHex; - let pendingBlobs; - let blobKzgCommitmentsLen; - let blockRoot; + let blockRootHex: RootHex; + let pendingBlobs: number | undefined; + let blobKzgCommitmentsLen: number | undefined; + let blockRoot: Uint8Array; if (unavailableBlockInput.block === null) { blockRootHex = unavailableBlockInput.blockRootHex; @@ -569,9 +568,9 @@ export class UnknownBlockSync { if (lastError) { lastError.message = `Error fetching UnavailableBlockInput after ${MAX_ATTEMPTS_PER_BLOCK} attempts: ${lastError.message}`; throw lastError; - } else { - throw Error(`Error fetching UnavailableBlockInput after ${MAX_ATTEMPTS_PER_BLOCK}: unknown error`); } + + throw Error(`Error fetching UnavailableBlockInput after ${MAX_ATTEMPTS_PER_BLOCK}: unknown error`); } /** diff --git a/packages/beacon-node/src/sync/utils/remoteSyncType.ts b/packages/beacon-node/src/sync/utils/remoteSyncType.ts index 87cca86375f0..247269ab409a 100644 --- a/packages/beacon-node/src/sync/utils/remoteSyncType.ts +++ b/packages/beacon-node/src/sync/utils/remoteSyncType.ts @@ -49,36 +49,33 @@ export function getPeerSyncType( return PeerSyncType.Behind; } - // - else if (remote.finalizedEpoch > local.finalizedEpoch) { + if (remote.finalizedEpoch > local.finalizedEpoch) { if ( // Peer is in next epoch, and head is within range => SYNCED - (local.finalizedEpoch + 1 == remote.finalizedEpoch && + (local.finalizedEpoch + 1 === remote.finalizedEpoch && withinRangeOf(remote.headSlot, local.headSlot, slotImportTolerance)) || // Peer's head is known => SYNCED forkChoice.hasBlock(remote.headRoot) ) { return PeerSyncType.FullySynced; - } else { - return PeerSyncType.Advanced; } + return PeerSyncType.Advanced; } // remote.finalizedEpoch == local.finalizedEpoch - else { - // NOTE: if a peer has our same `finalizedEpoch` with a different `finalized_root` - // they are not considered relevant and won't be propagated to sync. - // Check if the peer is the peer is inside the tolerance range to be considered synced. - if (remote.headSlot < nearRangeStart) { - return PeerSyncType.Behind; - } else if (remote.headSlot > nearRangeEnd && !forkChoice.hasBlock(remote.headRoot)) { - // This peer has a head ahead enough of ours and we have no knowledge of their best block. - return PeerSyncType.Advanced; - } else { - // This peer is either in the tolerance range, or ahead us with an already rejected block. - return PeerSyncType.FullySynced; - } + // NOTE: if a peer has our same `finalizedEpoch` with a different `finalized_root` + // they are not considered relevant and won't be propagated to sync. + // Check if the peer is the peer is inside the tolerance range to be considered synced. + if (remote.headSlot < nearRangeStart) { + return PeerSyncType.Behind; + } + + if (remote.headSlot > nearRangeEnd && !forkChoice.hasBlock(remote.headRoot)) { + // This peer has a head ahead enough of ours and we have no knowledge of their best block. + return PeerSyncType.Advanced; } + // This peer is either in the tolerance range, or ahead us with an already rejected block. + return PeerSyncType.FullySynced; } export enum RangeSyncType { @@ -99,9 +96,8 @@ export const rangeSyncTypes = Object.keys(RangeSyncType) as RangeSyncType[]; export function getRangeSyncType(local: phase0.Status, remote: phase0.Status, forkChoice: IForkChoice): RangeSyncType { if (remote.finalizedEpoch > local.finalizedEpoch && !forkChoice.hasBlock(remote.finalizedRoot)) { return RangeSyncType.Finalized; - } else { - return RangeSyncType.Head; } + return RangeSyncType.Head; } export function getRangeSyncTarget( @@ -134,16 +130,15 @@ export function getRangeSyncTarget( root: remote.finalizedRoot, }, }; - } else { - return { - syncType: RangeSyncType.Head, - // The new peer has the same finalized (earlier filters should prevent a peer with an - // earlier finalized chain from reaching here). - startEpoch: Math.min(computeEpochAtSlot(local.headSlot), remote.finalizedEpoch), - target: { - slot: remote.headSlot, - root: remote.headRoot, - }, - }; } + return { + syncType: RangeSyncType.Head, + // The new peer has the same finalized (earlier filters should prevent a peer with an + // earlier finalized chain from reaching here). + startEpoch: Math.min(computeEpochAtSlot(local.headSlot), remote.finalizedEpoch), + target: { + slot: remote.headSlot, + root: remote.headRoot, + }, + }; } diff --git a/packages/beacon-node/src/util/binarySearch.ts b/packages/beacon-node/src/util/binarySearch.ts index db7c03af50b7..459154eb0427 100644 --- a/packages/beacon-node/src/util/binarySearch.ts +++ b/packages/beacon-node/src/util/binarySearch.ts @@ -1,5 +1,5 @@ export function binarySearchLte(items: T[], value: number, getter: (item: T) => number): T { - if (items.length == 0) { + if (items.length === 0) { throw new ErrorNoValues(); } diff --git a/packages/beacon-node/src/util/bitArray.ts b/packages/beacon-node/src/util/bitArray.ts index 364110fe958f..3411886de3ca 100644 --- a/packages/beacon-node/src/util/bitArray.ts +++ b/packages/beacon-node/src/util/bitArray.ts @@ -72,7 +72,7 @@ export function intersectUint8Arrays(aUA: Uint8Array, bUA: Uint8Array): Intersec // subset = MUST subset MAYBE equal if (!someExcludes && !someSuperset && someSubset) return IntersectResult.Subset; // intersect = any other condition - else return IntersectResult.Intersect; + return IntersectResult.Intersect; } /** diff --git a/packages/beacon-node/src/util/kzg.ts b/packages/beacon-node/src/util/kzg.ts index efc6dd34ee1c..e89d4e0dfc99 100644 --- a/packages/beacon-node/src/util/kzg.ts +++ b/packages/beacon-node/src/util/kzg.ts @@ -59,7 +59,7 @@ export enum TrustedFileMode { */ export function loadEthereumTrustedSetup(mode: TrustedFileMode = TrustedFileMode.Txt, filePath?: string): void { try { - let setupFilePath; + let setupFilePath: string; if (mode === TrustedFileMode.Bin) { const binPath = filePath ?? TRUSTED_SETUP_BIN_FILEPATH; const bytes = fs.readFileSync(binPath); @@ -154,7 +154,6 @@ export function trustedSetupJsonToTxt(data: TrustedSetupJSON): TrustedSetupTXT { function strip0xPrefix(hex: string): string { if (hex.startsWith("0x")) { return hex.slice(2); - } else { - return hex; } + return hex; } diff --git a/packages/beacon-node/test/e2e/api/impl/beacon/block/endpoint.test.ts b/packages/beacon-node/test/e2e/api/impl/beacon/block/endpoint.test.ts index ee0b17348099..b8939b54c294 100644 --- a/packages/beacon-node/test/e2e/api/impl/beacon/block/endpoint.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/beacon/block/endpoint.test.ts @@ -14,7 +14,7 @@ import {getDevBeaconNode} from "../../../../../utils/node/beacon.js"; import {BeaconNode} from "../../../../../../src/node/nodejs.js"; import {getConfig} from "../../../../../utils/config.js"; -describe("beacon block api", function () { +describe("beacon block api", () => { vi.setConfig({testTimeout: 60_000, hookTimeout: 60_000}); const restPort = 9596; diff --git a/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts b/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts index 0789932e61e4..6dc01870a844 100644 --- a/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts @@ -9,7 +9,7 @@ import {getDevBeaconNode} from "../../../../../utils/node/beacon.js"; import {BeaconNode} from "../../../../../../src/node/nodejs.js"; import {getAndInitDevValidators} from "../../../../../utils/node/validator.js"; -describe("beacon node api", function () { +describe("beacon node api", () => { vi.setConfig({testTimeout: 60_000}); const restPort = 9596; diff --git a/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts b/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts index 01423d72341f..d8c87a3ba6b8 100644 --- a/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts @@ -8,7 +8,7 @@ import {LogLevel, testLogger} from "../../../../../utils/logger.js"; import {getDevBeaconNode} from "../../../../../utils/node/beacon.js"; import {BeaconNode} from "../../../../../../src/node/nodejs.js"; -describe("beacon state api", function () { +describe("beacon state api", () => { const restPort = 9596; const config = createBeaconConfig(chainConfigDef, Buffer.alloc(32, 0xaa)); const validatorCount = 512; diff --git a/packages/beacon-node/test/e2e/api/impl/config.test.ts b/packages/beacon-node/test/e2e/api/impl/config.test.ts index 4bdedfa16391..3ffdbc4beb21 100644 --- a/packages/beacon-node/test/e2e/api/impl/config.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/config.test.ts @@ -14,7 +14,7 @@ const CONSTANT_NAMES_SKIP_LIST = new Set([ "BLOB_SIDECAR_SUBNET_COUNT", ]); -describe("api / impl / config", function () { +describe("api / impl / config", () => { it("Ensure all constants are exposed", async () => { const constantNames = await downloadRemoteConstants(ethereumConsensusSpecsTests.specVersion); diff --git a/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts b/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts index 8f05ae41c468..effbed19fc2c 100644 --- a/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts @@ -13,7 +13,7 @@ import {getAndInitDevValidators} from "../../../../utils/node/validator.js"; import {BeaconNode} from "../../../../../src/node/nodejs.js"; import {waitForEvent} from "../../../../utils/events/resolver.js"; -describe("lightclient api", function () { +describe("lightclient api", () => { const SECONDS_PER_SLOT = 1; const ALTAIR_FORK_EPOCH = 0; const restPort = 9596; @@ -80,7 +80,7 @@ describe("lightclient api", function () { await sleep(2 * SECONDS_PER_SLOT * 1000); }; - it("getLightClientUpdatesByRange()", async function () { + it("getLightClientUpdatesByRange()", async () => { const client = getClient({baseUrl: `http://127.0.0.1:${restPort}`}, {config}).lightclient; await waitForBestUpdate(); const res = await client.getLightClientUpdatesByRange({startPeriod: 0, count: 1}); @@ -91,7 +91,7 @@ describe("lightclient api", function () { expect(res.meta().versions[0]).toBe(ForkName.altair); }); - it("getLightClientOptimisticUpdate()", async function () { + it("getLightClientOptimisticUpdate()", async () => { await waitForBestUpdate(); const client = getClient({baseUrl: `http://127.0.0.1:${restPort}`}, {config}).lightclient; const res = await client.getLightClientOptimisticUpdate(); @@ -105,7 +105,7 @@ describe("lightclient api", function () { expect(res.headers.get(HttpHeader.ExposeHeaders)?.includes("Eth-Consensus-Version")).toBe(true); }); - it.skip("getLightClientFinalityUpdate()", async function () { + it.skip("getLightClientFinalityUpdate()", async () => { // TODO: not sure how this causes subsequent tests failed await waitForEvent(bn.chain.emitter, routes.events.EventType.finalizedCheckpoint, 240000); await sleep(SECONDS_PER_SLOT * 1000); @@ -114,7 +114,7 @@ describe("lightclient api", function () { expect(finalityUpdate).toBeDefined(); }); - it("getLightClientCommitteeRoot() for the 1st period", async function () { + it("getLightClientCommitteeRoot() for the 1st period", async () => { await waitForBestUpdate(); const lightclient = getClient({baseUrl: `http://127.0.0.1:${restPort}`}, {config}).lightclient; diff --git a/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts b/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts index d505e38b3f9a..bc847b47e9a9 100644 --- a/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts +++ b/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts @@ -10,10 +10,10 @@ import {waitForEvent} from "../../../utils/events/resolver.js"; import {ClockEvent} from "../../../../src/util/clock.js"; import {BeaconNode} from "../../../../src/index.js"; -describe("api / impl / validator", function () { +describe("api / impl / validator", () => { vi.setConfig({testTimeout: 60_000}); - describe("getLiveness endpoint", function () { + describe("getLiveness endpoint", () => { let bn: BeaconNode | undefined; const SECONDS_PER_SLOT = 2; const ALTAIR_FORK_EPOCH = 0; @@ -30,7 +30,7 @@ describe("api / impl / validator", function () { if (bn) await bn.close(); }); - it("Should return validator indices that are live", async function () { + it("Should return validator indices that are live", async () => { const chainConfig: ChainConfig = {...chainConfigDef, SECONDS_PER_SLOT, ALTAIR_FORK_EPOCH}; const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); const config = createBeaconConfig(chainConfig, genesisValidatorsRoot); @@ -71,7 +71,7 @@ describe("api / impl / validator", function () { ]); }); - it("Should return only for previous, current and next epoch", async function () { + it("Should return only for previous, current and next epoch", async () => { const chainConfig: ChainConfig = {...chainConfigDef, SECONDS_PER_SLOT, ALTAIR_FORK_EPOCH}; const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); const config = createBeaconConfig(chainConfig, genesisValidatorsRoot); diff --git a/packages/beacon-node/test/e2e/chain/bls/multithread.test.ts b/packages/beacon-node/test/e2e/chain/bls/multithread.test.ts index 25f0d5133bcd..a544b3231e87 100644 --- a/packages/beacon-node/test/e2e/chain/bls/multithread.test.ts +++ b/packages/beacon-node/test/e2e/chain/bls/multithread.test.ts @@ -5,23 +5,11 @@ import {BlsMultiThreadWorkerPool} from "../../../../src/chain/bls/multithread/in import {testLogger} from "../../../utils/logger.js"; import {VerifySignatureOpts} from "../../../../src/chain/bls/interface.js"; -describe("chain / bls / multithread queue", function () { +describe("chain / bls / multithread queue", () => { const logger = testLogger(); let controller: AbortController; - beforeEach(() => { - controller = new AbortController(); - }); - afterEach(() => controller.abort()); - const afterEachCallbacks: (() => Promise | void)[] = []; - afterEach(async () => { - while (afterEachCallbacks.length > 0) { - const callback = afterEachCallbacks.pop(); - if (callback) await callback(); - } - }); - const sets: ISignatureSet[] = []; const sameMessageSets: {publicKey: PublicKey; signature: Uint8Array}[] = []; const sameMessage = Buffer.alloc(32, 100); @@ -45,6 +33,19 @@ describe("chain / bls / multithread queue", function () { } }); + beforeEach(() => { + controller = new AbortController(); + }); + + afterEach(async () => { + controller.abort(); + + while (afterEachCallbacks.length > 0) { + const callback = afterEachCallbacks.pop(); + if (callback) await callback(); + } + }); + async function initializePool(): Promise { const pool = new BlsMultiThreadWorkerPool({}, {logger, metrics: null}); // await terminating all workers diff --git a/packages/beacon-node/test/e2e/chain/lightclient.test.ts b/packages/beacon-node/test/e2e/chain/lightclient.test.ts index 5e7b7f36fff2..ed698f2844a1 100644 --- a/packages/beacon-node/test/e2e/chain/lightclient.test.ts +++ b/packages/beacon-node/test/e2e/chain/lightclient.test.ts @@ -14,7 +14,7 @@ import {getDevBeaconNode} from "../../utils/node/beacon.js"; import {getAndInitDevValidators} from "../../utils/node/validator.js"; import {HeadEventData} from "../../../src/chain/index.js"; -describe("chain / lightclient", function () { +describe("chain / lightclient", () => { vi.setConfig({testTimeout: 600_000}); /** @@ -46,7 +46,7 @@ describe("chain / lightclient", function () { } }); - it("Lightclient track head on server configuration", async function () { + it("Lightclient track head on server configuration", async () => { // delay a bit so regular sync sees it's up to date and sync is completed from the beginning // also delay to allow bls workers to be transpiled/initialized const genesisSlotsDelay = 7; @@ -152,7 +152,9 @@ describe("chain / lightclient", function () { const lcHeadSlot = lightclient.getHead().beacon.slot; if (head.slot - lcHeadSlot > maxLcHeadTrackingDiffSlots) { throw Error(`Lightclient head ${lcHeadSlot} is too far behind the beacon node ${head.slot}`); - } else if (head.slot > targetSlotToReach) { + } + + if (head.slot > targetSlotToReach) { resolve(); } } catch (e) { diff --git a/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts b/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts index ad32e2d5b270..fd6af72ad6cb 100644 --- a/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts +++ b/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts @@ -12,7 +12,7 @@ import {getAndInitDevValidators} from "../../utils/node/validator.js"; import {waitForEvent} from "../../utils/events/resolver.js"; import {ReorgEventData} from "../../../src/chain/emitter.js"; -describe("proposer boost reorg", function () { +describe("proposer boost reorg", () => { vi.setConfig({testTimeout: 60000}); const validatorCount = 8; diff --git a/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts b/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts index b6c5c30dace4..fcac715e1719 100644 --- a/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts +++ b/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts @@ -19,7 +19,7 @@ import {ReorgedForkChoice} from "../../../mocks/fork-choice/reorg.js"; * This includes several tests which make >6 min to pass in CI, so let's only run 1 of them and leave remaining ones * for local investigation. */ -describe("regen/reload states with n-historical states configuration", function () { +describe("regen/reload states with n-historical states configuration", () => { vi.setConfig({testTimeout: 96_000}); const validatorCount = 8; @@ -266,7 +266,7 @@ describe("regen/reload states with n-historical states configuration", function skip, } of testCases) { const wrappedIt = skip ? it.skip : it; - wrappedIt(`${name} reorgedSlot=${reorgedSlot} reorgDistance=${reorgDistance}`, async function () { + wrappedIt(`${name} reorgedSlot=${reorgedSlot} reorgDistance=${reorgDistance}`, async () => { // the node needs time to transpile/initialize bls worker threads const genesisSlotsDelay = 7; const genesisTime = Math.floor(Date.now() / 1000) + genesisSlotsDelay * testParams.SECONDS_PER_SLOT; diff --git a/packages/beacon-node/test/e2e/db/api/beacon/repositories/blockArchive.test.ts b/packages/beacon-node/test/e2e/db/api/beacon/repositories/blockArchive.test.ts index 5ecdc4c8b963..3c7a37e52a8b 100644 --- a/packages/beacon-node/test/e2e/db/api/beacon/repositories/blockArchive.test.ts +++ b/packages/beacon-node/test/e2e/db/api/beacon/repositories/blockArchive.test.ts @@ -4,7 +4,7 @@ import {ssz} from "@lodestar/types"; import {BeaconDb} from "../../../../../../src/db/index.js"; import {startTmpBeaconDb} from "../../../../../utils/db.js"; -describe("BlockArchiveRepository", function () { +describe("BlockArchiveRepository", () => { let db: BeaconDb; const sampleBlock = ssz.phase0.SignedBeaconBlock.defaultValue(); diff --git a/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts b/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts index bdfcbde056cd..949d0104d641 100644 --- a/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts +++ b/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts @@ -22,7 +22,7 @@ import {BeaconNode} from "../../../src/node/index.js"; // Attempting to do both 1. and 2. in this e2e test more expensive than necessary. // Unit tests in the validator cover 2., so some test in lodestar package should cover 1. // https://github.com/ChainSafe/lodestar/issues/5967 -describe.skip("doppelganger / doppelganger test", function () { +describe.skip("doppelganger / doppelganger test", () => { const afterEachCallbacks: (() => Promise | void)[] = []; afterEach(async () => { while (afterEachCallbacks.length > 0) { @@ -77,7 +77,7 @@ describe.skip("doppelganger / doppelganger test", function () { return {beaconNode: bn, validators: validatorsWithDoppelganger}; } - it("should not have doppelganger protection if started before genesis", async function () { + it("should not have doppelganger protection if started before genesis", async () => { const committeeIndex = 0; const validatorIndex = 0; @@ -113,7 +113,7 @@ describe.skip("doppelganger / doppelganger test", function () { ); }); - it("should shut down validator if same key is active and started after genesis", async function () { + it("should shut down validator if same key is active and started after genesis", async () => { // set genesis time to allow at least an epoch const genesisTime = Math.floor(Date.now() / 1000) - SLOTS_PER_EPOCH * beaconParams.SECONDS_PER_SLOT; @@ -149,7 +149,7 @@ describe.skip("doppelganger / doppelganger test", function () { ); }); - it("should shut down validator if same key is active with same BN and started after genesis", async function () { + it("should shut down validator if same key is active with same BN and started after genesis", async () => { const doppelgangerProtection = true; const testLoggerOpts: TestLoggerOpts = {level: LogLevel.info}; @@ -194,7 +194,7 @@ describe.skip("doppelganger / doppelganger test", function () { ); }); - it("should not shut down validator if key is different", async function () { + it("should not shut down validator if key is different", async () => { const doppelgangerProtection = true; const {beaconNode: bn, validators: validatorsWithDoppelganger} = await createBNAndVC({ @@ -227,7 +227,7 @@ describe.skip("doppelganger / doppelganger test", function () { ); }); - it("should not sign block if doppelganger period has not passed and not started at genesis", async function () { + it("should not sign block if doppelganger period has not passed and not started at genesis", async () => { const doppelgangerProtection = true; // set genesis time to allow at least an epoch @@ -258,7 +258,7 @@ describe.skip("doppelganger / doppelganger test", function () { ).resolves.toBeUndefined(); }); - it("should not sign attestations if doppelganger period has not passed and started after genesis", async function () { + it("should not sign attestations if doppelganger period has not passed and started after genesis", async () => { const doppelgangerProtection = true; // set genesis time to allow at least an epoch diff --git a/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts b/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts index 837a765d1710..21cadeb55d2c 100644 --- a/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts +++ b/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts @@ -25,7 +25,7 @@ const pyrmontDepositsDataRoot = [ ]; // https://github.com/ChainSafe/lodestar/issues/5967 -describe.skip("eth1 / Eth1Provider", function () { +describe.skip("eth1 / Eth1Provider", () => { const controller = new AbortController(); const config = getTestnetConfig(); @@ -48,7 +48,7 @@ describe.skip("eth1 / Eth1Provider", function () { await LevelDbController.destroy(dbLocation); }); - it("Should fetch real Pyrmont eth1 data for block proposing", async function () { + it("Should fetch real Pyrmont eth1 data for block proposing", async () => { const eth1Options: Eth1Options = { enabled: true, providerUrls: [getGoerliRpcUrl()], diff --git a/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts b/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts index 034493482c21..9423bb716b3f 100644 --- a/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts +++ b/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts @@ -14,7 +14,7 @@ import {getGoerliRpcUrl} from "../../testParams.js"; // It's OKAY to disable temporarily since this functionality is tested indirectly by the sim merge tests. // See https://github.com/ChainSafe/lodestar/issues/4197 // https://github.com/ChainSafe/lodestar/issues/5967 -describe.skip("eth1 / Eth1MergeBlockTracker", function () { +describe.skip("eth1 / Eth1MergeBlockTracker", () => { const logger = testLogger(); function getConfig(ttd: bigint): ChainConfig { diff --git a/packages/beacon-node/test/e2e/eth1/eth1Provider.test.ts b/packages/beacon-node/test/e2e/eth1/eth1Provider.test.ts index 8b7e9503485e..606845f40337 100644 --- a/packages/beacon-node/test/e2e/eth1/eth1Provider.test.ts +++ b/packages/beacon-node/test/e2e/eth1/eth1Provider.test.ts @@ -8,7 +8,7 @@ import {Eth1Block} from "../../../src/eth1/interface.js"; import {getGoerliRpcUrl} from "../../testParams.js"; // https://github.com/ChainSafe/lodestar/issues/5967 -describe.skip("eth1 / Eth1Provider", function () { +describe.skip("eth1 / Eth1Provider", () => { let controller: AbortController; beforeEach(() => { controller = new AbortController(); @@ -28,16 +28,16 @@ describe.skip("eth1 / Eth1Provider", function () { return new Eth1Provider(config, eth1Options, controller.signal); } - it("Should validate contract", async function () { + it("Should validate contract", async () => { await getEth1Provider().validateContract(); }); - it("Should get latest block number", async function () { + it("Should get latest block number", async () => { const blockNumber = await getEth1Provider().getBlockNumber(); expect(blockNumber).toBeGreaterThan(0); }); - it("Should get a specific block by number", async function () { + it("Should get a specific block by number", async () => { const goerliGenesisBlock: Eth1Block = { blockHash: fromHexString("0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a"), blockNumber: 0, @@ -47,7 +47,7 @@ describe.skip("eth1 / Eth1Provider", function () { expect(block && parseEth1Block(block)).toEqual(goerliGenesisBlock); }); - it("Should get deposits events for a block range", async function () { + it("Should get deposits events for a block range", async () => { const blockNumbers = goerliTestnetDepositEvents.map((log) => log.blockNumber); const fromBlock = Math.min(...blockNumbers); const toBlock = Math.min(...blockNumbers); @@ -74,26 +74,26 @@ describe.skip("eth1 / Eth1Provider", function () { code: "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a", }; - it("getBlocksByNumber: Should fetch a block range", async function () { + it("getBlocksByNumber: Should fetch a block range", async () => { const fromBlock = firstGoerliBlocks[0].blockNumber; const toBlock = firstGoerliBlocks[firstGoerliBlocks.length - 1].blockNumber; const blocks = await getEth1Provider().getBlocksByNumber(fromBlock, toBlock); expect(blocks.map(parseEth1Block)).toEqual(firstGoerliBlocks); }); - it("getBlockByNumber: Should fetch a single block", async function () { + it("getBlockByNumber: Should fetch a single block", async () => { const firstGoerliBlock = firstGoerliBlocks[0]; const block = await getEth1Provider().getBlockByNumber(firstGoerliBlock.blockNumber); expect(block && parseEth1Block(block)).toEqual(firstGoerliBlock); }); - it("getBlockNumber: Should fetch latest block number", async function () { + it("getBlockNumber: Should fetch latest block number", async () => { const blockNumber = await getEth1Provider().getBlockNumber(); expect(blockNumber).toBeInstanceOf(Number); expect(blockNumber).toBeGreaterThan(0); }); - it("getCode: Should fetch code for a contract", async function () { + it("getCode: Should fetch code for a contract", async () => { const code = await getEth1Provider().getCode(goerliSampleContract.address); expect(code).toEqual(expect.arrayContaining([goerliSampleContract.code])); }); diff --git a/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts b/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts index fac0e3810b6d..bc41b5f1c546 100644 --- a/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts +++ b/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts @@ -7,7 +7,7 @@ import {JsonRpcHttpClient} from "../../../src/eth1/provider/jsonRpcHttpClient.js import {getGoerliRpcUrl} from "../../testParams.js"; import {RpcPayload} from "../../../src/eth1/interface.js"; -describe("eth1 / jsonRpcHttpClient", function () { +describe("eth1 / jsonRpcHttpClient", () => { vi.setConfig({testTimeout: 10_000}); const port = 36421; @@ -113,7 +113,7 @@ describe("eth1 / jsonRpcHttpClient", function () { const afterHooks: (() => Promise)[] = []; - afterEach(async function () { + afterEach(async () => { while (afterHooks.length) { const afterHook = afterHooks.pop(); if (afterHook) await afterHook(); @@ -124,7 +124,7 @@ describe("eth1 / jsonRpcHttpClient", function () { const {id, requestListener, abort, timeout} = testCase; let {url, payload} = testCase; - it(id, async function () { + it(id, async () => { if (requestListener) { if (!url) url = `http://localhost:${port}`; @@ -162,14 +162,14 @@ describe("eth1 / jsonRpcHttpClient", function () { } }); -describe("eth1 / jsonRpcHttpClient - with retries", function () { +describe("eth1 / jsonRpcHttpClient - with retries", () => { vi.setConfig({testTimeout: 10_000}); const port = 36421; const noMethodError = {code: -32601, message: "Method not found"}; const afterHooks: (() => Promise)[] = []; - afterEach(async function () { + afterEach(async () => { while (afterHooks.length) { const afterHook = afterHooks.pop(); if (afterHook) @@ -179,7 +179,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () { } }); - it("should retry ENOTFOUND", async function () { + it("should retry ENOTFOUND", async () => { let retryCount = 0; const url = "https://goerli.fake-website.io"; @@ -201,7 +201,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () { expect(retryCount).toBeWithMessage(retries, "ENOTFOUND should be retried before failing"); }); - it("should retry ECONNREFUSED", async function () { + it("should retry ECONNREFUSED", async () => { let retryCount = 0; const url = `http://localhost:${port + 1}`; @@ -223,7 +223,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () { expect(retryCount).toBeWithMessage(retries, "code ECONNREFUSED should be retried before failing"); }); - it("should retry 404", async function () { + it("should retry 404", async () => { let requestCount = 0; const server = http.createServer((req, res) => { @@ -253,7 +253,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () { expect(requestCount).toBeWithMessage(retries + 1, "404 responses should be retried before failing"); }); - it("should retry timeout", async function () { + it("should retry timeout", async () => { let requestCount = 0; const server = http.createServer(async () => { @@ -284,7 +284,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () { expect(requestCount).toBeWithMessage(retries + 1, "Timeout request should be retried before failing"); }); - it("should not retry aborted", async function () { + it("should not retry aborted", async () => { let requestCount = 0; const server = http.createServer(() => { requestCount++; @@ -314,7 +314,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () { expect(requestCount).toBeWithMessage(1, "Aborted request should not be retried"); }); - it("should not retry payload error", async function () { + it("should not retry payload error", async () => { let requestCount = 0; const server = http.createServer((req, res) => { diff --git a/packages/beacon-node/test/e2e/eth1/stream.test.ts b/packages/beacon-node/test/e2e/eth1/stream.test.ts index a683e885b453..ce65d4353f0e 100644 --- a/packages/beacon-node/test/e2e/eth1/stream.test.ts +++ b/packages/beacon-node/test/e2e/eth1/stream.test.ts @@ -6,7 +6,7 @@ import {getGoerliRpcUrl} from "../../testParams.js"; import {Eth1Options} from "../../../src/eth1/options.js"; // https://github.com/ChainSafe/lodestar/issues/5967 -describe.skip("Eth1 streams", function () { +describe.skip("Eth1 streams", () => { let controller: AbortController; beforeEach(() => { controller = new AbortController(); @@ -30,7 +30,7 @@ describe.skip("Eth1 streams", function () { const depositsToFetch = 1000; const eth1Params = {...config, maxBlocksPerPoll}; - it(`Should fetch ${depositsToFetch} deposits with getDepositsStream`, async function () { + it(`Should fetch ${depositsToFetch} deposits with getDepositsStream`, async () => { const depositsStream = getDepositsStream( medallaTestnetConfig.blockWithDepositActivity, getEth1Provider(), @@ -49,7 +49,7 @@ describe.skip("Eth1 streams", function () { expect(depositCount).toBeGreaterThan(depositsToFetch); }); - it(`Should fetch ${depositsToFetch} deposits with getDepositsAndBlockStreamForGenesis`, async function () { + it(`Should fetch ${depositsToFetch} deposits with getDepositsAndBlockStreamForGenesis`, async () => { const stream = getDepositsAndBlockStreamForGenesis( medallaTestnetConfig.blockWithDepositActivity, getEth1Provider(), diff --git a/packages/beacon-node/test/e2e/network/gossipsub.test.ts b/packages/beacon-node/test/e2e/network/gossipsub.test.ts index 3d8b1e07bbd7..29a745455561 100644 --- a/packages/beacon-node/test/e2e/network/gossipsub.test.ts +++ b/packages/beacon-node/test/e2e/network/gossipsub.test.ts @@ -8,7 +8,7 @@ import {GossipType, GossipHandlers, GossipHandlerParamGeneric} from "../../../sr import {getNetworkForTest} from "../../utils/networkWithMockDb.js"; import {connect, onPeerConnect} from "../../utils/network.js"; -describe("gossipsub / main thread", function () { +describe("gossipsub / main thread", () => { vi.setConfig({testTimeout: 3000}); runTests({useWorker: false}); @@ -19,7 +19,7 @@ describe("gossipsub / main thread", function () { * Since we use vitest to run tests in parallel, including this causes the test to be unstable. * See https://github.com/ChainSafe/lodestar/issues/6358 */ -describe.skip("gossipsub / worker", function () { +describe.skip("gossipsub / worker", () => { vi.setConfig({testTimeout: 3000}); runTests({useWorker: true}); @@ -61,7 +61,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { return {netA, netB}; } - it("Publish and receive a voluntaryExit", async function () { + it("Publish and receive a voluntaryExit", async () => { let onVoluntaryExit: (ve: Uint8Array) => void; const onVoluntaryExitPromise = new Promise((resolve) => { onVoluntaryExit = resolve; @@ -98,7 +98,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { ); }); - it("Publish and receive a blsToExecutionChange", async function () { + it("Publish and receive a blsToExecutionChange", async () => { let onBlsToExecutionChange: (blsToExec: Uint8Array) => void; const onBlsToExecutionChangePromise = new Promise((resolve) => { onBlsToExecutionChange = resolve; @@ -136,7 +136,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { ); }); - it("Publish and receive an attesterSlashing", async function () { + it("Publish and receive an attesterSlashing", async () => { let onAttesterSlashingChange: (payload: Uint8Array) => void; const onAttesterSlashingChangePromise = new Promise((resolve) => { onAttesterSlashingChange = resolve; @@ -170,7 +170,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { expect(Buffer.from(received)).toEqual(Buffer.from(ssz.phase0.AttesterSlashing.serialize(attesterSlashing))); }); - it("Publish and receive a proposerSlashing", async function () { + it("Publish and receive a proposerSlashing", async () => { let onProposerSlashingChange: (payload: Uint8Array) => void; const onProposerSlashingChangePromise = new Promise((resolve) => { onProposerSlashingChange = resolve; @@ -204,7 +204,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { expect(Buffer.from(received)).toEqual(Buffer.from(ssz.phase0.ProposerSlashing.serialize(proposerSlashing))); }); - it("Publish and receive a LightClientOptimisticUpdate", async function () { + it("Publish and receive a LightClientOptimisticUpdate", async () => { let onLightClientOptimisticUpdate: (ou: Uint8Array) => void; const onLightClientOptimisticUpdatePromise = new Promise((resolve) => { onLightClientOptimisticUpdate = resolve; @@ -243,7 +243,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { ); }); - it("Publish and receive a LightClientFinalityUpdate", async function () { + it("Publish and receive a LightClientFinalityUpdate", async () => { let onLightClientFinalityUpdate: (fu: Uint8Array) => void; const onLightClientFinalityUpdatePromise = new Promise((resolve) => { onLightClientFinalityUpdate = resolve; diff --git a/packages/beacon-node/test/e2e/network/mdns.test.ts b/packages/beacon-node/test/e2e/network/mdns.test.ts index 5c796df985b9..6a1be8094137 100644 --- a/packages/beacon-node/test/e2e/network/mdns.test.ts +++ b/packages/beacon-node/test/e2e/network/mdns.test.ts @@ -21,18 +21,19 @@ let port = 9000; const mu = "/ip4/127.0.0.1/tcp/0"; // https://github.com/ChainSafe/lodestar/issues/5967 -describe.skip("mdns", function () { +describe.skip("mdns", () => { const afterEachCallbacks: (() => Promise | void)[] = []; - afterEach(async () => { - await Promise.all(afterEachCallbacks.map((cb) => cb())); - afterEachCallbacks.splice(0, afterEachCallbacks.length); - }); - let controller: AbortController; + beforeEach(() => { controller = new AbortController(); }); - afterEach(() => controller.abort()); + + afterEach(async () => { + await Promise.all(afterEachCallbacks.map((cb) => cb())); + afterEachCallbacks.splice(0, afterEachCallbacks.length); + controller.abort(); + }); async function getOpts(privateKey: PrivateKey): Promise { const bindAddrUdp = `/ip4/0.0.0.0/udp/${port++}`; @@ -114,7 +115,7 @@ describe.skip("mdns", function () { return Promise.all([createTestNode("mdns-A"), createTestNode("mdns-B")]); } - it("should connect two peers on a LAN", async function () { + it("should connect two peers on a LAN", async () => { const [{network: netA}, {network: netB}] = await createTestNodesAB(); await Promise.all([onPeerConnect(netA), onPeerConnect(netB)]); expect(netA.getConnectedPeerCount()).toBe(1); diff --git a/packages/beacon-node/test/e2e/network/network.test.ts b/packages/beacon-node/test/e2e/network/network.test.ts index a1c1546ef4fc..2435b005efa1 100644 --- a/packages/beacon-node/test/e2e/network/network.test.ts +++ b/packages/beacon-node/test/e2e/network/network.test.ts @@ -9,13 +9,13 @@ import {connect, disconnect, onPeerConnect, onPeerDisconnect} from "../../utils/ import {getNetworkForTest} from "../../utils/networkWithMockDb.js"; import {getValidPeerId} from "../../utils/peer.js"; -describe("network / main thread", function () { +describe("network / main thread", () => { vi.setConfig({testTimeout: 3000}); runTests({useWorker: false}); }); -describe("network / worker", function () { +describe("network / worker", () => { vi.setConfig({testTimeout: 10_000}); runTests({useWorker: true}); @@ -66,14 +66,14 @@ function runTests({useWorker}: {useWorker: boolean}): void { expect(networkIdentity.peerId).toBe(network.peerId.toString()); }); - it("should create a peer on connect", async function () { + it("should create a peer on connect", async () => { const [netA, netB] = await createTestNodesAB(); await Promise.all([onPeerConnect(netA), onPeerConnect(netB), connect(netA, netB)]); expect(netA.getConnectedPeerCount()).toBe(1); expect(netB.getConnectedPeerCount()).toBe(1); }); - it("should delete a peer on disconnect", async function () { + it("should delete a peer on disconnect", async () => { const [netA, netB] = await createTestNodesAB(); const connected = Promise.all([onPeerConnect(netA), onPeerConnect(netB)]); await connect(netA, netB); @@ -92,9 +92,9 @@ function runTests({useWorker}: {useWorker: boolean}): void { // Current implementation of discv5 consumer doesn't allow to deterministically force a peer to be found // a random find node lookup can yield no results if there are too few peers in the DHT - it.todo("should connect to new peer by subnet", async function () {}); + it.todo("should connect to new peer by subnet", async () => {}); - it("Should goodbye peers on stop", async function () { + it("Should goodbye peers on stop", async () => { const [netA, netB] = await createTestNodesAB(); const connected = Promise.all([onPeerConnect(netA), onPeerConnect(netB)]); 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 09c74f1f5dfe..741fd4b46696 100644 --- a/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts +++ b/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts @@ -30,7 +30,7 @@ import {CommitteeSubscription} from "../../../../src/network/subnets/interface.j import {EchoWorker, getEchoWorker} from "./workerEchoHandler.js"; // TODO: Need to find the way to load the echoWorker in the test environment -describe.skip("data serialization through worker boundary", function () { +describe.skip("data serialization through worker boundary", () => { let echoWorker: EchoWorker; beforeAll(async () => { diff --git a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts index e872a3882945..b46e151cadb3 100644 --- a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts +++ b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts @@ -22,7 +22,7 @@ import {LocalStatusCache} from "../../../../src/network/statusCache.js"; const logger = testLogger("peerManager"); -describe("network / peers / PeerManager", function () { +describe("network / peers / PeerManager", () => { const peerId1 = getValidPeerId(); const afterEachCallbacks: (() => Promise | void)[] = []; @@ -156,7 +156,7 @@ describe("network / peers / PeerManager", function () { remotePeer: peerId1, } as Connection; - it("Should emit peer connected event on relevant peer status", async function () { + it("Should emit peer connected event on relevant peer status", async () => { const {statusCache, libp2p, networkEventBus} = await mockModules(); // Simualate a peer connection, get() should return truthy @@ -175,7 +175,7 @@ describe("network / peers / PeerManager", function () { await peerConnectedPromise; }); - it("On peerConnect handshake flow", async function () { + it("On peerConnect handshake flow", async () => { const {statusCache, libp2p, reqResp, peerManager, networkEventBus} = await mockModules(); // Simualate a peer connection, get() should return truthy diff --git a/packages/beacon-node/test/e2e/network/reqresp.test.ts b/packages/beacon-node/test/e2e/network/reqresp.test.ts index a3c8b7b66ca0..b7ab190166e7 100644 --- a/packages/beacon-node/test/e2e/network/reqresp.test.ts +++ b/packages/beacon-node/test/e2e/network/reqresp.test.ts @@ -15,13 +15,13 @@ import {PeerIdStr} from "../../../src/util/peerId.js"; /* eslint-disable require-yield, @typescript-eslint/naming-convention */ -describe("network / reqresp / main thread", function () { +describe("network / reqresp / main thread", () => { vi.setConfig({testTimeout: 3000}); runTests({useWorker: false}); }); -describe("network / reqresp / worker", function () { +describe("network / reqresp / worker", () => { vi.setConfig({testTimeout: 30_000}); runTests({useWorker: true}); @@ -76,7 +76,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { return [netA, netB, await getPeerIdOf(netA), await getPeerIdOf(netB)]; } - it("should send/receive signed blocks", async function () { + it("should send/receive signed blocks", async () => { const req: phase0.BeaconBlocksByRangeRequest = {startSlot: 0, step: 1, count: 2}; const blocks: phase0.SignedBeaconBlock[] = []; for (let slot = req.startSlot; slot < req.count; slot++) { @@ -106,7 +106,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { } }); - it("should send/receive a light client bootstrap message", async function () { + it("should send/receive a light client bootstrap message", async () => { const root: Root = ssz.phase0.BeaconBlockHeader.defaultValue().bodyRoot; const expectedValue = ssz.altair.LightClientBootstrap.defaultValue(); @@ -128,7 +128,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { ); }); - it("should send/receive a light client optimistic update message", async function () { + it("should send/receive a light client optimistic update message", async () => { const expectedValue = ssz.altair.LightClientOptimisticUpdate.defaultValue(); const [netA, _, _0, peerIdB] = await createAndConnectPeers( @@ -149,7 +149,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { ); }); - it("should send/receive a light client finality update message", async function () { + it("should send/receive a light client finality update message", async () => { const expectedValue = ssz.altair.LightClientFinalityUpdate.defaultValue(); const [netA, _, _0, peerIdB] = await createAndConnectPeers( @@ -170,7 +170,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { ); }); - it("should send/receive a light client update message", async function () { + it("should send/receive a light client update message", async () => { const req: altair.LightClientUpdatesByRange = {startPeriod: 0, count: 2}; const lightClientUpdates: ResponseOutgoing[] = []; for (let slot = req.startPeriod; slot < req.count; slot++) { @@ -201,10 +201,11 @@ function runTests({useWorker}: {useWorker: boolean}): void { } }); - it("should handle a server error", async function () { + it("should handle a server error", async () => { const testErrorMessage = "TEST_EXAMPLE_ERROR_1234"; const [netA, _, _0, peerIdB] = await createAndConnectPeers( (method) => + // biome-ignore lint/correctness/useYield: No need for yield in test context async function* onRequest() { if (method === ReqRespMethod.BeaconBlocksByRange) { throw Error(testErrorMessage); @@ -218,7 +219,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { ); }); - it("should handle a server error after emitting two blocks", async function () { + it("should handle a server error after emitting two blocks", async () => { const testErrorMessage = "TEST_EXAMPLE_ERROR_1234"; const [netA, _, _0, peerIdB] = await createAndConnectPeers( @@ -241,7 +242,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { ); }); - it("trigger a TTFB_TIMEOUT error", async function () { + it("trigger a TTFB_TIMEOUT error", async () => { const ttfbTimeoutMs = 250; const [netA, _, _0, peerIdB] = await createAndConnectPeers( @@ -262,7 +263,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { ); }); - it("trigger a RESP_TIMEOUT error", async function () { + it("trigger a RESP_TIMEOUT error", async () => { const respTimeoutMs = 250; const [netA, _, _0, peerIdB] = await createAndConnectPeers( @@ -284,9 +285,10 @@ function runTests({useWorker}: {useWorker: boolean}): void { ); }); - it("Sleep infinite on first byte", async function () { + it("Sleep infinite on first byte", async () => { const [netA, _, _0, peerIdB] = await createAndConnectPeers( (method) => + // biome-ignore lint/correctness/useYield: No need for yield in test context async function* onRequest() { if (method === ReqRespMethod.BeaconBlocksByRange) { await sleep(100000000); @@ -301,7 +303,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { ); }); - it("Sleep infinite on second response chunk", async function () { + it("Sleep infinite on second response chunk", async () => { const [netA, _, _0, peerIdB] = await createAndConnectPeers( (method) => async function* onRequest() { diff --git a/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts b/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts index 123a4da420f0..eb994d2e848c 100644 --- a/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts +++ b/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts @@ -53,6 +53,7 @@ describe("reqresp encoder", () => { const {libp2p, multiaddr} = await getLibp2p(); const getHandlerNoop: GetReqRespHandlerFn = () => + // biome-ignore lint/correctness/useYield: No need for yield in test context async function* (): AsyncIterable { throw Error("not implemented"); }; diff --git a/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts b/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts index ed19617f0822..ba98f2a1facd 100644 --- a/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts +++ b/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts @@ -14,7 +14,7 @@ import {ChainEvent} from "../../../src/chain/index.js"; import {connect, onPeerConnect} from "../../utils/network.js"; import {testLogger, LogLevel, TestLoggerOpts} from "../../utils/logger.js"; -describe("sync / finalized sync", function () { +describe("sync / finalized sync", () => { // chain is finalized at slot 32, plus 4 slots for genesis delay => ~72s it should sync pretty fast vi.setConfig({testTimeout: 90_000}); @@ -31,7 +31,7 @@ describe("sync / finalized sync", function () { } }); - it("should do a finalized sync from another BN", async function () { + it("should do a finalized sync from another BN", async () => { // single node at beginning, use main thread to verify bls const genesisSlotsDelay = 4; const genesisTime = Math.floor(Date.now() / 1000) + genesisSlotsDelay * testParams.SECONDS_PER_SLOT; diff --git a/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts b/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts index 7d31d25a07d3..290213d2b1ee 100644 --- a/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts +++ b/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts @@ -17,7 +17,7 @@ import {testLogger, LogLevel, TestLoggerOpts} from "../../utils/logger.js"; import {BlockError, BlockErrorCode} from "../../../src/chain/errors/index.js"; import {BlockSource, getBlockInput} from "../../../src/chain/blocks/types.js"; -describe("sync / unknown block sync", function () { +describe("sync / unknown block sync", () => { vi.setConfig({testTimeout: 40_000}); const validatorCount = 8; @@ -45,7 +45,7 @@ describe("sync / unknown block sync", function () { ]; for (const {id, event} of testCases) { - it(id, async function () { + it(id, async () => { // the node needs time to transpile/initialize bls worker threads const genesisSlotsDelay = 4; const genesisTime = Math.floor(Date.now() / 1000) + genesisSlotsDelay * testParams.SECONDS_PER_SLOT; diff --git a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts index 247f8a4ea95a..1a317a7fe9d3 100644 --- a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts +++ b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts @@ -1,4 +1,5 @@ import crypto from "node:crypto"; +// biome-ignore lint/suspicious/noShadowRestrictedNames: We explicitly want `Map` name to be imported import {Map} from "immutable"; import {ValidatorIndex} from "@lodestar/types"; import {toMemoryEfficientHexStr} from "@lodestar/state-transition/src/cache/pubkeyCache.js"; diff --git a/packages/beacon-node/test/perf/bls/bls.test.ts b/packages/beacon-node/test/perf/bls/bls.test.ts index 988052f4a95c..9f1f90a4d879 100644 --- a/packages/beacon-node/test/perf/bls/bls.test.ts +++ b/packages/beacon-node/test/perf/bls/bls.test.ts @@ -11,7 +11,7 @@ import { } from "@chainsafe/blst"; import {linspace} from "../../../src/util/numpy.js"; -describe("BLS ops", function () { +describe("BLS ops", () => { type Keypair = {publicKey: PublicKey; secretKey: SecretKey}; // signature needs to be in Uint8Array to match real situation type BlsSet = {publicKey: PublicKey; message: Uint8Array; signature: Uint8Array}; diff --git a/packages/beacon-node/test/perf/chain/seenCache/seenAggregateAndProof.test.ts b/packages/beacon-node/test/perf/chain/seenCache/seenAggregateAndProof.test.ts index 8ba77ca8692f..49c3123c14dd 100644 --- a/packages/beacon-node/test/perf/chain/seenCache/seenAggregateAndProof.test.ts +++ b/packages/beacon-node/test/perf/chain/seenCache/seenAggregateAndProof.test.ts @@ -3,7 +3,7 @@ import {BitArray} from "@chainsafe/ssz"; import {TARGET_AGGREGATORS_PER_COMMITTEE} from "@lodestar/params"; import {SeenAggregatedAttestations} from "../../../../src/chain/seenCache/seenAggregateAndProof.js"; -describe("SeenAggregatedAttestations perf test", function () { +describe("SeenAggregatedAttestations perf test", () => { const targetEpoch = 2022; const attDataRoot = "0x55e1a1cce2aeb66f85b2285b8cb7aa55dfb67148b5e0067f0692b61ddbd2824b"; const fullByte = 0b11111111; diff --git a/packages/beacon-node/test/perf/chain/stateCache/inMemoryCheckpointsCache.test.ts b/packages/beacon-node/test/perf/chain/stateCache/inMemoryCheckpointsCache.test.ts index 3a4774655e7f..17a46b09af8d 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/inMemoryCheckpointsCache.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/inMemoryCheckpointsCache.test.ts @@ -4,7 +4,7 @@ import {ssz, phase0} from "@lodestar/types"; import {generateCachedState} from "../../../utils/state.js"; import {InMemoryCheckpointStateCache, toCheckpointHex} from "../../../../src/chain/stateCache/index.js"; -describe("InMemoryCheckpointStateCache perf tests", function () { +describe("InMemoryCheckpointStateCache perf tests", () => { setBenchOpts({noThreshold: true}); let state: CachedBeaconStateAllForks; diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index eab66d2bee53..a4bdbe9710cb 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -15,7 +15,7 @@ import {generateCachedElectraState} from "../../../utils/state.js"; // ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 1444.173 ops/s 692.4380 us/op - 1057 runs 6.03 s // ✔ updateUnfinalizedPubkeys - updating 100 pubkeys 189.5965 ops/s 5.274358 ms/op - 57 runs 1.15 s // ✔ updateUnfinalizedPubkeys - updating 1000 pubkeys 12.90495 ops/s 77.48967 ms/op - 13 runs 1.62 s -describe("updateUnfinalizedPubkeys perf tests", function () { +describe("updateUnfinalizedPubkeys perf tests", () => { setBenchOpts({noThreshold: true}); const numPubkeysToBeFinalizedCases = [10, 100, 1000]; diff --git a/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts b/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts index 6ae7112f5e3d..cd4d61b173c7 100644 --- a/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts +++ b/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts @@ -28,13 +28,22 @@ describe.skip("verify+import blocks - range sync perf test", () => { yieldEventLoopAfterEach: true, // So SubTree(s)'s WeakRef can be garbage collected https://github.com/nodejs/node/issues/39902 }); - before("Check correct params", () => { + let db: BeaconDb; + + before("Check correct params", async () => { // Must start at the first slot of the epoch to have a proper checkpoint state. // Using `computeStartSlotAtEpoch(...) - 1` will cause the chain to initialize with a state that's not the checkpoint // state, so processing the first block of the epoch will cause error `BLOCK_ERROR_WOULD_REVERT_FINALIZED_SLOT` if (rangeSyncTest.startSlot % SLOTS_PER_EPOCH !== 0) { throw Error("startSlot must be the first slot in the epoch"); } + + db = new BeaconDb(config, await LevelDbController.create({name: ".tmpdb"}, {logger})); + }); + + after(async () => { + // If before blocks fail, db won't be declared + if (db !== undefined) await db.close(); }); const blocks = beforeValue( @@ -57,15 +66,6 @@ describe.skip("verify+import blocks - range sync perf test", () => { return state; }, timeoutInfura); - let db: BeaconDb; - before(async () => { - db = new BeaconDb(config, await LevelDbController.create({name: ".tmpdb"}, {logger})); - }); - after(async () => { - // If before blocks fail, db won't be declared - if (db !== undefined) await db.close(); - }); - itBench({ id: `altair verifyImport ${network}_s${startSlot}:${slotCount}`, minRuns: 5, diff --git a/packages/beacon-node/test/perf/network/gossip/encoding.test.ts b/packages/beacon-node/test/perf/network/gossip/encoding.test.ts index 693c91f59249..e8e889de2194 100644 --- a/packages/beacon-node/test/perf/network/gossip/encoding.test.ts +++ b/packages/beacon-node/test/perf/network/gossip/encoding.test.ts @@ -8,7 +8,7 @@ import {toHex} from "@lodestar/utils"; ✔ Buffer.from 6696982 ops/s 149.3210 ns/op - 2023 runs 0.454 s ✔ shared Buffer 1.013911e+7 ops/s 98.62800 ns/op - 3083 runs 0.404 s */ -describe("encoding", function () { +describe("encoding", () => { const msgId = Uint8Array.from(Array.from({length: 20}, (_, i) => i)); const runsFactor = 1000; diff --git a/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts b/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts index ecc30ebacef9..18dca2c670cd 100644 --- a/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts +++ b/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts @@ -11,7 +11,7 @@ import {getAttnets, getSyncnets} from "../../../../utils/network.js"; describe("prioritizePeers", () => { const seedPeers: {id: PeerId; attnets: phase0.AttestationSubnets; syncnets: altair.SyncSubnets; score: number}[] = []; - before(async function () { + before(async () => { for (let i = 0; i < defaultNetworkOptions.maxPeers; i++) { const pk = await generateKeyPair("secp256k1"); const peer = peerIdFromPrivateKey(pk); diff --git a/packages/beacon-node/test/perf/util/bytes.test.ts b/packages/beacon-node/test/perf/util/bytes.test.ts index d1d2e968b181..8c692bd3f92d 100644 --- a/packages/beacon-node/test/perf/util/bytes.test.ts +++ b/packages/beacon-node/test/perf/util/bytes.test.ts @@ -1,6 +1,6 @@ import {itBench} from "@dapplion/benchmark"; -describe("bytes utils", function () { +describe("bytes utils", () => { const roots: Uint8Array[] = []; let buffers: Buffer[] = []; const count = 32; diff --git a/packages/beacon-node/test/perf/util/dataview.test.ts b/packages/beacon-node/test/perf/util/dataview.test.ts index e0f28a5079e3..b0e394a0e1c8 100644 --- a/packages/beacon-node/test/perf/util/dataview.test.ts +++ b/packages/beacon-node/test/perf/util/dataview.test.ts @@ -1,6 +1,6 @@ import {itBench} from "@dapplion/benchmark"; -describe("dataview", function () { +describe("dataview", () => { const data = Uint8Array.from([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); itBench({ diff --git a/packages/beacon-node/test/perf/util/transferBytes.test.ts b/packages/beacon-node/test/perf/util/transferBytes.test.ts index 1cda12f7acd4..25cecbf770bc 100644 --- a/packages/beacon-node/test/perf/util/transferBytes.test.ts +++ b/packages/beacon-node/test/perf/util/transferBytes.test.ts @@ -1,7 +1,7 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {expect} from "chai"; -describe("transfer bytes", function () { +describe("transfer bytes", () => { const sizes = [ {size: 84, name: "Status"}, {size: 112, name: "SignedVoluntaryExit"}, diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index 2d08428df558..20fedd3d4b0f 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -36,7 +36,7 @@ import {shell} from "./shell.js"; const jwtSecretHex = "0xdc6457099f127cf0bac78de8b297df04951281909db4f58b43def7c7151e765d"; const retries = defaultExecutionEngineHttpOpts.retries; const retryDelay = defaultExecutionEngineHttpOpts.retryDelay; -describe("executionEngine / ExecutionEngineHttp", function () { +describe("executionEngine / ExecutionEngineHttp", () => { if (!process.env.EL_BINARY_DIR || !process.env.EL_SCRIPT_DIR) { throw Error( `EL ENV must be provided, EL_BINARY_DIR: ${process.env.EL_BINARY_DIR}, EL_SCRIPT_DIR: ${process.env.EL_SCRIPT_DIR}` @@ -211,12 +211,12 @@ describe("executionEngine / ExecutionEngineHttp", function () { if (payload.transactions.length !== 1) { throw Error(`Number of transactions mismatched. Expected: 1, actual: ${payload.transactions.length}`); - } else { - const actualTransaction = bytesToData(payload.transactions[0]); + } - if (actualTransaction !== depositTransactionB) { - throw Error(`Transaction mismatched. Expected: ${depositTransactionB}, actual: ${actualTransaction}`); - } + const actualTransaction = bytesToData(payload.transactions[0]); + + if (actualTransaction !== depositTransactionB) { + throw Error(`Transaction mismatched. Expected: ${depositTransactionB}, actual: ${actualTransaction}`); } if (depositRequests === undefined || depositRequests.length !== 1) { @@ -234,7 +234,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { }); // TODO: get this post merge run working - it.skip("Post-merge, run for a few blocks", async function () { + it.skip("Post-merge, run for a few blocks", async () => { console.log("\n\nPost-merge, run for a few blocks\n\n"); const {elClient, tearDownCallBack} = await runEL( {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "electra.tmpl"}, @@ -331,7 +331,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { withEth1Credentials: true, }); - afterEachCallbacks.push(async function () { + afterEachCallbacks.push(async () => { await bn.close(); await sleep(1000); }); @@ -355,7 +355,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { valProposerConfig, }); - afterEachCallbacks.push(async function () { + afterEachCallbacks.push(async () => { await Promise.all(validators.map((v) => v.close())); }); diff --git a/packages/beacon-node/test/sim/mergemock.test.ts b/packages/beacon-node/test/sim/mergemock.test.ts index ee9839d58822..64020b070e11 100644 --- a/packages/beacon-node/test/sim/mergemock.test.ts +++ b/packages/beacon-node/test/sim/mergemock.test.ts @@ -29,7 +29,7 @@ import {shell} from "./shell.js"; const jwtSecretHex = "0xdc6457099f127cf0bac78de8b297df04951281909db4f58b43def7c7151e765d"; -describe("executionEngine / ExecutionEngineHttp", function () { +describe("executionEngine / ExecutionEngineHttp", () => { if (!process.env.EL_BINARY_DIR || !process.env.EL_SCRIPT_DIR) { throw Error( `EL ENV must be provided, EL_BINARY_DIR: ${process.env.EL_BINARY_DIR}, EL_SCRIPT_DIR: ${process.env.EL_SCRIPT_DIR}` @@ -64,7 +64,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { }); for (const useProduceBlockV3 of [false, true]) { - it(`Test builder with useProduceBlockV3=${useProduceBlockV3}`, async function () { + it(`Test builder with useProduceBlockV3=${useProduceBlockV3}`, async () => { console.log("\n\nPost-merge, run for a few blocks\n\n"); const {elClient, tearDownCallBack} = await runEL( {...elSetupConfig, mode: ELStartMode.PostMerge}, @@ -173,7 +173,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { // Enable builder by default, else because of circuit breaker we always start it with disabled bn.chain.executionBuilder.updateStatus(true); - afterEachCallbacks.push(async function () { + afterEachCallbacks.push(async () => { await bn.close(); await sleep(1000); }); @@ -204,7 +204,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { useProduceBlockV3, }); - afterEachCallbacks.push(async function () { + afterEachCallbacks.push(async () => { await Promise.all(validators.map((v) => v.close())); }); diff --git a/packages/beacon-node/test/spec/bls/index.test.ts b/packages/beacon-node/test/spec/bls/index.test.ts index b781685432e6..32baa00d9fbc 100644 --- a/packages/beacon-node/test/spec/bls/index.test.ts +++ b/packages/beacon-node/test/spec/bls/index.test.ts @@ -35,7 +35,7 @@ for (const fnName of readdirSyncSpec(blsSpecTests.outputDir)) { const fnTestDirpath = path.join(blsSpecTests.outputDir, fnName); for (const testName of readdirSyncSpec(fnTestDirpath)) { - it(`${fnName}/${testName}`, function (context) { + it(`${fnName}/${testName}`, (context) => { if (fn === "skip") { context.skip(); return; diff --git a/packages/beacon-node/test/spec/general/bls.ts b/packages/beacon-node/test/spec/general/bls.ts index fca8529e4e3b..dfebe945b069 100644 --- a/packages/beacon-node/test/spec/general/bls.ts +++ b/packages/beacon-node/test/spec/general/bls.ts @@ -41,9 +41,8 @@ export const blsTestRunner: TestRunnerFn = (_fork, testNam const {message} = e as Error; if (message.includes("BLST_ERROR") || message === "EMPTY_AGGREGATE_ARRAY" || message === "ZERO_SECRET_KEY") { return null; - } else { - throw e; } + throw e; } }, options: { diff --git a/packages/beacon-node/test/spec/general/ssz_generic_types.ts b/packages/beacon-node/test/spec/general/ssz_generic_types.ts index aa231c962ae3..fe19f08149b4 100644 --- a/packages/beacon-node/test/spec/general/ssz_generic_types.ts +++ b/packages/beacon-node/test/spec/general/ssz_generic_types.ts @@ -120,7 +120,7 @@ export function getTestType(testType: string, testCase: string): Type { const elementType = vecElementTypes[elementTypeStr as keyof typeof vecElementTypes]; if (elementType === undefined) throw Error(`No vecElementType for ${elementTypeStr}: '${testCase}'`); const length = parseInt(lengthStr); - if (isNaN(length)) throw Error(`Bad length ${length}: '${testCase}'`); + if (Number.isNaN(length)) throw Error(`Bad length ${length}: '${testCase}'`); return new VectorBasicType(elementType, length); } @@ -173,6 +173,6 @@ export function getTestType(testType: string, testCase: string): Type { function parseSecondNum(str: string, id: string): number { const match = str.match(/[^\W_]+_([0-9]+)/); const num = parseInt((match || [])[1]); - if (isNaN(num)) throw Error(`Bad ${id} ${str}`); + if (Number.isNaN(num)) throw Error(`Bad ${id} ${str}`); return num; } diff --git a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts index 17347269c6f6..146131f897ca 100644 --- a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts +++ b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts @@ -102,7 +102,7 @@ const epochProcessing = }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts shouldSkip: (_testcase, name, _index) => - skipTestNames !== undefined && skipTestNames.some((skipTestName) => name.includes(skipTestName)), + skipTestNames?.some((skipTestName) => name.includes(skipTestName)) ?? false, }, }; }; diff --git a/packages/beacon-node/test/spec/presets/light_client/sync.ts b/packages/beacon-node/test/spec/presets/light_client/sync.ts index d931a5f310a8..3e82256fab1d 100644 --- a/packages/beacon-node/test/spec/presets/light_client/sync.ts +++ b/packages/beacon-node/test/spec/presets/light_client/sync.ts @@ -128,7 +128,7 @@ export const sync: TestRunnerFn = (fork) => { } const headerSlot = Number(step.process_update.checks.optimistic_header.slot); - const update = config.getLightClientForkTypes(headerSlot)["LightClientUpdate"].deserialize(updateBytes); + const update = config.getLightClientForkTypes(headerSlot).LightClientUpdate.deserialize(updateBytes); logger.debug(`LightclientUpdateSummary: ${JSON.stringify(toLightClientUpdateSummary(update))}`); diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index 06c7aa1fd98d..f5cdcc719b6a 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -52,7 +52,7 @@ const sszStatic = (ssz.altair as Types)[typeName] || (ssz.phase0 as Types)[typeName]; - it(`${fork} - ${typeName} type exists`, function () { + it(`${fork} - ${typeName} type exists`, () => { expect(sszType).toEqualWithMessage(expect.any(Type), `SSZ type ${typeName} for fork ${fork} is not defined`); }); @@ -65,7 +65,7 @@ const sszStatic = for (const testCase of fs.readdirSync(testSuiteDirpath)) { // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts - it(testCase, function () { + it(testCase, () => { // Mainnet must deal with big full states and hash each one multiple times if (ACTIVE_PRESET === "mainnet") { vi.setConfig({testTimeout: 30 * 1000}); diff --git a/packages/beacon-node/test/spec/presets/transition.test.ts b/packages/beacon-node/test/spec/presets/transition.test.ts index df818f701c5d..76ad772f8dfb 100644 --- a/packages/beacon-node/test/spec/presets/transition.test.ts +++ b/packages/beacon-node/test/spec/presets/transition.test.ts @@ -83,7 +83,7 @@ const transition = }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts shouldSkip: (_testcase, name, _index) => - skipTestNames !== undefined && skipTestNames.some((skipTestName) => name.includes(skipTestName)), + skipTestNames?.some((skipTestName) => name.includes(skipTestName)) ?? false, }, }; }; diff --git a/packages/beacon-node/test/spec/utils/runValidSszTest.ts b/packages/beacon-node/test/spec/utils/runValidSszTest.ts index 7ca02cec2d1e..748a7770b19c 100644 --- a/packages/beacon-node/test/spec/utils/runValidSszTest.ts +++ b/packages/beacon-node/test/spec/utils/runValidSszTest.ts @@ -83,6 +83,7 @@ export function runValidSszTest(type: Type, testData: ValidTestCaseData if (type.isBasic) { console.log("ROOTS Basic", toHexString(type.serialize(testDataValue))); } else { + // biome-ignore lint/complexity/useLiteralKeys: The `getRoots` is a protected attribute const roots = (type as CompositeType)["getRoots"](testDataValue); console.log( "ROOTS Composite", @@ -168,9 +169,8 @@ function wrapErr(fn: () => T, prefix: string): T { export function toJsonOrString(value: unknown): unknown { if (typeof value === "number" || typeof value === "bigint") { return value.toString(10); - } else { - return value; } + return value; } function renderTree(node: Node): void { diff --git a/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts b/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts index 7ef09af2cd89..b3137755857f 100644 --- a/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts +++ b/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts @@ -12,7 +12,7 @@ import {ZERO_HASH} from "../../../../src/constants/index.js"; * Refer to Teku tests at * https://github.com/ConsenSys/teku/blob/e18ab9903442410aa04b590c4cc46734e13d3ffd/networking/eth2/src/test/java/tech/pegasys/teku/networking/eth2/gossip/config/GossipScoringConfiguratorTest.java#L38 */ -describe("computeGossipPeerScoreParams", function () { +describe("computeGossipPeerScoreParams", () => { const config = createBeaconConfig(mainnetChainConfig, ZERO_HASH); // Cheap stub on new BeaconConfig instance config.forkName2ForkDigest = () => Buffer.alloc(4, 1); diff --git a/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts index a8eaffa42005..99bac5de7ef4 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts @@ -4,17 +4,17 @@ import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; import {getBeaconApi} from "../../../../../src/api/impl/beacon/index.js"; import {Mutable} from "../../../../utils/types.js"; -describe("beacon api implementation", function () { +describe("beacon api implementation", () => { let modules: ApiTestModules; let api: ReturnType; - beforeAll(function () { + beforeAll(() => { modules = getApiTestModules(); api = getBeaconApi(modules); }); - describe("getGenesis", function () { - it("success", async function () { + describe("getGenesis", () => { + it("success", async () => { (modules.chain as Mutable).genesisTime = 0; (modules.chain as Mutable).genesisValidatorsRoot = Buffer.alloc(32); diff --git a/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts index 9b3c960ff2ec..5e4e8a31ec7f 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts @@ -7,12 +7,12 @@ import {ApiTestModules, getApiTestModules} from "../../../../../utils/api.js"; import {generateProtoBlock, generateSignedBlockAtSlot} from "../../../../../utils/typeGenerator.js"; import {getBeaconBlockApi} from "../../../../../../src/api/impl/beacon/blocks/index.js"; -describe("api - beacon - getBlockHeaders", function () { +describe("api - beacon - getBlockHeaders", () => { let modules: ApiTestModules; let api: ReturnType; const parentRoot = toHexString(Buffer.alloc(32, 1)); - beforeEach(function () { + beforeEach(() => { modules = getApiTestModules(); api = getBeaconBlockApi(modules); @@ -24,7 +24,7 @@ describe("api - beacon - getBlockHeaders", function () { vi.clearAllMocks(); }); - it.skip("no filters - assume head slot", async function () { + it.skip("no filters - assume head slot", async () => { modules.forkChoice.getHead.mockReturnValue(generateProtoBlock({slot: 1})); when(modules.chain.getCanonicalBlockAtSlot) .calledWith(1) @@ -55,13 +55,13 @@ describe("api - beacon - getBlockHeaders", function () { expect(modules.db.block.get).toHaveBeenCalledTimes(1); }); - it("future slot", async function () { + it("future slot", async () => { modules.forkChoice.getHead.mockReturnValue(generateProtoBlock({slot: 1})); const {data: blockHeaders} = await api.getBlockHeaders({slot: 2}); expect(blockHeaders.length).toBe(0); }); - it("finalized slot", async function () { + it("finalized slot", async () => { modules.forkChoice.getHead.mockReturnValue(generateProtoBlock({slot: 2})); when(modules.chain.getCanonicalBlockAtSlot) .calledWith(0) @@ -72,14 +72,14 @@ describe("api - beacon - getBlockHeaders", function () { expect(blockHeaders[0].canonical).toBe(true); }); - it("skip slot", async function () { + it("skip slot", async () => { modules.forkChoice.getHead.mockReturnValue(generateProtoBlock({slot: 2})); when(modules.chain.getCanonicalBlockAtSlot).calledWith(0).thenResolve(null); const {data: blockHeaders} = await api.getBlockHeaders({slot: 0}); expect(blockHeaders.length).toBe(0); }); - it.skip("parent root filter - both finalized and non finalized results", async function () { + it.skip("parent root filter - both finalized and non finalized results", async () => { modules.db.blockArchive.getByParentRoot.mockResolvedValue(ssz.phase0.SignedBeaconBlock.defaultValue()); modules.forkChoice.getBlockSummariesByParentRoot.mockReturnValue([ generateProtoBlock({slot: 2}), @@ -99,7 +99,7 @@ describe("api - beacon - getBlockHeaders", function () { expect(blockHeaders.filter((b) => b.canonical).length).toBe(2); }); - it("parent root - no finalized block", async function () { + it("parent root - no finalized block", async () => { modules.db.blockArchive.getByParentRoot.mockResolvedValue(null); modules.forkChoice.getBlockSummariesByParentRoot.mockReturnValue([generateProtoBlock({slot: 1})]); when(modules.forkChoice.getCanonicalBlockAtSlot).calledWith(1).thenReturn(generateProtoBlock()); @@ -109,14 +109,14 @@ describe("api - beacon - getBlockHeaders", function () { expect(blockHeaders.length).toBe(1); }); - it("parent root - no non finalized blocks", async function () { + it("parent root - no non finalized blocks", async () => { modules.db.blockArchive.getByParentRoot.mockResolvedValue(ssz.phase0.SignedBeaconBlock.defaultValue()); modules.forkChoice.getBlockSummariesByParentRoot.mockReturnValue([]); const {data: blockHeaders} = await api.getBlockHeaders({parentRoot}); expect(blockHeaders.length).toBe(1); }); - it("parent root + slot filter", async function () { + it("parent root + slot filter", async () => { modules.db.blockArchive.getByParentRoot.mockResolvedValue(ssz.phase0.SignedBeaconBlock.defaultValue()); modules.forkChoice.getBlockSummariesByParentRoot.mockReturnValue([ generateProtoBlock({slot: 2}), diff --git a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts index 39c936c0d025..958093ffba6d 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts @@ -3,7 +3,7 @@ import {toHexString} from "@chainsafe/ssz"; import {getStateValidatorIndex} from "../../../../../../src/api/impl/beacon/state/utils.js"; import {generateCachedAltairState} from "../../../../../utils/state.js"; -describe("beacon state api utils", function () { +describe("beacon state api utils", () => { describe("getStateValidatorIndex", () => { const state = generateCachedAltairState(); const pubkey2index = state.epochCtx.pubkey2index; diff --git a/packages/beacon-node/test/unit/api/impl/config/config.test.ts b/packages/beacon-node/test/unit/api/impl/config/config.test.ts index d6954f632d5e..7d0adebbea89 100644 --- a/packages/beacon-node/test/unit/api/impl/config/config.test.ts +++ b/packages/beacon-node/test/unit/api/impl/config/config.test.ts @@ -3,34 +3,34 @@ import {routes} from "@lodestar/api"; import {config} from "@lodestar/config/default"; import {getConfigApi, renderJsonSpec} from "../../../../../src/api/impl/config/index.js"; -describe("config api implementation", function () { +describe("config api implementation", () => { let api: ReturnType; - beforeEach(function () { + beforeEach(() => { api = getConfigApi({config}); }); - describe("getForkSchedule", function () { - it("should get known scheduled forks", async function () { + describe("getForkSchedule", () => { + it("should get known scheduled forks", async () => { const {data: forkSchedule} = await api.getForkSchedule(); expect(forkSchedule.length).toBe(Object.keys(config.forks).length); }); }); - describe("getDepositContract", function () { - it("should get the deposit contract from config", async function () { + describe("getDepositContract", () => { + it("should get the deposit contract from config", async () => { const {data: depositContract} = (await api.getDepositContract()) as {data: routes.config.DepositContract}; expect(depositContract.address).toBe(config.DEPOSIT_CONTRACT_ADDRESS); expect(depositContract.chainId).toBe(config.DEPOSIT_CHAIN_ID); }); }); - describe("getSpec", function () { + describe("getSpec", () => { it("Ensure spec can be rendered", () => { renderJsonSpec(config); }); - it("should get the spec", async function () { + it("should get the spec", async () => { const {data: specJson} = (await api.getSpec()) as {data: routes.config.Spec}; expect(specJson.SECONDS_PER_ETH1_BLOCK).toBe("14"); diff --git a/packages/beacon-node/test/unit/api/impl/events/events.test.ts b/packages/beacon-node/test/unit/api/impl/events/events.test.ts index a5dd21d14fd3..5b1686d42f57 100644 --- a/packages/beacon-node/test/unit/api/impl/events/events.test.ts +++ b/packages/beacon-node/test/unit/api/impl/events/events.test.ts @@ -22,22 +22,20 @@ vi.mock("../../../../../src/chain/index.js", async (importActual) => { }; }); -describe("Events api impl", function () { - describe("beacon event stream", function () { +describe("Events api impl", () => { + describe("beacon event stream", () => { let chainStub: MockedObject; let chainEventEmmitter: ChainEventEmitter; let api: ReturnType; + let controller: AbortController; - beforeEach(function () { + beforeEach(() => { chainStub = vi.mocked(new BeaconChain({} as any, {} as any), {partial: true, deep: false}); chainEventEmmitter = chainStub.emitter; api = getEventsApi({config, chain: chainStub}); - }); - - let controller: AbortController; - beforeEach(() => { controller = new AbortController(); }); + afterEach(() => controller.abort()); function getEvents(topics: routes.events.EventType[]): routes.events.BeaconEvent[] { @@ -62,7 +60,7 @@ describe("Events api impl", function () { executionOptimistic: false, }; - it("should ignore not sent topics", async function () { + it("should ignore not sent topics", async () => { const events = getEvents([routes.events.EventType.head]); chainEventEmmitter.emit(routes.events.EventType.attestation, ssz.phase0.Attestation.defaultValue()); diff --git a/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts b/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts index 49758c9bca58..b954f983adcc 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts @@ -13,7 +13,7 @@ import {createCachedBeaconStateTest} from "../../../../../utils/cachedBeaconStat import {SyncState} from "../../../../../../src/sync/interface.js"; import {defaultApiOptions} from "../../../../../../src/api/options.js"; -describe("get proposers api impl", function () { +describe("get proposers api impl", () => { const currentEpoch = 2; const currentSlot = SLOTS_PER_EPOCH * currentEpoch; @@ -22,7 +22,7 @@ describe("get proposers api impl", function () { let state: BeaconStateAllForks; let cachedState: ReturnType; - beforeEach(function () { + beforeEach(() => { vi.useFakeTimers({now: 0}); vi.advanceTimersByTime(currentSlot * config.SECONDS_PER_SLOT * 1000); modules = getApiTestModules({clock: "real"}); diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts index 84872ca6045c..fdbfec5ac503 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts @@ -5,16 +5,16 @@ import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; import {getValidatorApi} from "../../../../../src/api/impl/validator/index.js"; import {defaultApiOptions} from "../../../../../src/api/options.js"; -describe("api - validator - produceAttestationData", function () { +describe("api - validator - produceAttestationData", () => { let modules: ApiTestModules; let api: ReturnType; - beforeEach(function () { + beforeEach(() => { modules = getApiTestModules(); api = getValidatorApi(defaultApiOptions, modules); }); - it("Should throw when node is not synced", async function () { + it("Should throw when node is not synced", async () => { // Set the node's state to way back from current slot const currentSlot = 100000; const headSlot = 0; @@ -25,7 +25,7 @@ describe("api - validator - produceAttestationData", function () { await expect(api.produceAttestationData({committeeIndex: 0, slot: 0})).rejects.toThrow("Node is syncing"); }); - it("Should throw error when node is stopped", async function () { + it("Should throw error when node is stopped", async () => { const currentSlot = 100000; vi.spyOn(modules.chain.clock, "currentSlot", "get").mockReturnValue(currentSlot); vi.spyOn(modules.sync, "state", "get").mockReturnValue(SyncState.Stalled); diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts index a23373938f64..306b18481c1f 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts @@ -16,7 +16,7 @@ import {generateProtoBlock} from "../../../../utils/typeGenerator.js"; import {ZERO_HASH_HEX} from "../../../../../src/constants/index.js"; import {defaultApiOptions} from "../../../../../src/api/options.js"; -describe("api/validator - produceBlockV2", function () { +describe("api/validator - produceBlockV2", () => { let api: ReturnType; let modules: ApiTestModules; let state: CachedBeaconStateBellatrix; @@ -32,7 +32,7 @@ describe("api/validator - produceBlockV2", function () { vi.clearAllMocks(); }); - it("correctly pass feeRecipient to produceBlock", async function () { + it("correctly pass feeRecipient to produceBlock", async () => { const fullBlock = ssz.bellatrix.BeaconBlock.defaultValue(); const executionPayloadValue = ssz.Wei.defaultValue(); const consensusBlockValue = ssz.Wei.defaultValue(); diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts index d8f1b9a317b9..f705e4b38e14 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts @@ -12,7 +12,7 @@ import {CommonBlockBody} from "../../../../../src/chain/interface.js"; import {zeroProtoBlock} from "../../../../utils/state.js"; import {defaultApiOptions} from "../../../../../src/api/options.js"; -describe("api/validator - produceBlockV3", function () { +describe("api/validator - produceBlockV3", () => { let modules: ApiTestModules; let api: ReturnType; @@ -64,102 +64,100 @@ describe("api/validator - produceBlockV3", function () { [routes.validator.BuilderSelection.ExecutionOnly, 1, 1, 1, true, "engine"], ]; - testCases.forEach( - ([ - builderSelection, - builderPayloadValue, - enginePayloadValue, - consensusBlockValue, - shouldOverrideBuilder, - finalSelection, - ]) => { - it(`produceBlockV3 - ${finalSelection} produces block`, async () => { - const fullBlock = ssz.bellatrix.BeaconBlock.defaultValue(); - const blindedBlock = ssz.bellatrix.BlindedBeaconBlock.defaultValue(); - - const slot = 1 * SLOTS_PER_EPOCH; - const randaoReveal = fullBlock.body.randaoReveal; - const graffiti = "a".repeat(32); - const feeRecipient = "0xccccccccccccccccccccccccccccccccccccccaa"; - const currentSlot = 1 * SLOTS_PER_EPOCH; - - vi.spyOn(modules.chain.clock, "currentSlot", "get").mockReturnValue(currentSlot); - vi.spyOn(modules.sync, "state", "get").mockReturnValue(SyncState.Synced); - modules.chain.recomputeForkChoiceHead.mockReturnValue({ - blockRoot: toHexString(fullBlock.parentRoot), - } as ProtoBlock); - modules.chain.getProposerHead.mockReturnValue({blockRoot: toHexString(fullBlock.parentRoot)} as ProtoBlock); - modules.chain.forkChoice.getBlock.mockReturnValue(zeroProtoBlock); - - if (enginePayloadValue !== null) { - const commonBlockBody: CommonBlockBody = { - attestations: fullBlock.body.attestations, - attesterSlashings: fullBlock.body.attesterSlashings, - deposits: fullBlock.body.deposits, - proposerSlashings: fullBlock.body.proposerSlashings, - eth1Data: fullBlock.body.eth1Data, - graffiti: fullBlock.body.graffiti, - randaoReveal: fullBlock.body.randaoReveal, - voluntaryExits: fullBlock.body.voluntaryExits, - blsToExecutionChanges: [], - syncAggregate: fullBlock.body.syncAggregate, - }; - - modules.chain.produceCommonBlockBody.mockResolvedValue(commonBlockBody); - - modules.chain.produceBlock.mockResolvedValue({ - block: fullBlock, - executionPayloadValue: BigInt(enginePayloadValue), - consensusBlockValue: BigInt(consensusBlockValue), - shouldOverrideBuilder, - }); - } else { - modules.chain.produceBlock.mockRejectedValue(Error("not produced")); - } - - if (builderPayloadValue !== null) { - modules.chain.produceBlindedBlock.mockResolvedValue({ - block: blindedBlock, - executionPayloadValue: BigInt(builderPayloadValue), - consensusBlockValue: BigInt(consensusBlockValue), - }); - } else { - modules.chain.produceBlindedBlock.mockRejectedValue(Error("not produced")); - } - const _skipRandaoVerification = false; - const produceBlockOpts = { - strictFeeRecipientCheck: false, - builderSelection, - feeRecipient, + for (const [ + builderSelection, + builderPayloadValue, + enginePayloadValue, + consensusBlockValue, + shouldOverrideBuilder, + finalSelection, + ] of testCases) { + it(`produceBlockV3 - ${finalSelection} produces block`, async () => { + const fullBlock = ssz.bellatrix.BeaconBlock.defaultValue(); + const blindedBlock = ssz.bellatrix.BlindedBeaconBlock.defaultValue(); + + const slot = 1 * SLOTS_PER_EPOCH; + const randaoReveal = fullBlock.body.randaoReveal; + const graffiti = "a".repeat(32); + const feeRecipient = "0xccccccccccccccccccccccccccccccccccccccaa"; + const currentSlot = 1 * SLOTS_PER_EPOCH; + + vi.spyOn(modules.chain.clock, "currentSlot", "get").mockReturnValue(currentSlot); + vi.spyOn(modules.sync, "state", "get").mockReturnValue(SyncState.Synced); + modules.chain.recomputeForkChoiceHead.mockReturnValue({ + blockRoot: toHexString(fullBlock.parentRoot), + } as ProtoBlock); + modules.chain.getProposerHead.mockReturnValue({blockRoot: toHexString(fullBlock.parentRoot)} as ProtoBlock); + modules.chain.forkChoice.getBlock.mockReturnValue(zeroProtoBlock); + + if (enginePayloadValue !== null) { + const commonBlockBody: CommonBlockBody = { + attestations: fullBlock.body.attestations, + attesterSlashings: fullBlock.body.attesterSlashings, + deposits: fullBlock.body.deposits, + proposerSlashings: fullBlock.body.proposerSlashings, + eth1Data: fullBlock.body.eth1Data, + graffiti: fullBlock.body.graffiti, + randaoReveal: fullBlock.body.randaoReveal, + voluntaryExits: fullBlock.body.voluntaryExits, + blsToExecutionChanges: [], + syncAggregate: fullBlock.body.syncAggregate, }; - const {data: block, meta} = await api.produceBlockV3({ - slot, - randaoReveal, - graffiti, - skipRandaoVerification: _skipRandaoVerification, - ...produceBlockOpts, - }); - - const expectedBlock = finalSelection === "builder" ? blindedBlock : fullBlock; - const expectedExecution = finalSelection === "builder"; - - expect(block).toEqual(expectedBlock); - expect(meta.executionPayloadBlinded).toEqual(expectedExecution); - - // check call counts - if (builderSelection === routes.validator.BuilderSelection.ExecutionOnly) { - expect(modules.chain.produceBlindedBlock).toBeCalledTimes(0); - } else { - expect(modules.chain.produceBlindedBlock).toBeCalledTimes(1); - } + modules.chain.produceCommonBlockBody.mockResolvedValue(commonBlockBody); - if (builderSelection === routes.validator.BuilderSelection.BuilderOnly) { - expect(modules.chain.produceBlock).toBeCalledTimes(0); - } else { - expect(modules.chain.produceBlock).toBeCalledTimes(1); - } + modules.chain.produceBlock.mockResolvedValue({ + block: fullBlock, + executionPayloadValue: BigInt(enginePayloadValue), + consensusBlockValue: BigInt(consensusBlockValue), + shouldOverrideBuilder, + }); + } else { + modules.chain.produceBlock.mockRejectedValue(Error("not produced")); + } + + if (builderPayloadValue !== null) { + modules.chain.produceBlindedBlock.mockResolvedValue({ + block: blindedBlock, + executionPayloadValue: BigInt(builderPayloadValue), + consensusBlockValue: BigInt(consensusBlockValue), + }); + } else { + modules.chain.produceBlindedBlock.mockRejectedValue(Error("not produced")); + } + const _skipRandaoVerification = false; + const produceBlockOpts = { + strictFeeRecipientCheck: false, + builderSelection, + feeRecipient, + }; + + const {data: block, meta} = await api.produceBlockV3({ + slot, + randaoReveal, + graffiti, + skipRandaoVerification: _skipRandaoVerification, + ...produceBlockOpts, }); - } - ); + + const expectedBlock = finalSelection === "builder" ? blindedBlock : fullBlock; + const expectedExecution = finalSelection === "builder"; + + expect(block).toEqual(expectedBlock); + expect(meta.executionPayloadBlinded).toEqual(expectedExecution); + + // check call counts + if (builderSelection === routes.validator.BuilderSelection.ExecutionOnly) { + expect(modules.chain.produceBlindedBlock).toBeCalledTimes(0); + } else { + expect(modules.chain.produceBlindedBlock).toBeCalledTimes(1); + } + + if (builderSelection === routes.validator.BuilderSelection.BuilderOnly) { + expect(modules.chain.produceBlock).toBeCalledTimes(0); + } else { + expect(modules.chain.produceBlock).toBeCalledTimes(1); + } + }); + } }); diff --git a/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts b/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts index d9c3b93a76ee..dc7c9bb75291 100644 --- a/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts +++ b/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts @@ -9,14 +9,14 @@ import {archiveBlocks} from "../../../../src/chain/archiver/archiveBlocks.js"; import {MockedBeaconDb, getMockedBeaconDb} from "../../../mocks/mockedBeaconDb.js"; import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; -describe("block archiver task", function () { +describe("block archiver task", () => { const logger = testLogger(); let dbStub: MockedBeaconDb; let forkChoiceStub: MockedBeaconChain["forkChoice"]; let lightclientServer: MockedBeaconChain["lightClientServer"]; - beforeEach(function () { + beforeEach(() => { const chain = getMockedBeaconChain(); dbStub = getMockedBeaconDb(); forkChoiceStub = chain.forkChoice; @@ -30,7 +30,7 @@ describe("block archiver task", function () { vi.clearAllMocks(); }); - it("should archive finalized blocks", async function () { + it("should archive finalized blocks", async () => { const blockBytes = ssz.phase0.SignedBeaconBlock.serialize(ssz.phase0.SignedBeaconBlock.defaultValue()); vi.spyOn(dbStub.block, "getBinary").mockResolvedValue(Buffer.from(blockBytes)); // block i has slot i+1 diff --git a/packages/beacon-node/test/unit/chain/beaconProposerCache.ts b/packages/beacon-node/test/unit/chain/beaconProposerCache.ts index 538fe8518458..b75bbf546a98 100644 --- a/packages/beacon-node/test/unit/chain/beaconProposerCache.ts +++ b/packages/beacon-node/test/unit/chain/beaconProposerCache.ts @@ -2,30 +2,30 @@ import {expect, describe, it, beforeEach} from "vitest"; import {BeaconProposerCache} from "../../../src/chain/beaconProposerCache.js"; const suggestedFeeRecipient = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; -describe("BeaconProposerCache", function () { +describe("BeaconProposerCache", () => { let cache: BeaconProposerCache; - beforeEach(function () { + beforeEach(() => { // max 2 items cache = new BeaconProposerCache({suggestedFeeRecipient}); cache.add(1, {validatorIndex: 23, feeRecipient: "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}); cache.add(3, {validatorIndex: 43, feeRecipient: "0xcccccccccccccccccccccccccccccccccccccccc"}); }); - it("get default", function () { + it("get default", () => { expect(cache.get(32)).toBe("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); }); - it("get what has been set", function () { + it("get what has been set", () => { expect(cache.get(23)).toBe("0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); }); - it("override and get latest", function () { + it("override and get latest", () => { cache.add(5, {validatorIndex: 23, feeRecipient: "0xdddddddddddddddddddddddddddddddddddddddd"}); expect(cache.get(23)).toBe("0xdddddddddddddddddddddddddddddddddddddddd"); }); - it("prune", function () { + it("prune", () => { cache.prune(4); // Default for what has been pruned diff --git a/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts b/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts index a45678e5bf48..1296a79d5eab 100644 --- a/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts +++ b/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts @@ -13,7 +13,7 @@ import {ClockStopped} from "../../../mocks/clock.js"; import {BlockSource, getBlockInput} from "../../../../src/chain/blocks/types.js"; import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; -describe("chain / blocks / verifyBlocksSanityChecks", function () { +describe("chain / blocks / verifyBlocksSanityChecks", () => { let forkChoice: MockedBeaconChain["forkChoice"]; let clock: ClockStopped; let modules: {forkChoice: IForkChoice; clock: IClock; config: ChainForkConfig}; diff --git a/packages/beacon-node/test/unit/chain/bls/bls.test.ts b/packages/beacon-node/test/unit/chain/bls/bls.test.ts index 4203d7f9768c..137f2c4dd9df 100644 --- a/packages/beacon-node/test/unit/chain/bls/bls.test.ts +++ b/packages/beacon-node/test/unit/chain/bls/bls.test.ts @@ -5,7 +5,7 @@ import {BlsSingleThreadVerifier} from "../../../../src/chain/bls/singleThread.js import {BlsMultiThreadWorkerPool} from "../../../../src/chain/bls/multithread/index.js"; import {testLogger} from "../../../utils/logger.js"; -describe("BlsVerifier ", function () { +describe("BlsVerifier ", () => { // take time for creating thread pool const numKeys = 3; const secretKeys = Array.from({length: numKeys}, (_, i) => SecretKey.fromKeygen(Buffer.alloc(32, i))); diff --git a/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts b/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts index 611673086ce5..7cb5d23ba296 100644 --- a/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts +++ b/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts @@ -20,7 +20,7 @@ import {generateValidators} from "../../../utils/validator.js"; // We mock this package globally vi.unmock("@lodestar/fork-choice"); -describe("LodestarForkChoice", function () { +describe("LodestarForkChoice", () => { let forkChoice: ForkChoice; const anchorState = createCachedBeaconStateTest( generateState( @@ -71,7 +71,7 @@ describe("LodestarForkChoice", function () { ); }); - describe("forkchoice", function () { + describe("forkchoice", () => { /** * slot 32(checkpoint) - orphaned (36) * \ diff --git a/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts b/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts index 5b48ca9fd953..40570fcd26e1 100644 --- a/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts +++ b/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts @@ -11,7 +11,7 @@ import {testLogger} from "../../../utils/logger.js"; import {ZERO_HASH_HEX} from "../../../../src/constants/index.js"; import {Eth1ProviderState, EthJsonRpcBlockRaw, IEth1Provider} from "../../../../src/eth1/interface.js"; -describe("genesis builder", function () { +describe("genesis builder", () => { const logger = testLogger(); const schlesiConfig = Object.assign({}, config, { MIN_GENESIS_TIME: 1587755000, diff --git a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts index ab8f166076b9..3c2f5a664c77 100644 --- a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts +++ b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts @@ -4,7 +4,7 @@ import {ForkName, ForkSeq} from "@lodestar/params"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {upgradeLightClientHeader} from "@lodestar/light-client/spec"; -describe("UpgradeLightClientHeader", function () { +describe("UpgradeLightClientHeader", () => { let lcHeaderByFork: Record; let testSlots: Record; @@ -20,7 +20,7 @@ describe("UpgradeLightClientHeader", function () { const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); const config = createBeaconConfig(chainConfig, genesisValidatorsRoot); - beforeEach(function () { + beforeEach(() => { lcHeaderByFork = { phase0: ssz.altair.LightClientHeader.defaultValue(), altair: ssz.altair.LightClientHeader.defaultValue(), @@ -45,7 +45,7 @@ describe("UpgradeLightClientHeader", function () { const fromFork = ForkName[ForkSeq[i] as ForkName]; const toFork = ForkName[ForkSeq[j] as ForkName]; - it(`Successful upgrade ${fromFork}=>${toFork}`, function () { + it(`Successful upgrade ${fromFork}=>${toFork}`, () => { lcHeaderByFork[fromFork].beacon.slot = testSlots[fromFork]; lcHeaderByFork[toFork].beacon.slot = testSlots[fromFork]; @@ -60,7 +60,7 @@ describe("UpgradeLightClientHeader", function () { const fromFork = ForkName[ForkSeq[i] as ForkName]; const toFork = ForkName[ForkSeq[j] as ForkName]; - it(`Throw upgrade error ${fromFork}=>${toFork}`, function () { + it(`Throw upgrade error ${fromFork}=>${toFork}`, () => { lcHeaderByFork[fromFork].beacon.slot = testSlots[fromFork]; lcHeaderByFork[toFork].beacon.slot = testSlots[fromFork]; diff --git a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts index f00a300bbe4d..8742d7da9147 100644 --- a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts @@ -34,7 +34,7 @@ const validSignature = fromHexString( "0xb2afb700f6c561ce5e1b4fedaec9d7c06b822d38c720cf588adfda748860a940adf51634b6788f298c552de40183b5a203b2bbe8b7dd147f0bb5bc97080a12efbb631c8888cb31a99cc4706eb3711865b8ea818c10126e4d818b542e9dbf9ae8" ); -describe("AggregatedAttestationPool", function () { +describe("AggregatedAttestationPool", () => { let pool: AggregatedAttestationPool; const fork = ForkName.altair; const config = createChainForkConfig({ @@ -116,7 +116,7 @@ describe("AggregatedAttestationPool", function () { ]; for (const {name, attestingBits, isReturned} of testCases) { - it(name, function () { + it(name, () => { const aggregationBits = new BitArray(new Uint8Array(attestingBits), committeeLength); pool.add( {...attestation, aggregationBits}, @@ -136,7 +136,7 @@ describe("AggregatedAttestationPool", function () { }); } - it("incorrect source", function () { + it("incorrect source", () => { altairState.currentJustifiedCheckpoint.epoch = 1000; // all attesters are not seen const attestingIndices = [2, 3]; @@ -146,7 +146,7 @@ describe("AggregatedAttestationPool", function () { expect(forkchoiceStub.iterateAncestorBlocks).not.toHaveBeenCalledTimes(1); }); - it("incompatible shuffling - incorrect pivot block root", function () { + it("incompatible shuffling - incorrect pivot block root", () => { // all attesters are not seen const attestingIndices = [2, 3]; pool.add(attestation, attDataRootHex, attestingIndices.length, committee); @@ -305,7 +305,7 @@ describe("MatchingDataAttestationGroup.getAttestationsForBlock", () => { } }); -describe("MatchingDataAttestationGroup aggregateInto", function () { +describe("MatchingDataAttestationGroup aggregateInto", () => { const attestationSeed = ssz.phase0.Attestation.defaultValue(); const attestation1 = {...attestationSeed, ...{aggregationBits: BitArray.fromBoolArray([false, true])}}; const attestation2 = {...attestationSeed, ...{aggregationBits: BitArray.fromBoolArray([true, false])}}; @@ -334,7 +334,7 @@ describe("MatchingDataAttestationGroup aggregateInto", function () { }); }); -describe("aggregateConsolidation", function () { +describe("aggregateConsolidation", () => { const sk0 = SecretKey.fromBytes(Buffer.alloc(32, 1)); const sk1 = SecretKey.fromBytes(Buffer.alloc(32, 2)); const sk2 = SecretKey.fromBytes(Buffer.alloc(32, 3)); diff --git a/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts index eba01888fa7c..98453efaa3b6 100644 --- a/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts @@ -8,11 +8,11 @@ import {AttestationPool} from "../../../../src/chain/opPools/attestationPool.js" import {getMockedClock} from "../../../mocks/clock.js"; /** Valid signature of random data to prevent BLS errors */ -export const validSignature = fromHexString( +const validSignature = fromHexString( "0xb2afb700f6c561ce5e1b4fedaec9d7c06b822d38c720cf588adfda748860a940adf51634b6788f298c552de40183b5a203b2bbe8b7dd147f0bb5bc97080a12efbb631c8888cb31a99cc4706eb3711865b8ea818c10126e4d818b542e9dbf9ae8" ); -describe("AttestationPool", function () { +describe("AttestationPool", () => { const config = createChainForkConfig({ ...defaultChainConfig, ELECTRA_FORK_EPOCH: 5, diff --git a/packages/beacon-node/test/unit/chain/opPools/syncCommittee.test.ts b/packages/beacon-node/test/unit/chain/opPools/syncCommittee.test.ts index 507c78d560b6..e91eaa58aa73 100644 --- a/packages/beacon-node/test/unit/chain/opPools/syncCommittee.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/syncCommittee.test.ts @@ -7,7 +7,7 @@ import {Clock} from "../../../../src/util/clock.js"; vi.mock("../../../../src/util/clock.js"); -describe("chain / opPools / SyncCommitteeMessagePool", function () { +describe("chain / opPools / SyncCommitteeMessagePool", () => { let cache: SyncCommitteeMessagePool; const subcommitteeIndex = 2; const indexInSubcommittee = 3; @@ -33,7 +33,7 @@ describe("chain / opPools / SyncCommitteeMessagePool", function () { cache.add(subcommitteeIndex, syncCommittee, indexInSubcommittee); }); - afterEach(function () { + afterEach(() => { vi.clearAllTimers(); vi.clearAllMocks(); }); diff --git a/packages/beacon-node/test/unit/chain/opPools/syncCommitteeContribution.test.ts b/packages/beacon-node/test/unit/chain/opPools/syncCommitteeContribution.test.ts index e34a5d006272..e1bd60a2305e 100644 --- a/packages/beacon-node/test/unit/chain/opPools/syncCommitteeContribution.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/syncCommitteeContribution.test.ts @@ -15,7 +15,7 @@ import {EMPTY_SIGNATURE} from "../../../../src/constants/index.js"; import {renderBitArray} from "../../../utils/render.js"; import {VALID_BLS_SIGNATURE_RAND} from "../../../utils/typeGenerator.js"; -describe("chain / opPools / SyncContributionAndProofPool", function () { +describe("chain / opPools / SyncContributionAndProofPool", () => { let cache: SyncContributionAndProofPool; const beaconBlockRoot = Buffer.alloc(32, 1); const slot = 10; @@ -44,7 +44,7 @@ describe("chain / opPools / SyncContributionAndProofPool", function () { }); }); -describe("replaceIfBetter", function () { +describe("replaceIfBetter", () => { const numParticipants = 2; let bestContribution: SyncContributionFast; // const subnetSize = Math.floor(SYNC_COMMITTEE_SIZE / SYNC_COMMITTEE_SUBNET_COUNT); @@ -77,7 +77,7 @@ describe("replaceIfBetter", function () { }); }); -describe("aggregate", function () { +describe("aggregate", () => { const sks: SecretKey[] = []; let bestContributionBySubnet: Map; beforeAll(async () => { diff --git a/packages/beacon-node/test/unit/chain/reprocess.test.ts b/packages/beacon-node/test/unit/chain/reprocess.test.ts index a8160544f509..927e4cf8d05f 100644 --- a/packages/beacon-node/test/unit/chain/reprocess.test.ts +++ b/packages/beacon-node/test/unit/chain/reprocess.test.ts @@ -1,7 +1,7 @@ import {describe, it, expect, beforeEach} from "vitest"; import {ReprocessController} from "../../../src/chain/reprocess.js"; -describe("ReprocessController", function () { +describe("ReprocessController", () => { let controller: ReprocessController; beforeEach(() => { diff --git a/packages/beacon-node/test/unit/chain/seenCache/aggregateAndProof.test.ts b/packages/beacon-node/test/unit/chain/seenCache/aggregateAndProof.test.ts index 3118fdcadc43..d83433a649ca 100644 --- a/packages/beacon-node/test/unit/chain/seenCache/aggregateAndProof.test.ts +++ b/packages/beacon-node/test/unit/chain/seenCache/aggregateAndProof.test.ts @@ -6,7 +6,7 @@ import { SeenAggregatedAttestations, } from "../../../../src/chain/seenCache/seenAggregateAndProof.js"; -describe("SeenAggregatedAttestations.isKnown", function () { +describe("SeenAggregatedAttestations.isKnown", () => { const testCases: { id: string; seenAttestingBits: number[]; @@ -62,7 +62,7 @@ describe("SeenAggregatedAttestations.isKnown", function () { } }); -describe("insertDesc", function () { +describe("insertDesc", () => { const testCases: { id: string; arr: number[][]; diff --git a/packages/beacon-node/test/unit/chain/seenCache/syncCommittee.test.ts b/packages/beacon-node/test/unit/chain/seenCache/syncCommittee.test.ts index 901c19cad9f8..59c67f9cedc2 100644 --- a/packages/beacon-node/test/unit/chain/seenCache/syncCommittee.test.ts +++ b/packages/beacon-node/test/unit/chain/seenCache/syncCommittee.test.ts @@ -5,7 +5,7 @@ import {SeenSyncCommitteeMessages, SeenContributionAndProof} from "../../../../s const NUM_SLOTS_IN_CACHE = 3; -describe("chain / seenCache / SeenSyncCommittee caches", function () { +describe("chain / seenCache / SeenSyncCommittee caches", () => { describe("SeenSyncCommitteeMessages", () => { const slot = 10; const subnet = 2; diff --git a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts index 3c1824b8c01d..d417e555872c 100644 --- a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts +++ b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts @@ -2,7 +2,7 @@ import {describe, it, expect, beforeEach} from "vitest"; import {generateTestCachedBeaconStateOnlyValidators} from "../../../../state-transition/test/perf/util.js"; import {ShufflingCache} from "../../../src/chain/shufflingCache.js"; -describe("ShufflingCache", function () { +describe("ShufflingCache", () => { const vc = 64; const stateSlot = 100; const state = generateTestCachedBeaconStateOnlyValidators({vc, slot: stateSlot}); @@ -19,11 +19,11 @@ describe("ShufflingCache", function () { ]); }); - it("should get shuffling from cache", async function () { + it("should get shuffling from cache", async () => { expect(await shufflingCache.get(currentEpoch, currentDecisionRoot)).toEqual(state.epochCtx.currentShuffling); }); - it("should bound by maxSize(=1)", async function () { + it("should bound by maxSize(=1)", async () => { expect(await shufflingCache.get(currentEpoch, currentDecisionRoot)).toEqual(state.epochCtx.currentShuffling); // insert promises at the same epoch does not prune the cache shufflingCache.insertPromise(currentEpoch, "0x00"); @@ -34,7 +34,7 @@ describe("ShufflingCache", function () { expect(await shufflingCache.get(currentEpoch, currentDecisionRoot)).toBeNull(); }); - it("should return shuffling from promise", async function () { + it("should return shuffling from promise", async () => { const previousEpoch = state.epochCtx.epoch - 1; const previousDecisionRoot = state.epochCtx.previousDecisionRoot; shufflingCache.insertPromise(previousEpoch, previousDecisionRoot); @@ -45,7 +45,7 @@ describe("ShufflingCache", function () { expect(await shufflingRequest1).toEqual(state.epochCtx.previousShuffling); }); - it("should support up to 2 promises at a time", async function () { + it("should support up to 2 promises at a time", async () => { // insert 2 promises at the same epoch shufflingCache.insertPromise(currentEpoch, "0x00"); shufflingCache.insertPromise(currentEpoch, "0x01"); diff --git a/packages/beacon-node/test/unit/chain/stateCache/blockStateCacheImpl.test.ts b/packages/beacon-node/test/unit/chain/stateCache/blockStateCacheImpl.test.ts index b89a71399237..19dc0f3a2c60 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/blockStateCacheImpl.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/blockStateCacheImpl.test.ts @@ -7,7 +7,7 @@ import {BlockStateCacheImpl} from "../../../../src/chain/stateCache/index.js"; import {generateCachedState} from "../../../utils/state.js"; import {ZERO_HASH} from "../../../../src/constants/index.js"; -describe("BlockStateCacheImpl", function () { +describe("BlockStateCacheImpl", () => { let cache: BlockStateCacheImpl; let key1: Root, key2: Root; const shuffling: EpochShuffling = { @@ -18,7 +18,7 @@ describe("BlockStateCacheImpl", function () { committeesPerSlot: 1, }; - beforeEach(function () { + beforeEach(() => { // max 2 items cache = new BlockStateCacheImpl({maxStates: 2}); const state1 = generateCachedState({slot: 0}); @@ -31,7 +31,7 @@ describe("BlockStateCacheImpl", function () { cache.add(state2); }); - it("should prune", function () { + it("should prune", () => { expect(cache.size).toBe(2); const state3 = generateCachedState({slot: 2 * SLOTS_PER_EPOCH}); state3.epochCtx.currentShuffling = {...shuffling, epoch: 2}; @@ -46,7 +46,7 @@ describe("BlockStateCacheImpl", function () { expect(cache.get(toHexString(key2))).toBeDefined(); }); - it("should deleteAllBeforeEpoch", function () { + it("should deleteAllBeforeEpoch", () => { cache.deleteAllBeforeEpoch(2); expect(cache.size).toBe(0); }); diff --git a/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts index b4aac92dd9bb..07a8ec12093d 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts @@ -5,7 +5,7 @@ import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {FIFOBlockStateCache} from "../../../../src/chain/stateCache/index.js"; import {generateCachedState} from "../../../utils/state.js"; -describe("FIFOBlockStateCache", function () { +describe("FIFOBlockStateCache", () => { let cache: FIFOBlockStateCache; const shuffling: EpochShuffling = { epoch: 0, @@ -27,7 +27,7 @@ describe("FIFOBlockStateCache", function () { const key3 = toHexString(state3.hashTreeRoot()); state3.epochCtx.currentShuffling = {...shuffling, epoch: 2}; - beforeEach(function () { + beforeEach(() => { // max 2 items cache = new FIFOBlockStateCache({maxBlockStates: 2}, {}); cache.add(state1); diff --git a/packages/beacon-node/test/unit/chain/stateCache/inMemoryCheckpointsCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/inMemoryCheckpointsCache.test.ts index 59f320178118..23a792bef0a8 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/inMemoryCheckpointsCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/inMemoryCheckpointsCache.test.ts @@ -9,7 +9,7 @@ import { } from "../../../../src/chain/stateCache/inMemoryCheckpointsCache.js"; import {generateCachedState} from "../../../utils/state.js"; -describe("InMemoryCheckpointStateCache", function () { +describe("InMemoryCheckpointStateCache", () => { let root0a: Buffer, root0b: Buffer, root1: Buffer, root2: Buffer; let cp0a: phase0.Checkpoint, cp0b: phase0.Checkpoint, cp1: phase0.Checkpoint, cp2: phase0.Checkpoint; let cp0aHex: CheckpointHex, cp0bHex: CheckpointHex, cp1Hex: CheckpointHex, cp2Hex: CheckpointHex; diff --git a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts index 9614263b4312..f98b180fa983 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts @@ -12,7 +12,7 @@ import {getTestDatastore} from "../../../utils/chain/stateCache/datastore.js"; import {CheckpointHex} from "../../../../src/chain/stateCache/types.js"; import {FIFOBlockStateCache, toCheckpointHex} from "../../../../src/chain/index.js"; -describe("PersistentCheckpointStateCache", function () { +describe("PersistentCheckpointStateCache", () => { let root0a: Buffer, root0b: Buffer, root1: Buffer, root2: Buffer; let cp0a: phase0.Checkpoint, cp0b: phase0.Checkpoint, cp1: phase0.Checkpoint, cp2: phase0.Checkpoint; let cp0aHex: CheckpointHex, cp0bHex: CheckpointHex, cp1Hex: CheckpointHex, cp2Hex: CheckpointHex; @@ -135,7 +135,7 @@ describe("PersistentCheckpointStateCache", function () { expect((await cache.getOrReloadLatest(cp0bHex.rootHex, cp0b.epoch - 1))?.serialize()).toBeUndefined(); }); - it("pruneFinalized and getStateOrBytes", async function () { + it("pruneFinalized and getStateOrBytes", async () => { cache.add(cp2, states["cp2"]); expect(((await cache.getStateOrBytes(cp0bHex)) as CachedBeaconStateAllForks).hashTreeRoot()).toEqual( states["cp0b"].hashTreeRoot() @@ -182,7 +182,7 @@ describe("PersistentCheckpointStateCache", function () { // |0b--------root1--------root2 // | // 0a - it("single state at lowest memory epoch", async function () { + it("single state at lowest memory epoch", async () => { cache.add(cp2, states["cp2"]); expect(await cache.processState(toHexString(cp2.root), states["cp2"])).toEqual(1); expect(cache.findSeedStateToReload(cp0aHex)?.hashTreeRoot()).toEqual(states["cp1"].hashTreeRoot()); @@ -198,7 +198,7 @@ describe("PersistentCheckpointStateCache", function () { // 0a------------------------------root3 // ^ ^ // cp1a={0a, 21} {0a, 22}=cp2a - it("multiple states at lowest memory epoch", async function () { + it("multiple states at lowest memory epoch", async () => { cache.add(cp2, states["cp2"]); expect(await cache.processState(toHexString(cp2.root), states["cp2"])).toEqual(1); @@ -259,7 +259,7 @@ describe("PersistentCheckpointStateCache", function () { // |0b--------root1--------root2-----root3 // | // 0a - it("no reorg", async function () { + it("no reorg", async () => { expect(fileApisBuffer.size).toEqual(0); cache.add(cp2, states["cp2"]); expect(await cache.processState(toHexString(cp2.root), states["cp2"])).toEqual(1); @@ -293,7 +293,7 @@ describe("PersistentCheckpointStateCache", function () { // |0b--------root1--------root2-root3 | // | | // 0a |---------root4 - it("reorg in same epoch", async function () { + it("reorg in same epoch", async () => { // mostly the same to the above test expect(fileApisBuffer.size).toEqual(0); cache.add(cp2, states["cp2"]); @@ -338,7 +338,7 @@ describe("PersistentCheckpointStateCache", function () { // 1a ^ // | // {1a, 22}=cp2a - it("reorg 1 epoch", async function () { + it("reorg 1 epoch", async () => { // process root2 state cache.add(cp2, states["cp2"]); expect(await cache.processState(toHexString(cp2.root), states["cp2"])).toEqual(1); @@ -382,7 +382,7 @@ describe("PersistentCheckpointStateCache", function () { // 0a ^ ^ // | | // cp1a={0a, 21} {0a, 22}=cp2a - it("reorg 2 epochs", async function () { + it("reorg 2 epochs", async () => { // process root2 state cache.add(cp2, states["cp2"]); expect(await cache.processState(toHexString(cp2.root), states["cp2"])).toEqual(1); @@ -435,7 +435,7 @@ describe("PersistentCheckpointStateCache", function () { // ^ ^ // | | // cp1a={0a, 21} {0a, 22}=cp2a - it("reorg 3 epochs, persist cp 0a", async function () { + it("reorg 3 epochs, persist cp 0a", async () => { // process root2 state cache.add(cp2, states["cp2"]); expect(await cache.processState(toHexString(cp2.root), states["cp2"])).toEqual(1); @@ -491,7 +491,7 @@ describe("PersistentCheckpointStateCache", function () { // 0a ^ ^ // | | // cp1b={0b, 21} {0b, 22}=cp2b - it("reorg 3 epochs, prune but no persist", async function () { + it("reorg 3 epochs, prune but no persist", async () => { // process root2 state cache.add(cp2, states["cp2"]); expect(await cache.processState(toHexString(cp2.root), states["cp2"])).toEqual(1); diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts index 9aa7c29c7825..4ba65270e17a 100644 --- a/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts @@ -40,17 +40,15 @@ describe("getShufflingForAttestationVerification", () => { forkchoiceStub.getDependentRoot.mockImplementationOnce((block, epochDiff) => { if (block === attHeadBlock && epochDiff === EpochDifference.previous) { return previousDependentRoot; - } else { - throw new Error("Unexpected input"); } + throw new Error("Unexpected input"); }); const expectedShuffling = {epoch: attEpoch} as EpochShuffling; shufflingCacheStub.get.mockImplementationOnce((epoch, root) => { if (epoch === attEpoch && root === previousDependentRoot) { return Promise.resolve(expectedShuffling); - } else { - return Promise.resolve(null); } + return Promise.resolve(null); }); const resultShuffling = await getShufflingForAttestationVerification( chain, @@ -72,17 +70,15 @@ describe("getShufflingForAttestationVerification", () => { forkchoiceStub.getDependentRoot.mockImplementationOnce((block, epochDiff) => { if (block === attHeadBlock && epochDiff === EpochDifference.current) { return currentDependentRoot; - } else { - throw new Error("Unexpected input"); } + throw new Error("Unexpected input"); }); const expectedShuffling = {epoch: attEpoch} as EpochShuffling; shufflingCacheStub.get.mockImplementationOnce((epoch, root) => { if (epoch === attEpoch && root === currentDependentRoot) { return Promise.resolve(expectedShuffling); - } else { - return Promise.resolve(null); } + return Promise.resolve(null); }); const resultShuffling = await getShufflingForAttestationVerification( chain, @@ -107,12 +103,10 @@ describe("getShufflingForAttestationVerification", () => { if (callCount === 0) { callCount++; return Promise.resolve(null); - } else { - return Promise.resolve(expectedShuffling); } - } else { - return Promise.resolve(null); + return Promise.resolve(expectedShuffling); } + return Promise.resolve(null); }); chain.regenStateForAttestationVerification.mockImplementationOnce(() => Promise.resolve(expectedShuffling)); diff --git a/packages/beacon-node/test/unit/chain/validation/block.test.ts b/packages/beacon-node/test/unit/chain/validation/block.test.ts index 28375f1625e1..f8a2b7245ef7 100644 --- a/packages/beacon-node/test/unit/chain/validation/block.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/block.test.ts @@ -12,7 +12,7 @@ import {EMPTY_SIGNATURE, ZERO_HASH} from "../../../../src/constants/index.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {generateCachedState} from "../../../utils/state.js"; -describe("gossip block validation", function () { +describe("gossip block validation", () => { let chain: MockedBeaconChain; let forkChoice: MockedBeaconChain["forkChoice"]; let regen: Mocked; @@ -25,7 +25,7 @@ describe("gossip block validation", function () { const signature = EMPTY_SIGNATURE; const maxSkipSlots = 10; - beforeEach(function () { + beforeEach(() => { chain = getMockedBeaconChain(); vi.spyOn(chain.clock, "currentSlotWithGossipDisparity", "get").mockReturnValue(clockSlot); forkChoice = chain.forkChoice; @@ -49,7 +49,7 @@ describe("gossip block validation", function () { job = {signature, message: block}; }); - it("FUTURE_SLOT", async function () { + it("FUTURE_SLOT", async () => { // Set the block slot to after the current clock const signedBlock = {signature, message: {...block, slot: clockSlot + 1}}; @@ -59,7 +59,7 @@ describe("gossip block validation", function () { ); }); - it("WOULD_REVERT_FINALIZED_SLOT", async function () { + it("WOULD_REVERT_FINALIZED_SLOT", async () => { // Set finalized epoch to be greater than block's epoch forkChoice.getFinalizedCheckpoint.mockReturnValue({epoch: Infinity, root: ZERO_HASH, rootHex: ""}); @@ -69,7 +69,7 @@ describe("gossip block validation", function () { ); }); - it("ALREADY_KNOWN", async function () { + it("ALREADY_KNOWN", async () => { // Make the fork choice return a block summary for the proposed block forkChoice.getBlockHex.mockReturnValue({} as ProtoBlock); @@ -79,7 +79,7 @@ describe("gossip block validation", function () { ); }); - it("REPEAT_PROPOSAL", async function () { + it("REPEAT_PROPOSAL", async () => { // Register the proposer as known chain.seenBlockProposers.add(job.message.slot, job.message.proposerIndex); @@ -89,7 +89,7 @@ describe("gossip block validation", function () { ); }); - it("PARENT_UNKNOWN (fork-choice)", async function () { + it("PARENT_UNKNOWN (fork-choice)", async () => { // Return not known for proposed block forkChoice.getBlockHex.mockReturnValueOnce(null); // Return not known for parent block too @@ -101,7 +101,7 @@ describe("gossip block validation", function () { ); }); - it("TOO_MANY_SKIPPED_SLOTS", async function () { + it("TOO_MANY_SKIPPED_SLOTS", async () => { // Return not known for proposed block forkChoice.getBlockHex.mockReturnValueOnce(null); // Return parent block with 1 slot way back than maxSkipSlots @@ -113,7 +113,7 @@ describe("gossip block validation", function () { ); }); - it("NOT_LATER_THAN_PARENT", async function () { + it("NOT_LATER_THAN_PARENT", async () => { // Return not known for proposed block forkChoice.getBlockHex.mockReturnValueOnce(null); // Returned parent block is latter than proposed block @@ -125,7 +125,7 @@ describe("gossip block validation", function () { ); }); - it("PARENT_UNKNOWN (regen)", async function () { + it("PARENT_UNKNOWN (regen)", async () => { // Return not known for proposed block forkChoice.getBlockHex.mockReturnValueOnce(null); // Returned parent block is latter than proposed block @@ -139,7 +139,7 @@ describe("gossip block validation", function () { ); }); - it("PROPOSAL_SIGNATURE_INVALID", async function () { + it("PROPOSAL_SIGNATURE_INVALID", async () => { // Return not known for proposed block forkChoice.getBlockHex.mockReturnValueOnce(null); // Returned parent block is latter than proposed block @@ -155,7 +155,7 @@ describe("gossip block validation", function () { ); }); - it("INCORRECT_PROPOSER", async function () { + it("INCORRECT_PROPOSER", async () => { // Return not known for proposed block forkChoice.getBlockHex.mockReturnValueOnce(null); // Returned parent block is latter than proposed block @@ -174,7 +174,7 @@ describe("gossip block validation", function () { ); }); - it("valid", async function () { + it("valid", async () => { // Return not known for proposed block forkChoice.getBlockHex.mockReturnValueOnce(null); // Returned parent block is latter than proposed block diff --git a/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts b/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts index 76eb18fc38eb..cbd231c926ce 100644 --- a/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts @@ -8,7 +8,7 @@ import {LightClientErrorCode} from "../../../../src/chain/errors/lightClientErro import {IBeaconChain} from "../../../../src/chain/index.js"; import {getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; -describe("Light Client Finality Update validation", function () { +describe("Light Client Finality Update validation", () => { const afterEachCallbacks: (() => Promise | void)[] = []; const config = createChainForkConfig({ ...defaultChainConfig, diff --git a/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts b/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts index 7e35f1272ad6..7665b4f89179 100644 --- a/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts @@ -8,7 +8,7 @@ import {LightClientErrorCode} from "../../../../src/chain/errors/lightClientErro import {IBeaconChain} from "../../../../src/chain/index.js"; import {getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; -describe("Light Client Optimistic Update validation", function () { +describe("Light Client Optimistic Update validation", () => { const afterEachCallbacks: (() => Promise | void)[] = []; const config = createChainForkConfig({ ...defaultChainConfig, diff --git a/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts b/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts index 26571ab19a77..cbffc2a4ffd9 100644 --- a/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts @@ -12,7 +12,7 @@ import {SeenSyncCommitteeMessages} from "../../../../src/chain/seenCache/index.j import {ZERO_HASH} from "../../../../src/constants/constants.js"; // https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/altair/p2p-interface.md -describe("Sync Committee Signature validation", function () { +describe("Sync Committee Signature validation", () => { let chain: MockedBeaconChain; let clockStub: MockedBeaconChain["clock"]; let forkchoiceStub: MockedBeaconChain["forkChoice"]; @@ -24,16 +24,16 @@ describe("Sync Committee Signature validation", function () { // all validators have same pubkey const validatorIndexInSyncCommittee = 15; - beforeAll(async function () { + beforeAll(async () => { altairForkEpochBk = config.ALTAIR_FORK_EPOCH; config.ALTAIR_FORK_EPOCH = altairForkEpoch; }); - afterAll(function () { + afterAll(() => { config.ALTAIR_FORK_EPOCH = altairForkEpochBk; }); - beforeEach(function () { + beforeEach(() => { chain = getMockedBeaconChain(); ( chain as { @@ -45,11 +45,11 @@ describe("Sync Committee Signature validation", function () { vi.spyOn(clockStub, "isCurrentSlotGivenGossipDisparity").mockReturnValue(true); }); - afterEach(function () { + afterEach(() => { vi.clearAllMocks(); }); - it("should throw error - the signature's slot is in the past", async function () { + it("should throw error - the signature's slot is in the past", async () => { (clockStub.isCurrentSlotGivenGossipDisparity as Mock).mockReturnValue(false); vi.spyOn(clockStub, "currentSlot", "get").mockReturnValue(100); @@ -60,7 +60,7 @@ describe("Sync Committee Signature validation", function () { ); }); - it("should throw error - messageRoot is same to prevRoot", async function () { + it("should throw error - messageRoot is same to prevRoot", async () => { const syncCommittee = getSyncCommitteeSignature(currentSlot, validatorIndexInSyncCommittee); const headState = generateCachedAltairState({slot: currentSlot}, altairForkEpoch); chain.getHeadState.mockReturnValue(headState); @@ -71,7 +71,7 @@ describe("Sync Committee Signature validation", function () { ); }); - it("should throw error - messageRoot is different to prevRoot but not forkchoice head", async function () { + it("should throw error - messageRoot is different to prevRoot but not forkchoice head", async () => { const syncCommittee = getSyncCommitteeSignature(currentSlot, validatorIndexInSyncCommittee); const headState = generateCachedAltairState({slot: currentSlot}, altairForkEpoch); chain.getHeadState.mockReturnValue(headState); @@ -84,7 +84,7 @@ describe("Sync Committee Signature validation", function () { ); }); - it("should throw error - the validator is not part of the current sync committee", async function () { + it("should throw error - the validator is not part of the current sync committee", async () => { const syncCommittee = getSyncCommitteeSignature(currentSlot, 100); const headState = generateCachedAltairState({slot: currentSlot}, altairForkEpoch); chain.getHeadState.mockReturnValue(headState); @@ -99,7 +99,7 @@ describe("Sync Committee Signature validation", function () { * Skip this spec check: [REJECT] The subnet_id is correct, i.e. subnet_id in compute_subnets_for_sync_committee(state, sync_committee_signature.validator_index) * because it's the same to VALIDATOR_NOT_IN_SYNC_COMMITTEE */ - it.skip("should throw error - incorrect subnet", async function () { + it.skip("should throw error - incorrect subnet", async () => { const syncCommittee = getSyncCommitteeSignature(currentSlot, 1); const headState = generateCachedAltairState({slot: currentSlot}, altairForkEpoch); chain.getHeadState.mockReturnValue(headState); @@ -109,7 +109,7 @@ describe("Sync Committee Signature validation", function () { ); }); - it("should throw error - invalid signature", async function () { + it("should throw error - invalid signature", async () => { const syncCommittee = getSyncCommitteeSignature(currentSlot, validatorIndexInSyncCommittee); const headState = generateCachedAltairState({slot: currentSlot}, altairForkEpoch); @@ -121,7 +121,7 @@ describe("Sync Committee Signature validation", function () { ); }); - it("should pass, no prev root", async function () { + it("should pass, no prev root", async () => { const syncCommittee = getSyncCommitteeSignature(currentSlot, validatorIndexInSyncCommittee); const subnet = 3; const {slot, validatorIndex} = syncCommittee; @@ -142,7 +142,7 @@ describe("Sync Committee Signature validation", function () { ); }); - it("should pass, there is prev root but message root is forkchoice head", async function () { + it("should pass, there is prev root but message root is forkchoice head", async () => { const syncCommittee = getSyncCommitteeSignature(currentSlot, validatorIndexInSyncCommittee); const headState = generateCachedAltairState({slot: currentSlot}, altairForkEpoch); diff --git a/packages/beacon-node/test/unit/db/api/repositories/blockArchive.test.ts b/packages/beacon-node/test/unit/db/api/repositories/blockArchive.test.ts index 532016242f95..b87e9b926fdd 100644 --- a/packages/beacon-node/test/unit/db/api/repositories/blockArchive.test.ts +++ b/packages/beacon-node/test/unit/db/api/repositories/blockArchive.test.ts @@ -9,21 +9,21 @@ import {BlockArchiveRepository} from "../../../../../src/db/repositories/index.j import {testLogger} from "../../../../utils/logger.js"; import {Bucket} from "../../../../../src/db/buckets.js"; -describe("block archive repository", function () { +describe("block archive repository", () => { const testDir = "./.tmp"; let blockArchive: BlockArchiveRepository; let db: LevelDbController; - beforeEach(async function () { + beforeEach(async () => { db = await LevelDbController.create({name: testDir}, {logger: testLogger()}); blockArchive = new BlockArchiveRepository(config, db); }); - afterEach(async function () { + afterEach(async () => { await db.close(); rimraf.sync(testDir); }); - it("should retrieve blocks in order", async function () { + it("should retrieve blocks in order", async () => { await blockArchive.batchPut( Array.from({length: 1001}, (_, i) => { const slot = i; @@ -106,7 +106,7 @@ describe("block archive repository", function () { } }); - it("should store indexes when adding single block", async function () { + it("should store indexes when adding single block", async () => { const spy = vi.spyOn(db, "put"); const block = ssz.phase0.SignedBeaconBlock.defaultValue(); await blockArchive.add(block); @@ -120,7 +120,7 @@ describe("block archive repository", function () { ); }); - it("should store indexes when block batch", async function () { + it("should store indexes when block batch", async () => { const spy = vi.spyOn(db, "put"); const blocks = [ssz.phase0.SignedBeaconBlock.defaultValue(), ssz.phase0.SignedBeaconBlock.defaultValue()]; await blockArchive.batchAdd(blocks); @@ -152,14 +152,14 @@ describe("block archive repository", function () { ); }); - it("should get slot by root", async function () { + it("should get slot by root", async () => { const block = ssz.phase0.SignedBeaconBlock.defaultValue(); await blockArchive.add(block); const slot = await blockArchive.getSlotByRoot(ssz.phase0.BeaconBlock.hashTreeRoot(block.message)); expect(slot).toBe(block.message.slot); }); - it("should get block by root", async function () { + it("should get block by root", async () => { const block = ssz.phase0.SignedBeaconBlock.defaultValue(); await blockArchive.add(block); const retrieved = await blockArchive.getByRoot(ssz.phase0.BeaconBlock.hashTreeRoot(block.message)); @@ -167,14 +167,14 @@ describe("block archive repository", function () { expect(ssz.phase0.SignedBeaconBlock.equals(retrieved, block)).toBe(true); }); - it("should get slot by parent root", async function () { + it("should get slot by parent root", async () => { const block = ssz.phase0.SignedBeaconBlock.defaultValue(); await blockArchive.add(block); const slot = await blockArchive.getSlotByParentRoot(block.message.parentRoot); expect(slot).toBe(block.message.slot); }); - it("should get block by parent root", async function () { + it("should get block by parent root", async () => { const block = ssz.phase0.SignedBeaconBlock.defaultValue(); await blockArchive.add(block); const retrieved = await blockArchive.getByParentRoot(block.message.parentRoot); diff --git a/packages/beacon-node/test/unit/db/api/repository.test.ts b/packages/beacon-node/test/unit/db/api/repository.test.ts index 28065c84c7ea..3b2840b3f0be 100644 --- a/packages/beacon-node/test/unit/db/api/repository.test.ts +++ b/packages/beacon-node/test/unit/db/api/repository.test.ts @@ -41,10 +41,10 @@ class TestRepository extends Repository { } } -describe("database repository", function () { +describe("database repository", () => { let repository: TestRepository, controller: MockedObject; - beforeEach(function () { + beforeEach(() => { controller = vi.mocked(new LevelDbController({} as any, {} as any, {} as any)); repository = new TestRepository(controller as unknown as LevelDbController); }); @@ -53,7 +53,7 @@ describe("database repository", function () { vi.clearAllMocks(); }); - it("should get single item", async function () { + it("should get single item", async () => { const item = {bool: true, bytes: Buffer.alloc(32)}; controller.get.mockResolvedValue(TestSSZType.serialize(item) as Buffer); const result = await repository.get("id"); @@ -61,14 +61,14 @@ describe("database repository", function () { expect(controller.get).toHaveBeenCalledTimes(1); }); - it("should return null if item not found", async function () { + it("should return null if item not found", async () => { controller.get.mockResolvedValue(null); const result = await repository.get("id"); expect(result).toEqual(null); expect(controller.get).toHaveBeenCalledTimes(1); }); - it("should return true if item exists", async function () { + it("should return true if item exists", async () => { const item = {bool: true, bytes: Buffer.alloc(32)}; controller.get.mockResolvedValue(TestSSZType.serialize(item) as Buffer); const result = await repository.has("id"); @@ -76,31 +76,31 @@ describe("database repository", function () { expect(controller.get).toHaveBeenCalledTimes(1); }); - it("should return false if item doesnt exists", async function () { + it("should return false if item doesnt exists", async () => { controller.get.mockResolvedValue(null); const result = await repository.has("id"); expect(result).toBe(false); expect(controller.get).toHaveBeenCalledTimes(1); }); - it("should store with hashTreeRoot as id", async function () { + it("should store with hashTreeRoot as id", async () => { const item = {bool: true, bytes: Buffer.alloc(32)}; await expect(repository.add(item)).resolves.toBeUndefined(); expect(controller.put).toHaveBeenCalledTimes(1); }); - it("should store with given id", async function () { + it("should store with given id", async () => { const item = {bool: true, bytes: Buffer.alloc(32)}; await expect(repository.put("1", item)).resolves.toBeUndefined(); expect(controller.put).toHaveBeenCalledTimes(1); }); - it("should delete", async function () { + it("should delete", async () => { await expect(repository.delete("1")).resolves.toBeUndefined(); expect(controller.delete).toHaveBeenCalledTimes(1); }); - it("should return all items", async function () { + it("should return all items", async () => { const item = {bool: true, bytes: Buffer.alloc(32)}; const itemSerialized = TestSSZType.serialize(item); const items = [itemSerialized, itemSerialized, itemSerialized]; @@ -110,24 +110,24 @@ describe("database repository", function () { expect(controller.values).toHaveBeenCalledTimes(1); }); - it("should return range of items", async function () { + it("should return range of items", async () => { await repository.values({gt: "a", lt: "b"}); expect(controller.values).toHaveBeenCalledTimes(1); }); - it("should delete given items", async function () { + it("should delete given items", async () => { await repository.batchDelete(["1", "2", "3"]); expect(controller.batchDelete.mock.calls[0][0]).toHaveLength(3); }); - it("should delete given items by value", async function () { + it("should delete given items by value", async () => { const item = {bool: true, bytes: Buffer.alloc(32)}; await repository.batchRemove([item, item]); expect(controller.batchDelete.mock.calls[0][0]).toHaveLength(2); }); - it("should add multiple values", async function () { + it("should add multiple values", async () => { await repository.batchAdd([ {bool: true, bytes: Buffer.alloc(32)}, {bool: false, bytes: Buffer.alloc(32)}, @@ -136,7 +136,7 @@ describe("database repository", function () { expect(controller.batchPut.mock.calls[0][0]).toHaveLength(2); }); - it("should fetch values stream", async function () { + it("should fetch values stream", async () => { async function* sample(): AsyncGenerator { yield TestSSZType.serialize({bool: true, bytes: Buffer.alloc(32)}) as Buffer; yield TestSSZType.serialize({bool: false, bytes: Buffer.alloc(32)}) as Buffer; diff --git a/packages/beacon-node/test/unit/db/buckets.test.ts b/packages/beacon-node/test/unit/db/buckets.test.ts index 0fb09af95cbc..c7c11d831427 100644 --- a/packages/beacon-node/test/unit/db/buckets.test.ts +++ b/packages/beacon-node/test/unit/db/buckets.test.ts @@ -6,7 +6,7 @@ describe("db buckets", () => { let prevBucket = -1; for (const key of Object.keys(Bucket)) { - if (isNaN(parseInt(key))) { + if (Number.isNaN(parseInt(key))) { const bucket = (Bucket as unknown as Record)[key]; if (bucket < prevBucket) { throw Error(`Bucket ${key} not sorted`); diff --git a/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts b/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts index d0bd3faffcf8..40988ed21728 100644 --- a/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts +++ b/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts @@ -8,7 +8,7 @@ import {defaultEth1Options} from "../../../src/eth1/options.js"; import {BeaconDb} from "../../../src/db/beacon.js"; import {getMockedBeaconDb} from "../../mocks/mockedBeaconDb.js"; -describe("Eth1DepositDataTracker", function () { +describe("Eth1DepositDataTracker", () => { const controller = new AbortController(); const logger = testLogger(); @@ -43,7 +43,7 @@ describe("Eth1DepositDataTracker", function () { vi.clearAllMocks(); }); - it("Should dynamically adjust blocks batch size", async function () { + it("Should dynamically adjust blocks batch size", async () => { let expectedSize = 1000; expect(eth1DepositDataTracker["eth1GetBlocksBatchSizeDynamic"]).toBe(expectedSize); @@ -66,7 +66,7 @@ describe("Eth1DepositDataTracker", function () { expect(expectedSize).toBe(1000); }); - it("Should dynamically adjust logs batch size", async function () { + it("Should dynamically adjust logs batch size", async () => { let expectedSize = 1000; expect(eth1DepositDataTracker["eth1GetLogsBatchSizeDynamic"]).toBe(expectedSize); diff --git a/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts b/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts index edf571b905b3..c7f4c8fb7aa4 100644 --- a/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts +++ b/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts @@ -16,9 +16,7 @@ describe("eth1 / Eth1MergeBlockTracker", () => { let controller: AbortController; beforeEach(() => { controller = new AbortController(); - }); - afterEach(() => controller.abort()); - beforeEach(() => { + config = { // Set time units to 0 to make the test as fast as possible SECONDS_PER_ETH1_BLOCK: 0, @@ -29,6 +27,8 @@ describe("eth1 / Eth1MergeBlockTracker", () => { } as Partial as ChainConfig; }); + afterEach(() => controller.abort()); + it("Should find terminal pow block through TERMINAL_BLOCK_HASH", async () => { config.TERMINAL_BLOCK_HASH = Buffer.alloc(32, 1); const block: EthJsonRpcBlockRaw = { @@ -115,9 +115,8 @@ describe("eth1 / Eth1MergeBlockTracker", () => { if (blockNumber === "latest") { if (latestBlockPointer >= blocks.length) { throw Error("Fetched too many blocks"); - } else { - return blocks[latestBlockPointer++]; } + return blocks[latestBlockPointer++]; } return blocks[blockNumber]; }, diff --git a/packages/beacon-node/test/unit/eth1/utils/depositContract.test.ts b/packages/beacon-node/test/unit/eth1/utils/depositContract.test.ts index e36fc865a75a..22ca95765a9a 100644 --- a/packages/beacon-node/test/unit/eth1/utils/depositContract.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/depositContract.test.ts @@ -2,7 +2,7 @@ import {describe, it, expect} from "vitest"; import {goerliTestnetLogs, goerliTestnetDepositEvents} from "../../../utils/testnet.js"; import {parseDepositLog} from "../../../../src/eth1/utils/depositContract.js"; -describe("eth1 / util / depositContract", function () { +describe("eth1 / util / depositContract", () => { it("Should parse a raw deposit log", () => { const depositEvents = goerliTestnetLogs.map((log) => parseDepositLog(log)); expect(depositEvents).toEqual(goerliTestnetDepositEvents); diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index 88d2796a12de..34334d1b3f8b 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -11,7 +11,7 @@ import {getDeposits, getDepositsWithProofs, DepositGetter} from "../../../../src import {DepositTree} from "../../../../src/db/repositories/depositDataRoot.js"; import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; -describe("eth1 / util / deposits", function () { +describe("eth1 / util / deposits", () => { describe("getDeposits", () => { type TestCase = { id: string; @@ -111,7 +111,7 @@ describe("eth1 / util / deposits", function () { for (const testCase of testCases) { const {id, depositIndexes, eth1DepositIndex, depositCount, expectedReturnedIndexes, error, postElectra} = testCase; - it(id, async function () { + it(id, async () => { const state = postElectra ? generateState({slot: postElectraSlot, eth1DepositIndex}, postElectraConfig) : generateState({eth1DepositIndex}); @@ -139,7 +139,7 @@ describe("eth1 / util / deposits", function () { }); describe("getDepositsWithProofs", () => { - it("return empty array if no pending deposits", function () { + it("return empty array if no pending deposits", () => { const initialValues = [Buffer.alloc(32)]; const depositRootTree = ssz.phase0.DepositDataRootList.toViewDU(initialValues); const depositCount = 0; @@ -149,7 +149,7 @@ describe("eth1 / util / deposits", function () { expect(deposits).toEqual([]); }); - it("return deposits with valid proofs", function () { + it("return deposits with valid proofs", () => { const depositEvents = Array.from( {length: 2}, (_, index): phase0.DepositEvent => ({ diff --git a/packages/beacon-node/test/unit/eth1/utils/eth1Data.test.ts b/packages/beacon-node/test/unit/eth1/utils/eth1Data.test.ts index 4b5bf74772b7..dff98500b293 100644 --- a/packages/beacon-node/test/unit/eth1/utils/eth1Data.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/eth1Data.test.ts @@ -12,7 +12,7 @@ import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {Eth1ErrorCode} from "../../../../src/eth1/errors.js"; import {DepositTree} from "../../../../src/db/repositories/depositDataRoot.js"; -describe("eth1 / util / getEth1DataForBlocks", function () { +describe("eth1 / util / getEth1DataForBlocks", () => { type TestCase = { id: string; blocks: Eth1Block[]; @@ -95,7 +95,7 @@ describe("eth1 / util / getEth1DataForBlocks", function () { for (const testCase of testCases) { const {id, blocks, deposits, depositRootTree, lastProcessedDepositBlockNumber, expectedEth1Data, error} = testCase(); - it(id, async function () { + it(id, async () => { const eth1DatasPromise = getEth1DataForBlocks( blocks, // Simulate a descending stream reading from DB @@ -117,7 +117,7 @@ describe("eth1 / util / getEth1DataForBlocks", function () { } }); -describe("eth1 / util / getDepositsByBlockNumber", function () { +describe("eth1 / util / getDepositsByBlockNumber", () => { type TestCase = { id: string; fromBlock: number; @@ -181,7 +181,7 @@ describe("eth1 / util / getDepositsByBlockNumber", function () { for (const testCase of testCases) { const {id, fromBlock, toBlock, deposits, expectedResult} = testCase(); - it(id, async function () { + it(id, async () => { const result = await getDepositsByBlockNumber( fromBlock, toBlock, // Simulate a descending stream reading from DB @@ -192,7 +192,7 @@ describe("eth1 / util / getDepositsByBlockNumber", function () { } }); -describe("eth1 / util / getDepositRootByDepositCount", function () { +describe("eth1 / util / getDepositRootByDepositCount", () => { type TestCase = { id: string; depositCounts: number[]; @@ -243,7 +243,7 @@ describe("eth1 / util / getDepositRootByDepositCount", function () { for (const testCase of testCases) { const {id, depositCounts, depositRootTree, expectedMap} = testCase(); - it(id, function () { + it(id, () => { const map = getDepositRootByDepositCount(depositCounts, depositRootTree); expect(renderDepositRootByDepositCount(map)).toEqual(renderDepositRootByDepositCount(expectedMap)); }); diff --git a/packages/beacon-node/test/unit/eth1/utils/eth1DepositEvent.test.ts b/packages/beacon-node/test/unit/eth1/utils/eth1DepositEvent.test.ts index 7538dc0acf63..ea504464778c 100644 --- a/packages/beacon-node/test/unit/eth1/utils/eth1DepositEvent.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/eth1DepositEvent.test.ts @@ -1,7 +1,7 @@ import {describe, it, expect} from "vitest"; import {assertConsecutiveDeposits} from "../../../../src/eth1/utils/eth1DepositEvent.js"; -describe("eth1 / util / assertConsecutiveDeposits", function () { +describe("eth1 / util / assertConsecutiveDeposits", () => { const testCases: { id: string; ok: boolean; diff --git a/packages/beacon-node/test/unit/eth1/utils/eth1Vote.test.ts b/packages/beacon-node/test/unit/eth1/utils/eth1Vote.test.ts index 0ad63e5e0d8f..e9a9ab5aad24 100644 --- a/packages/beacon-node/test/unit/eth1/utils/eth1Vote.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/eth1Vote.test.ts @@ -12,7 +12,7 @@ import { Eth1DataGetter, } from "../../../../src/eth1/utils/eth1Vote.js"; -describe("eth1 / util / eth1Vote", function () { +describe("eth1 / util / eth1Vote", () => { function generateEth1Vote(i: number): phase0.Eth1Data { return { blockHash: Buffer.alloc(32, i), @@ -21,7 +21,7 @@ describe("eth1 / util / eth1Vote", function () { }; } - describe("pickEth1Vote", function () { + describe("pickEth1Vote", () => { // Function array to scope votes in each test case defintion const testCases: (() => { id: string; @@ -82,7 +82,7 @@ describe("eth1 / util / eth1Vote", function () { for (const testCase of testCases) { const {id, eth1DataVotesInState, votesToConsider, expectedEth1Vote} = testCase(); - it(id, async function () { + it(id, async () => { const state = generateState({slot: 5, eth1DataVotes: eth1DataVotesInState}); const eth1Vote = pickEth1Vote(state, votesToConsider); expect(ssz.phase0.Eth1Data.toJson(eth1Vote)).toEqual(ssz.phase0.Eth1Data.toJson(expectedEth1Vote)); @@ -90,7 +90,7 @@ describe("eth1 / util / eth1Vote", function () { } }); - describe("getEth1VotesToConsider", function () { + describe("getEth1VotesToConsider", () => { // Function array to scope votes in each test case defintion const testCases: (() => { id: string; @@ -127,7 +127,7 @@ describe("eth1 / util / eth1Vote", function () { for (const testCase of testCases) { const {id, state, eth1Datas, expectedVotesToConsider} = testCase(); - it(`get votesToConsider: ${id}`, async function () { + it(`get votesToConsider: ${id}`, async () => { const eth1DataGetter: Eth1DataGetter = async ({timestampRange}) => filterBy(eth1Datas, timestampRange, (eth1Data) => eth1Data.timestamp); diff --git a/packages/beacon-node/test/unit/eth1/utils/groupDepositEventsByBlock.test.ts b/packages/beacon-node/test/unit/eth1/utils/groupDepositEventsByBlock.test.ts index 5712d1095270..a4e786b3aa68 100644 --- a/packages/beacon-node/test/unit/eth1/utils/groupDepositEventsByBlock.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/groupDepositEventsByBlock.test.ts @@ -2,7 +2,7 @@ import {describe, it, expect} from "vitest"; import {phase0} from "@lodestar/types"; import {groupDepositEventsByBlock} from "../../../../src/eth1/utils/groupDepositEventsByBlock.js"; -describe("eth1 / util / groupDepositEventsByBlock", function () { +describe("eth1 / util / groupDepositEventsByBlock", () => { it("should return deposit events by block sorted by index", () => { const depositData = { amount: 0, diff --git a/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts b/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts index 0521823d1283..39c4a4d6e773 100644 --- a/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts @@ -2,7 +2,7 @@ import {describe, it, expect} from "vitest"; import {optimizeNextBlockDiffForGenesis} from "../../../../src/eth1/utils/optimizeNextBlockDiffForGenesis.js"; import {Eth1Block} from "../../../../src/eth1/interface.js"; -describe("eth1 / utils / optimizeNextBlockDiffForGenesis", function () { +describe("eth1 / utils / optimizeNextBlockDiffForGenesis", () => { it("should return optimized block diff to find genesis time", () => { const params = { MIN_GENESIS_TIME: 1578009600, @@ -29,9 +29,8 @@ describe("eth1 / utils / optimizeNextBlockDiffForGenesis", function () { if (lastFetchedBlock.timestamp > params.MIN_GENESIS_TIME - params.GENESIS_DELAY) { break; - } else { - diffRecord.push({number: lastFetchedBlock.blockNumber, blockDiff}); } + diffRecord.push({number: lastFetchedBlock.blockNumber, blockDiff}); } // Make sure the returned diffs converge to genesis time fast diff --git a/packages/beacon-node/test/unit/executionEngine/httpRetry.test.ts b/packages/beacon-node/test/unit/executionEngine/httpRetry.test.ts index b75dc8048283..b254fc9d8b45 100644 --- a/packages/beacon-node/test/unit/executionEngine/httpRetry.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/httpRetry.test.ts @@ -32,10 +32,10 @@ describe("ExecutionEngine / http ", () => { reqJsonRpcPayload = req.body; delete (reqJsonRpcPayload as {id?: number}).id; return returnValue; - } else { - --errorResponsesBeforeSuccess; - throw Error(`Will succeed after ${errorResponsesBeforeSuccess} more attempts`); } + + --errorResponsesBeforeSuccess; + throw Error(`Will succeed after ${errorResponsesBeforeSuccess} more attempts`); }); afterCallbacks.push(async () => { @@ -56,8 +56,8 @@ describe("ExecutionEngine / http ", () => { ); }); - describe("notifyForkchoiceUpdate", function () { - it("notifyForkchoiceUpdate no retry when no pay load attributes", async function () { + describe("notifyForkchoiceUpdate", () => { + it("notifyForkchoiceUpdate no retry when no pay load attributes", async () => { errorResponsesBeforeSuccess = 2; const forkChoiceHeadData = { headBlockHash: "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", @@ -85,7 +85,7 @@ describe("ExecutionEngine / http ", () => { expect(errorResponsesBeforeSuccess).toBe(1); }); - it("notifyForkchoiceUpdate with retry when pay load attributes", async function () { + it("notifyForkchoiceUpdate with retry when pay load attributes", async () => { errorResponsesBeforeSuccess = defaultExecutionEngineHttpOpts.retries - 1; const forkChoiceHeadData = { headBlockHash: "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", diff --git a/packages/beacon-node/test/unit/monitoring/remoteService.ts b/packages/beacon-node/test/unit/monitoring/remoteService.ts index bea50eee3bdd..d407adb9d175 100644 --- a/packages/beacon-node/test/unit/monitoring/remoteService.ts +++ b/packages/beacon-node/test/unit/monitoring/remoteService.ts @@ -22,7 +22,7 @@ export const remoteServiceError: RemoteServiceError = {status: "error", data: nu export async function startRemoteService(): Promise<{baseUrl: URL}> { const server = fastify(); - server.post(remoteServiceRoutes.success, {}, async function (request, reply) { + server.post(remoteServiceRoutes.success, {}, async (request, reply) => { if (Array.isArray(request.body)) { request.body.forEach(validateRequestData); } else { @@ -32,11 +32,9 @@ export async function startRemoteService(): Promise<{baseUrl: URL}> { return reply.status(200).send(); }); - server.post(remoteServiceRoutes.error, {}, async function (_request, reply) { - return reply.status(400).send(remoteServiceError); - }); + server.post(remoteServiceRoutes.error, {}, async (_request, reply) => reply.status(400).send(remoteServiceError)); - server.post(remoteServiceRoutes.pending, {}, function () { + server.post(remoteServiceRoutes.pending, {}, () => { // keep request pending until timeout is reached or aborted }); @@ -74,7 +72,7 @@ function validateRequestData(data: ReceivedData): void { } function validateClientStats(data: ReceivedData, schema: ClientStatsSchema): void { - schema.forEach((s) => { + for (const s of schema) { try { expect(data[s.key]).toBeInstanceOf(s.type); } catch (_e) { @@ -82,5 +80,5 @@ function validateClientStats(data: ReceivedData, schema: ClientStatsSchema): voi `Validation of property "${s.key}" failed. Expected type "${s.type}" but received "${typeof data[s.key]}".` ); } - }); + } } diff --git a/packages/beacon-node/test/unit/monitoring/service.test.ts b/packages/beacon-node/test/unit/monitoring/service.test.ts index 0795a165538e..fed64b9bc553 100644 --- a/packages/beacon-node/test/unit/monitoring/service.test.ts +++ b/packages/beacon-node/test/unit/monitoring/service.test.ts @@ -169,7 +169,7 @@ describe("monitoring / service", () => { service?.close(); }); - (["beacon", "validator"] as const).forEach((client) => { + for (const client of ["beacon", "validator"] as const) { it(`should collect and send ${client} stats to remote service`, async () => { const endpoint = `${baseUrl}${remoteServiceRoutes.success}`; service = new MonitoringService(client, {endpoint, collectSystemStats: true}, {register, logger}); @@ -181,7 +181,7 @@ describe("monitoring / service", () => { // Fail test if warning was logged due to a 500 response. expect(logger.warn).not.toHaveBeenCalledWith("Failed to send client stats"); }); - }); + } it("should properly handle remote service errors", async () => { const endpoint = `${baseUrl}${remoteServiceRoutes.error}`; diff --git a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts index dda4959c7b3e..2104235e7215 100644 --- a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts +++ b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts @@ -10,7 +10,7 @@ import {INetwork} from "../../../src/network/interface.js"; import {ZERO_HASH} from "../../../src/constants/constants.js"; describe("beaconBlocksMaybeBlobsByRange", () => { - beforeAll(async function () { + beforeAll(async () => { await initCKZG(); loadEthereumTrustedSetup(); }); diff --git a/packages/beacon-node/test/unit/network/gossip/topic.test.ts b/packages/beacon-node/test/unit/network/gossip/topic.test.ts index dbaa4002bfcc..2a61d8604439 100644 --- a/packages/beacon-node/test/unit/network/gossip/topic.test.ts +++ b/packages/beacon-node/test/unit/network/gossip/topic.test.ts @@ -4,7 +4,7 @@ import {GossipType, GossipEncoding, GossipTopicMap} from "../../../../src/networ import {parseGossipTopic, stringifyGossipTopic} from "../../../../src/network/gossip/topic.js"; import {config} from "../../../utils/config.js"; -describe("network / gossip / topic", function () { +describe("network / gossip / topic", () => { const encoding = GossipEncoding.ssz_snappy; // Enforce with Typescript that we test all GossipType diff --git a/packages/beacon-node/test/unit/network/metadata.test.ts b/packages/beacon-node/test/unit/network/metadata.test.ts index 12bd9b168425..50e4157a29cd 100644 --- a/packages/beacon-node/test/unit/network/metadata.test.ts +++ b/packages/beacon-node/test/unit/network/metadata.test.ts @@ -4,7 +4,7 @@ import {ssz} from "@lodestar/types"; import {getENRForkID} from "../../../src/network/metadata.js"; import {config} from "../../utils/config.js"; -describe("network / metadata / getENRForkID", function () { +describe("network / metadata / getENRForkID", () => { // At 0, next fork is altair const currentEpoch = 0; const enrForkID = getENRForkID(config, currentEpoch); diff --git a/packages/beacon-node/test/unit/network/peers/priorization.test.ts b/packages/beacon-node/test/unit/network/peers/priorization.test.ts index 5b318a9b007f..e72cc32ce28c 100644 --- a/packages/beacon-node/test/unit/network/peers/priorization.test.ts +++ b/packages/beacon-node/test/unit/network/peers/priorization.test.ts @@ -265,7 +265,7 @@ describe("network / peers / priorization", async () => { } }); -describe("sortPeersToPrune", async function () { +describe("sortPeersToPrune", async () => { const peers: PeerId[] = []; for (let i = 0; i < 8; i++) { const pk = await generateKeyPair("secp256k1"); diff --git a/packages/beacon-node/test/unit/network/peers/score.test.ts b/packages/beacon-node/test/unit/network/peers/score.test.ts index 54cb721a4c21..8962b282e0ad 100644 --- a/packages/beacon-node/test/unit/network/peers/score.test.ts +++ b/packages/beacon-node/test/unit/network/peers/score.test.ts @@ -19,7 +19,7 @@ vi.mock("../../../../src/network/peers/score/index.js", async (importActual) => }; }); -describe("simple block provider score tracking", function () { +describe("simple block provider score tracking", () => { const peer = peerIdFromString("Qma9T5YraSnpRDZqRR4krcSJabThc8nwZuJV3LercPHufi"); const MIN_SCORE = -100; const actionName = "test-action"; @@ -30,7 +30,7 @@ describe("simple block provider score tracking", function () { return {scoreStore, peerScores}; } - it("Should return default score, without any previous action", function () { + it("Should return default score, without any previous action", () => { const {scoreStore} = mockStore(); const score = scoreStore.getScore(peer); expect(score).toBe(0); @@ -69,7 +69,7 @@ describe("simple block provider score tracking", function () { expect(scoreStore.getScore(peer)).toBeGreaterThan(minScore); }); - it("should not go below min score", function () { + it("should not go below min score", () => { const {scoreStore} = mockStore(); scoreStore.applyAction(peer, PeerAction.Fatal, actionName); scoreStore.applyAction(peer, PeerAction.Fatal, actionName); @@ -77,7 +77,7 @@ describe("simple block provider score tracking", function () { }); }); -describe("updateGossipsubScores", function () { +describe("updateGossipsubScores", () => { let peerRpcScoresStub: PeerRpcScoreStore; beforeEach(() => { diff --git a/packages/beacon-node/test/unit/network/processorQueues.test.ts b/packages/beacon-node/test/unit/network/processorQueues.test.ts index 378d87ab7861..07a10591c0ad 100644 --- a/packages/beacon-node/test/unit/network/processorQueues.test.ts +++ b/packages/beacon-node/test/unit/network/processorQueues.test.ts @@ -21,10 +21,10 @@ async function validateTest(job: string, tracker: string[], opts: ValidateOpts): async function getStateFromCache(retrieveSync: boolean): Promise { if (retrieveSync) { return 1; - } else { - await sleep(0); - return 2; } + + await sleep(0); + return 2; } describe("event loop with branching async", () => { diff --git a/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts b/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts index cf9345172083..d279a5d759d7 100644 --- a/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts +++ b/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts @@ -35,7 +35,7 @@ describe("AttnetsService", () => { let clock: IClock; const logger = testLogger(); - beforeEach(function () { + beforeEach(() => { vi.useFakeTimers({now: Date.now()}); gossipStub = vi.mocked(new Eth2Gossipsub({} as any, {} as any)); vi.spyOn(gossipStub, "subscribeTopic").mockReturnValue(undefined); diff --git a/packages/beacon-node/test/unit/network/util.test.ts b/packages/beacon-node/test/unit/network/util.test.ts index 14c74930e521..70da41bd2c2a 100644 --- a/packages/beacon-node/test/unit/network/util.test.ts +++ b/packages/beacon-node/test/unit/network/util.test.ts @@ -4,7 +4,7 @@ import {ForkName} from "@lodestar/params"; import {getDiscv5Multiaddrs} from "../../../src/network/libp2p/index.js"; import {getCurrentAndNextFork} from "../../../src/network/forks.js"; -describe("getCurrentAndNextFork", function () { +describe("getCurrentAndNextFork", () => { const altairEpoch = config.forks.altair.epoch; afterEach(() => { config.forks.altair.epoch = altairEpoch; @@ -34,7 +34,7 @@ describe("getCurrentAndNextFork", function () { }); describe("getDiscv5Multiaddrs", () => { - it("should extract bootMultiaddrs from enr with tcp", async function () { + it("should extract bootMultiaddrs from enr with tcp", async () => { const enrWithTcp = [ "enr:-LK4QDiPGwNomqUqNDaM3iHYvtdX7M5qngson6Qb2xGIg1LwC8-Nic0aQwO0rVbJt5xp32sRE3S1YqvVrWO7OgVNv0kBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpA7CIeVAAAgCf__________gmlkgnY0gmlwhBKNA4qJc2VjcDI1NmsxoQKbBS4ROQ_sldJm5tMgi36qm5I5exKJFb4C8dDVS_otAoN0Y3CCIyiDdWRwgiMo", ]; @@ -45,7 +45,7 @@ describe("getDiscv5Multiaddrs", () => { ); }); - it("should not extract bootMultiaddrs from enr without tcp", async function () { + it("should not extract bootMultiaddrs from enr without tcp", async () => { const enrWithoutTcp = [ "enr:-Ku4QCFQW96tEDYPjtaueW3WIh1CB0cJnvw_ibx5qIFZGqfLLj-QajMX6XwVs2d4offuspwgH3NkIMpWtCjCytVdlywGh2F0dG5ldHOIEAIAAgABAUyEZXRoMpCi7FS9AQAAAAAiAQAAAAAAgmlkgnY0gmlwhFA4VK6Jc2VjcDI1NmsxoQNGH1sJJS86-0x9T7qQewz9Wn9zlp6bYxqqrR38JQ49yIN1ZHCCIyg", ]; diff --git a/packages/beacon-node/test/unit/sync/backfill/verify.test.ts b/packages/beacon-node/test/unit/sync/backfill/verify.test.ts index 3d1a2cd7e7e5..bba1f7c93f19 100644 --- a/packages/beacon-node/test/unit/sync/backfill/verify.test.ts +++ b/packages/beacon-node/test/unit/sync/backfill/verify.test.ts @@ -14,14 +14,14 @@ import {BackfillSyncErrorCode, BackfillSyncError} from "./../../../../src/sync/b // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules const __dirname = path.dirname(fileURLToPath(import.meta.url)); -describe("backfill sync - verify block sequence", function () { +describe("backfill sync - verify block sequence", () => { //mainnet validators root const beaconConfig = createBeaconConfig( config, ssz.Root.fromJson("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95") ); - it("should verify valid chain of blocks", function () { + it("should verify valid chain of blocks", () => { const blocks = getBlocks(); expect(() => @@ -29,14 +29,14 @@ describe("backfill sync - verify block sequence", function () { ).not.toThrow(); }); - it("should fail with sequence not anchored", function () { + it("should fail with sequence not anchored", () => { const blocks = getBlocks(); const wrongAncorRoot = ssz.Root.defaultValue(); expect(() => verifyBlockSequence(beaconConfig, blocks, wrongAncorRoot)).toThrow(BackfillSyncErrorCode.NOT_ANCHORED); }); - it("should fail with sequence not linear", function () { + it("should fail with sequence not linear", () => { const blocks = getBlocks(); expect(() => { const {error} = verifyBlockSequence( diff --git a/packages/beacon-node/test/unit/sync/unknownBlock.test.ts b/packages/beacon-node/test/unit/sync/unknownBlock.test.ts index 4805bd123898..0694cb97f4ab 100644 --- a/packages/beacon-node/test/unit/sync/unknownBlock.test.ts +++ b/packages/beacon-node/test/unit/sync/unknownBlock.test.ts @@ -239,7 +239,7 @@ describe("sync by UnknownBlockSync", () => { } }); -describe("UnknownBlockSync", function () { +describe("UnknownBlockSync", () => { let network: INetwork; let chain: MockedBeaconChain; const logger = testLogger(); diff --git a/packages/beacon-node/test/unit/util/array.test.ts b/packages/beacon-node/test/unit/util/array.test.ts index d505d27c2e9f..75d3a1b0856d 100644 --- a/packages/beacon-node/test/unit/util/array.test.ts +++ b/packages/beacon-node/test/unit/util/array.test.ts @@ -3,13 +3,13 @@ import {findLastIndex, LinkedList} from "../../../src/util/array.js"; describe("findLastIndex", () => { it("should return the last index that matches a predicate", () => { - expect(findLastIndex([1, 2, 3, 4], (n) => n % 2 == 0)).toEqual(3); - expect(findLastIndex([1, 2, 3, 4, 5], (n) => n % 2 == 0)).toEqual(3); + expect(findLastIndex([1, 2, 3, 4], (n) => n % 2 === 0)).toEqual(3); + expect(findLastIndex([1, 2, 3, 4, 5], (n) => n % 2 === 0)).toEqual(3); expect(findLastIndex([1, 2, 3, 4, 5], () => true)).toEqual(4); }); it("should return -1 if there are no matches", () => { - expect(findLastIndex([1, 3, 5], (n) => n % 2 == 0)).toEqual(-1); + expect(findLastIndex([1, 3, 5], (n) => n % 2 === 0)).toEqual(-1); expect(findLastIndex([1, 2, 3, 4, 5], () => false)).toEqual(-1); }); }); diff --git a/packages/beacon-node/test/unit/util/clock.test.ts b/packages/beacon-node/test/unit/util/clock.test.ts index ff224c1b378a..87955b98182c 100644 --- a/packages/beacon-node/test/unit/util/clock.test.ts +++ b/packages/beacon-node/test/unit/util/clock.test.ts @@ -4,7 +4,7 @@ import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {Clock, ClockEvent} from "../../../src/util/clock.js"; import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../../../src/constants/index.js"; -describe("Clock", function () { +describe("Clock", () => { let abortController: AbortController; let clock: Clock; @@ -26,7 +26,7 @@ describe("Clock", function () { }); // TODO: Debug why this test is fragile after migrating to vitest - it.skip("Should notify on new slot", function () { + it.skip("Should notify on new slot", () => { const spy = vi.fn(); clock.on(ClockEvent.slot, spy); vi.advanceTimersByTime(config.SECONDS_PER_SLOT * 1000); @@ -34,7 +34,7 @@ describe("Clock", function () { expect(spy).toBeCalledWith(clock.currentSlot); }); - it("Should notify on new epoch", function () { + it("Should notify on new epoch", () => { const spy = vi.fn(); clock.on(ClockEvent.epoch, spy); vi.advanceTimersByTime(SLOTS_PER_EPOCH * config.SECONDS_PER_SLOT * 1000); diff --git a/packages/beacon-node/test/unit/util/dependentRoot.test.ts b/packages/beacon-node/test/unit/util/dependentRoot.test.ts index e7923f111d0b..c8044f332e34 100644 --- a/packages/beacon-node/test/unit/util/dependentRoot.test.ts +++ b/packages/beacon-node/test/unit/util/dependentRoot.test.ts @@ -26,9 +26,8 @@ describe("util / getShufflingDependentRoot", () => { forkchoiceStub.getDependentRoot.mockImplementation((block, epochDiff) => { if (block === headBattHeadBlock && epochDiff === EpochDifference.previous) { return "current"; - } else { - throw new Error("should not be called"); } + throw new Error("should not be called"); }); expect(getShufflingDependentRoot(forkchoiceStub, attEpoch, blockEpoch, headBattHeadBlock)).toEqual("current"); }); @@ -39,9 +38,8 @@ describe("util / getShufflingDependentRoot", () => { forkchoiceStub.getDependentRoot.mockImplementation((block, epochDiff) => { if (block === headBattHeadBlock && epochDiff === EpochDifference.current) { return "0x000"; - } else { - throw new Error("should not be called"); } + throw new Error("should not be called"); }); expect(getShufflingDependentRoot(forkchoiceStub, attEpoch, blockEpoch, headBattHeadBlock)).toEqual("0x000"); }); diff --git a/packages/beacon-node/test/unit/util/file.test.ts b/packages/beacon-node/test/unit/util/file.test.ts index 9e519ac01681..6040e14b4263 100644 --- a/packages/beacon-node/test/unit/util/file.test.ts +++ b/packages/beacon-node/test/unit/util/file.test.ts @@ -3,10 +3,10 @@ import path from "node:path"; import {describe, it, expect, beforeAll, afterAll} from "vitest"; import {ensureDir, writeIfNotExist} from "../../../src/util/file.js"; -describe("file util", function () { +describe("file util", () => { const dirPath = path.join(".", "keys/toml/test_config.toml"); - describe("ensureDir", function () { + describe("ensureDir", () => { it("create dir if not exists", async () => { // ${dirPath} should not exist expect(fs.existsSync(dirPath)).toBe(false); @@ -17,7 +17,7 @@ describe("file util", function () { }); }); - describe("writeIfNotExist", function () { + describe("writeIfNotExist", () => { const filePath = path.join(dirPath, "test.txt"); const data = new Uint8Array([0, 1, 2]); beforeAll(async () => { diff --git a/packages/beacon-node/test/unit/util/kzg.test.ts b/packages/beacon-node/test/unit/util/kzg.test.ts index 13cea96d87a6..3b1de419ae93 100644 --- a/packages/beacon-node/test/unit/util/kzg.test.ts +++ b/packages/beacon-node/test/unit/util/kzg.test.ts @@ -16,7 +16,7 @@ describe("C-KZG", () => { } }); - beforeAll(async function () { + beforeAll(async () => { await initCKZG(); loadEthereumTrustedSetup(); }); @@ -63,14 +63,14 @@ describe("C-KZG", () => { // Full validation validateBlobSidecars(slot, blockRoot, kzgCommitments, blobSidecars); - blobSidecars.forEach(async (blobSidecar) => { + for (const blobSidecar of blobSidecars) { try { await validateGossipBlobSidecar(chain, blobSidecar, blobSidecar.index); } catch (_e) { // We expect some error from here // console.log(error); } - }); + } }); }); diff --git a/packages/beacon-node/test/unit/util/wrapError.test.ts b/packages/beacon-node/test/unit/util/wrapError.test.ts index 19bff7321e3c..2a8e5ca15ceb 100644 --- a/packages/beacon-node/test/unit/util/wrapError.test.ts +++ b/packages/beacon-node/test/unit/util/wrapError.test.ts @@ -5,13 +5,15 @@ describe("util / wrapError", () => { const error = Error("test-error"); async function throwNoAwait(shouldThrow: boolean): Promise { if (shouldThrow) throw error; - else return true; + + return true; } async function throwAwait(shouldThrow: boolean): Promise { await new Promise((r) => setTimeout(r, 0)); if (shouldThrow) throw error; - else return true; + + return true; } it("Handle error and result with throwNoAwait", async () => { diff --git a/packages/beacon-node/test/utils/cache.ts b/packages/beacon-node/test/utils/cache.ts index 9d5d3566c99d..2fd15427c659 100644 --- a/packages/beacon-node/test/utils/cache.ts +++ b/packages/beacon-node/test/utils/cache.ts @@ -3,7 +3,7 @@ import {toHexString} from "@chainsafe/ssz"; export function memoOnce(fn: () => R): () => R { let value: R | null = null; - return function () { + return () => { if (value === null) { value = fn(); } diff --git a/packages/beacon-node/test/utils/errors.ts b/packages/beacon-node/test/utils/errors.ts index c3d293e83c78..1bf31a2ce9af 100644 --- a/packages/beacon-node/test/utils/errors.ts +++ b/packages/beacon-node/test/utils/errors.ts @@ -53,9 +53,11 @@ export function expectLodestarError(err1: LodestarErro export function getErrorMetadata(err: LodestarError | Error | unknown): unknown { if (err instanceof LodestarError) { return mapValues(err.getMetadata(), (value) => getErrorMetadata(value as any)); - } else if (err instanceof Error) { + } + + if (err instanceof Error) { return err.message; - } else { - return err; } + + return err; } diff --git a/packages/beacon-node/test/utils/runEl.ts b/packages/beacon-node/test/utils/runEl.ts index f7a2b2f52e58..8a2da7104510 100644 --- a/packages/beacon-node/test/utils/runEl.ts +++ b/packages/beacon-node/test/utils/runEl.ts @@ -196,7 +196,7 @@ async function waitForELOffline(ENGINE_PORT: string): Promise { async function isPortInUse(port: number): Promise { return new Promise((resolve, reject) => { const server = net.createServer(); - server.once("error", function (err) { + server.once("error", (err) => { if ((err as unknown as {code: string}).code === "EADDRINUSE") { resolve(true); } else { @@ -204,7 +204,7 @@ async function isPortInUse(port: number): Promise { } }); - server.once("listening", function () { + server.once("listening", () => { // close the server if listening doesn't fail server.close(() => { resolve(false); diff --git a/packages/cli/src/applyPreset.ts b/packages/cli/src/applyPreset.ts index e40ac98841c0..612c5d648c63 100644 --- a/packages/cli/src/applyPreset.ts +++ b/packages/cli/src/applyPreset.ts @@ -90,6 +90,3 @@ function valueOfArg(argName: string): string | null { return null; } - -// Add empty export to make this a module -export {}; diff --git a/packages/cli/src/cmds/beacon/initBeaconState.ts b/packages/cli/src/cmds/beacon/initBeaconState.ts index 67b578e9fdb9..8dc9e9317c65 100644 --- a/packages/cli/src/cmds/beacon/initBeaconState.ts +++ b/packages/cli/src/cmds/beacon/initBeaconState.ts @@ -162,7 +162,9 @@ export async function initBeaconState( db, logger ); - } else if (args.checkpointSyncUrl) { + } + + if (args.checkpointSyncUrl) { return fetchWSStateFromBeaconApi( lastDbStateWithBytes, lastDbValidatorsBytes, @@ -175,24 +177,24 @@ export async function initBeaconState( db, logger ); - } else { - const genesisStateFile = args.genesisStateFile || getGenesisFileUrl(args.network || defaultNetwork); - if (genesisStateFile && !args.forceGenesis) { - const stateBytes = await downloadOrLoadFile(genesisStateFile); - const anchorState = getStateTypeFromBytes(chainForkConfig, stateBytes).deserializeToViewDU(stateBytes); - const config = createBeaconConfig(chainForkConfig, anchorState.genesisValidatorsRoot); - const wssCheck = isWithinWeakSubjectivityPeriod(config, anchorState, getCheckpointFromState(anchorState)); - await checkAndPersistAnchorState(config, db, logger, anchorState, stateBytes, { - isWithinWeakSubjectivityPeriod: wssCheck, - isCheckpointState: true, - }); - return {anchorState}; - } else { - // Only place we will not bother checking isWithinWeakSubjectivityPeriod as forceGenesis passed by user - const anchorState = await initStateFromEth1({config: chainForkConfig, db, logger, opts: options.eth1, signal}); - return {anchorState}; - } } + + const genesisStateFile = args.genesisStateFile || getGenesisFileUrl(args.network || defaultNetwork); + if (genesisStateFile && !args.forceGenesis) { + const stateBytes = await downloadOrLoadFile(genesisStateFile); + const anchorState = getStateTypeFromBytes(chainForkConfig, stateBytes).deserializeToViewDU(stateBytes); + const config = createBeaconConfig(chainForkConfig, anchorState.genesisValidatorsRoot); + const wssCheck = isWithinWeakSubjectivityPeriod(config, anchorState, getCheckpointFromState(anchorState)); + await checkAndPersistAnchorState(config, db, logger, anchorState, stateBytes, { + isWithinWeakSubjectivityPeriod: wssCheck, + isCheckpointState: true, + }); + return {anchorState}; + } + + // Only place we will not bother checking isWithinWeakSubjectivityPeriod as forceGenesis passed by user + const anchorState = await initStateFromEth1({config: chainForkConfig, db, logger, opts: options.eth1, signal}); + return {anchorState}; } async function readWSState( diff --git a/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts b/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts index 68a4cbed59af..a9f91af87152 100644 --- a/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts +++ b/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts @@ -125,6 +125,7 @@ export function overwriteEnrWithCliArgs( enr.seq = preSeq + BigInt(1); } // invalidate cached signature + // biome-ignore lint/complexity/useLiteralKeys: `_signature` is a private attribute delete enr["_signature"]; } } @@ -186,9 +187,8 @@ export async function initPrivateKeyAndEnr( writeFile600Perm(peerIdFile, exportToJSON(privateKey)); writeFile600Perm(enrFile, enr.encodeTxt()); return {privateKey, enr}; - } else { - const {privateKey, enr} = await newPrivateKeyAndENR(); - overwriteEnrWithCliArgs(enr, args, logger, {newEnr: true, bootnode}); - return {privateKey, enr}; } + const {privateKey, enr} = await newPrivateKeyAndENR(); + overwriteEnrWithCliArgs(enr, args, logger, {newEnr: true, bootnode}); + return {privateKey, enr}; } diff --git a/packages/cli/src/cmds/bootnode/options.ts b/packages/cli/src/cmds/bootnode/options.ts index dd597e6a22ef..f3422b4029a1 100644 --- a/packages/cli/src/cmds/bootnode/options.ts +++ b/packages/cli/src/cmds/bootnode/options.ts @@ -55,7 +55,7 @@ export const bootnodeExtraOptions: CliCommandOptions = { // Each bootnode entry could be comma separated, just deserialize it into a single array // as comma separated entries are generally most friendly in ansible kind of setups, i.e. // [ "en1", "en2,en3" ] => [ 'en1', 'en2', 'en3' ] - coerce: (args: string[]) => args.map((item) => item.split(",")).flat(1), + coerce: (args: string[]) => args.flatMap((item) => item.split(",")), group: "network", }, diff --git a/packages/cli/src/cmds/dev/options.ts b/packages/cli/src/cmds/dev/options.ts index 5286b81729c6..e442b0605cdc 100644 --- a/packages/cli/src/cmds/dev/options.ts +++ b/packages/cli/src/cmds/dev/options.ts @@ -81,12 +81,12 @@ const externalOptionsOverrides: Partial closeMetrics()); // only start server if metrics are explicitly enabled - if (args["metrics"]) { + if (args.metrics) { const port = args["metrics.port"] ?? validatorMetricsDefaultOptions.port; const address = args["metrics.address"] ?? validatorMetricsDefaultOptions.address; const metricsServer = await getHttpMetricsServer({port, address}, {register, logger}); @@ -186,7 +186,7 @@ export async function validatorHandler(args: IValidatorCliArgs & GlobalArgs): Pr // Start keymanager API backend // Only if keymanagerEnabled flag is set to true - if (args["keymanager"]) { + if (args.keymanager) { // if proposerSettingsFile provided disable the key proposerConfigWrite in keymanager const proposerConfigWriteDisabled = args.proposerSettingsFile !== undefined; if (proposerConfigWriteDisabled) { @@ -234,7 +234,7 @@ function getProposerConfigFromArgs( builder: { gasLimit: args.defaultGasLimit, selection: parseBuilderSelection( - args["builder.selection"] ?? (args["builder"] ? defaultOptions.builderAliasSelection : undefined) + args["builder.selection"] ?? (args.builder ? defaultOptions.builderAliasSelection : undefined) ), boostFactor: parseBuilderBoostFactor(args["builder.boostFactor"]), }, diff --git a/packages/cli/src/cmds/validator/keymanager/impl.ts b/packages/cli/src/cmds/validator/keymanager/impl.ts index d965b2af5075..b4233f3162cd 100644 --- a/packages/cli/src/cmds/validator/keymanager/impl.ts +++ b/packages/cli/src/cmds/validator/keymanager/impl.ts @@ -378,7 +378,6 @@ export class KeymanagerApi implements Api { function ensureJSON(strOrJson: string | T): T { if (typeof strOrJson === "string") { return JSON.parse(strOrJson) as T; - } else { - return strOrJson; } + return strOrJson; } diff --git a/packages/cli/src/cmds/validator/keymanager/server.ts b/packages/cli/src/cmds/validator/keymanager/server.ts index c4d3256c6151..e48c708c96a8 100644 --- a/packages/cli/src/cmds/validator/keymanager/server.ts +++ b/packages/cli/src/cmds/validator/keymanager/server.ts @@ -80,6 +80,7 @@ function readFileIfExists(filepath: string): string | null { return fs.readFileSync(filepath, "utf8").trim(); } catch (e) { if ((e as {code: string}).code === "ENOENT") return null; - else throw e; + + throw e; } } diff --git a/packages/cli/src/cmds/validator/options.ts b/packages/cli/src/cmds/validator/options.ts index 83190dcf4a58..3beb8197793c 100644 --- a/packages/cli/src/cmds/validator/options.ts +++ b/packages/cli/src/cmds/validator/options.ts @@ -195,9 +195,7 @@ export const validatorOptions: CliCommandOptions = { string: true, coerce: (urls: string[]): string[] => // Parse ["url1,url2"] to ["url1", "url2"] - urls - .map((item) => item.split(",")) - .flat(1), + urls.flatMap((item) => item.split(",")), alias: ["server"], // for backwards compatibility }, @@ -354,8 +352,7 @@ export const validatorOptions: CliCommandOptions = { coerce: (pubkeys: string[]): string[] => // Parse ["0x11,0x22"] to ["0x11", "0x22"] pubkeys - .map((item) => item.split(",")) - .flat(1) + .flatMap((item) => item.split(",")) .map(ensure0xPrefix), group: "externalSigner", }, diff --git a/packages/cli/src/cmds/validator/signers/importExternalKeystores.ts b/packages/cli/src/cmds/validator/signers/importExternalKeystores.ts index 7b90d16d1d88..f86ea90ab1a8 100644 --- a/packages/cli/src/cmds/validator/signers/importExternalKeystores.ts +++ b/packages/cli/src/cmds/validator/signers/importExternalKeystores.ts @@ -28,17 +28,17 @@ export function importKeystoreDefinitionsFromExternalDir(args: { export async function readPassphraseOrPrompt(args: {importKeystoresPassword?: string}): Promise { if (args.importKeystoresPassword) { return readPassphraseFile(args.importKeystoresPassword); - } else { - const answers = await inquirer.prompt<{password: string}>([ - { - name: "password", - type: "password", - message: "Enter the keystore(s) password", - }, - ]); - - return answers.password; } + + const answers = await inquirer.prompt<{password: string}>([ + { + name: "password", + type: "password", + message: "Enter the keystore(s) password", + }, + ]); + + return answers.password; } /** diff --git a/packages/cli/src/cmds/validator/signers/index.ts b/packages/cli/src/cmds/validator/signers/index.ts index c155b52d186a..950be2db1cf5 100644 --- a/packages/cli/src/cmds/validator/signers/index.ts +++ b/packages/cli/src/cmds/validator/signers/index.ts @@ -53,13 +53,12 @@ export async function getSignersFromArgs( // Using a remote signer with TESTNETS if (args["externalSigner.pubkeys"] || args["externalSigner.fetch"]) { return getRemoteSigners(args); - } else { - return indexes.map((index) => ({type: SignerType.Local, secretKey: interopSecretKey(index)})); } + return indexes.map((index) => ({type: SignerType.Local, secretKey: interopSecretKey(index)})); } // UNSAFE, ONLY USE FOR TESTNETS - Derive keys directly from a mnemonic - else if (args.fromMnemonic) { + if (args.fromMnemonic) { if (network === defaultNetwork) { throw new YargsError("fromMnemonic must only be used in testnets"); } @@ -76,7 +75,7 @@ export async function getSignersFromArgs( } // Import JSON keystores and run - else if (args.importKeystores) { + if (args.importKeystores) { const keystoreDefinitions = importKeystoreDefinitionsFromExternalDir({ keystoresPath: args.importKeystores, password: await readPassphraseOrPrompt(args), @@ -98,52 +97,50 @@ export async function getSignersFromArgs( ignoreLockFile: args.force, onDecrypt: needle, cacheFilePath: path.join(accountPaths.cacheDir, "imported_keystores.cache"), - disableThreadPool: args["disableKeystoresThreadPool"], + disableThreadPool: args.disableKeystoresThreadPool, logger, signal, }); } // Remote keys are declared manually or will be fetched from external signer - else if (args["externalSigner.pubkeys"] || args["externalSigner.fetch"]) { + if (args["externalSigner.pubkeys"] || args["externalSigner.fetch"]) { return getRemoteSigners(args); } // Read keys from local account manager - else { - const persistedKeysBackend = new PersistedKeysBackend(accountPaths); - - // Read and decrypt local keystores, imported via keymanager api or import cmd - const keystoreDefinitions = persistedKeysBackend.readAllKeystores(); - - const needle = showProgress({ - total: keystoreDefinitions.length, - frequencyMs: KEYSTORE_IMPORT_PROGRESS_MS, - signal, - progress: ({ratePerSec, percentage, current, total}) => { - logger.info( - `${percentage.toFixed(0)}% of local keystores imported. current=${current} total=${total} rate=${( - ratePerSec * 60 - ).toFixed(2)}keys/m` - ); - }, - }); - - const keystoreSigners = await decryptKeystoreDefinitions(keystoreDefinitions, { - ignoreLockFile: args.force, - onDecrypt: needle, - cacheFilePath: path.join(accountPaths.cacheDir, "local_keystores.cache"), - disableThreadPool: args["disableKeystoresThreadPool"], - logger, - signal, - }); - - // Read local remote keys, imported via keymanager api - const signerDefinitions = persistedKeysBackend.readAllRemoteKeys(); - const remoteSigners = signerDefinitions.map(({url, pubkey}): Signer => ({type: SignerType.Remote, url, pubkey})); - - return [...keystoreSigners, ...remoteSigners]; - } + const persistedKeysBackend = new PersistedKeysBackend(accountPaths); + + // Read and decrypt local keystores, imported via keymanager api or import cmd + const keystoreDefinitions = persistedKeysBackend.readAllKeystores(); + + const needle = showProgress({ + total: keystoreDefinitions.length, + frequencyMs: KEYSTORE_IMPORT_PROGRESS_MS, + signal, + progress: ({ratePerSec, percentage, current, total}) => { + logger.info( + `${percentage.toFixed(0)}% of local keystores imported. current=${current} total=${total} rate=${( + ratePerSec * 60 + ).toFixed(2)}keys/m` + ); + }, + }); + + const keystoreSigners = await decryptKeystoreDefinitions(keystoreDefinitions, { + ignoreLockFile: args.force, + onDecrypt: needle, + cacheFilePath: path.join(accountPaths.cacheDir, "local_keystores.cache"), + disableThreadPool: args.disableKeystoresThreadPool, + logger, + signal, + }); + + // Read local remote keys, imported via keymanager api + const signerDefinitions = persistedKeysBackend.readAllRemoteKeys(); + const remoteSigners = signerDefinitions.map(({url, pubkey}): Signer => ({type: SignerType.Remote, url, pubkey})); + + return [...keystoreSigners, ...remoteSigners]; } export function getSignerPubkeyHex(signer: Signer): string { diff --git a/packages/cli/src/cmds/validator/signers/logSigners.ts b/packages/cli/src/cmds/validator/signers/logSigners.ts index 20aa50d25ff6..d245ee75883a 100644 --- a/packages/cli/src/cmds/validator/signers/logSigners.ts +++ b/packages/cli/src/cmds/validator/signers/logSigners.ts @@ -60,11 +60,11 @@ function groupRemoteSignersByUrl(remoteSigners: SignerRemote[]): {url: string; p * is connected with fetching enabled, but otherwise exit the process and suggest a different configuration. */ export function warnOrExitNoSigners(args: IValidatorCliArgs, logger: Pick): void { - if (args["keymanager"] && !args["externalSigner.fetch"]) { + if (args.keymanager && !args["externalSigner.fetch"]) { logger.warn("No local keystores or remote keys found with current args, expecting to be added via keymanager"); - } else if (!args["keymanager"] && args["externalSigner.fetch"]) { + } else if (!args.keymanager && args["externalSigner.fetch"]) { logger.warn("No remote keys found with current args, expecting to be added to external signer and fetched later"); - } else if (args["keymanager"] && args["externalSigner.fetch"]) { + } else if (args.keymanager && args["externalSigner.fetch"]) { logger.warn( "No local keystores or remote keys found with current args, expecting to be added via keymanager or fetched from external signer later" ); diff --git a/packages/cli/src/cmds/validator/slashingProtection/export.ts b/packages/cli/src/cmds/validator/slashingProtection/export.ts index c18b020f5782..f57f9d3ec0bd 100644 --- a/packages/cli/src/cmds/validator/slashingProtection/export.ts +++ b/packages/cli/src/cmds/validator/slashingProtection/export.ts @@ -43,8 +43,7 @@ export const exportCmd: CliCommand // Parse ["0x11,0x22"] to ["0x11", "0x22"] pubkeys - .map((item) => item.split(",")) - .flat(1) + .flatMap((item) => item.split(",")) .map(ensure0xPrefix), }, }, diff --git a/packages/cli/src/cmds/validator/voluntaryExit.ts b/packages/cli/src/cmds/validator/voluntaryExit.ts index c3982d8d45ee..5b4cfdf270f0 100644 --- a/packages/cli/src/cmds/validator/voluntaryExit.ts +++ b/packages/cli/src/cmds/validator/voluntaryExit.ts @@ -59,8 +59,7 @@ If no `pubkeys` are provided, it will exit all validators that have been importe coerce: (pubkeys: string[]): string[] => // Parse ["0x11,0x22"] to ["0x11", "0x22"] pubkeys - .map((item) => item.split(",")) - .flat(1) + .flatMap((item) => item.split(",")) .map(ensure0xPrefix), }, @@ -151,7 +150,7 @@ async function processVoluntaryExit( const voluntaryExit: phase0.VoluntaryExit = {epoch: exitEpoch, validatorIndex: index}; const signingRoot = computeSigningRoot(ssz.phase0.VoluntaryExit, voluntaryExit, domain); - let signature; + let signature: Signature; switch (signer.type) { case SignerType.Local: signature = signer.secretKey.sign(signingRoot); @@ -192,15 +191,13 @@ function selectSignersToExit(args: VoluntaryExitArgs, signers: Signer[]): Signer const signer = signersByPubkey.get(pubkey); if (!signer) { throw new YargsError(`Unknown pubkey ${pubkey}`); - } else { - selectedSigners.push({pubkey, signer}); } + selectedSigners.push({pubkey, signer}); } return selectedSigners; - } else { - return signersWithPubkey; } + return signersWithPubkey; } async function resolveValidatorIndexes(client: ApiClient, signersToExit: SignerPubkey[]) { diff --git a/packages/cli/src/networks/dev.ts b/packages/cli/src/networks/dev.ts index ff8afc127dcc..6ce87273b3cb 100644 --- a/packages/cli/src/networks/dev.ts +++ b/packages/cli/src/networks/dev.ts @@ -1,8 +1,9 @@ import {gnosisChainConfig} from "@lodestar/config/networks"; import {minimalChainConfig, mainnetChainConfig} from "@lodestar/config/configs"; import {ACTIVE_PRESET, PresetName} from "@lodestar/params"; +import {ChainConfig} from "@lodestar/config"; -let chainConfig; +let chainConfig: ChainConfig; switch (ACTIVE_PRESET) { case PresetName.mainnet: chainConfig = mainnetChainConfig; diff --git a/packages/cli/src/networks/index.ts b/packages/cli/src/networks/index.ts index ba42cf4c7798..e2fc9dd621b6 100644 --- a/packages/cli/src/networks/index.ts +++ b/packages/cli/src/networks/index.ts @@ -210,7 +210,7 @@ export async function fetchWeakSubjectivityState( } export function getCheckpointFromArg(checkpointStr: string): Checkpoint { - const checkpointRegex = new RegExp("^(?:0x)?([0-9a-f]{64}):([0-9]+)$"); + const checkpointRegex = /^(?:0x)?([0-9a-f]{64}):([0-9]+)$/; const match = checkpointRegex.exec(checkpointStr.toLowerCase()); if (!match) { throw new Error(`Could not parse checkpoint string: ${checkpointStr}`); diff --git a/packages/cli/src/options/beaconNodeOptions/api.ts b/packages/cli/src/options/beaconNodeOptions/api.ts index bed0105fd944..ea4d4ebccf84 100644 --- a/packages/cli/src/options/beaconNodeOptions/api.ts +++ b/packages/cli/src/options/beaconNodeOptions/api.ts @@ -22,7 +22,7 @@ export function parseArgs(args: ApiArgs): IBeaconNodeOptions["api"] { rest: { api: args["rest.namespace"] as IBeaconNodeOptions["api"]["rest"]["api"], cors: args["rest.cors"], - enabled: args["rest"], + enabled: args.rest, address: args["rest.address"], port: args["rest.port"], headerLimit: args["rest.headerLimit"], @@ -59,7 +59,7 @@ export const options: CliCommandOptions = { // Enable all if (namespaces.includes(enabledAll)) return allNamespaces; // Parse ["debug,lodestar"] to ["debug", "lodestar"] - return namespaces.map((val) => val.split(",")).flat(1); + return namespaces.flatMap((val) => val.split(",")); }, }, diff --git a/packages/cli/src/options/beaconNodeOptions/builder.ts b/packages/cli/src/options/beaconNodeOptions/builder.ts index 2c89cbad89d2..d0e4089dd81c 100644 --- a/packages/cli/src/options/beaconNodeOptions/builder.ts +++ b/packages/cli/src/options/beaconNodeOptions/builder.ts @@ -18,7 +18,7 @@ export function parseArgs(args: ExecutionBuilderArgs): IBeaconNodeOptions["execu } return { - enabled: args["builder"], + enabled: args.builder, url: args["builder.url"] ?? defaultExecutionBuilderHttpOpts.url, timeout: args["builder.timeout"], faultInspectionWindow: args["builder.faultInspectionWindow"], diff --git a/packages/cli/src/options/beaconNodeOptions/chain.ts b/packages/cli/src/options/beaconNodeOptions/chain.ts index 7540dd56a636..78ffd47da8f4 100644 --- a/packages/cli/src/options/beaconNodeOptions/chain.ts +++ b/packages/cli/src/options/beaconNodeOptions/chain.ts @@ -36,7 +36,7 @@ export type ChainArgs = { export function parseArgs(args: ChainArgs): IBeaconNodeOptions["chain"] { return { - suggestedFeeRecipient: args["suggestedFeeRecipient"], + suggestedFeeRecipient: args.suggestedFeeRecipient, blsVerifyAllMultiThread: args["chain.blsVerifyAllMultiThread"], blsVerifyAllMainThread: args["chain.blsVerifyAllMainThread"], disableBlsBatchVerify: args["chain.disableBlsBatchVerify"], @@ -55,8 +55,8 @@ export function parseArgs(args: ChainArgs): IBeaconNodeOptions["chain"] { trustedSetup: args["chain.trustedSetup"], safeSlotsToImportOptimistically: args["safe-slots-to-import-optimistically"], archiveStateEpochFrequency: args["chain.archiveStateEpochFrequency"], - emitPayloadAttributes: args["emitPayloadAttributes"], - broadcastValidationStrictness: args["broadcastValidationStrictness"], + emitPayloadAttributes: args.emitPayloadAttributes, + broadcastValidationStrictness: args.broadcastValidationStrictness, minSameMessageSignatureSetsToBatch: args["chain.minSameMessageSignatureSetsToBatch"] ?? defaultOptions.chain.minSameMessageSignatureSetsToBatch, maxShufflingCacheEpochs: args["chain.maxShufflingCacheEpochs"] ?? defaultOptions.chain.maxShufflingCacheEpochs, diff --git a/packages/cli/src/options/beaconNodeOptions/eth1.ts b/packages/cli/src/options/beaconNodeOptions/eth1.ts index c558bda61b4e..f12a1704dec7 100644 --- a/packages/cli/src/options/beaconNodeOptions/eth1.ts +++ b/packages/cli/src/options/beaconNodeOptions/eth1.ts @@ -25,14 +25,12 @@ export function parseArgs(args: Eth1Args & Partial): IBeaco // jwt auth mechanism. if (providerUrls === undefined && args["execution.urls"]) { providerUrls = args["execution.urls"]; - jwtSecretHex = args["jwtSecret"] - ? extractJwtHexSecret(fs.readFileSync(args["jwtSecret"], "utf-8").trim()) - : undefined; - jwtId = args["jwtId"]; + jwtSecretHex = args.jwtSecret ? extractJwtHexSecret(fs.readFileSync(args.jwtSecret, "utf-8").trim()) : undefined; + jwtId = args.jwtId; } return { - enabled: args["eth1"], + enabled: args.eth1, providerUrls, jwtSecretHex, jwtId, @@ -59,9 +57,7 @@ export const options: CliCommandOptions = { string: true, coerce: (urls: string[]): string[] => // Parse ["url1,url2"] to ["url1", "url2"] - urls - .map((item) => item.split(",")) - .flat(1), + urls.flatMap((item) => item.split(",")), group: "eth1", }, diff --git a/packages/cli/src/options/beaconNodeOptions/execution.ts b/packages/cli/src/options/beaconNodeOptions/execution.ts index d60a621d1cdb..2d32ee2ae786 100644 --- a/packages/cli/src/options/beaconNodeOptions/execution.ts +++ b/packages/cli/src/options/beaconNodeOptions/execution.ts @@ -30,10 +30,8 @@ export function parseArgs(args: ExecutionEngineArgs): IBeaconNodeOptions["execut * jwtSecret is parsed as hex instead of bytes because the merge with defaults * in beaconOptions messes up the bytes array as as index => value object */ - jwtSecretHex: args["jwtSecret"] - ? extractJwtHexSecret(fs.readFileSync(args["jwtSecret"], "utf-8").trim()) - : undefined, - jwtId: args["jwtId"], + jwtSecretHex: args.jwtSecret ? extractJwtHexSecret(fs.readFileSync(args.jwtSecret, "utf-8").trim()) : undefined, + jwtId: args.jwtId, }; } @@ -45,9 +43,7 @@ export const options: CliCommandOptions = { string: true, coerce: (urls: string[]): string[] => // Parse ["url1,url2"] to ["url1", "url2"] - urls - .map((item) => item.split(",")) - .flat(1), + urls.flatMap((item) => item.split(",")), group: "execution", }, diff --git a/packages/cli/src/options/beaconNodeOptions/metrics.ts b/packages/cli/src/options/beaconNodeOptions/metrics.ts index ba12a7546eae..ded63b7dc24d 100644 --- a/packages/cli/src/options/beaconNodeOptions/metrics.ts +++ b/packages/cli/src/options/beaconNodeOptions/metrics.ts @@ -9,7 +9,7 @@ export type MetricsArgs = { export function parseArgs(args: MetricsArgs): IBeaconNodeOptions["metrics"] { return { - enabled: args["metrics"], + enabled: args.metrics, port: args["metrics.port"], address: args["metrics.address"], }; diff --git a/packages/cli/src/options/beaconNodeOptions/network.ts b/packages/cli/src/options/beaconNodeOptions/network.ts index fc13f3293c29..cfd109bdc50a 100644 --- a/packages/cli/src/options/beaconNodeOptions/network.ts +++ b/packages/cli/src/options/beaconNodeOptions/network.ts @@ -100,16 +100,16 @@ export function parseArgs(args: NetworkArgs): IBeaconNodeOptions["network"] { const bindMu6 = listenAddress6 ? `${muArgs.listenAddress6}${muArgs.discoveryPort6}` : undefined; const localMu6 = listenAddress6 ? `${muArgs.listenAddress6}${muArgs.port6}` : undefined; - const targetPeers = args["targetPeers"]; + const targetPeers = args.targetPeers; const maxPeers = args["network.maxPeers"] ?? (targetPeers !== undefined ? Math.floor(targetPeers * 1.1) : undefined); if (targetPeers != null && maxPeers != null && targetPeers > maxPeers) { throw new YargsError("network.maxPeers must be greater than or equal to targetPeers"); } // Set discv5 opts to null to disable only if explicitly disabled - const enableDiscv5 = args["discv5"] ?? true; + const enableDiscv5 = args.discv5 ?? true; // TODO: Okay to set to empty array? - const bootEnrs = args["bootnodes"] ?? []; + const bootEnrs = args.bootnodes ?? []; // throw if user-provided enrs are invalid for (const enrStr of bootEnrs) { try { @@ -135,10 +135,10 @@ export function parseArgs(args: NetworkArgs): IBeaconNodeOptions["network"] { maxPeers: maxPeers ?? defaultOptions.network.maxPeers, targetPeers: targetPeers ?? defaultOptions.network.targetPeers, localMultiaddrs: [localMu, localMu6].filter(Boolean) as string[], - subscribeAllSubnets: args["subscribeAllSubnets"], + subscribeAllSubnets: args.subscribeAllSubnets, slotsToSubscribeBeforeAggregatorDuty: - args["slotsToSubscribeBeforeAggregatorDuty"] ?? defaultOptions.network.slotsToSubscribeBeforeAggregatorDuty, - disablePeerScoring: args["disablePeerScoring"], + args.slotsToSubscribeBeforeAggregatorDuty ?? defaultOptions.network.slotsToSubscribeBeforeAggregatorDuty, + disablePeerScoring: args.disablePeerScoring, connectToDiscv5Bootnodes: args["network.connectToDiscv5Bootnodes"], discv5FirstQueryDelayMs: args["network.discv5FirstQueryDelayMs"], dontSendGossipAttestationsToForkchoice: args["network.dontSendGossipAttestationsToForkchoice"], @@ -148,7 +148,7 @@ export function parseArgs(args: NetworkArgs): IBeaconNodeOptions["network"] { gossipsubDHigh: args["network.gossipsubDHigh"], gossipsubAwaitHandler: args["network.gossipsubAwaitHandler"], disableFloodPublish: args["network.disableFloodPublish"], - mdns: args["mdns"], + mdns: args.mdns, rateLimitMultiplier: args["network.rateLimitMultiplier"], maxGossipTopicConcurrency: args["network.maxGossipTopicConcurrency"], useWorker: args["network.useWorker"], @@ -211,12 +211,12 @@ export const options: CliCommandOptions = { bootnodes: { type: "array", description: "Bootnodes for discv5 discovery", - defaultDescription: JSON.stringify((defaultOptions.network.discv5 || {}).bootEnrs || []), + defaultDescription: JSON.stringify(defaultOptions.network.discv5?.bootEnrs || []), group: "network", // Each bootnode entry could be comma separated, just deserialize it into a single array // as comma separated entries are generally most friendly in ansible kind of setups, i.e. // [ "en1", "en2,en3" ] => [ 'en1', 'en2', 'en3' ] - coerce: (args: string[]) => args.map((item) => item.split(",")).flat(1), + coerce: (args: string[]) => args.flatMap((item) => item.split(",")), }, targetPeers: { diff --git a/packages/cli/src/options/logOptions.ts b/packages/cli/src/options/logOptions.ts index b45057a4532f..09eb5b1d56cb 100644 --- a/packages/cli/src/options/logOptions.ts +++ b/packages/cli/src/options/logOptions.ts @@ -65,6 +65,6 @@ export const logOptions: CliCommandOptions = { description: "Set log level for a specific module by name: 'chain=debug' or 'network=debug,chain=debug'", type: "array", string: true, - coerce: (args: string[]) => args.map((item) => item.split(",")).flat(1), + coerce: (args: string[]) => args.flatMap((item) => item.split(",")), }, }; diff --git a/packages/cli/src/options/paramsOptions.ts b/packages/cli/src/options/paramsOptions.ts index b35a15e3c9b6..bd89ffa77d9e 100644 --- a/packages/cli/src/options/paramsOptions.ts +++ b/packages/cli/src/options/paramsOptions.ts @@ -25,14 +25,14 @@ export function parseBeaconParamsArgs(args: Record): IB } const paramsOptionsByName = ObjectKeys(chainConfigTypes).reduce( - (options: Record, key): Record => ({ - ...options, - [getArgKey(key)]: { + (options: Record, key): Record => { + options[getArgKey(key)] = { hidden: true, type: "string", group: "params", - }, - }), + }; + return options; + }, {} ); diff --git a/packages/cli/src/util/file.ts b/packages/cli/src/util/file.ts index 5415cf2affa6..a18768d456b9 100644 --- a/packages/cli/src/util/file.ts +++ b/packages/cli/src/util/file.ts @@ -104,9 +104,8 @@ export function readFileIfExists(filepath: string, acceptedFormats?: string[] } catch (e) { if ((e as {code: string}).code === "ENOENT") { return null; - } else { - throw e; } + throw e; } } @@ -141,9 +140,8 @@ export async function downloadOrLoadFile(pathOrUrl: string): Promise if (isUrl(pathOrUrl)) { const res = await got.get(pathOrUrl, {encoding: "binary"}); return res.rawBody; - } else { - return fs.promises.readFile(pathOrUrl); } + return fs.promises.readFile(pathOrUrl); } /** diff --git a/packages/cli/src/util/format.ts b/packages/cli/src/util/format.ts index a86ca0662a9f..e8361649824a 100644 --- a/packages/cli/src/util/format.ts +++ b/packages/cli/src/util/format.ts @@ -36,8 +36,8 @@ export function parseRange(range: string): number[] { const [from, to] = range.split("..").map((n) => parseInt(n)); - if (isNaN(from)) throw Error(`Invalid range from isNaN '${range}'`); - if (isNaN(to)) throw Error(`Invalid range to isNaN '${range}'`); + if (Number.isNaN(from)) throw Error(`Invalid range from isNaN '${range}'`); + if (Number.isNaN(to)) throw Error(`Invalid range to isNaN '${range}'`); if (from > to) throw Error(`Invalid range from > to '${range}'`); const arr: number[] = []; diff --git a/packages/cli/src/util/fs.ts b/packages/cli/src/util/fs.ts index 37464c877b85..17501bea78c9 100644 --- a/packages/cli/src/util/fs.ts +++ b/packages/cli/src/util/fs.ts @@ -21,7 +21,8 @@ export function unlinkSyncMaybe(filepath: string): boolean { } catch (e) { const {code} = e as ErrorFs; if (code === "ENOENT") return false; - else throw e; + + throw e; } } @@ -37,7 +38,8 @@ export function rmdirSyncMaybe(dirpath: string): boolean { // about error codes https://nodejs.org/api/fs.html#fspromisesrmdirpath-options // ENOENT error on Windows and an ENOTDIR if (code === "ENOENT" || code === "ENOTDIR") return false; - else throw e; + + throw e; } } diff --git a/packages/cli/src/util/jwt.ts b/packages/cli/src/util/jwt.ts index e77e9e692cd6..b79b0a0dea7f 100644 --- a/packages/cli/src/util/jwt.ts +++ b/packages/cli/src/util/jwt.ts @@ -2,7 +2,7 @@ export function extractJwtHexSecret(jwtSecretContents: string): string { const hexPattern = new RegExp(/^(0x|0X)?(?[a-fA-F0-9]+)$/, "g"); const jwtSecretHexMatch = hexPattern.exec(jwtSecretContents); const jwtSecret = jwtSecretHexMatch?.groups?.jwtSecret; - if (!jwtSecret || jwtSecret.length != 64) { + if (!jwtSecret || jwtSecret.length !== 64) { throw Error(`Need a valid 256 bit hex encoded secret ${jwtSecret} ${jwtSecretContents}`); } // Return the secret in proper hex format diff --git a/packages/cli/src/util/logger.ts b/packages/cli/src/util/logger.ts index e08029f5f1df..7a394c9ce25f 100644 --- a/packages/cli/src/util/logger.ts +++ b/packages/cli/src/util/logger.ts @@ -89,14 +89,16 @@ export function cleanOldLogFiles(args: LogArgs, paths: {defaultLogFilepath: stri .filter((logFileName) => shouldDeleteLogFile(prefix, extension, logFileName, args.logFileDailyRotate)) .map((logFileName) => path.join(folder, logFileName)); // delete files - toDelete.forEach((filename) => fs.unlinkSync(filename)); + for (const filename of toDelete) { + fs.unlinkSync(filename); + } } export function shouldDeleteLogFile(prefix: string, extension: string, logFileName: string, maxFiles: number): boolean { const maxDifferenceMs = maxFiles * 24 * 60 * 60 * 1000; const match = logFileName.match(new RegExp(`${prefix}-([0-9]{4}-[0-9]{2}-[0-9]{2}).${extension}`)); // if match[1] exists, it should be the date pattern of YYYY-MM-DD - if (match && match[1] && Date.now() - new Date(match[1]).getTime() > maxDifferenceMs) { + if (match?.[1] && Date.now() - new Date(match[1]).getTime() > maxDifferenceMs) { return true; } return false; diff --git a/packages/cli/test/e2e/blsToExecutionchange.test.ts b/packages/cli/test/e2e/blsToExecutionchange.test.ts index 51720e424c7e..57f32421d313 100644 --- a/packages/cli/test/e2e/blsToExecutionchange.test.ts +++ b/packages/cli/test/e2e/blsToExecutionchange.test.ts @@ -8,7 +8,7 @@ import {interopSecretKey} from "@lodestar/state-transition"; import {execCliCommand, spawnCliCommand, stopChildProcess} from "@lodestar/test-utils"; import {testFilesDir} from "../utils.js"; -describe("bLSToExecutionChange cmd", function () { +describe("bLSToExecutionChange cmd", () => { vi.setConfig({testTimeout: 60_000}); it("Perform bLSToExecutionChange", async () => { diff --git a/packages/cli/test/e2e/importFromFsDirect.test.ts b/packages/cli/test/e2e/importFromFsDirect.test.ts index 644635bc0ffe..6f612e84afe6 100644 --- a/packages/cli/test/e2e/importFromFsDirect.test.ts +++ b/packages/cli/test/e2e/importFromFsDirect.test.ts @@ -7,24 +7,17 @@ import {testFilesDir} from "../utils.js"; import {cachedPubkeysHex, cachedSeckeysHex} from "../utils/cachedKeys.js"; import {expectKeys, startValidatorWithKeyManager} from "../utils/validator.js"; -describe("import from fs same cmd as validate", function () { +describe("import from fs same cmd as validate", () => { vi.setConfig({testTimeout: 30_000}); const dataDir = path.join(testFilesDir, "import-and-validate-test"); const importFromDir = path.join(dataDir, "eth2.0_deposit_out"); const passphraseFilepath = path.join(importFromDir, "password.text"); - beforeAll(() => { + beforeAll(async () => { rimraf.sync(dataDir); rimraf.sync(importFromDir); - }); - - const passphrase = "AAAAAAAA0000000000"; - const keyCount = 2; - const pubkeys = cachedPubkeysHex.slice(0, keyCount); - const secretKeys = cachedSeckeysHex.slice(0, keyCount); - beforeAll(async () => { // Produce and encrypt keystores const keystoresStr = await getKeystoresStr(passphrase, secretKeys); @@ -35,6 +28,11 @@ describe("import from fs same cmd as validate", function () { } }); + const passphrase = "AAAAAAAA0000000000"; + const keyCount = 2; + const pubkeys = cachedPubkeysHex.slice(0, keyCount); + const secretKeys = cachedSeckeysHex.slice(0, keyCount); + // Check that there are not keys loaded without adding extra args `--importKeystores` it("run 'validator' there are no keys loaded", async () => { const {keymanagerClient, stopValidator} = await startValidatorWithKeyManager([], { diff --git a/packages/cli/test/e2e/importFromFsPreStep.test.ts b/packages/cli/test/e2e/importFromFsPreStep.test.ts index 7eebf2d4946e..437180ef07e5 100644 --- a/packages/cli/test/e2e/importFromFsPreStep.test.ts +++ b/packages/cli/test/e2e/importFromFsPreStep.test.ts @@ -8,7 +8,7 @@ import {testFilesDir} from "../utils.js"; import {cachedPubkeysHex, cachedSeckeysHex} from "../utils/cachedKeys.js"; import {expectKeys, startValidatorWithKeyManager} from "../utils/validator.js"; -describe("import from fs then validate", function () { +describe("import from fs then validate", () => { vi.setConfig({testTimeout: 30_000}); const dataDir = path.join(testFilesDir, "import-then-validate-test"); @@ -47,7 +47,7 @@ describe("import from fs then validate", function () { } }); - it("run 'validator list' and check pubkeys are imported", async function () { + it("run 'validator list' and check pubkeys are imported", async () => { fs.mkdirSync(path.join(dataDir, "keystores"), {recursive: true}); fs.mkdirSync(path.join(dataDir, "secrets"), {recursive: true}); @@ -58,7 +58,7 @@ describe("import from fs then validate", function () { } }); - it("run 'validator' check keys are loaded", async function () { + it("run 'validator' check keys are loaded", async () => { const {keymanagerClient, stopValidator} = await startValidatorWithKeyManager([], {dataDir}); onTestFinished(async () => { await stopValidator(); diff --git a/packages/cli/test/e2e/importKeystoresFromApi.test.ts b/packages/cli/test/e2e/importKeystoresFromApi.test.ts index 584ded47bfdd..7f71e2977a92 100644 --- a/packages/cli/test/e2e/importKeystoresFromApi.test.ts +++ b/packages/cli/test/e2e/importKeystoresFromApi.test.ts @@ -12,7 +12,7 @@ import {cachedPubkeysHex, cachedSeckeysHex} from "../utils/cachedKeys.js"; import {expectDeepEquals} from "../utils/runUtils.js"; import {expectKeys, startValidatorWithKeyManager} from "../utils/validator.js"; -describe("import keystores from api", function () { +describe("import keystores from api", () => { vi.setConfig({testTimeout: 30_000}); const dataDir = path.join(testFilesDir, "import-keystores-test"); @@ -118,7 +118,7 @@ describe("import keystores from api", function () { }); }); - it("run 'validator' check keys are loaded + delete", async function () { + it("run 'validator' check keys are loaded + delete", async () => { const {keymanagerClient, stopValidator} = await startValidatorWithKeyManager([], {dataDir}); onTestFinished(async () => { await stopValidator(); @@ -138,7 +138,7 @@ describe("import keystores from api", function () { await expectKeys(keymanagerClient, [], "Wrong listKeys after deleting"); }); - it("different process check no keys are loaded", async function () { + it("different process check no keys are loaded", async () => { const {keymanagerClient, stopValidator} = await startValidatorWithKeyManager([], {dataDir}); onTestFinished(async () => { await stopValidator(); @@ -148,7 +148,7 @@ describe("import keystores from api", function () { await expectKeys(keymanagerClient, [], "Wrong listKeys"); }); - it("reject calls without bearerToken", async function () { + it("reject calls without bearerToken", async () => { const {stopValidator} = await startValidatorWithKeyManager([], {dataDir}); onTestFinished(async () => { await stopValidator(); diff --git a/packages/cli/test/e2e/importRemoteKeysFromApi.test.ts b/packages/cli/test/e2e/importRemoteKeysFromApi.test.ts index 0d7e4aa58da3..b66611cbf4f4 100644 --- a/packages/cli/test/e2e/importRemoteKeysFromApi.test.ts +++ b/packages/cli/test/e2e/importRemoteKeysFromApi.test.ts @@ -20,7 +20,7 @@ async function expectKeys(keymanagerClient: ApiClient, expectedPubkeys: string[] ); } -describe("import remoteKeys from api", function () { +describe("import remoteKeys from api", () => { vi.setConfig({testTimeout: 30_000}); const dataDir = path.join(testFilesDir, "import-remoteKeys-test"); @@ -65,7 +65,7 @@ describe("import remoteKeys from api", function () { ); }); - it("run 'validator' check keys are loaded + delete", async function () { + it("run 'validator' check keys are loaded + delete", async () => { const {keymanagerClient, stopValidator} = await startValidatorWithKeyManager([], {dataDir}); onTestFinished(async () => { await stopValidator(); @@ -86,7 +86,7 @@ describe("import remoteKeys from api", function () { await expectKeys(keymanagerClient, [], "Wrong listRemoteKeys after deleting"); }); - it("reject calls without bearerToken", async function () { + it("reject calls without bearerToken", async () => { const {stopValidator} = await startValidatorWithKeyManager([], {dataDir}); onTestFinished(async () => { await stopValidator(); diff --git a/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts b/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts index 6a6c391b4014..2f25c82999a7 100644 --- a/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts +++ b/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts @@ -9,7 +9,7 @@ import {cachedPubkeysHex, cachedSeckeysHex} from "../utils/cachedKeys.js"; import {expectDeepEquals} from "../utils/runUtils.js"; import {startValidatorWithKeyManager} from "../utils/validator.js"; -describe("import keystores from api, test DefaultProposerConfig", function () { +describe("import keystores from api, test DefaultProposerConfig", () => { vi.setConfig({testTimeout: 30_000}); const dataDir = path.join(testFilesDir, "proposer-config-test"); diff --git a/packages/cli/test/e2e/runDevCmd.test.ts b/packages/cli/test/e2e/runDevCmd.test.ts index 68dcca156d88..3beb68393815 100644 --- a/packages/cli/test/e2e/runDevCmd.test.ts +++ b/packages/cli/test/e2e/runDevCmd.test.ts @@ -4,7 +4,7 @@ import {config} from "@lodestar/config/default"; import {retry} from "@lodestar/utils"; import {spawnCliCommand, stopChildProcess} from "@lodestar/test-utils"; -describe("Run dev command", function () { +describe("Run dev command", () => { vi.setConfig({testTimeout: 30_000}); it("Run dev command with no --dataDir until beacon api is listening", async () => { diff --git a/packages/cli/test/e2e/validatorList.test.ts b/packages/cli/test/e2e/validatorList.test.ts index b6fe4da5faeb..7f86fb8ef89b 100644 --- a/packages/cli/test/e2e/validatorList.test.ts +++ b/packages/cli/test/e2e/validatorList.test.ts @@ -9,7 +9,7 @@ import {runCliCommand} from "@lodestar/test-utils"; import {testFilesDir} from "../utils.js"; import {getLodestarCli} from "../../src/cli.js"; -describe("cmds / validator", function () { +describe("cmds / validator", () => { vi.setConfig({testTimeout: 30_000}); const lodestar = getLodestarCli(); @@ -54,7 +54,7 @@ describe("cmds / validator", function () { expect(console.log).toHaveBeenCalledWith(`Imported keystore ${pkHex} ${keystoreFilepath}`); }); - it("should list validators", async function () { + it("should list validators", async () => { fs.mkdirSync(path.join(dataDir, "keystores"), {recursive: true}); fs.mkdirSync(path.join(dataDir, "secrets"), {recursive: true}); diff --git a/packages/cli/test/e2e/voluntaryExit.test.ts b/packages/cli/test/e2e/voluntaryExit.test.ts index 25d4ab345aa7..0abddcab7652 100644 --- a/packages/cli/test/e2e/voluntaryExit.test.ts +++ b/packages/cli/test/e2e/voluntaryExit.test.ts @@ -7,7 +7,7 @@ import {interopSecretKey} from "@lodestar/state-transition"; import {spawnCliCommand, execCliCommand, stopChildProcess} from "@lodestar/test-utils"; import {testFilesDir} from "../utils.js"; -describe("voluntaryExit cmd", function () { +describe("voluntaryExit cmd", () => { vi.setConfig({testTimeout: 60_000}); it("Perform a voluntary exit", async () => { @@ -78,9 +78,8 @@ describe("voluntaryExit cmd", function () { const validator = (await client.beacon.getStateValidator({stateId: "head", validatorId: pubkey})).value(); if (validator.status !== "active_exiting") { throw Error("Validator not exiting"); - } else { - console.log(`Confirmed validator ${pubkey} = ${validator.status}`); } + console.log(`Confirmed validator ${pubkey} = ${validator.status}`); }, {retryDelay: 1000, retries: 20} ); diff --git a/packages/cli/test/e2e/voluntaryExitFromApi.test.ts b/packages/cli/test/e2e/voluntaryExitFromApi.test.ts index 21a9c0fc6872..97ac06d5fc5c 100644 --- a/packages/cli/test/e2e/voluntaryExitFromApi.test.ts +++ b/packages/cli/test/e2e/voluntaryExitFromApi.test.ts @@ -8,7 +8,7 @@ import {spawnCliCommand, stopChildProcess} from "@lodestar/test-utils"; import {retry} from "@lodestar/utils"; import {testFilesDir} from "../utils.js"; -describe("voluntary exit from api", function () { +describe("voluntary exit from api", () => { vi.setConfig({testTimeout: 60_000}); it("Perform a voluntary exit", async () => { @@ -85,9 +85,8 @@ describe("voluntary exit from api", function () { const validator = (await beaconClient.getStateValidator({stateId: "head", validatorId: pubkeyToExit})).value(); if (validator.status !== "active_exiting") { throw Error("Validator not exiting"); - } else { - console.log(`Confirmed validator ${pubkeyToExit} = ${validator.status}`); } + console.log(`Confirmed validator ${pubkeyToExit} = ${validator.status}`); }, {retryDelay: 1000, retries: 20} ); diff --git a/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts b/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts index 8cb5f0d44d95..769380f2053f 100644 --- a/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts +++ b/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts @@ -14,7 +14,7 @@ import { } from "@lodestar/test-utils"; import {testFilesDir} from "../utils.js"; -describe("voluntaryExit using remote signer", function () { +describe("voluntaryExit using remote signer", () => { vi.setConfig({testTimeout: 30_000}); let externalSigner: StartedExternalSigner; @@ -100,9 +100,8 @@ describe("voluntaryExit using remote signer", function () { const validator = (await client.beacon.getStateValidator({stateId: "head", validatorId: pubkey})).value(); if (validator.status !== "active_exiting") { throw Error("Validator not exiting"); - } else { - console.log(`Confirmed validator ${pubkey} = ${validator.status}`); } + console.log(`Confirmed validator ${pubkey} = ${validator.status}`); }, {retryDelay: 1000, retries: 20} ); diff --git a/packages/cli/test/unit/util/gitData.test.ts b/packages/cli/test/unit/util/gitData.test.ts index 12a6b5b18339..9e15fc2f4956 100644 --- a/packages/cli/test/unit/util/gitData.test.ts +++ b/packages/cli/test/unit/util/gitData.test.ts @@ -10,7 +10,7 @@ import {getGitData} from "../../../src/util/index.js"; // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules const __dirname = path.dirname(fileURLToPath(import.meta.url)); -describe("util / gitData", function () { +describe("util / gitData", () => { // .gitData file is created at build time with the command // ``` // npm run write-git-data diff --git a/packages/cli/test/unit/util/logger.test.ts b/packages/cli/test/unit/util/logger.test.ts index bddc86f2a483..fa17218bfd1c 100644 --- a/packages/cli/test/unit/util/logger.test.ts +++ b/packages/cli/test/unit/util/logger.test.ts @@ -1,7 +1,7 @@ import {describe, it, expect, vi, beforeEach, afterEach} from "vitest"; import {shouldDeleteLogFile} from "../../../src/util/logger.js"; -describe("shouldDeleteLogFile", function () { +describe("shouldDeleteLogFile", () => { const prefix = "beacon"; const extension = "log"; diff --git a/packages/cli/test/unit/validator/keys.test.ts b/packages/cli/test/unit/validator/keys.test.ts index c977c2242c33..6902d17b3883 100644 --- a/packages/cli/test/unit/validator/keys.test.ts +++ b/packages/cli/test/unit/validator/keys.test.ts @@ -10,7 +10,7 @@ describe("validator / signers / importKeystoreDefinitionsFromExternalDir", () => if (tmpDir) fs.rmSync(tmpDir, {recursive: true}); }); - it("should filter out deposit data files", function () { + it("should filter out deposit data files", () => { tmpDir = fs.mkdtempSync("cli-keystores-import-test"); // Populate dir diff --git a/packages/cli/test/utils/crucible/assertions/defaults/attestationCountAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/attestationCountAssertion.ts index 5d0f7a268f88..922ce80ae329 100644 --- a/packages/cli/test/utils/crucible/assertions/defaults/attestationCountAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/attestationCountAssertion.ts @@ -32,7 +32,7 @@ export const attestationsCountAssertion: Assertion<"attestationsCount", number, async assert({clock, store, epoch, node, dependantStores}) { const errors: AssertionResult[] = []; - const inclusionDelayStore = dependantStores["inclusionDelay"]; + const inclusionDelayStore = dependantStores.inclusionDelay; const startSlot = epoch === 0 ? 1 : clock.getFirstSlotOfEpoch(epoch); const endSlot = clock.getLastSlotOfEpoch(epoch); diff --git a/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts b/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts index 9659cc34e7bf..04c9b393d245 100644 --- a/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts @@ -17,7 +17,7 @@ export const nodeAssertion: Assertion<"node", {health: number; keyManagerKeys: s let keyManagerKeys: string[]; // There is an authentication issue with the lighthouse keymanager client - if (node.validator.client == ValidatorClient.Lighthouse || getAllKeys(node.validator.keys).length === 0) { + if (node.validator.client === ValidatorClient.Lighthouse || getAllKeys(node.validator.keys).length === 0) { keyManagerKeys = []; } else { const keys = (await node.validator.keyManager.listKeys()).value(); @@ -30,7 +30,7 @@ export const nodeAssertion: Assertion<"node", {health: number; keyManagerKeys: s const errors: AssertionResult[] = []; // There is an authentication issue with the lighthouse keymanager client - if (node.validator?.client == ValidatorClient.Lighthouse) return errors; + if (node.validator?.client === ValidatorClient.Lighthouse) return errors; const {health, keyManagerKeys} = store[slot]; diff --git a/packages/cli/test/utils/crucible/clients/beacon/lodestar.ts b/packages/cli/test/utils/crucible/clients/beacon/lodestar.ts index 3321401a21dd..2bc7c27ead41 100644 --- a/packages/cli/test/utils/crucible/clients/beacon/lodestar.ts +++ b/packages/cli/test/utils/crucible/clients/beacon/lodestar.ts @@ -58,11 +58,11 @@ export const generateLodestarBeaconNode: BeaconNodeGenerator = (o "--verbosity", "5", ...(mining ? ["--mine", "--miner.etherbase", EL_GENESIS_ACCOUNT] : []), - ...(mode == ExecutionStartMode.PreMerge ? ["--nodiscover"] : []), + ...(mode === ExecutionStartMode.PreMerge ? ["--nodiscover"] : []), ...clientOptions, ], env: {}, diff --git a/packages/cli/test/utils/crucible/tableReporter.ts b/packages/cli/test/utils/crucible/tableReporter.ts index d11fc9ca3fbc..d40be13ad6e8 100644 --- a/packages/cli/test/utils/crucible/tableReporter.ts +++ b/packages/cli/test/utils/crucible/tableReporter.ts @@ -33,9 +33,8 @@ export class TableReporter extends SimulationReporter // Print slots once, may be called twice for missed block timer if (slot <= this.lastPrintedSlot) { return; - } else { - this.lastPrintedSlot = slot; } + this.lastPrintedSlot = slot; if (slot <= 0) { return; @@ -59,12 +58,10 @@ export class TableReporter extends SimulationReporter const participation: {head: number; source: number; target: number}[] = []; for (const node of nodes) { - participation.push( - stores["attestationParticipation"][node.beacon.id][slot] ?? {head: 0, source: 0, target: 0} - ); + participation.push(stores.attestationParticipation[node.beacon.id][slot] ?? {head: 0, source: 0, target: 0}); const syncCommitteeParticipation: number[] = []; for (let slot = startSlot; slot <= endSlot; slot++) { - syncCommitteeParticipation.push(stores["syncCommitteeParticipation"][node.beacon.id][slot] ?? 0); + syncCommitteeParticipation.push(stores.syncCommitteeParticipation[node.beacon.id][slot] ?? 0); } nodesSyncParticipationAvg.push(avg(syncCommitteeParticipation)); } @@ -88,19 +85,19 @@ export class TableReporter extends SimulationReporter const peersCount: number[] = []; for (const node of nodes) { - const finalized = stores["finalized"][node.beacon.id][slot]; + const finalized = stores.finalized[node.beacon.id][slot]; if (!isNullish(finalized)) finalizedSlots.push(finalized); - const inclusionDelay = stores["inclusionDelay"][node.beacon.id][slot]; + const inclusionDelay = stores.inclusionDelay[node.beacon.id][slot]; if (!isNullish(inclusionDelay)) inclusionDelays.push(inclusionDelay); - const attestationsCount = stores["attestationsCount"][node.beacon.id][slot]; + const attestationsCount = stores.attestationsCount[node.beacon.id][slot]; if (!isNullish(attestationsCount)) attestationCounts.push(attestationsCount); - const head = stores["head"][node.beacon.id][slot]; + const head = stores.head[node.beacon.id][slot]; if (!isNullish(head)) heads.push(head); - const connectedPeerCount = stores["connectedPeerCount"][node.beacon.id][slot]; + const connectedPeerCount = stores.connectedPeerCount[node.beacon.id][slot]; if (!isNullish(connectedPeerCount)) peersCount.push(connectedPeerCount); } diff --git a/packages/cli/test/utils/crucible/utils/network.ts b/packages/cli/test/utils/crucible/utils/network.ts index 7f41b87aff04..a9a70b5561b4 100644 --- a/packages/cli/test/utils/crucible/utils/network.ts +++ b/packages/cli/test/utils/crucible/utils/network.ts @@ -78,9 +78,8 @@ export async function waitForNodeSyncStatus(env: Simulation, node: NodePair): Pr const result = (await node.beacon.api.node.getSyncingStatus()).value(); if (!result.isSyncing) { break; - } else { - await sleep(1000, env.options.controller.signal); } + await sleep(1000, env.options.controller.signal); } } diff --git a/packages/cli/test/utils/crucible/utils/paths.ts b/packages/cli/test/utils/crucible/utils/paths.ts index 9f0628e34656..4ff149d6f308 100644 --- a/packages/cli/test/utils/crucible/utils/paths.ts +++ b/packages/cli/test/utils/crucible/utils/paths.ts @@ -79,10 +79,15 @@ export const getNodeMountedPaths = => { return Object.entries(paths) - .map(([key, value]) => [ + .flatMap(([key, value]) => [ [key, value], [`${key}Mounted`, mount ? (value as string).replace(paths.rootDir, mountPath) : value], ]) - .flat() - .reduce((o, [key, value]) => ({...o, [key]: value as string}), {}) as MountedPaths; + .reduce( + (o, [key, value]) => { + o[key] = value as string; + return o; + }, + {} as Record + ) as MountedPaths; }; diff --git a/packages/cli/test/utils/crucible/utils/syncing.ts b/packages/cli/test/utils/crucible/utils/syncing.ts index d31575e74e5d..b720c6bf6ccc 100644 --- a/packages/cli/test/utils/crucible/utils/syncing.ts +++ b/packages/cli/test/utils/crucible/utils/syncing.ts @@ -184,8 +184,7 @@ export async function waitForNodeSyncStatus(env: Simulation, node: NodePair): Pr const result = (await node.beacon.api.node.getSyncingStatus()).value(); if (!result.isSyncing) { break; - } else { - await sleep(1000, env.options.controller.signal); } + await sleep(1000, env.options.controller.signal); } } diff --git a/packages/db/src/controller/level.ts b/packages/db/src/controller/level.ts index 084b577b6a01..82fbf631f7ae 100644 --- a/packages/db/src/controller/level.ts +++ b/packages/db/src/controller/level.ts @@ -78,11 +78,11 @@ export class LevelDbController implements DatabaseController 0: ${batchSize}`); if (batchSize > MAX_VALIDATORS_PER_COMMITTEE) throw Error("batchSize must be < MAX_VALIDATORS_PER_COMMITTEE"); diff --git a/packages/flare/src/cmds/selfSlashProposer.ts b/packages/flare/src/cmds/selfSlashProposer.ts index 14a270239268..dd9580232e71 100644 --- a/packages/flare/src/cmds/selfSlashProposer.ts +++ b/packages/flare/src/cmds/selfSlashProposer.ts @@ -52,7 +52,7 @@ export async function selfSlashProposerHandler(args: SelfSlashArgs): Promise 0: ${batchSize}`); // TODO: Ask the user to confirm the range and slash action diff --git a/packages/flare/src/util/format.ts b/packages/flare/src/util/format.ts index 0da0fa509be6..989472932ca6 100644 --- a/packages/flare/src/util/format.ts +++ b/packages/flare/src/util/format.ts @@ -8,8 +8,8 @@ export function parseRange(range: string): number[] { const [from, to] = range.split("..").map((n) => parseInt(n)); - if (isNaN(from)) throw Error(`Invalid range from isNaN '${range}'`); - if (isNaN(to)) throw Error(`Invalid range to isNaN '${range}'`); + if (Number.isNaN(from)) throw Error(`Invalid range from isNaN '${range}'`); + if (Number.isNaN(to)) throw Error(`Invalid range to isNaN '${range}'`); if (from > to) throw Error(`Invalid range from > to '${range}'`); const arr: number[] = []; diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index 1084ec8b8e00..dcc76441865e 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -1248,7 +1248,9 @@ export class ForkChoice implements IForkChoice { currentEpoch: epochNow, }, }); - } else if (!forceImport && targetEpoch + 1 < epochNow) { + } + + if (!forceImport && targetEpoch + 1 < epochNow) { throw new ForkChoiceError({ code: ForkChoiceErrorCode.INVALID_ATTESTATION, err: { @@ -1533,7 +1535,9 @@ export function assertValidTerminalPowBlock( throw Error( `Invalid terminal POW block: total difficulty not reached expected >= ${config.TERMINAL_TOTAL_DIFFICULTY}, actual = ${powBlock.totalDifficulty}` ); - } else if (!isParentTotalDifficultyValid) { + } + + if (!isParentTotalDifficultyValid) { throw Error( `Invalid terminal POW block parent: expected < ${config.TERMINAL_TOTAL_DIFFICULTY}, actual = ${powBlockParent.totalDifficulty}` ); diff --git a/packages/fork-choice/src/protoArray/computeDeltas.ts b/packages/fork-choice/src/protoArray/computeDeltas.ts index a3366fa738ae..c921e12f751e 100644 --- a/packages/fork-choice/src/protoArray/computeDeltas.ts +++ b/packages/fork-choice/src/protoArray/computeDeltas.ts @@ -26,8 +26,8 @@ export function computeDeltas( deltas.fill(0); // avoid creating new variables in the loop to potentially reduce GC pressure - let oldBalance, newBalance: number; - let currentIndex, nextIndex: number | null; + let oldBalance: number, newBalance: number; + let currentIndex: number | null, nextIndex: number | null; for (let vIndex = 0; vIndex < votes.length; vIndex++) { const vote = votes[vIndex]; diff --git a/packages/fork-choice/src/protoArray/protoArray.ts b/packages/fork-choice/src/protoArray/protoArray.ts index b8bb63837e36..82a8b2620880 100644 --- a/packages/fork-choice/src/protoArray/protoArray.ts +++ b/packages/fork-choice/src/protoArray/protoArray.ts @@ -304,9 +304,9 @@ export class ProtoArray { * EL is lazy (or buggy) with its LVH response. */ throw Error(`Unable to find latestValidExecHash=${latestValidExecHash} in the forkchoice`); - } else { - this.propagateInValidExecutionStatusByIndex(invalidateFromParentIndex, latestValidHashIndex, currentSlot); } + + this.propagateInValidExecutionStatusByIndex(invalidateFromParentIndex, latestValidHashIndex, currentSlot); } } @@ -431,7 +431,9 @@ export class ProtoArray { code: ProtoArrayErrorCode.INVALID_LVH_EXECUTION_RESPONSE, ...this.lvhError, }); - } else if (validNode.executionStatus === ExecutionStatus.Syncing) { + } + + if (validNode.executionStatus === ExecutionStatus.Syncing) { validNode.executionStatus = ExecutionStatus.Valid; } return validNode; @@ -808,10 +810,9 @@ export class ProtoArray { descendantRoot: blockRoot, ancestorSlot, }); - } else { - // Root is older or equal than queried slot, thus a skip slot. Return most recent root prior to slot. - return blockRoot; } + // Root is older or equal than queried slot, thus a skip slot. Return most recent root prior to slot. + return blockRoot; } /** diff --git a/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts b/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts index 40988a0e4a71..f47849136bff 100644 --- a/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts @@ -14,11 +14,9 @@ import { EpochDifference, DataAvailabilityStatus, } from "../../../src/index.js"; +import {getBlockRoot, getStateRoot} from "../../utils/index.js"; -const rootStateBytePrefix = 0xaa; -const rootBlockBytePrefix = 0xbb; - -describe("Forkchoice", function () { +describe("Forkchoice", () => { const genesisSlot = 0; const genesisEpoch = 0; const genesisRoot = "0x0000000000000000000000000000000000000000000000000000000000000000"; @@ -118,7 +116,7 @@ describe("Forkchoice", function () { } }; - it("getAllAncestorBlocks", function () { + it("getAllAncestorBlocks", () => { // Add block that is a finalized descendant. const block = getBlock(genesisSlot + 1); protoArr.onBlock(block, block.slot); @@ -175,20 +173,6 @@ describe("Forkchoice", function () { // TODO: more unit tests for other apis }); -export function getStateRoot(slot: number): RootHex { - const root = Buffer.alloc(32, 0x00); - root[0] = rootStateBytePrefix; - root[31] = slot; - return toHex(root); -} - -export function getBlockRoot(slot: number): RootHex { - const root = Buffer.alloc(32, 0x00); - root[0] = rootBlockBytePrefix; - root[31] = slot; - return toHex(root); -} - function range(from: number, toInclusive: number): number[] { const arr: number[] = []; for (let i = from; i <= toInclusive; i++) { diff --git a/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts b/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts index f603a4069b83..187834e6d63a 100644 --- a/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts @@ -13,11 +13,11 @@ import { DataAvailabilityStatus, } from "../../../src/index.js"; import {NotReorgedReason} from "../../../src/forkChoice/interface.js"; -import {getBlockRoot, getStateRoot} from "./forkChoice.test.js"; +import {getBlockRoot, getStateRoot} from "../../utils/index.js"; type ProtoBlockWithWeight = ProtoBlock & {weight: number}; // weight of the block itself -describe("Forkchoice / GetProposerHead", function () { +describe("Forkchoice / GetProposerHead", () => { const genesisSlot = 0; const genesisEpoch = 0; const genesisRoot = "0x0000000000000000000000000000000000000000000000000000000000000000"; diff --git a/packages/fork-choice/test/unit/forkChoice/utils.test.ts b/packages/fork-choice/test/unit/forkChoice/utils.test.ts index d8793206f4ba..44b0eb8b719b 100644 --- a/packages/fork-choice/test/unit/forkChoice/utils.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/utils.test.ts @@ -3,11 +3,11 @@ import {createChainForkConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; import {assertValidTerminalPowBlock, ExecutionStatus} from "../../../src/index.js"; -describe("assertValidTerminalPowBlock", function () { +describe("assertValidTerminalPowBlock", () => { const config = createChainForkConfig({TERMINAL_TOTAL_DIFFICULTY: BigInt(10)}); const block = ssz.bellatrix.BeaconBlock.defaultValue(); const executionStatus = ExecutionStatus.Valid; - it("should accept ttd >= genesis block as terminal without powBlockParent", function () { + it("should accept ttd >= genesis block as terminal without powBlockParent", () => { const powBlock = { blockHash: "0x" + "ab".repeat(32), // genesis powBlock will have zero parent hash @@ -19,7 +19,7 @@ describe("assertValidTerminalPowBlock", function () { ).not.toThrow(); }); - it("should require powBlockParent if powBlock not genesis", function () { + it("should require powBlockParent if powBlock not genesis", () => { const powBlock = { blockHash: "0x" + "ab".repeat(32), // genesis powBlock will have non zero parent hash @@ -31,7 +31,7 @@ describe("assertValidTerminalPowBlock", function () { ).toThrow(); }); - it("should require powBlock >= ttd", function () { + it("should require powBlock >= ttd", () => { const powBlock = { blockHash: "0x" + "ab".repeat(32), // genesis powBlock will have non zero parent hash @@ -43,7 +43,7 @@ describe("assertValidTerminalPowBlock", function () { ).toThrow(); }); - it("should require powBlockParent < ttd", function () { + it("should require powBlockParent < ttd", () => { const powBlock = { blockHash: "0x" + "ab".repeat(32), // genesis powBlock will have non zero parent hash @@ -55,7 +55,7 @@ describe("assertValidTerminalPowBlock", function () { ).toThrow(); }); - it("should accept powBlockParent < ttd and powBlock >= ttd", function () { + it("should accept powBlockParent < ttd and powBlock >= ttd", () => { const powBlock = { blockHash: "0x" + "ab".repeat(32), // genesis powBlock will have non zero parent hash diff --git a/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts b/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts index 9c06682ca351..b9b7f9c37b43 100644 --- a/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts +++ b/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts @@ -79,7 +79,11 @@ describe("getCommonAncestor", () => { it(`${nodeA} & ${nodeB} -> ${ancestor}`, () => { // biome-ignore lint/style/noNonNullAssertion: const ancestorNode = fc.getCommonAncestor(fc.getNode(nodeA)!, fc.getNode(nodeB)!); - expect(ancestorNode && ancestorNode.blockRoot).toBe(ancestor); + if (ancestor) { + expect(ancestorNode?.blockRoot).toBe(ancestor); + } else { + expect(ancestorNode).toBeNull(); + } }); } diff --git a/packages/fork-choice/test/utils/index.ts b/packages/fork-choice/test/utils/index.ts new file mode 100644 index 000000000000..8354a8c31d56 --- /dev/null +++ b/packages/fork-choice/test/utils/index.ts @@ -0,0 +1,19 @@ +import {RootHex} from "@lodestar/types"; +import {toHex} from "@lodestar/utils"; + +const rootStateBytePrefix = 0xaa; +const rootBlockBytePrefix = 0xbb; + +export function getStateRoot(slot: number): RootHex { + const root = Buffer.alloc(32, 0x00); + root[0] = rootStateBytePrefix; + root[31] = slot; + return toHex(root); +} + +export function getBlockRoot(slot: number): RootHex { + const root = Buffer.alloc(32, 0x00); + root[0] = rootBlockBytePrefix; + root[31] = slot; + return toHex(root); +} diff --git a/packages/light-client/src/spec/isBetterUpdate.ts b/packages/light-client/src/spec/isBetterUpdate.ts index 260d54434fba..00220cd6b5dd 100644 --- a/packages/light-client/src/spec/isBetterUpdate.ts +++ b/packages/light-client/src/spec/isBetterUpdate.ts @@ -28,49 +28,49 @@ export function isBetterUpdate(newUpdate: LightClientUpdateSummary, oldUpdate: L const oldNumActiveParticipants = oldUpdate.activeParticipants; const newHasSupermajority = newNumActiveParticipants * 3 >= SYNC_COMMITTEE_SIZE * 2; const oldHasSupermajority = oldNumActiveParticipants * 3 >= SYNC_COMMITTEE_SIZE * 2; - if (newHasSupermajority != oldHasSupermajority) { + if (newHasSupermajority !== oldHasSupermajority) { return newHasSupermajority; } - if (!newHasSupermajority && newNumActiveParticipants != oldNumActiveParticipants) { + if (!newHasSupermajority && newNumActiveParticipants !== oldNumActiveParticipants) { return newNumActiveParticipants > oldNumActiveParticipants; } // Compare presence of relevant sync committee const newHasRelevantSyncCommittee = newUpdate.isSyncCommitteeUpdate && - computeSyncPeriodAtSlot(newUpdate.attestedHeaderSlot) == computeSyncPeriodAtSlot(newUpdate.signatureSlot); + computeSyncPeriodAtSlot(newUpdate.attestedHeaderSlot) === computeSyncPeriodAtSlot(newUpdate.signatureSlot); const oldHasRelevantSyncCommittee = oldUpdate.isSyncCommitteeUpdate && - computeSyncPeriodAtSlot(oldUpdate.attestedHeaderSlot) == computeSyncPeriodAtSlot(oldUpdate.signatureSlot); - if (newHasRelevantSyncCommittee != oldHasRelevantSyncCommittee) { + computeSyncPeriodAtSlot(oldUpdate.attestedHeaderSlot) === computeSyncPeriodAtSlot(oldUpdate.signatureSlot); + if (newHasRelevantSyncCommittee !== oldHasRelevantSyncCommittee) { return newHasRelevantSyncCommittee; } // Compare indication of any finality const newHasFinality = newUpdate.isFinalityUpdate; const oldHasFinality = oldUpdate.isFinalityUpdate; - if (newHasFinality != oldHasFinality) { + if (newHasFinality !== oldHasFinality) { return newHasFinality; } // Compare sync committee finality if (newHasFinality) { const newHasSyncCommitteeFinality = - computeSyncPeriodAtSlot(newUpdate.finalizedHeaderSlot) == computeSyncPeriodAtSlot(newUpdate.attestedHeaderSlot); + computeSyncPeriodAtSlot(newUpdate.finalizedHeaderSlot) === computeSyncPeriodAtSlot(newUpdate.attestedHeaderSlot); const oldHasSyncCommitteeFinality = - computeSyncPeriodAtSlot(oldUpdate.finalizedHeaderSlot) == computeSyncPeriodAtSlot(oldUpdate.attestedHeaderSlot); - if (newHasSyncCommitteeFinality != oldHasSyncCommitteeFinality) { + computeSyncPeriodAtSlot(oldUpdate.finalizedHeaderSlot) === computeSyncPeriodAtSlot(oldUpdate.attestedHeaderSlot); + if (newHasSyncCommitteeFinality !== oldHasSyncCommitteeFinality) { return newHasSyncCommitteeFinality; } } // Tiebreaker 1: Sync committee participation beyond supermajority - if (newNumActiveParticipants != oldNumActiveParticipants) { + if (newNumActiveParticipants !== oldNumActiveParticipants) { return newNumActiveParticipants > oldNumActiveParticipants; } // Tiebreaker 2: Prefer older data (fewer changes to best) - if (newUpdate.attestedHeaderSlot != oldUpdate.attestedHeaderSlot) { + if (newUpdate.attestedHeaderSlot !== oldUpdate.attestedHeaderSlot) { return newUpdate.attestedHeaderSlot < oldUpdate.attestedHeaderSlot; } return newUpdate.signatureSlot < oldUpdate.signatureSlot; diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index d80b9bb7d9a1..36bc7098fcc5 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -96,16 +96,19 @@ export function upgradeLightClientHeader( const startUpgradeFromFork = Object.values(ForkName)[ForkSeq[headerFork] + 1]; switch (startUpgradeFromFork) { + // biome-ignore lint/suspicious/useDefaultSwitchClauseLast: We want default to evaluate at first to throw error early default: throw Error( `Invalid startUpgradeFromFork=${startUpgradeFromFork} for headerFork=${headerFork} in upgradeLightClientHeader to targetFork=${targetFork}` ); case ForkName.altair: + // biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here case ForkName.bellatrix: // Break if no further upgradation is required else fall through if (ForkSeq[targetFork] <= ForkSeq.bellatrix) break; + // biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here case ForkName.capella: (upgradedHeader as LightClientHeader).execution = ssz.capella.LightClientHeader.fields.execution.defaultValue(); @@ -115,6 +118,7 @@ export function upgradeLightClientHeader( // Break if no further upgradation is required else fall through if (ForkSeq[targetFork] <= ForkSeq.capella) break; + // biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here case ForkName.deneb: (upgradedHeader as LightClientHeader).execution.blobGasUsed = ssz.deneb.LightClientHeader.fields.execution.fields.blobGasUsed.defaultValue(); diff --git a/packages/light-client/src/utils/clock.ts b/packages/light-client/src/utils/clock.ts index 44b74b1b601b..efe210b620d8 100644 --- a/packages/light-client/src/utils/clock.ts +++ b/packages/light-client/src/utils/clock.ts @@ -39,7 +39,7 @@ export function timeUntilNextEpoch(config: Pick const msFromGenesis = Date.now() - genesisTime * 1000; if (msFromGenesis >= 0) { return milliSecondsPerEpoch - (msFromGenesis % milliSecondsPerEpoch); - } else { - return Math.abs(msFromGenesis % milliSecondsPerEpoch); } + + return Math.abs(msFromGenesis % milliSecondsPerEpoch); } diff --git a/packages/light-client/test/unit/isValidLightClientHeader.test.ts b/packages/light-client/test/unit/isValidLightClientHeader.test.ts index 8181c6a5def4..2bbbd1250961 100644 --- a/packages/light-client/test/unit/isValidLightClientHeader.test.ts +++ b/packages/light-client/test/unit/isValidLightClientHeader.test.ts @@ -4,7 +4,7 @@ import {LightClientHeader, ssz} from "@lodestar/types"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {isValidLightClientHeader} from "../../src/spec/utils.js"; -describe("isValidLightClientHeader", function () { +describe("isValidLightClientHeader", () => { const chainConfig = createChainForkConfig({ ...defaultChainConfig, ALTAIR_FORK_EPOCH: 0, @@ -87,10 +87,10 @@ describe("isValidLightClientHeader", function () { ["capella upgraded to deneb LC header", capellaUpgradedDenebHeader], ]; - testCases.forEach(([name, header]: [string, LightClientHeader]) => { - it(name, function () { + for (const [name, header] of testCases) { + it(name, () => { const isValid = isValidLightClientHeader(config, header); expect(isValid).toBe(true); }); - }); + } }); diff --git a/packages/light-client/test/unit/syncInMemory.test.ts b/packages/light-client/test/unit/syncInMemory.test.ts index 770827e86655..6118a1b4e61a 100644 --- a/packages/light-client/test/unit/syncInMemory.test.ts +++ b/packages/light-client/test/unit/syncInMemory.test.ts @@ -22,7 +22,7 @@ function getSyncCommittee( return syncCommitteeKeys; } -describe("syncInMemory", function () { +describe("syncInMemory", () => { // In browser test this process is taking more time than default 2000ms vi.setConfig({testTimeout: 10000}); @@ -39,9 +39,7 @@ describe("syncInMemory", function () { expect(sk.toPublicKey().toHex()).toBe( "0xaa1a1c26055a329817a5759d877a2795f9499b97d6056edde0eea39512f24e8bc874b4471f0501127abb1ea0d9f68ac1" ); - }); - beforeAll(() => { // Create a state that has as nextSyncCommittee the committee 2 const finalizedBlockSlot = SLOTS_PER_EPOCH * EPOCHS_PER_SYNC_COMMITTEE_PERIOD + 1; const headerBlockSlot = finalizedBlockSlot + 1; diff --git a/packages/light-client/test/unit/validation.test.ts b/packages/light-client/test/unit/validation.test.ts index 61442fb4bf8c..6ed3b714a690 100644 --- a/packages/light-client/test/unit/validation.test.ts +++ b/packages/light-client/test/unit/validation.test.ts @@ -15,7 +15,7 @@ import {assertValidLightClientUpdate} from "../../src/validation.js"; import {LightClientSnapshotFast, SyncCommitteeFast} from "../../src/types.js"; import {defaultBeaconBlockHeader, getSyncAggregateSigningRoot, signAndAggregate} from "../utils/utils.js"; -describe("validation", function () { +describe("validation", () => { // In browser test this process is taking more time than default 2000ms // specially on the CI vi.setConfig({testTimeout: 15000}); @@ -26,7 +26,7 @@ describe("validation", function () { let update: altair.LightClientUpdate; let snapshot: LightClientSnapshotFast; - beforeAll(function () { + beforeAll(() => { // Update slot must > snapshot slot // attestedHeaderSlot must == updateHeaderSlot + 1 const snapshotHeaderSlot = 1; diff --git a/packages/logger/src/browser.ts b/packages/logger/src/browser.ts index 65a0c2a6a64b..7f4972111459 100644 --- a/packages/logger/src/browser.ts +++ b/packages/logger/src/browser.ts @@ -57,7 +57,7 @@ class BrowserConsole extends Transport { constructor(opts: winston.transport.TransportStreamOptions | undefined) { super(opts); - this.level = opts?.level && this.levels.hasOwnProperty(opts.level) ? opts.level : "info"; + this.level = opts?.level && Object.prototype.hasOwnProperty.call(this.levels, opts.level) ? opts.level : "info"; } log(info: WinstonLogInfo, callback: () => void): void { diff --git a/packages/logger/src/env.ts b/packages/logger/src/env.ts index 201d91c69069..e81ae9613e15 100644 --- a/packages/logger/src/env.ts +++ b/packages/logger/src/env.ts @@ -6,20 +6,18 @@ import {LogFormat, TimestampFormat} from "./interface.js"; export function getEnvLogLevel(): LogLevel | null { if (process == null) return null; - if (process.env["LOG_LEVEL"]) return process.env["LOG_LEVEL"] as LogLevel; - if (process.env["DEBUG"]) return LogLevel.debug; - if (process.env["VERBOSE"]) return LogLevel.verbose; + if (process.env.LOG_LEVEL) return process.env.LOG_LEVEL as LogLevel; + if (process.env.DEBUG) return LogLevel.debug; + if (process.env.VERBOSE) return LogLevel.verbose; return null; } export function getEnvLogger(opts?: Partial): Logger { const level = opts?.level ?? getEnvLogLevel(); - const format = (opts?.format ?? process.env["LOG_FORMAT"]) as LogFormat; + const format = (opts?.format ?? process.env.LOG_FORMAT) as LogFormat; const timestampFormat = opts?.timestampFormat ?? - ((process.env["LOG_TIMESTAMP_FORMAT"] - ? {format: process.env["LOG_TIMESTAMP_FORMAT"]} - : undefined) as TimestampFormat); + ((process.env.LOG_TIMESTAMP_FORMAT ? {format: process.env.LOG_TIMESTAMP_FORMAT} : undefined) as TimestampFormat); if (level != null) { return getBrowserLogger({...opts, level, format, timestampFormat}); diff --git a/packages/logger/src/node.ts b/packages/logger/src/node.ts index 60ca87e0367c..fcd9c535dd9e 100644 --- a/packages/logger/src/node.ts +++ b/packages/logger/src/node.ts @@ -128,7 +128,7 @@ export class WinstonLoggerNode extends WinstonLogger implements LoggerNode { } static fromOpts(opts: LoggerNodeOpts, transports: winston.transport[]): WinstonLoggerNode { - return new WinstonLoggerNode(this.createWinstonInstance(opts, transports), opts); + return new WinstonLoggerNode(WinstonLoggerNode.createWinstonInstance(opts, transports), opts); } static fromNewTransports(opts: LoggerNodeOpts): WinstonLoggerNode { diff --git a/packages/logger/src/utils/json.ts b/packages/logger/src/utils/json.ts index f1919a38da8b..bab060cc8187 100644 --- a/packages/logger/src/utils/json.ts +++ b/packages/logger/src/utils/json.ts @@ -44,10 +44,9 @@ export function logCtxToJson(arg: unknown, depth = 0, fromError = false): LogDat if (arg instanceof LodestarError) { if (fromError) { return "[LodestarErrorCircular]"; - } else { - // Allow one extra depth level for LodestarError - metadata = logCtxToJson(arg.getMetadata(), depth - 1, true) as Record; } + // Allow one extra depth level for LodestarError + metadata = logCtxToJson(arg.getMetadata(), depth - 1, true) as Record; } else { metadata = {message: arg.message}; } @@ -105,10 +104,9 @@ export function logCtxToString(arg: unknown, depth = 0, fromError = false): stri if (arg instanceof LodestarError) { if (fromError) { return "[LodestarErrorCircular]"; - } else { - // Allow one extra depth level for LodestarError - metadata = logCtxToString(arg.getMetadata(), depth - 1, true); } + // Allow one extra depth level for LodestarError + metadata = logCtxToString(arg.getMetadata(), depth - 1, true); } else { metadata = arg.message; } diff --git a/packages/logger/src/winston.ts b/packages/logger/src/winston.ts index 4e6fbbecd6b2..b886894e6aba 100644 --- a/packages/logger/src/winston.ts +++ b/packages/logger/src/winston.ts @@ -42,7 +42,7 @@ export class WinstonLogger implements Logger { constructor(protected readonly winston: Winston) {} static fromOpts(options: Partial = {}, transports?: winston.transport[]): WinstonLogger { - return new WinstonLogger(this.createWinstonInstance(options, transports)); + return new WinstonLogger(WinstonLogger.createWinstonInstance(options, transports)); } static createWinstonInstance(options: Partial = {}, transports?: winston.transport[]): Winston { diff --git a/packages/logger/test/e2e/logger/workerLogs.test.ts b/packages/logger/test/e2e/logger/workerLogs.test.ts index 969cd84bc5ff..01ede8f6e4ec 100644 --- a/packages/logger/test/e2e/logger/workerLogs.test.ts +++ b/packages/logger/test/e2e/logger/workerLogs.test.ts @@ -9,7 +9,7 @@ import {LoggerWorker, getLoggerWorker} from "./workerLoggerHandler.js"; // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules const __dirname = path.dirname(fileURLToPath(import.meta.url)); -describe("worker logs", function () { +describe("worker logs", () => { vi.setConfig({testTimeout: 60_000}); const logFilepath = path.join(__dirname, "../../../test-logs/test_worker_logs.log"); diff --git a/packages/logger/test/unit/utils/json.test.ts b/packages/logger/test/unit/utils/json.test.ts index 4b91fd1995b5..7ca5604edf00 100644 --- a/packages/logger/test/unit/utils/json.test.ts +++ b/packages/logger/test/unit/utils/json.test.ts @@ -24,8 +24,10 @@ describe("Json helper", () => { {id: "symbol", arg: Symbol("foo"), json: "Symbol(foo)"}, // Functions + // biome-ignore lint/complexity/useArrowFunction: We need a function for the this test {id: "function", arg: function () {}, json: "function() {\n }"}, {id: "arrow function", arg: () => {}, json: "() => {\n }"}, + // biome-ignore lint/complexity/useArrowFunction: We need a function for the this test {id: "async function", arg: async function () {}, json: "async function() {\n }"}, {id: "async arrow function", arg: async () => {}, json: "async () => {\n }"}, @@ -160,7 +162,7 @@ describe("Json helper", () => { // Objects {id: "object of basic types", json: {a: 1, b: "a", c: root}, output: `a=1, b=a, c=${rootHex}`}, - {id: "object of objects", json: {a: {b: 1}}, output: `a=[object]`}, + {id: "object of objects", json: {a: {b: 1}}, output: "a=[object]"}, { id: "error metadata", json: { diff --git a/packages/params/src/json.ts b/packages/params/src/json.ts index 8d475e680f4d..9fe49a920424 100644 --- a/packages/params/src/json.ts +++ b/packages/params/src/json.ts @@ -50,7 +50,7 @@ function deserializePresetValue(valueStr: unknown, keyName: string): number { const value = parseInt(valueStr, 10); - if (isNaN(value)) { + if (Number.isNaN(value)) { throw Error(`Invalid ${keyName} value ${valueStr} expected number`); } diff --git a/packages/params/test/e2e/ensure-config-is-synced.test.ts b/packages/params/test/e2e/ensure-config-is-synced.test.ts index 12e4c2a35e55..2322b2e1ff10 100644 --- a/packages/params/test/e2e/ensure-config-is-synced.test.ts +++ b/packages/params/test/e2e/ensure-config-is-synced.test.ts @@ -10,15 +10,15 @@ import {loadConfigYaml} from "../yaml.js"; /** https://github.com/ethereum/consensus-specs/releases */ const specConfigCommit = "v1.5.0-alpha.3"; -describe("Ensure config is synced", function () { +describe("Ensure config is synced", () => { vi.setConfig({testTimeout: 60 * 1000}); - it("mainnet", async function () { + it("mainnet", async () => { const remotePreset = await downloadRemoteConfig("mainnet", specConfigCommit); assertCorrectPreset({...mainnetPreset}, remotePreset); }); - it("minimal", async function () { + it("minimal", async () => { const remotePreset = await downloadRemoteConfig("minimal", specConfigCommit); assertCorrectPreset({...minimalPreset}, remotePreset); }); diff --git a/packages/params/test/e2e/overridePreset.test.ts b/packages/params/test/e2e/overridePreset.test.ts index 12fa1fb095c6..df7afbbf84da 100644 --- a/packages/params/test/e2e/overridePreset.test.ts +++ b/packages/params/test/e2e/overridePreset.test.ts @@ -15,7 +15,7 @@ const exec = util.promisify(child.exec); // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules const __dirname = path.dirname(fileURLToPath(import.meta.url)); -describe("Override preset", function () { +describe("Override preset", () => { // Allow time for ts-node to compile Typescript source vi.setConfig({testTimeout: 30_000}); diff --git a/packages/params/test/e2e/setPreset.test.ts b/packages/params/test/e2e/setPreset.test.ts index 1e236b8f2d85..2108a4f23342 100644 --- a/packages/params/test/e2e/setPreset.test.ts +++ b/packages/params/test/e2e/setPreset.test.ts @@ -15,7 +15,7 @@ const exec = util.promisify(child.exec); // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules const __dirname = path.dirname(fileURLToPath(import.meta.url)); -describe("setPreset", function () { +describe("setPreset", () => { // Allow time for ts-node to compile Typescript source vi.setConfig({testTimeout: 30_000}); diff --git a/packages/params/test/yaml.ts b/packages/params/test/yaml.ts index d1bc72125923..f56016a4dbc0 100644 --- a/packages/params/test/yaml.ts +++ b/packages/params/test/yaml.ts @@ -8,9 +8,7 @@ export const schema = FAILSAFE_SCHEMA.extend({ implicit: [ new Type("tag:yaml.org,2002:str", { kind: "scalar", - construct: function (data) { - return data !== null ? data : ""; - }, + construct: (data) => (data !== null ? data : ""), }), ], }); diff --git a/packages/prover/src/cli/applyPreset.ts b/packages/prover/src/cli/applyPreset.ts index 4a79a1a4417b..f0c3d83c7751 100644 --- a/packages/prover/src/cli/applyPreset.ts +++ b/packages/prover/src/cli/applyPreset.ts @@ -82,6 +82,3 @@ function valueOfArg(argName: string): string | null { return null; } - -// Add empty export to make this a module -export {}; diff --git a/packages/prover/src/cli/cmds/start/options.ts b/packages/prover/src/cli/cmds/start/options.ts index bdf0670771ef..5366efd96f6e 100644 --- a/packages/prover/src/cli/cmds/start/options.ts +++ b/packages/prover/src/cli/cmds/start/options.ts @@ -57,9 +57,7 @@ export const startOptions: CliCommandOptions = { string: true, coerce: (urls: string[]): string[] => // Parse ["url1,url2"] to ["url1", "url2"] - urls - .map((item) => item.split(",")) - .flat(), + urls.flatMap((item) => item.split(",")), demandOption: true, group: "beacon", }, diff --git a/packages/prover/src/proof_provider/payload_store.ts b/packages/prover/src/proof_provider/payload_store.ts index 343ec63719f9..c891cb994da1 100644 --- a/packages/prover/src/proof_provider/payload_store.ts +++ b/packages/prover/src/proof_provider/payload_store.ts @@ -39,7 +39,7 @@ export class PayloadStore { const maxBlockNumberForFinalized = this.finalizedRoots.max; if (maxBlockNumberForFinalized === undefined) { - return; + return undefined; } const finalizedMaxRoot = this.finalizedRoots.get(maxBlockNumberForFinalized); diff --git a/packages/prover/src/utils/process.ts b/packages/prover/src/utils/process.ts index 80748544302c..75bb79516609 100644 --- a/packages/prover/src/utils/process.ts +++ b/packages/prover/src/utils/process.ts @@ -106,7 +106,6 @@ export async function processAndVerifyRequest({ if (responses.length === 1) { return responses[0]; - } else { - return responses; } + return responses; } diff --git a/packages/prover/src/web3_provider_inspector.ts b/packages/prover/src/web3_provider_inspector.ts index c81847b64d61..154a860d0922 100644 --- a/packages/prover/src/web3_provider_inspector.ts +++ b/packages/prover/src/web3_provider_inspector.ts @@ -68,7 +68,7 @@ export class Web3ProviderInspector { return; } - const index = this.providerTypes.findIndex((p) => p.name == indexOrName); + const index = this.providerTypes.findIndex((p) => p.name === indexOrName); if (index < 0) { throw Error(`Provider type '${indexOrName}' is not registered.`); } diff --git a/packages/prover/test/e2e/cli/cmds/start.test.ts b/packages/prover/test/e2e/cli/cmds/start.test.ts index 8ac71e1a1797..75773ac02d36 100644 --- a/packages/prover/test/e2e/cli/cmds/start.test.ts +++ b/packages/prover/test/e2e/cli/cmds/start.test.ts @@ -29,7 +29,7 @@ describe("prover/proxy", () => { const paramsFilePath = path.join("/tmp", "e2e-test-env", "params.json"); const web3: Web3 = new Web3(proxyUrl); - beforeAll(async function () { + beforeAll(async () => { await waitForCapellaFork(); await mkdir(path.dirname(paramsFilePath), {recursive: true}); await writeFile(paramsFilePath, JSON.stringify(chainConfigToJson(config as ChainConfig))); diff --git a/packages/prover/test/e2e/web3_batch_request.test.ts b/packages/prover/test/e2e/web3_batch_request.test.ts index e232208a15b3..6dae04a9c36d 100644 --- a/packages/prover/test/e2e/web3_batch_request.test.ts +++ b/packages/prover/test/e2e/web3_batch_request.test.ts @@ -5,7 +5,7 @@ import {createVerifiedExecutionProvider} from "../../src/web3_provider.js"; import {rpcUrl, beaconUrl, config, waitForCapellaFork, minCapellaTimeMs} from "../utils/e2e_env.js"; import {getVerificationFailedMessage} from "../../src/utils/json_rpc.js"; -describe("web3_batch_requests", function () { +describe("web3_batch_requests", () => { vi.setConfig({hookTimeout: minCapellaTimeMs}); let web3: Web3; diff --git a/packages/prover/test/e2e/web3_provider.test.ts b/packages/prover/test/e2e/web3_provider.test.ts index 3d670d7ed412..edb3bb09e2fb 100644 --- a/packages/prover/test/e2e/web3_provider.test.ts +++ b/packages/prover/test/e2e/web3_provider.test.ts @@ -5,7 +5,7 @@ import {LCTransport} from "../../src/interfaces.js"; import {createVerifiedExecutionProvider} from "../../src/web3_provider.js"; import {waitForCapellaFork, minCapellaTimeMs, rpcUrl, beaconUrl, config} from "../utils/e2e_env.js"; -describe("web3_provider", function () { +describe("web3_provider", () => { vi.setConfig({hookTimeout: minCapellaTimeMs}); beforeAll(async () => { diff --git a/packages/prover/test/unit/proof_provider/payload_store.test.ts b/packages/prover/test/unit/proof_provider/payload_store.test.ts index b482bb579e77..6bc1e4265205 100644 --- a/packages/prover/test/unit/proof_provider/payload_store.test.ts +++ b/packages/prover/test/unit/proof_provider/payload_store.test.ts @@ -53,7 +53,7 @@ const buildBlockResponse = ({ return apiResponse; }; -describe("proof_provider/payload_store", function () { +describe("proof_provider/payload_store", () => { let api: ApiClient & {beacon: MockedObject}; let logger: Logger; let store: PayloadStore; diff --git a/packages/reqresp/src/encoders/responseDecode.ts b/packages/reqresp/src/encoders/responseDecode.ts index d55b283df5e6..0dde5bcdc95e 100644 --- a/packages/reqresp/src/encoders/responseDecode.ts +++ b/packages/reqresp/src/encoders/responseDecode.ts @@ -110,7 +110,7 @@ export async function readResultHeader(bufferedSource: BufferedSource): Promise< */ export async function readErrorMessage(bufferedSource: BufferedSource): Promise { // Read at least 256 or wait for the stream to end - let length; + let length: number | undefined; for await (const buffer of bufferedSource) { // Wait for next chunk with bytes or for the stream to end // Note: The entire is expected to be in the same chunk @@ -121,6 +121,7 @@ export async function readErrorMessage(bufferedSource: BufferedSource): Promise< length = buffer.length; } + // biome-ignore lint/complexity/useLiteralKeys: It is a private attribute const bytes = bufferedSource["buffer"].slice(0, length); try { diff --git a/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/uncompress.ts b/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/uncompress.ts index 69d9ea44d834..8530bc7aeb88 100644 --- a/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/uncompress.ts +++ b/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/uncompress.ts @@ -51,9 +51,8 @@ export class SnappyFramesUncompress { } if (result.length === 0) { return null; - } else { - return result; } + return result; } reset(): void { diff --git a/packages/reqresp/src/rate_limiter/ReqRespRateLimiter.ts b/packages/reqresp/src/rate_limiter/ReqRespRateLimiter.ts index 66dfbd9f1cc7..7bb87cbd1fb2 100644 --- a/packages/reqresp/src/rate_limiter/ReqRespRateLimiter.ts +++ b/packages/reqresp/src/rate_limiter/ReqRespRateLimiter.ts @@ -68,9 +68,9 @@ export class ReqRespRateLimiter { if ((byPeer && !byPeer.allows(peerIdStr, requestCount)) || (total && !total.allows(null, requestCount))) { this.opts?.onRateLimit?.(peerId, protocolID); return false; - } else { - return true; } + + return true; } prune(peerId: PeerId): void { diff --git a/packages/reqresp/src/request/index.ts b/packages/reqresp/src/request/index.ts index b79df24e2adf..9a374db3b8be 100644 --- a/packages/reqresp/src/request/index.ts +++ b/packages/reqresp/src/request/index.ts @@ -106,9 +106,8 @@ export async function* sendRequest( ).catch((e: Error) => { if (e instanceof TimeoutError) { throw new RequestError({code: RequestErrorCode.DIAL_TIMEOUT}); - } else { - throw new RequestError({code: RequestErrorCode.DIAL_ERROR, error: e}); } + throw new RequestError({code: RequestErrorCode.DIAL_ERROR, error: e}); }); // TODO: Does the TTFB timer start on opening stream or after receiving request @@ -133,9 +132,8 @@ export async function* sendRequest( if (e instanceof TimeoutError) { throw new RequestError({code: RequestErrorCode.REQUEST_TIMEOUT}); - } else { - throw new RequestError({code: RequestErrorCode.REQUEST_ERROR, error: e as Error}); } + throw new RequestError({code: RequestErrorCode.REQUEST_ERROR, error: e as Error}); } ); @@ -209,8 +207,7 @@ export async function* sendRequest( if (e instanceof ResponseError) { throw new RequestError(responseStatusErrorToRequestError(e)); - } else { - throw e; } + throw e; } } diff --git a/packages/reqresp/src/response/index.ts b/packages/reqresp/src/response/index.ts index ad13ba8b9359..d9f0e1b1806a 100644 --- a/packages/reqresp/src/response/index.ts +++ b/packages/reqresp/src/response/index.ts @@ -77,9 +77,8 @@ export async function handleRequest({ ).catch((e: unknown) => { if (e instanceof TimeoutError) { throw e; // Let outter catch (_e) {} re-type the error as SERVER_ERROR - } else { - throw new ResponseError(RespStatus.INVALID_REQUEST, (e as Error).message); } + throw new ResponseError(RespStatus.INVALID_REQUEST, (e as Error).message); }); logger.debug("Req received", logCtx); @@ -134,8 +133,7 @@ export async function handleRequest({ if (responseError !== null) { logger.verbose("Resp error", logCtx, responseError); throw responseError; - } else { - // NOTE: Only log once per request to verbose, intermediate steps to debug - logger.verbose("Resp done", logCtx); } + // NOTE: Only log once per request to verbose, intermediate steps to debug + logger.verbose("Resp done", logCtx); } diff --git a/packages/reqresp/src/utils/abortableSource.ts b/packages/reqresp/src/utils/abortableSource.ts index 17ea836bcac3..127339bbd597 100644 --- a/packages/reqresp/src/utils/abortableSource.ts +++ b/packages/reqresp/src/utils/abortableSource.ts @@ -53,9 +53,9 @@ export function abortableSource( if (result.done) { return; - } else { - yield result.value; } + + yield result.value; } } catch (err) { // End the iterator if it is a generator diff --git a/packages/reqresp/src/utils/bufferedSource.ts b/packages/reqresp/src/utils/bufferedSource.ts index 569cc217ea23..e5daca1d2f67 100644 --- a/packages/reqresp/src/utils/bufferedSource.ts +++ b/packages/reqresp/src/utils/bufferedSource.ts @@ -35,11 +35,11 @@ export class BufferedSource { if (done === true) { that.isDone = true; return {done: true, value: undefined}; - } else { - // Concat new chunk and return a reference to its BufferList instance - that.buffer.append(chunk); - return {done: false, value: that.buffer}; } + + // Concat new chunk and return a reference to its BufferList instance + that.buffer.append(chunk); + return {done: false, value: that.buffer}; }, }; } diff --git a/packages/reqresp/test/unit/encodingStrategies/sszSnappy/snappyFrames/uncompress.test.ts b/packages/reqresp/test/unit/encodingStrategies/sszSnappy/snappyFrames/uncompress.test.ts index b47621082a65..dc01a1952142 100644 --- a/packages/reqresp/test/unit/encodingStrategies/sszSnappy/snappyFrames/uncompress.test.ts +++ b/packages/reqresp/test/unit/encodingStrategies/sszSnappy/snappyFrames/uncompress.test.ts @@ -4,7 +4,7 @@ import {pipe} from "it-pipe"; import {SnappyFramesUncompress} from "../../../../../src/encodingStrategies/sszSnappy/snappyFrames/uncompress.js"; import {encodeSnappy} from "../../../../../src/encodingStrategies/sszSnappy/snappyFrames/compress.js"; -describe("encodingStrategies / sszSnappy / snappy frames / uncompress", function () { +describe("encodingStrategies / sszSnappy / snappy frames / uncompress", () => { it("should work with short input", () => new Promise((done) => { const testData = "Small test data"; @@ -12,7 +12,7 @@ describe("encodingStrategies / sszSnappy / snappy frames / uncompress", function const decompress = new SnappyFramesUncompress(); - void pipe(compressIterable, async function (source) { + void pipe(compressIterable, async (source) => { for await (const data of source) { const result = decompress.uncompress(new Uint8ArrayList(data)); if (result) { @@ -30,7 +30,7 @@ describe("encodingStrategies / sszSnappy / snappy frames / uncompress", function let result = Buffer.alloc(0); const decompress = new SnappyFramesUncompress(); - void pipe(compressIterable, async function (source) { + void pipe(compressIterable, async (source) => { for await (const data of source) { // testData will come compressed as two or more chunks result = Buffer.concat([ @@ -45,13 +45,13 @@ describe("encodingStrategies / sszSnappy / snappy frames / uncompress", function }); })); - it("should detect malformed input", function () { + it("should detect malformed input", () => { const decompress = new SnappyFramesUncompress(); expect(() => decompress.uncompress(new Uint8ArrayList(Buffer.alloc(32, 5)))).toThrow(); }); - it("should return null if not enough data", function () { + it("should return null if not enough data", () => { const decompress = new SnappyFramesUncompress(); expect(decompress.uncompress(new Uint8ArrayList(Buffer.alloc(3, 1)))).toBe(null); diff --git a/packages/reqresp/test/utils/errors.ts b/packages/reqresp/test/utils/errors.ts index 16c098f2f57c..e4697a6d97d5 100644 --- a/packages/reqresp/test/utils/errors.ts +++ b/packages/reqresp/test/utils/errors.ts @@ -53,9 +53,10 @@ export function expectLodestarError(err1: LodestarErro export function getErrorMetadata(err: LodestarError | Error | unknown): unknown { if (err instanceof LodestarError) { return mapValues(err.getMetadata(), (value) => getErrorMetadata(value as any)); - } else if (err instanceof Error) { + } + + if (err instanceof Error) { return err.message; - } else { - return err; } + return err; } diff --git a/packages/spec-test-util/src/downloadTests.ts b/packages/spec-test-util/src/downloadTests.ts index e13478934927..bca6a8ac52c9 100644 --- a/packages/spec-test-util/src/downloadTests.ts +++ b/packages/spec-test-util/src/downloadTests.ts @@ -51,9 +51,8 @@ export async function downloadGenericSpecTests( if (existingVersion === specVersion) { return log(`version ${specVersion} already downloaded`); - } else { - log(`Downloading new version ${specVersion}`); } + log(`Downloading new version ${specVersion}`); if (fs.existsSync(outputDir)) { log(`Cleaning existing version ${existingVersion} at ${outputDir}`); diff --git a/packages/spec-test-util/src/single.ts b/packages/spec-test-util/src/single.ts index af77d45f6242..888c87e3ffa8 100644 --- a/packages/spec-test-util/src/single.ts +++ b/packages/spec-test-util/src/single.ts @@ -124,7 +124,7 @@ export function describeDirectorySpecTest let testCase = loadInputFiles(testSubDirPath, options, meta); if (options.mapToTestCase) testCase = options.mapToTestCase(testCase); - if (options.shouldSkip && options.shouldSkip(testCase, testName, 0)) { + if (options.shouldSkip?.(testCase, testName, 0)) { context.skip(); return; } @@ -157,7 +157,8 @@ function loadInputFiles( meta?: TestCase["meta"] ): TestCase { const testCase: any = {}; - fs.readdirSync(directory) + const files = fs + .readdirSync(directory) .map((name) => path.join(directory, name)) .filter((file) => { if (isDirectory(file)) { @@ -170,33 +171,37 @@ function loadInputFiles( options.inputTypes[name] = inputType; const extension = inputType.type as string; return file.endsWith(extension); - }) - .forEach((file) => { - const inputName = path.basename(file).replace(".ssz_snappy", "").replace(".ssz", "").replace(".yaml", ""); - const inputType = getInputType(file); - testCase[inputName] = deserializeInputFile(file, inputName, inputType, options, meta); - switch (inputType) { - case InputType.SSZ: - testCase[`${inputName}_raw`] = fs.readFileSync(file); - break; - case InputType.SSZ_SNAPPY: - testCase[`${inputName}_raw`] = uncompress(fs.readFileSync(file)); - break; - } - if (!options.inputProcessing) throw Error("inputProcessing is not defined"); - if (options.inputProcessing[inputName] !== undefined) { - testCase[inputName] = options.inputProcessing[inputName](testCase[inputName]); - } }); + for (const file of files) { + const inputName = path.basename(file).replace(".ssz_snappy", "").replace(".ssz", "").replace(".yaml", ""); + const inputType = getInputType(file); + testCase[inputName] = deserializeInputFile(file, inputName, inputType, options, meta); + switch (inputType) { + case InputType.SSZ: + testCase[`${inputName}_raw`] = fs.readFileSync(file); + break; + case InputType.SSZ_SNAPPY: + testCase[`${inputName}_raw`] = uncompress(fs.readFileSync(file)); + break; + } + if (!options.inputProcessing) throw Error("inputProcessing is not defined"); + if (options.inputProcessing[inputName] !== undefined) { + testCase[inputName] = options.inputProcessing[inputName](testCase[inputName]); + } + } return testCase as TestCase; } function getInputType(filename: string): InputType { if (filename.endsWith(InputType.YAML)) { return InputType.YAML; - } else if (filename.endsWith(InputType.SSZ_SNAPPY)) { + } + + if (filename.endsWith(InputType.SSZ_SNAPPY)) { return InputType.SSZ_SNAPPY; - } else if (filename.endsWith(InputType.SSZ)) { + } + + if (filename.endsWith(InputType.SSZ)) { return InputType.SSZ; } throw new Error(`Could not get InputType from ${filename}`); @@ -211,7 +216,9 @@ function deserializeInputFile( ): any { if (inputType === InputType.YAML) { return loadYaml(fs.readFileSync(file, "utf8")); - } else if (inputType === InputType.SSZ || inputType === InputType.SSZ_SNAPPY) { + } + + if (inputType === InputType.SSZ || inputType === InputType.SSZ_SNAPPY) { const sszTypes = options.getSszTypes ? options.getSszTypes(meta) : options.sszTypes; if (!sszTypes) throw Error("sszTypes is not defined"); let data = fs.readFileSync(file); @@ -239,9 +246,8 @@ function deserializeInputFile( throw Error("BeaconState type has no deserializeToViewDU method"); } return sszType.deserializeToViewDU(data); - } else { - return sszType.deserialize(data); } + return sszType.deserialize(data); } } diff --git a/packages/state-transition/src/block/isValidIndexedAttestation.ts b/packages/state-transition/src/block/isValidIndexedAttestation.ts index 33d92a208260..8c7502ceedb5 100644 --- a/packages/state-transition/src/block/isValidIndexedAttestation.ts +++ b/packages/state-transition/src/block/isValidIndexedAttestation.ts @@ -18,9 +18,8 @@ export function isValidIndexedAttestation( if (verifySignature) { return verifySignatureSet(getIndexedAttestationSignatureSet(state, indexedAttestation)); - } else { - return true; } + return true; } export function isValidIndexedAttestationBigint( @@ -34,9 +33,8 @@ export function isValidIndexedAttestationBigint( if (verifySignature) { return verifySignatureSet(getIndexedAttestationBigintSignatureSet(state, indexedAttestation)); - } else { - return true; } + return true; } /** diff --git a/packages/state-transition/src/block/processAttestationPhase0.ts b/packages/state-transition/src/block/processAttestationPhase0.ts index ba6bc9089693..e2b32bbbbee8 100644 --- a/packages/state-transition/src/block/processAttestationPhase0.ts +++ b/packages/state-transition/src/block/processAttestationPhase0.ts @@ -91,13 +91,13 @@ export function validateAttestation(fork: ForkSeq, state: CachedBeaconStateAllFo if (committeeIndices.length === 0) { throw Error("Attestation should have at least one committee bit set"); - } else { - const lastCommitteeIndex = committeeIndices[committeeIndices.length - 1]; - if (lastCommitteeIndex >= committeeCount) { - throw new Error( - `Attestation committee index exceeds committee count: lastCommitteeIndex=${lastCommitteeIndex} numCommittees=${committeeCount}` - ); - } + } + + const lastCommitteeIndex = committeeIndices[committeeIndices.length - 1]; + if (lastCommitteeIndex >= committeeCount) { + throw new Error( + `Attestation committee index exceeds committee count: lastCommitteeIndex=${lastCommitteeIndex} numCommittees=${committeeCount}` + ); } // Get total number of attestation participant of every committee specified @@ -133,9 +133,8 @@ export function isTimelyTarget(fork: ForkSeq, inclusionDistance: Slot): boolean // post deneb attestation is valid till end of next epoch for target if (fork >= ForkSeq.deneb) { return true; - } else { - return inclusionDistance <= SLOTS_PER_EPOCH; } + return inclusionDistance <= SLOTS_PER_EPOCH; } export function checkpointToStr(checkpoint: phase0.Checkpoint): string { diff --git a/packages/state-transition/src/block/processEth1Data.ts b/packages/state-transition/src/block/processEth1Data.ts index 3d1927744328..92ab147aa772 100644 --- a/packages/state-transition/src/block/processEth1Data.ts +++ b/packages/state-transition/src/block/processEth1Data.ts @@ -58,9 +58,8 @@ export function becomesNewEth1Data( // The +1 is to account for the `eth1Data` supplied to the function. if ((sameVotesCount + 1) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD) { return true; - } else { - return false; } + return false; } function isEqualEth1DataView( diff --git a/packages/state-transition/src/block/processSyncCommittee.ts b/packages/state-transition/src/block/processSyncCommittee.ts index 70c918ed60bf..5f81a984b677 100644 --- a/packages/state-transition/src/block/processSyncCommittee.ts +++ b/packages/state-transition/src/block/processSyncCommittee.ts @@ -96,9 +96,8 @@ export function getSyncCommitteeSignatureSet( // https://github.com/ethereum/eth2.0-specs/blob/30f2a076377264677e27324a8c3c78c590ae5e20/specs/altair/bls.md#eth2_fast_aggregate_verify if (byteArrayEquals(signature, G2_POINT_AT_INFINITY)) { return null; - } else { - throw Error("Empty sync committee signature is not infinity"); } + throw Error("Empty sync committee signature is not infinity"); } const domain = state.config.getDomain(state.slot, DOMAIN_SYNC_COMMITTEE, previousSlot); diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 5601162b2c2a..66ce12b82d18 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -957,20 +957,19 @@ export class EpochCache { const validatorIndices = this.getBeaconCommittee(data.slot, data.index); return aggregationBits.intersectValues(validatorIndices); - } else { - const {aggregationBits, committeeBits, data} = attestation as electra.Attestation; + } + const {aggregationBits, committeeBits, data} = attestation as electra.Attestation; - // There is a naming conflict on the term `committeeIndices` - // In Lodestar it usually means a list of validator indices of participants in a committee - // In the spec it means a list of committee indices according to committeeBits - // This `committeeIndices` refers to the latter - // TODO Electra: resolve the naming conflicts - const committeeIndices = committeeBits.getTrueBitIndexes(); + // There is a naming conflict on the term `committeeIndices` + // In Lodestar it usually means a list of validator indices of participants in a committee + // In the spec it means a list of committee indices according to committeeBits + // This `committeeIndices` refers to the latter + // TODO Electra: resolve the naming conflicts + const committeeIndices = committeeBits.getTrueBitIndexes(); - const validatorIndices = this.getBeaconCommittees(data.slot, committeeIndices); + const validatorIndices = this.getBeaconCommittees(data.slot, committeeIndices); - return aggregationBits.intersectValues(validatorIndices); - } + return aggregationBits.intersectValues(validatorIndices); } getCommitteeAssignments( @@ -1030,9 +1029,8 @@ export class EpochCache { getValidatorIndex(pubkey: Uint8Array): ValidatorIndex | null { if (this.isPostElectra()) { return this.pubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)) ?? null; - } else { - return this.pubkey2index.get(pubkey); } + return this.pubkey2index.get(pubkey); } /** @@ -1072,12 +1070,11 @@ export class EpochCache { // Repeated insert. metrics?.finalizedPubkeyDuplicateInsert.inc(); return; - } else { - // attempt to insert the same pubkey with different index, should never happen. - throw Error( - `inserted existing pubkey into finalizedPubkey2index cache with a different index, index=${index} priorIndex=${existingIndex}` - ); } + // attempt to insert the same pubkey with different index, should never happen. + throw Error( + `inserted existing pubkey into finalizedPubkey2index cache with a different index, index=${index} priorIndex=${existingIndex}` + ); } this.pubkey2index.set(pubkey, index); diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 5412675352e9..3eeeb285b660 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -254,9 +254,11 @@ export function isCachedBeaconState( // This cache is populated during epoch transition, and should be preserved for performance. // If the cache is missing too often, means that our clone strategy is not working well. export function isStateValidatorsNodesPopulated(state: CachedBeaconStateAllForks): boolean { + // biome-ignore lint/complexity/useLiteralKeys: It is a private attribute return state.validators["nodesPopulated"] === true; } export function isStateBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean { + // biome-ignore lint/complexity/useLiteralKeys: It is a private attribute return state.balances["nodesPopulated"] === true; } diff --git a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts index bef3ec0b2724..1cd9e17efbad 100644 --- a/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingBalanceDeposits.ts @@ -41,14 +41,13 @@ export function processPendingBalanceDeposits(state: CachedBeaconStateElectra, c if (processedAmount + amount > availableForProcessing) { // Deposit does not fit in the churn, no more deposit processing in this epoch. break; - } else { - // Deposit fits in the churn, process it. Increase balance and consume churn. - increaseBalance(state, depositIndex, Number(amount)); - if (cachedBalances) { - cachedBalances[depositIndex] += Number(amount); - } - processedAmount = processedAmount + amount; } + // Deposit fits in the churn, process it. Increase balance and consume churn. + increaseBalance(state, depositIndex, Number(amount)); + if (cachedBalances) { + cachedBalances[depositIndex] += Number(amount); + } + processedAmount = processedAmount + amount; } // Regardless of how the deposit was handled, we move on in the queue. nextDepositIndex++; diff --git a/packages/state-transition/src/metrics.ts b/packages/state-transition/src/metrics.ts index a5e5463231fa..ac558a1be139 100644 --- a/packages/state-transition/src/metrics.ts +++ b/packages/state-transition/src/metrics.ts @@ -74,9 +74,11 @@ export function onPostStateMetrics(postState: CachedBeaconStateAllForks, metrics // This cache is populated during epoch transition, and should be preserved for performance. // If the cache is missing too often, means that our clone strategy is not working well. function isValidatorsNodesPopulated(state: CachedBeaconStateAllForks): boolean { + // biome-ignore lint/complexity/useLiteralKeys: It is a private attribute return state.validators["nodesPopulated"] === true; } function isBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean { + // biome-ignore lint/complexity/useLiteralKeys: It is a private attribute return state.balances["nodesPopulated"] === true; } diff --git a/packages/state-transition/src/signatureSets/attesterSlashings.ts b/packages/state-transition/src/signatureSets/attesterSlashings.ts index 8088c2522282..36f31d97e083 100644 --- a/packages/state-transition/src/signatureSets/attesterSlashings.ts +++ b/packages/state-transition/src/signatureSets/attesterSlashings.ts @@ -8,9 +8,9 @@ export function getAttesterSlashingsSignatureSets( state: CachedBeaconStateAllForks, signedBlock: SignedBeaconBlock ): ISignatureSet[] { - return signedBlock.message.body.attesterSlashings - .map((attesterSlashing) => getAttesterSlashingSignatureSets(state, attesterSlashing)) - .flat(1); + return signedBlock.message.body.attesterSlashings.flatMap((attesterSlashing) => + getAttesterSlashingSignatureSets(state, attesterSlashing) + ); } /** Get signature sets from a single AttesterSlashing object */ diff --git a/packages/state-transition/src/signatureSets/proposerSlashings.ts b/packages/state-transition/src/signatureSets/proposerSlashings.ts index 8a004225111d..b0c1aa465bd5 100644 --- a/packages/state-transition/src/signatureSets/proposerSlashings.ts +++ b/packages/state-transition/src/signatureSets/proposerSlashings.ts @@ -35,7 +35,7 @@ export function getProposerSlashingsSignatureSets( state: CachedBeaconStateAllForks, signedBlock: SignedBeaconBlock ): ISignatureSet[] { - return signedBlock.message.body.proposerSlashings - .map((proposerSlashing) => getProposerSlashingSignatureSets(state, proposerSlashing)) - .flat(1); + return signedBlock.message.body.proposerSlashings.flatMap((proposerSlashing) => + getProposerSlashingSignatureSets(state, proposerSlashing) + ); } diff --git a/packages/state-transition/src/slot/upgradeStateToAltair.ts b/packages/state-transition/src/slot/upgradeStateToAltair.ts index cfe43e097939..22ab8b13882c 100644 --- a/packages/state-transition/src/slot/upgradeStateToAltair.ts +++ b/packages/state-transition/src/slot/upgradeStateToAltair.ts @@ -92,6 +92,7 @@ export function upgradeStateToAltair(statePhase0: CachedBeaconStatePhase0): Cach // // TODO: This could only drop the caches of index 15,16. However this would couple this code tightly with SSZ ViewDU // internals. If the cache is not cleared, consuming the ViewDU instance could break in strange ways. + // biome-ignore lint/complexity/useLiteralKeys: It is a protected attribute stateAltair["clearCache"](); // TODO: describe issue. Compute progressive target balances diff --git a/packages/state-transition/src/slot/upgradeStateToCapella.ts b/packages/state-transition/src/slot/upgradeStateToCapella.ts index ce27a17bf9b0..30a0701e58e8 100644 --- a/packages/state-transition/src/slot/upgradeStateToCapella.ts +++ b/packages/state-transition/src/slot/upgradeStateToCapella.ts @@ -64,6 +64,7 @@ export function upgradeStateToCapella(stateBellatrix: CachedBeaconStateBellatrix // Commit new added fields ViewDU to the root node stateCapella.commit(); // Clear cache to ensure the cache of bellatrix fields is not used by new capella fields + // biome-ignore lint/complexity/useLiteralKeys: It is a protected attribute stateCapella["clearCache"](); return stateCapella; diff --git a/packages/state-transition/src/slot/upgradeStateToDeneb.ts b/packages/state-transition/src/slot/upgradeStateToDeneb.ts index 53be75f72ad8..2344a8d4e08e 100644 --- a/packages/state-transition/src/slot/upgradeStateToDeneb.ts +++ b/packages/state-transition/src/slot/upgradeStateToDeneb.ts @@ -34,6 +34,7 @@ export function upgradeStateToDeneb(stateCapella: CachedBeaconStateCapella): Cac stateDeneb.commit(); // Clear cache to ensure the cache of capella fields is not used by new deneb fields + // biome-ignore lint/complexity/useLiteralKeys: It is a protected attribute stateDeneb["clearCache"](); return stateDeneb; diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 0bd36a909b46..b7cdde86a479 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -112,6 +112,7 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache // Commit new added fields ViewDU to the root node stateElectra.commit(); // Clear cache to ensure the cache of deneb fields is not used by new ELECTRA fields + // biome-ignore lint/complexity/useLiteralKeys: It is a protected attribute stateElectra["clearCache"](); return stateElectra; @@ -154,6 +155,7 @@ export function upgradeStateToElectraOriginal(stateDeneb: CachedBeaconStateDeneb // Commit new added fields ViewDU to the root node stateElectra.commit(); // Clear cache to ensure the cache of deneb fields is not used by new ELECTRA fields + // biome-ignore lint/complexity/useLiteralKeys: It is a protected attribute stateElectra["clearCache"](); return stateElectra; diff --git a/packages/state-transition/src/util/blindedBlock.ts b/packages/state-transition/src/util/blindedBlock.ts index ceda91c94bb1..1793ff37255e 100644 --- a/packages/state-transition/src/util/blindedBlock.ts +++ b/packages/state-transition/src/util/blindedBlock.ts @@ -102,12 +102,11 @@ export function parseExecutionPayloadAndBlobsBundle(data: ExecutionPayload | Exe } { if (isExecutionPayloadAndBlobsBundle(data)) { return data; - } else { - return { - executionPayload: data, - blobsBundle: null, - }; } + return { + executionPayload: data, + blobsBundle: null, + }; } export function reconstructFullBlockOrContents( @@ -128,7 +127,6 @@ export function reconstructFullBlockOrContents( } return {signedBlock, ...contents} as SignedBeaconBlockOrContents; - } else { - return signedBlock as SignedBeaconBlockOrContents; } + return signedBlock as SignedBeaconBlockOrContents; } diff --git a/packages/state-transition/src/util/computeAnchorCheckpoint.ts b/packages/state-transition/src/util/computeAnchorCheckpoint.ts index e2efc18952c2..e37ffc2c632d 100644 --- a/packages/state-transition/src/util/computeAnchorCheckpoint.ts +++ b/packages/state-transition/src/util/computeAnchorCheckpoint.ts @@ -9,8 +9,8 @@ export function computeAnchorCheckpoint( config: ChainForkConfig, anchorState: BeaconStateAllForks ): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader} { - let blockHeader; - let root; + let blockHeader: phase0.BeaconBlockHeader; + let root: Uint8Array; const blockTypes = config.getForkTypes(anchorState.latestBlockHeader.slot); if (anchorState.latestBlockHeader.slot === GENESIS_SLOT) { diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index e8ef93c515d2..4370a13c783c 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -15,10 +15,8 @@ export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: if (state.eth1DepositIndex < eth1DataIndexLimit) { return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); - } else { - return 0; } - } else { - return Math.min(MAX_DEPOSITS, eth1DataToUse.depositCount - state.eth1DepositIndex); + return 0; } + return Math.min(MAX_DEPOSITS, eth1DataToUse.depositCount - state.eth1DepositIndex); } diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index b9243ebe7874..deed64bd6c51 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -71,13 +71,13 @@ export function isMergeTransitionComplete(state: BeaconStateExecutions): boolean // TODO: Performance ssz.bellatrix.ExecutionPayloadHeader.defaultValue() ); - } else { - return !ssz.capella.ExecutionPayloadHeader.equals( - state.latestExecutionPayloadHeader, - // TODO: Performance - ssz.capella.ExecutionPayloadHeader.defaultValue() - ); } + + return !ssz.capella.ExecutionPayloadHeader.equals( + state.latestExecutionPayloadHeader, + // TODO: Performance + ssz.capella.ExecutionPayloadHeader.defaultValue() + ); } /** Type guard for bellatrix.BeaconState */ @@ -112,11 +112,13 @@ export function getFullOrBlindedPayloadFromBody( ): ExecutionPayload | ExecutionPayloadHeader { if (isBlindedBeaconBlockBody(body)) { return body.executionPayloadHeader; - } else if ((body as bellatrix.BeaconBlockBody).executionPayload !== undefined) { + } + + if ((body as bellatrix.BeaconBlockBody).executionPayload !== undefined) { return (body as bellatrix.BeaconBlockBody).executionPayload; - } else { - throw Error("Not full or blinded beacon block"); } + + throw Error("Not full or blinded beacon block"); } export function isCapellaPayload( diff --git a/packages/state-transition/src/util/loadState/loadValidator.ts b/packages/state-transition/src/util/loadState/loadValidator.ts index dcf5051c9c6d..406c848ef089 100644 --- a/packages/state-transition/src/util/loadState/loadValidator.ts +++ b/packages/state-transition/src/util/loadState/loadValidator.ts @@ -17,9 +17,8 @@ export function loadValidator( newValidatorValue[field] = seedValidator[field]; } return ssz.phase0.Validator.toViewDU(newValidatorValue); - } else { - return ssz.phase0.Validator.deserializeToViewDU(newValidatorBytes); } + return ssz.phase0.Validator.deserializeToViewDU(newValidatorBytes); } /** diff --git a/packages/state-transition/src/util/shufflingDecisionRoot.ts b/packages/state-transition/src/util/shufflingDecisionRoot.ts index 10af814e9af3..5a6c500d3987 100644 --- a/packages/state-transition/src/util/shufflingDecisionRoot.ts +++ b/packages/state-transition/src/util/shufflingDecisionRoot.ts @@ -12,11 +12,10 @@ import {computeStartSlotAtEpoch} from "./epoch.js"; */ export function proposerShufflingDecisionRoot(state: CachedBeaconStateAllForks): Root | null { const decisionSlot = proposerShufflingDecisionSlot(state); - if (state.slot == decisionSlot) { + if (state.slot === decisionSlot) { return null; - } else { - return getBlockRootAtSlot(state, decisionSlot); } + return getBlockRootAtSlot(state, decisionSlot); } /** @@ -37,11 +36,10 @@ function proposerShufflingDecisionSlot(state: CachedBeaconStateAllForks): Slot { */ export function attesterShufflingDecisionRoot(state: CachedBeaconStateAllForks, requestedEpoch: Epoch): Root | null { const decisionSlot = attesterShufflingDecisionSlot(state, requestedEpoch); - if (state.slot == decisionSlot) { + if (state.slot === decisionSlot) { return null; - } else { - return getBlockRootAtSlot(state, decisionSlot); } + return getBlockRootAtSlot(state, decisionSlot); } /** @@ -75,7 +73,6 @@ function attesterShufflingDecisionEpoch(state: CachedBeaconStateAllForks, reques if (requestedEpoch < currentEpoch) { throw Error(`EpochTooLow: current ${currentEpoch} requested ${requestedEpoch}`); - } else { - throw Error(`EpochTooHigh: current ${currentEpoch} requested ${requestedEpoch}`); } + throw Error(`EpochTooHigh: current ${currentEpoch} requested ${requestedEpoch}`); } diff --git a/packages/state-transition/src/util/validator.ts b/packages/state-transition/src/util/validator.ts index ebad21d9d25c..bf79f9264342 100644 --- a/packages/state-transition/src/util/validator.ts +++ b/packages/state-transition/src/util/validator.ts @@ -45,9 +45,8 @@ export function getActiveValidatorIndices(state: BeaconStateAllForks, epoch: Epo export function getActivationChurnLimit(config: ChainForkConfig, fork: ForkSeq, activeValidatorCount: number): number { if (fork >= ForkSeq.deneb) { return Math.min(config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT, getChurnLimit(config, activeValidatorCount)); - } else { - return getChurnLimit(config, activeValidatorCount); } + return getChurnLimit(config, activeValidatorCount); } export function getChurnLimit(config: ChainForkConfig, activeValidatorCount: number): number { @@ -79,9 +78,8 @@ export function getMaxEffectiveBalance(withdrawalCredentials: Uint8Array): numbe // Compounding withdrawal credential only available since Electra if (hasCompoundingWithdrawalCredential(withdrawalCredentials)) { return MAX_EFFECTIVE_BALANCE_ELECTRA; - } else { - return MIN_ACTIVATION_BALANCE; } + return MIN_ACTIVATION_BALANCE; } export function getActiveBalance(state: CachedBeaconStateElectra, validatorIndex: ValidatorIndex): number { diff --git a/packages/state-transition/test/perf/block/util.ts b/packages/state-transition/test/perf/block/util.ts index baa86dcac6a5..441c67deb198 100644 --- a/packages/state-transition/test/perf/block/util.ts +++ b/packages/state-transition/test/perf/block/util.ts @@ -206,7 +206,9 @@ function getDeposits(preState: CachedBeaconStateAllForks, count: number): phase0 // Fill depositRootViewDU up to depositCount // Instead of actually filling it, just mutate the length to allow .set() + // biome-ignore lint/complexity/useLiteralKeys: It is a protected attribute depositRootViewDU["_length"] = depositCount + count; + // biome-ignore lint/complexity/useLiteralKeys: It is a protected attribute depositRootViewDU["dirtyLength"] = true; for (let i = 0; i < count; i++) { diff --git a/packages/state-transition/test/perf/csv.ts b/packages/state-transition/test/perf/csv.ts index d54b277d707c..2f47fd79f05d 100644 --- a/packages/state-transition/test/perf/csv.ts +++ b/packages/state-transition/test/perf/csv.ts @@ -41,7 +41,7 @@ export function readCsv>(filepath: string): T[] for (let i = 0; i < headers.length; i++) { const str = valuesRow[i]; const num = parseInt(str); - value[headers[i] as keyof T] = (isNaN(num) ? str : num) as T[keyof T]; + value[headers[i] as keyof T] = (Number.isNaN(num) ? str : num) as T[keyof T]; } values[j] = value; } diff --git a/packages/state-transition/test/perf/dataStructures/arrayish.test.ts b/packages/state-transition/test/perf/dataStructures/arrayish.test.ts index 5b6af0d989b6..353f81951aa7 100644 --- a/packages/state-transition/test/perf/dataStructures/arrayish.test.ts +++ b/packages/state-transition/test/perf/dataStructures/arrayish.test.ts @@ -104,7 +104,7 @@ describe("Array", () => { let arr: number[]; - before(function () { + before(() => { arr = createArray(n); }); diff --git a/packages/state-transition/test/perf/misc/aggregationBits.test.ts b/packages/state-transition/test/perf/misc/aggregationBits.test.ts index 7954f6a06a71..a0578970dfe9 100644 --- a/packages/state-transition/test/perf/misc/aggregationBits.test.ts +++ b/packages/state-transition/test/perf/misc/aggregationBits.test.ts @@ -12,7 +12,7 @@ describe("aggregationBits", () => { let indexes: number[]; let bitlistTree: BitArray; - before(function () { + before(() => { const aggregationBits = BitArray.fromBoolArray(Array.from({length: len}, () => true)); bitlistTree = ssz.phase0.CommitteeBits.toViewDU(aggregationBits); indexes = Array.from({length: len}, () => 165432); diff --git a/packages/state-transition/test/perf/misc/arrayCreation.test.ts b/packages/state-transition/test/perf/misc/arrayCreation.test.ts index c6a3cf29ed8e..4568948c678d 100644 --- a/packages/state-transition/test/perf/misc/arrayCreation.test.ts +++ b/packages/state-transition/test/perf/misc/arrayCreation.test.ts @@ -1,4 +1,4 @@ -describe.skip("array creation", function () { +describe.skip("array creation", () => { const testCases: {id: string; fn: (n: number) => void}[] = [ { id: "Array.from(() => 0)", diff --git a/packages/state-transition/test/perf/misc/proxy.test.ts b/packages/state-transition/test/perf/misc/proxy.test.ts index 6a3536a12de5..08618a1727e2 100644 --- a/packages/state-transition/test/perf/misc/proxy.test.ts +++ b/packages/state-transition/test/perf/misc/proxy.test.ts @@ -12,9 +12,8 @@ describe("Proxy cost", () => { get(target, p) { if (p === "length") { return target.length; - } else { - return target[p as unknown as number]; } + return target[p as unknown as number]; }, }); diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index 7a0bfb29efb3..0f47c241f8f9 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -194,7 +194,7 @@ export function generatePerfTestCachedStatePhase0(opts?: {goBackOneSlot: boolean ) as CachedBeaconStatePhase0; phase0CachedState23638.slot += 1; } - const resultingState = opts && opts.goBackOneSlot ? phase0CachedState23637 : phase0CachedState23638; + const resultingState = opts?.goBackOneSlot ? phase0CachedState23637 : phase0CachedState23638; return resultingState.clone(); } @@ -241,7 +241,7 @@ export function generatePerfTestCachedStateAltair(opts?: { ) as CachedBeaconStateAltair; altairCachedState23638.slot += 1; } - const resultingState = opts && opts.goBackOneSlot ? altairCachedState23637 : altairCachedState23638; + const resultingState = opts?.goBackOneSlot ? altairCachedState23637 : altairCachedState23638; return resultingState.clone(); } diff --git a/packages/state-transition/test/perf/util/signingRoot.test.ts b/packages/state-transition/test/perf/util/signingRoot.test.ts index 96684c753364..1d308c2e3e43 100644 --- a/packages/state-transition/test/perf/util/signingRoot.test.ts +++ b/packages/state-transition/test/perf/util/signingRoot.test.ts @@ -15,7 +15,7 @@ import {computeSigningRoot} from "../../../src/util/signingRoot.js"; ✔ toHexString serialized data 727592.3 ops/s 1.374396 us/op - 6916 runs 10.0 s ✔ Buffer.toString(base64) 2570800 ops/s 388.9840 ns/op - 24628 runs 10.1 s */ -describe("computeSigningRoot", function () { +describe("computeSigningRoot", () => { setBenchOpts({ minMs: 10_000, }); diff --git a/packages/state-transition/test/unit/util/aggregator.test.ts b/packages/state-transition/test/unit/util/aggregator.test.ts index 6a9d0a45a2c7..58c2b0afbf58 100644 --- a/packages/state-transition/test/unit/util/aggregator.test.ts +++ b/packages/state-transition/test/unit/util/aggregator.test.ts @@ -8,7 +8,7 @@ import { } from "@lodestar/params"; import {isAggregatorFromCommitteeLength, isSyncCommitteeAggregator} from "../../../src/util/aggregator.js"; -describe("isAttestationAggregator", function () { +describe("isAttestationAggregator", () => { const committeeLength = 130; beforeAll(() => { @@ -19,7 +19,7 @@ describe("isAttestationAggregator", function () { }); }); - it("should be false", function () { + it("should be false", () => { const result = isAggregatorFromCommitteeLength( committeeLength, fromHexString( @@ -29,7 +29,7 @@ describe("isAttestationAggregator", function () { expect(result).toBe(false); }); - it("should be true", function () { + it("should be true", () => { const result = isAggregatorFromCommitteeLength( committeeLength, fromHexString( @@ -40,7 +40,7 @@ describe("isAttestationAggregator", function () { }); }); -describe("isSyncCommitteeAggregator", function () { +describe("isSyncCommitteeAggregator", () => { beforeAll(() => { expect({ SYNC_COMMITTEE_SIZE, @@ -53,7 +53,7 @@ describe("isSyncCommitteeAggregator", function () { }); }); - it("should be false", function () { + it("should be false", () => { const result = isSyncCommitteeAggregator( fromHexString( "0x8191d16330837620f0ed85d0d3d52af5b56f7cec12658fa391814251d4b32977eb2e6ca055367354fd63175f8d1d2d7b0678c3c482b738f96a0df40bd06450d99c301a659b8396c227ed781abb37a1604297922219374772ab36b46b84817036" @@ -63,7 +63,7 @@ describe("isSyncCommitteeAggregator", function () { }); // NOTE: Invalid sig, bruteforced last characters to get a true result - it("should be true", function () { + it("should be true", () => { const result = isSyncCommitteeAggregator( fromHexString( "0xa8f8bb92931234ca6d8a34530526bcd6a4cfa3bf33bd0470200dc8fa3ebdc3ba24bc8c6e994d58a0f884eb24336d746c01a29693ed0354c0862c2d5de5859e3f58747045182844d267ba232058f7df1867a406f63a1eb8afec0cf3f00a115142" diff --git a/packages/state-transition/test/unit/util/validator.test.ts b/packages/state-transition/test/unit/util/validator.test.ts index 65727126742d..203adf9d8ba3 100644 --- a/packages/state-transition/test/unit/util/validator.test.ts +++ b/packages/state-transition/test/unit/util/validator.test.ts @@ -49,7 +49,7 @@ describe("isActiveValidator", () => { describe("isSlashableValidator", () => { let validator: phase0.Validator; - beforeEach(function () { + beforeEach(() => { validator = generateValidator(); }); diff --git a/packages/state-transition/test/unit/util/weakSubjectivity.test.ts b/packages/state-transition/test/unit/util/weakSubjectivity.test.ts index 5f5c784e975a..ce9f02b5ed2f 100644 --- a/packages/state-transition/test/unit/util/weakSubjectivity.test.ts +++ b/packages/state-transition/test/unit/util/weakSubjectivity.test.ts @@ -4,7 +4,7 @@ import {computeWeakSubjectivityPeriodFromConstituents} from "../../../src/util/w import {getChurnLimit} from "../../../src/util/validator.js"; describe("weak subjectivity tests", () => { - describe("computeWeakSubjectivityPeriodFromConstituents", function () { + describe("computeWeakSubjectivityPeriodFromConstituents", () => { const balance28 = 28; const balance32 = 32; diff --git a/packages/state-transition/test/utils/beforeValue.ts b/packages/state-transition/test/utils/beforeValue.ts index 6a2f5ee86945..6eaa0846b155 100644 --- a/packages/state-transition/test/utils/beforeValue.ts +++ b/packages/state-transition/test/utils/beforeValue.ts @@ -14,23 +14,21 @@ export type LazyValue = {value: T}; export function beforeValue(fn: () => T | Promise, timeout?: number): LazyValue { let value: T = null as unknown as T; - beforeAll(async function () { + beforeAll(async () => { value = await fn(); }, timeout ?? 300_000); return new Proxy<{value: T}>( {value}, { - get: function (_target, prop) { + get: (_target, prop) => { if (prop === "value") { if (value === null) { throw Error("beforeValue has not yet run the before() block"); - } else { - return value; } - } else { - return undefined; + return value; } + return undefined; }, } ); diff --git a/packages/state-transition/test/utils/beforeValueMocha.ts b/packages/state-transition/test/utils/beforeValueMocha.ts index d078357bd3b4..daac7c915d0c 100644 --- a/packages/state-transition/test/utils/beforeValueMocha.ts +++ b/packages/state-transition/test/utils/beforeValueMocha.ts @@ -20,16 +20,15 @@ export function beforeValue(fn: () => T | Promise, timeout?: number): Lazy return new Proxy<{value: T}>( {value}, { - get: function (_target, prop) { + get: (_target, prop) => { if (prop === "value") { if (value === null) { throw Error("beforeValue has not yet run the before() block"); - } else { - return value; } - } else { - return undefined; + return value; } + + return undefined; }, } ); diff --git a/packages/state-transition/test/utils/rand.ts b/packages/state-transition/test/utils/rand.ts index 988146ac4bf4..d3dc3af278cc 100644 --- a/packages/state-transition/test/utils/rand.ts +++ b/packages/state-transition/test/utils/rand.ts @@ -3,7 +3,7 @@ * Source https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript */ export function mulberry32(a: number) { - return function () { + return () => { a += 0x6d2b79f5; let t = a; t = Math.imul(t ^ (t >>> 15), t | 1); diff --git a/packages/state-transition/test/utils/testFileCache.ts b/packages/state-transition/test/utils/testFileCache.ts index 28741bf932c5..5283a6f87fa1 100644 --- a/packages/state-transition/test/utils/testFileCache.ts +++ b/packages/state-transition/test/utils/testFileCache.ts @@ -41,23 +41,23 @@ export async function getNetworkCachedState( if (fs.existsSync(filepath)) { const stateSsz = fs.readFileSync(filepath); return createCachedBeaconStateTest(config.getForkTypes(slot).BeaconState.deserializeToViewDU(stateSsz), config); - } else { - const stateSsz = await tryEach([ - () => downloadTestFile(fileId), - () => { - const client = getClient( - {baseUrl: getInfuraBeaconUrl(network), globalInit: {timeoutMs: timeout ?? 300_000}}, - {config} - ); - return client.debug.getStateV2({stateId: slot}).then((r) => { - return r.ssz(); - }); - }, - ]); - - fs.writeFileSync(filepath, stateSsz); - return createCachedBeaconStateTest(config.getForkTypes(slot).BeaconState.deserializeToViewDU(stateSsz), config); } + + const stateSsz = await tryEach([ + () => downloadTestFile(fileId), + () => { + const client = getClient( + {baseUrl: getInfuraBeaconUrl(network), globalInit: {timeoutMs: timeout ?? 300_000}}, + {config} + ); + return client.debug.getStateV2({stateId: slot}).then((r) => { + return r.ssz(); + }); + }, + ]); + + fs.writeFileSync(filepath, stateSsz); + return createCachedBeaconStateTest(config.getForkTypes(slot).BeaconState.deserializeToViewDU(stateSsz), config); } /** @@ -76,22 +76,22 @@ export async function getNetworkCachedBlock( if (fs.existsSync(filepath)) { const blockSsz = fs.readFileSync(filepath); return config.getForkTypes(slot).SignedBeaconBlock.deserialize(blockSsz); - } else { - const blockSsz = await tryEach([ - () => downloadTestFile(fileId), - async () => { - const client = getClient( - {baseUrl: getInfuraBeaconUrl(network), globalInit: {timeoutMs: timeout ?? 300_000}}, - {config} - ); - - return (await client.beacon.getBlockV2({blockId: slot})).ssz(); - }, - ]); - - fs.writeFileSync(filepath, blockSsz); - return config.getForkTypes(slot).SignedBeaconBlock.deserialize(blockSsz); } + + const blockSsz = await tryEach([ + () => downloadTestFile(fileId), + async () => { + const client = getClient( + {baseUrl: getInfuraBeaconUrl(network), globalInit: {timeoutMs: timeout ?? 300_000}}, + {config} + ); + + return (await client.beacon.getBlockV2({blockId: slot})).ssz(); + }, + ]); + + fs.writeFileSync(filepath, blockSsz); + return config.getForkTypes(slot).SignedBeaconBlock.deserialize(blockSsz); } async function downloadTestFile(fileId: string): Promise { diff --git a/packages/test-utils/src/cli.ts b/packages/test-utils/src/cli.ts index c081a65e03c2..a7b2a248bc7e 100644 --- a/packages/test-utils/src/cli.ts +++ b/packages/test-utils/src/cli.ts @@ -12,7 +12,7 @@ import { // We need to make it easy for the user to pass the args for the CLI // yargs treat `["--preset minimal"] as a single arg, so we need to split it ["--preset", "minimal"] function parseArgs(args: string[]): string[] { - return args.map((a) => a.split(" ")).flat(); + return args.flatMap((a) => a.split(" ")); } type CommandRunOptions = { @@ -28,6 +28,7 @@ export async function runCliCommand( opts: CommandRunOptions = {timeoutMs: 1000} ): Promise { return wrapTimeout( + // biome-ignore lint/suspicious/noAsyncPromiseExecutor: We want to resolve with parser call back not on main promise new Promise(async (resolve, reject) => { try { await cli diff --git a/packages/types/src/phase0/validator.ts b/packages/types/src/phase0/validator.ts index 3c2f72aac509..a6ec0fb18103 100644 --- a/packages/types/src/phase0/validator.ts +++ b/packages/types/src/phase0/validator.ts @@ -1,6 +1,7 @@ import {ByteViews, ContainerNodeStructType, ValueOfFields} from "@chainsafe/ssz"; import * as primitiveSsz from "../primitive/sszTypes.js"; +// biome-ignore lint/suspicious/noShadowRestrictedNames: We explicitly want `Boolean` name to be imported const {Boolean, Bytes32, UintNum64, BLSPubkey, EpochInf} = primitiveSsz; // this is to work with uint32, see https://github.com/ChainSafe/ssz/blob/ssz-v0.15.1/packages/ssz/src/type/uint.ts diff --git a/packages/types/src/primitive/sszTypes.ts b/packages/types/src/primitive/sszTypes.ts index 376e17c3f1b6..0b5156eaf24d 100644 --- a/packages/types/src/primitive/sszTypes.ts +++ b/packages/types/src/primitive/sszTypes.ts @@ -1,6 +1,7 @@ import {ByteVectorType, UintNumberType, UintBigintType, BooleanType} from "@chainsafe/ssz"; import {ExecutionAddressType} from "../utils/executionAddress.js"; +// biome-ignore lint/suspicious/noShadowRestrictedNames: We explicitly want this name for variable export const Boolean = new BooleanType(); export const Byte = new UintNumberType(1); export const Bytes4 = new ByteVectorType(4); diff --git a/packages/types/src/utils/validatorStatus.ts b/packages/types/src/utils/validatorStatus.ts index aa8171fbbbd2..9e72c39d9df2 100644 --- a/packages/types/src/utils/validatorStatus.ts +++ b/packages/types/src/utils/validatorStatus.ts @@ -24,7 +24,9 @@ export function getValidatorStatus(validator: phase0.Validator, currentEpoch: Ep if (validator.activationEpoch > currentEpoch) { if (validator.activationEligibilityEpoch === FAR_FUTURE_EPOCH) { return "pending_initialized"; - } else if (validator.activationEligibilityEpoch < FAR_FUTURE_EPOCH) { + } + + if (validator.activationEligibilityEpoch < FAR_FUTURE_EPOCH) { return "pending_queued"; } } @@ -32,7 +34,9 @@ export function getValidatorStatus(validator: phase0.Validator, currentEpoch: Ep if (validator.activationEpoch <= currentEpoch && currentEpoch < validator.exitEpoch) { if (validator.exitEpoch === FAR_FUTURE_EPOCH) { return "active_ongoing"; - } else if (validator.exitEpoch < FAR_FUTURE_EPOCH) { + } + + if (validator.exitEpoch < FAR_FUTURE_EPOCH) { return validator.slashed ? "active_slashed" : "active_exiting"; } } diff --git a/packages/types/test/unit/blinded.test.ts b/packages/types/test/unit/blinded.test.ts index 3a4b346d29bf..3d087b610b2d 100644 --- a/packages/types/test/unit/blinded.test.ts +++ b/packages/types/test/unit/blinded.test.ts @@ -2,7 +2,7 @@ import {describe, it, expect} from "vitest"; import {ForkName, isForkExecution} from "@lodestar/params"; import {ssz} from "../../src/index.js"; -describe("blinded data structures", function () { +describe("blinded data structures", () => { it("should have the same number of fields as non-blinded", () => { const blindedTypes = [ {a: "BlindedBeaconBlockBody" as const, b: "BeaconBlockBody" as const}, diff --git a/packages/types/test/unit/phase0/sszTypes.test.ts b/packages/types/test/unit/phase0/sszTypes.test.ts index 0cda0fc888f6..4bdb2031e5ea 100644 --- a/packages/types/test/unit/phase0/sszTypes.test.ts +++ b/packages/types/test/unit/phase0/sszTypes.test.ts @@ -5,7 +5,7 @@ import {ValidatorType} from "../../../src/phase0/validator.js"; const ValidatorContainer = new ContainerType(ValidatorType, {typeName: "Validator", jsonCase: "eth2"}); -describe("Validator ssz types", function () { +describe("Validator ssz types", () => { it("should serialize to the same value", () => { const seedValidator = { activationEligibilityEpoch: 10, diff --git a/packages/types/test/unit/ssz.test.ts b/packages/types/test/unit/ssz.test.ts index b5c972a8f471..41e4e0bbd23b 100644 --- a/packages/types/test/unit/ssz.test.ts +++ b/packages/types/test/unit/ssz.test.ts @@ -1,7 +1,7 @@ import {describe, it, expect} from "vitest"; import {ssz} from "../../src/index.js"; -describe("size", function () { +describe("size", () => { it("should calculate correct minSize and maxSize", () => { const minSize = ssz.phase0.BeaconState.minSize; const maxSize = ssz.phase0.BeaconState.maxSize; @@ -11,8 +11,8 @@ describe("size", function () { }); }); -describe("container serialization/deserialization field casing(s)", function () { - it("AttesterSlashing", function () { +describe("container serialization/deserialization field casing(s)", () => { + it("AttesterSlashing", () => { const test = { attestation1: ssz.phase0.IndexedAttestation.defaultValue(), attestation2: ssz.phase0.IndexedAttestation.defaultValue(), @@ -27,7 +27,7 @@ describe("container serialization/deserialization field casing(s)", function () expect(back).toEqual(json); }); - it("ProposerSlashing", function () { + it("ProposerSlashing", () => { const test = { signedHeader1: ssz.phase0.SignedBeaconBlockHeader.defaultValue(), signedHeader2: ssz.phase0.SignedBeaconBlockHeader.defaultValue(), diff --git a/packages/types/test/unit/validatorStatus.test.ts b/packages/types/test/unit/validatorStatus.test.ts index 8d04c0f98e3d..b5bd34004bdc 100644 --- a/packages/types/test/unit/validatorStatus.test.ts +++ b/packages/types/test/unit/validatorStatus.test.ts @@ -2,8 +2,8 @@ import {describe, it, expect} from "vitest"; import {getValidatorStatus} from "../../src/utils/validatorStatus.js"; import {phase0} from "../../src/types.js"; -describe("getValidatorStatus", function () { - it("should return PENDING_INITIALIZED", function () { +describe("getValidatorStatus", () => { + it("should return PENDING_INITIALIZED", () => { const validator = { activationEpoch: 1, activationEligibilityEpoch: Infinity, @@ -12,7 +12,7 @@ describe("getValidatorStatus", function () { const status = getValidatorStatus(validator, currentEpoch); expect(status).toBe("pending_initialized"); }); - it("should return PENDING_QUEUED", function () { + it("should return PENDING_QUEUED", () => { const validator = { activationEpoch: 1, activationEligibilityEpoch: 101010101101010, @@ -21,7 +21,7 @@ describe("getValidatorStatus", function () { const status = getValidatorStatus(validator, currentEpoch); expect(status).toBe("pending_queued"); }); - it("should return ACTIVE_ONGOING", function () { + it("should return ACTIVE_ONGOING", () => { const validator = { activationEpoch: 1, exitEpoch: Infinity, @@ -30,7 +30,7 @@ describe("getValidatorStatus", function () { const status = getValidatorStatus(validator, currentEpoch); expect(status).toBe("active_ongoing"); }); - it("should return ACTIVE_SLASHED", function () { + it("should return ACTIVE_SLASHED", () => { const validator = { activationEpoch: 1, exitEpoch: 101010101101010, @@ -40,7 +40,7 @@ describe("getValidatorStatus", function () { const status = getValidatorStatus(validator, currentEpoch); expect(status).toBe("active_slashed"); }); - it("should return ACTIVE_EXITING", function () { + it("should return ACTIVE_EXITING", () => { const validator = { activationEpoch: 1, exitEpoch: 101010101101010, @@ -50,7 +50,7 @@ describe("getValidatorStatus", function () { const status = getValidatorStatus(validator, currentEpoch); expect(status).toBe("active_exiting"); }); - it("should return EXITED_SLASHED", function () { + it("should return EXITED_SLASHED", () => { const validator = { exitEpoch: 1, withdrawableEpoch: 3, @@ -60,7 +60,7 @@ describe("getValidatorStatus", function () { const status = getValidatorStatus(validator, currentEpoch); expect(status).toBe("exited_slashed"); }); - it("should return EXITED_UNSLASHED", function () { + it("should return EXITED_UNSLASHED", () => { const validator = { exitEpoch: 1, withdrawableEpoch: 3, @@ -70,7 +70,7 @@ describe("getValidatorStatus", function () { const status = getValidatorStatus(validator, currentEpoch); expect(status).toBe("exited_unslashed"); }); - it("should return WITHDRAWAL_POSSIBLE", function () { + it("should return WITHDRAWAL_POSSIBLE", () => { const validator = { withdrawableEpoch: 1, effectiveBalance: 32, @@ -79,7 +79,7 @@ describe("getValidatorStatus", function () { const status = getValidatorStatus(validator, currentEpoch); expect(status).toBe("withdrawal_possible"); }); - it("should return WITHDRAWAL_DONE", function () { + it("should return WITHDRAWAL_DONE", () => { const validator = { withdrawableEpoch: 1, effectiveBalance: 0, @@ -88,7 +88,7 @@ describe("getValidatorStatus", function () { const status = getValidatorStatus(validator, currentEpoch); expect(status).toBe("withdrawal_done"); }); - it("should error", function () { + it("should error", () => { const validator = {} as phase0.Validator; const currentEpoch = 0; try { diff --git a/packages/utils/src/bytes.ts b/packages/utils/src/bytes.ts index 95bb62ebd548..c290232ce8db 100644 --- a/packages/utils/src/bytes.ts +++ b/packages/utils/src/bytes.ts @@ -34,7 +34,8 @@ export function bytesToInt(value: Uint8Array, endianness: Endianness = "le"): nu export function bigIntToBytes(value: bigint, length: number, endianness: Endianness = "le"): Buffer { if (endianness === "le") { return toBufferLE(value, length); - } else if (endianness === "be") { + } + if (endianness === "be") { return toBufferBE(value, length); } throw new Error("endianness must be either 'le' or 'be'"); @@ -43,7 +44,8 @@ export function bigIntToBytes(value: bigint, length: number, endianness: Endiann export function bytesToBigInt(value: Uint8Array, endianness: Endianness = "le"): bigint { if (endianness === "le") { return toBigIntLE(value as Buffer); - } else if (endianness === "be") { + } + if (endianness === "be") { return toBigIntBE(value as Buffer); } throw new Error("endianness must be either 'le' or 'be'"); diff --git a/packages/utils/src/bytes/nodejs.ts b/packages/utils/src/bytes/nodejs.ts index 4cf8e78c67c6..efa7a585835f 100644 --- a/packages/utils/src/bytes/nodejs.ts +++ b/packages/utils/src/bytes/nodejs.ts @@ -1,11 +1,11 @@ export function toHex(buffer: Uint8Array | Parameters[0]): string { if (Buffer.isBuffer(buffer)) { return "0x" + buffer.toString("hex"); - } else if (buffer instanceof Uint8Array) { + } + if (buffer instanceof Uint8Array) { return "0x" + Buffer.from(buffer.buffer, buffer.byteOffset, buffer.length).toString("hex"); - } else { - return "0x" + Buffer.from(buffer).toString("hex"); } + return "0x" + Buffer.from(buffer).toString("hex"); } // Shared buffer to convert root to hex diff --git a/packages/utils/src/diff.ts b/packages/utils/src/diff.ts index 4aab18e32779..f7357cde19fa 100644 --- a/packages/utils/src/diff.ts +++ b/packages/utils/src/diff.ts @@ -215,7 +215,7 @@ export function diff(val1: unknown, val2: unknown, outputValues = false, filenam const diffs = getDiffs(val1, val2, ""); let output = ""; if (diffs.length) { - diffs.forEach((diff) => { + for (const diff of diffs) { let diffOutput = `value${diff.objectPath}`; if (diff.errorMessage) { diffOutput += `\n ${diff.errorMessage}`; @@ -224,7 +224,7 @@ export function diff(val1: unknown, val2: unknown, outputValues = false, filenam diffOutput += `\n - ${diff.val1.toString()}\n - ${diff.val2.toString()}\n`; } output += `${diffOutput}\n`; - }); + } if (filename) { fs.writeFileSync(filename, output); } else { diff --git a/packages/utils/src/objects.ts b/packages/utils/src/objects.ts index 913bc80275b7..602e758e360c 100644 --- a/packages/utils/src/objects.ts +++ b/packages/utils/src/objects.ts @@ -18,7 +18,7 @@ export function toExpectedCase( customCasingMap?: Record ): string { if (expectedCase === "notransform") return value; - if (customCasingMap && customCasingMap[value]) return customCasingMap[value]; + if (customCasingMap?.[value]) return customCasingMap[value]; switch (expectedCase) { case "param": return Case.kebab(value); @@ -45,7 +45,7 @@ export function isPlainObject(o: unknown): o is object { if (isObjectObject(prot) === false) return false; // If constructor does not have an Object-specific method - if (prot.hasOwnProperty("isPrototypeOf") === false) { + if (Object.prototype.hasOwnProperty.call(prot, "isPrototypeOf") === false) { return false; } @@ -91,7 +91,7 @@ export function objectToExpectedCase | Record< const newObj: Record = {}; for (const name of Object.getOwnPropertyNames(obj)) { const newName = toExpectedCase(name, expectedCase); - if (newName !== name && obj.hasOwnProperty(newName)) { + if (newName !== name && Object.prototype.hasOwnProperty.call(obj, newName)) { throw new Error(`object already has a ${newName} property`); } diff --git a/packages/utils/src/retry.ts b/packages/utils/src/retry.ts index 6c5e63deca42..bc759d62e9b2 100644 --- a/packages/utils/src/retry.ts +++ b/packages/utils/src/retry.ts @@ -60,9 +60,13 @@ export async function retry(fn: (attempt: number) => A | Promise, opts?: R if (i === maxAttempts) { // Reached maximum number of attempts, there's no need to check if we should retry break; - } else if (shouldRetry && !shouldRetry(lastError)) { + } + + if (shouldRetry && !shouldRetry(lastError)) { break; - } else if (opts?.retryDelay !== undefined) { + } + + if (opts?.retryDelay !== undefined) { await sleep(opts?.retryDelay, opts?.signal); } } diff --git a/packages/utils/src/sleep.ts b/packages/utils/src/sleep.ts index c31a9daffd32..f2ff74255f48 100644 --- a/packages/utils/src/sleep.ts +++ b/packages/utils/src/sleep.ts @@ -10,7 +10,7 @@ export async function sleep(ms: number, signal?: AbortSignal): Promise { } return new Promise((resolve, reject) => { - if (signal && signal.aborted) return reject(new ErrorAborted()); + if (signal?.aborted) return reject(new ErrorAborted()); let onDone: () => void = () => {}; diff --git a/packages/utils/src/url.ts b/packages/utils/src/url.ts index f00b70edbde2..d4eba3bd67cf 100644 --- a/packages/utils/src/url.ts +++ b/packages/utils/src/url.ts @@ -1,5 +1,5 @@ export function isValidHttpUrl(urlStr: string): boolean { - let url; + let url: URL; try { url = new URL(urlStr); diff --git a/packages/utils/src/yaml/int.ts b/packages/utils/src/yaml/int.ts index bc68895cfd42..264d1297f888 100644 --- a/packages/utils/src/yaml/int.ts +++ b/packages/utils/src/yaml/int.ts @@ -27,7 +27,7 @@ function resolveYamlInteger(data: string): boolean { if (data === null) return false; const max = data.length; - let ch, + let ch: string, index = 0, hasDigits = false; @@ -111,7 +111,7 @@ function resolveYamlInteger(data: string): boolean { function constructYamlInteger(data: string): bigint { let value: string | bigint = data, sign = 1, - ch, + ch: string, base: number | bigint; const digits: number[] = []; diff --git a/packages/utils/test/perf/bytes.test.ts b/packages/utils/test/perf/bytes.test.ts index 649ea0b51e3e..6a1e96ab1579 100644 --- a/packages/utils/test/perf/bytes.test.ts +++ b/packages/utils/test/perf/bytes.test.ts @@ -3,7 +3,7 @@ import {toHex, toRootHex} from "../../src/bytes/nodejs.js"; import {toHex as browserToHex, toRootHex as browserToRootHex} from "../../src/bytes/browser.js"; import {toHexString} from "../../src/bytes.js"; -describe("bytes utils", function () { +describe("bytes utils", () => { const runsFactor = 1000; const blockRoot = new Uint8Array(Array.from({length: 32}, (_, i) => i)); diff --git a/packages/utils/test/unit/math.test.ts b/packages/utils/test/unit/math.test.ts index 6827fea2bbb0..e324714600b1 100644 --- a/packages/utils/test/unit/math.test.ts +++ b/packages/utils/test/unit/math.test.ts @@ -1,7 +1,7 @@ import {describe, it, expect} from "vitest"; import {bigIntMin, bigIntMax, intDiv, intSqrt, bigIntSqrt} from "../../src/index.js"; -describe("util/maths", function () { +describe("util/maths", () => { describe("bigIntMin", () => { it("if a is lt should return a", () => { const a = BigInt(1); diff --git a/packages/utils/test/unit/promise.node.test.ts b/packages/utils/test/unit/promise.node.test.ts index c9f6a3c2f98d..55cbad36b211 100644 --- a/packages/utils/test/unit/promise.node.test.ts +++ b/packages/utils/test/unit/promise.node.test.ts @@ -2,7 +2,7 @@ import {describe, it, expect, vi, beforeEach, afterEach} from "vitest"; import {callFnWhenAwait} from "../../src/promise.js"; // TODO: Need to debug why vi.useFakeTimers() is not working for the browsers -describe("callFnWhenAwait util", function () { +describe("callFnWhenAwait util", () => { beforeEach(() => { vi.useFakeTimers(); }); diff --git a/packages/utils/test/unit/promiserace.test.ts b/packages/utils/test/unit/promiserace.test.ts index 1f31a55014a4..4b20f19f9fba 100644 --- a/packages/utils/test/unit/promiserace.test.ts +++ b/packages/utils/test/unit/promiserace.test.ts @@ -58,9 +58,8 @@ describe("resolveOrRacePromises", () => { const testPromises = timeouts.map((timeMs) => { if (timeMs > 0) { return resolveAfter(`${timeMs}`, timeMs); - } else { - return rejectAfter(`${timeMs}`, -timeMs); } + return rejectAfter(`${timeMs}`, -timeMs); }); const testResults = (await resolveOrRacePromises(testPromises as unknown as NonEmptyArray>, { resolveTimeoutMs: cutoffMs, diff --git a/packages/utils/test/unit/retry.test.ts b/packages/utils/test/unit/retry.test.ts index 12afb7597015..bd77c499a364 100644 --- a/packages/utils/test/unit/retry.test.ts +++ b/packages/utils/test/unit/retry.test.ts @@ -28,7 +28,8 @@ describe("retry", () => { id: "Succeed at the last attempt", fn: async (attempt) => { if (attempt < retries) throw sampleError; - else return sampleResult; + + return sampleResult; }, opts: {retries}, result: sampleResult, diff --git a/packages/utils/test/unit/sleep.test.ts b/packages/utils/test/unit/sleep.test.ts index a887560836eb..ef632fd34f64 100644 --- a/packages/utils/test/unit/sleep.test.ts +++ b/packages/utils/test/unit/sleep.test.ts @@ -2,13 +2,13 @@ import {describe, it, expect} from "vitest"; import {sleep} from "../../src/sleep.js"; import {ErrorAborted} from "../../src/errors.js"; -describe("sleep", function () { - it("Should resolve timeout", async function () { +describe("sleep", () => { + it("Should resolve timeout", async () => { const controller = new AbortController(); await sleep(0, controller.signal); }); - it("Should abort timeout with signal", async function () { + it("Should abort timeout with signal", async () => { const controller = new AbortController(); setTimeout(() => controller.abort(), 10); @@ -17,7 +17,7 @@ describe("sleep", function () { await expect(sleep(sleepTime, controller.signal)).rejects.toThrow(ErrorAborted); }); - it("Should abort timeout with already aborted signal", async function () { + it("Should abort timeout with already aborted signal", async () => { const controller = new AbortController(); controller.abort(); diff --git a/packages/utils/test/unit/timeout.test.ts b/packages/utils/test/unit/timeout.test.ts index b8844355effb..7b4b1eb883be 100644 --- a/packages/utils/test/unit/timeout.test.ts +++ b/packages/utils/test/unit/timeout.test.ts @@ -2,7 +2,7 @@ import {describe, it, expect, afterEach} from "vitest"; import {withTimeout} from "../../src/timeout.js"; import {ErrorAborted, TimeoutError} from "../../src/errors.js"; -describe("withTimeout", function () { +describe("withTimeout", () => { const data = "DATA"; const shortTimeoutMs = 10; const longTimeoutMs = 5000; @@ -27,19 +27,19 @@ describe("withTimeout", function () { return returnValue; } - it("Should resolve timeout", async function () { + it("Should resolve timeout", async () => { const res = await withTimeout(() => pause(shortTimeoutMs, data), longTimeoutMs); expect(res).toBe(data); }); - it("Should resolve timeout with not triggered signal", async function () { + it("Should resolve timeout with not triggered signal", async () => { const controller = new AbortController(); const res = await withTimeout(() => pause(shortTimeoutMs, data), longTimeoutMs, controller.signal); expect(res).toBe(data); }); - it("Should abort timeout with triggered signal", async function () { + it("Should abort timeout with triggered signal", async () => { const controller = new AbortController(); setTimeout(() => controller.abort(), shortTimeoutMs); @@ -48,11 +48,11 @@ describe("withTimeout", function () { ); }); - it("Should timeout with no signal", async function () { + it("Should timeout with no signal", async () => { await expect(withTimeout(() => pause(longTimeoutMs, data), shortTimeoutMs)).rejects.toThrow(TimeoutError); }); - it("Should timeout with not triggered signal", async function () { + it("Should timeout with not triggered signal", async () => { const controller = new AbortController(); await expect(withTimeout(() => pause(longTimeoutMs, data), shortTimeoutMs, controller.signal)).rejects.toThrow( @@ -60,7 +60,7 @@ describe("withTimeout", function () { ); }); - it("Should abort timeout with already aborted signal", async function () { + it("Should abort timeout with already aborted signal", async () => { const controller = new AbortController(); controller.abort(); diff --git a/packages/validator/src/buckets.ts b/packages/validator/src/buckets.ts index df30370b8810..3313f7b5ae35 100644 --- a/packages/validator/src/buckets.ts +++ b/packages/validator/src/buckets.ts @@ -17,11 +17,11 @@ export enum Bucket { export function getBucketNameByValue(enumValue: T): keyof typeof Bucket { const keys = Object.keys(Bucket).filter((x) => { - if (isNaN(parseInt(x))) { - return Bucket[x as keyof typeof Bucket] == enumValue; - } else { - return false; + if (Number.isNaN(parseInt(x))) { + return Bucket[x as keyof typeof Bucket] === enumValue; } + + return false; }) as (keyof typeof Bucket)[]; if (keys.length > 0) { return keys[0]; diff --git a/packages/validator/src/services/block.ts b/packages/validator/src/services/block.ts index c3acf19c1669..cb295450e96b 100644 --- a/packages/validator/src/services/block.ts +++ b/packages/validator/src/services/block.ts @@ -265,18 +265,17 @@ export class BlockProposingService { debugLogCtx, builderSelection ); - } else { - Object.assign(debugLogCtx, {api: "produceBlindedBlock"}); - const res = await this.api.validator.produceBlindedBlock({slot, randaoReveal, graffiti}); - const {version} = res.meta(); - const executionPayloadSource = ProducedBlockSource.builder; - - return parseProduceBlockResponse( - {data: res.value(), executionPayloadBlinded: true, executionPayloadSource, version}, - debugLogCtx, - builderSelection - ); } + Object.assign(debugLogCtx, {api: "produceBlindedBlock"}); + const res = await this.api.validator.produceBlindedBlock({slot, randaoReveal, graffiti}); + const {version} = res.meta(); + const executionPayloadSource = ProducedBlockSource.builder; + + return parseProduceBlockResponse( + {data: res.value(), executionPayloadBlinded: true, executionPayloadSource, version}, + debugLogCtx, + builderSelection + ); }; } @@ -311,26 +310,26 @@ function parseProduceBlockResponse( executionPayloadSource, debugLogCtx, } as FullOrBlindedBlockWithContents & DebugLogCtx; - } else { - const data = response.data; - if (isBlockContents(data)) { - return { - block: data.block, - contents: {blobs: data.blobs, kzgProofs: data.kzgProofs}, - version: response.version, - executionPayloadBlinded: false, - executionPayloadSource, - debugLogCtx, - } as FullOrBlindedBlockWithContents & DebugLogCtx; - } else { - return { - block: response.data, - contents: null, - version: response.version, - executionPayloadBlinded: false, - executionPayloadSource, - debugLogCtx, - } as FullOrBlindedBlockWithContents & DebugLogCtx; - } } + + const data = response.data; + if (isBlockContents(data)) { + return { + block: data.block, + contents: {blobs: data.blobs, kzgProofs: data.kzgProofs}, + version: response.version, + executionPayloadBlinded: false, + executionPayloadSource, + debugLogCtx, + } as FullOrBlindedBlockWithContents & DebugLogCtx; + } + + return { + block: response.data, + contents: null, + version: response.version, + executionPayloadBlinded: false, + executionPayloadSource, + debugLogCtx, + } as FullOrBlindedBlockWithContents & DebugLogCtx; } diff --git a/packages/validator/src/services/doppelgangerService.ts b/packages/validator/src/services/doppelgangerService.ts index e167ee1d5028..aa43d7bba55b 100644 --- a/packages/validator/src/services/doppelgangerService.ts +++ b/packages/validator/src/services/doppelgangerService.ts @@ -275,11 +275,12 @@ export class DoppelgangerService { function getStatus(state: DoppelgangerState | undefined): DoppelgangerStatus { if (!state) { return DoppelgangerStatus.Unknown; - } else if (state.remainingEpochs <= 0) { + } + if (state.remainingEpochs <= 0) { return DoppelgangerStatus.VerifiedSafe; - } else if (state.remainingEpochs === REMAINING_EPOCHS_IF_DOPPELGANGER) { + } + if (state.remainingEpochs === REMAINING_EPOCHS_IF_DOPPELGANGER) { return DoppelgangerStatus.DoppelgangerDetected; - } else { - return DoppelgangerStatus.Unverified; } + return DoppelgangerStatus.Unverified; } diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index c2b18bfd7e09..dfd856b18d13 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -247,7 +247,7 @@ export class ValidatorStore { throw Error(`Validator pubkey ${pubkeyHex} not known`); } // This should directly modify data in the map - delete validatorData["feeRecipient"]; + delete validatorData.feeRecipient; } getGraffiti(pubkeyHex: PubkeyHex): string | undefined { @@ -267,14 +267,14 @@ export class ValidatorStore { if (validatorData === undefined) { throw Error(`Validator pubkey ${pubkeyHex} not known`); } - delete validatorData["graffiti"]; + delete validatorData.graffiti; } getBuilderSelectionParams(pubkeyHex: PubkeyHex): {selection: routes.validator.BuilderSelection; boostFactor: bigint} { const selection = - (this.validators.get(pubkeyHex)?.builder || {}).selection ?? this.defaultProposerConfig.builder.selection; + this.validators.get(pubkeyHex)?.builder?.selection ?? this.defaultProposerConfig.builder.selection; - let boostFactor; + let boostFactor: bigint; switch (selection) { case routes.validator.BuilderSelection.Default: // Default value slightly favors local block to improve censorship resistance of Ethereum @@ -284,7 +284,7 @@ export class ValidatorStore { case routes.validator.BuilderSelection.MaxProfit: boostFactor = - (this.validators.get(pubkeyHex)?.builder || {}).boostFactor ?? this.defaultProposerConfig.builder.boostFactor; + this.validators.get(pubkeyHex)?.builder?.boostFactor ?? this.defaultProposerConfig.builder.boostFactor; break; case routes.validator.BuilderSelection.BuilderAlways: @@ -386,7 +386,7 @@ export class ValidatorStore { async addSigner(signer: Signer, valProposerConfig?: ValidatorProposerConfig): Promise { const pubkey = getSignerPubkeyHex(signer); - const proposerConfig = (valProposerConfig?.proposerConfig ?? {})[pubkey]; + const proposerConfig = valProposerConfig?.proposerConfig?.[pubkey]; const builderBoostFactor = proposerConfig?.builder?.boostFactor; if (builderBoostFactor !== undefined && builderBoostFactor > MAX_BUILDER_BOOST_FACTOR) { throw Error(`Invalid builderBoostFactor=${builderBoostFactor} > MAX_BUILDER_BOOST_FACTOR for pubkey=${pubkey}`); @@ -538,13 +538,13 @@ export class ValidatorStore { signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage), committeeBits: BitArray.fromSingleBit(MAX_COMMITTEES_PER_SLOT, duty.committeeIndex), }; - } else { - return { - aggregationBits: BitArray.fromSingleBit(duty.committeeLength, duty.validatorCommitteeIndex), - data: attestationData, - signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage), - } as phase0.Attestation; } + + return { + aggregationBits: BitArray.fromSingleBit(duty.committeeLength, duty.validatorCommitteeIndex), + data: attestationData, + signature: await this.getSignature(duty.pubkey, signingRoot, signingSlot, signableMessage), + } as phase0.Attestation; } async signAggregateAndProof( @@ -731,15 +731,14 @@ export class ValidatorStore { const builderData = validatorData?.builderData; if (builderData?.regFullKey === regFullKey) { return builderData.validatorRegistration; - } else { - const validatorRegistration = await this.signValidatorRegistration(pubkeyMaybeHex, regAttributes, slot); - // If pubkeyHex was actually registered, then update the regData - if (validatorData !== undefined) { - validatorData.builderData = {validatorRegistration, regFullKey}; - this.validators.set(pubkeyHex, validatorData); - } - return validatorRegistration; } + const validatorRegistration = await this.signValidatorRegistration(pubkeyMaybeHex, regAttributes, slot); + // If pubkeyHex was actually registered, then update the regData + if (validatorData !== undefined) { + validatorData.builderData = {validatorRegistration, regFullKey}; + this.validators.set(pubkeyHex, validatorData); + } + return validatorRegistration; } private async getSignature( @@ -803,7 +802,7 @@ export class ValidatorStore { } const isPostElectra = this.config.getForkSeq(data.slot) >= ForkSeq.electra; - if (!isPostElectra && duty.committeeIndex != data.index) { + if (!isPostElectra && duty.committeeIndex !== data.index) { throw Error( `Inconsistent duties during signing: duty.committeeIndex ${duty.committeeIndex} != att.committeeIndex ${data.index}` ); diff --git a/packages/validator/src/slashingProtection/attestation/index.ts b/packages/validator/src/slashingProtection/attestation/index.ts index 681bdf5f0b13..f0d3a0bca172 100644 --- a/packages/validator/src/slashingProtection/attestation/index.ts +++ b/packages/validator/src/slashingProtection/attestation/index.ts @@ -39,7 +39,7 @@ export class SlashingProtectionAttestationService { async checkAndInsertAttestation(pubKey: BLSPubkey, attestation: SlashingProtectionAttestation): Promise { const safeStatus = await this.checkAttestation(pubKey, attestation); - if (safeStatus != SafeStatus.SAME_DATA) { + if (safeStatus !== SafeStatus.SAME_DATA) { await this.insertAttestation(pubKey, attestation); } @@ -63,13 +63,12 @@ export class SlashingProtectionAttestationService { // Interchange format allows for attestations without signing_root, then assume root is equal if (isEqualNonZeroRoot(sameTargetAtt.signingRoot, attestation.signingRoot)) { return SafeStatus.SAME_DATA; - } else { - throw new InvalidAttestationError({ - code: InvalidAttestationErrorCode.DOUBLE_VOTE, - attestation: attestation, - prev: sameTargetAtt, - }); } + throw new InvalidAttestationError({ + code: InvalidAttestationErrorCode.DOUBLE_VOTE, + attestation: attestation, + prev: sameTargetAtt, + }); } // Check for a surround vote diff --git a/packages/validator/src/slashingProtection/block/index.ts b/packages/validator/src/slashingProtection/block/index.ts index bab380f99809..385575e82a0a 100644 --- a/packages/validator/src/slashingProtection/block/index.ts +++ b/packages/validator/src/slashingProtection/block/index.ts @@ -24,7 +24,7 @@ export class SlashingProtectionBlockService { async checkAndInsertBlockProposal(pubkey: BLSPubkey, block: SlashingProtectionBlock): Promise { const safeStatus = await this.checkBlockProposal(pubkey, block); - if (safeStatus != SafeStatus.SAME_DATA) { + if (safeStatus !== SafeStatus.SAME_DATA) { await this.insertBlockProposal(pubkey, block); } @@ -41,13 +41,13 @@ export class SlashingProtectionBlockService { // Interchange format allows for blocks without signing_root, then assume root is equal if (isEqualNonZeroRoot(sameSlotBlock.signingRoot, block.signingRoot)) { return SafeStatus.SAME_DATA; - } else { - throw new InvalidBlockError({ - code: InvalidBlockErrorCode.DOUBLE_BLOCK_PROPOSAL, - block, - block2: sameSlotBlock, - }); } + + throw new InvalidBlockError({ + code: InvalidBlockErrorCode.DOUBLE_BLOCK_PROPOSAL, + block, + block2: sameSlotBlock, + }); } // Refuse to sign any block with slot <= min(b.slot for b in data.signed_blocks if b.pubkey == proposer_pubkey), diff --git a/packages/validator/src/util/clock.ts b/packages/validator/src/util/clock.ts index ca29eacd41c2..4b3fc45cd803 100644 --- a/packages/validator/src/util/clock.ts +++ b/packages/validator/src/util/clock.ts @@ -119,17 +119,14 @@ export class Clock implements IClock { if (timeItem === TimeItem.Slot) { if (msFromGenesis >= 0) { return milliSecondsPerSlot - (msFromGenesis % milliSecondsPerSlot); - } else { - return Math.abs(msFromGenesis % milliSecondsPerSlot); - } - } else { - const milliSecondsPerEpoch = SLOTS_PER_EPOCH * milliSecondsPerSlot; - if (msFromGenesis >= 0) { - return milliSecondsPerEpoch - (msFromGenesis % milliSecondsPerEpoch); - } else { - return Math.abs(msFromGenesis % milliSecondsPerEpoch); } + return Math.abs(msFromGenesis % milliSecondsPerSlot); + } + const milliSecondsPerEpoch = SLOTS_PER_EPOCH * milliSecondsPerSlot; + if (msFromGenesis >= 0) { + return milliSecondsPerEpoch - (msFromGenesis % milliSecondsPerEpoch); } + return Math.abs(msFromGenesis % milliSecondsPerEpoch); } } diff --git a/packages/validator/src/util/externalSignerClient.ts b/packages/validator/src/util/externalSignerClient.ts index 64d595452296..54c0c16946ad 100644 --- a/packages/validator/src/util/externalSignerClient.ts +++ b/packages/validator/src/util/externalSignerClient.ts @@ -241,14 +241,14 @@ function serializerSignableMessagePayload(config: BeaconConfig, payload: Signabl block_header: ssz.phase0.BeaconBlockHeader.toJson(blindedOrFullBlockToHeader(config, payload.data)), }, }; - } else { - return { - beacon_block: { - version, - block: config.getForkTypes(payload.data.slot).BeaconBlock.toJson(payload.data), - }, - }; } + + return { + beacon_block: { + version, + block: config.getForkTypes(payload.data.slot).BeaconBlock.toJson(payload.data), + }, + }; } case SignableMessageType.DEPOSIT: diff --git a/packages/validator/src/validator.ts b/packages/validator/src/validator.ts index 6ffebff2b3bd..1d370c35cc33 100644 --- a/packages/validator/src/validator.ts +++ b/packages/validator/src/validator.ts @@ -264,7 +264,7 @@ export class Validator { } ); - return new this({ + return new Validator({ opts, genesis, validatorStore, diff --git a/packages/validator/test/e2e/web3signer.test.ts b/packages/validator/test/e2e/web3signer.test.ts index ae22bc31446b..855b3dd9f754 100644 --- a/packages/validator/test/e2e/web3signer.test.ts +++ b/packages/validator/test/e2e/web3signer.test.ts @@ -12,7 +12,7 @@ import {Interchange, ISlashingProtection, Signer, SignerType, ValidatorStore} fr import {IndicesService} from "../../src/services/indices.js"; import {testLogger} from "../utils/logger.js"; -describe("web3signer signature test", function () { +describe("web3signer signature test", () => { vi.setConfig({testTimeout: 60_000, hookTimeout: 60_000}); const altairSlot = 2375711; @@ -82,7 +82,7 @@ describe("web3signer signature test", function () { }); } - it("signRandao", async function () { + it("signRandao", async () => { await assertSameSignature("signRandao", pubkeyBytes, epoch); }); diff --git a/packages/validator/test/unit/services/attestation.test.ts b/packages/validator/test/unit/services/attestation.test.ts index b225ab09cdd2..1652af83c5d1 100644 --- a/packages/validator/test/unit/services/attestation.test.ts +++ b/packages/validator/test/unit/services/attestation.test.ts @@ -22,7 +22,7 @@ vi.mock("../../../src/services/emitter.js"); vi.mock("../../../src/services/chainHeaderTracker.js"); vi.mock("../../../src/services/syncingStatusTracker.js"); -describe("AttestationService", function () { +describe("AttestationService", () => { const api = getApiClientStub(); // @ts-expect-error - Mocked class don't need parameters const validatorStore = vi.mocked(new ValidatorStore()); diff --git a/packages/validator/test/unit/services/attestationDuties.test.ts b/packages/validator/test/unit/services/attestationDuties.test.ts index f59b00d88c9c..fafccf209777 100644 --- a/packages/validator/test/unit/services/attestationDuties.test.ts +++ b/packages/validator/test/unit/services/attestationDuties.test.ts @@ -18,7 +18,7 @@ import {ZERO_HASH_HEX} from "../../utils/types.js"; vi.mock("../../../src/services/chainHeaderTracker.js"); -describe("AttestationDutiesService", function () { +describe("AttestationDutiesService", () => { const api = getApiClientStub(); let validatorStore: ValidatorStore; @@ -61,7 +61,7 @@ describe("AttestationDutiesService", function () { controller.abort(); }); - it("Should fetch indexes and duties", async function () { + it("Should fetch indexes and duties", async () => { // Reply with some duties const slot = 1; const epoch = computeEpochAtSlot(slot); @@ -118,7 +118,7 @@ describe("AttestationDutiesService", function () { expect(api.validator.prepareBeaconCommitteeSubnet).toHaveBeenCalledOnce(); }); - it("Should remove signer from attestation duties", async function () { + it("Should remove signer from attestation duties", async () => { // Reply with some duties const slot = 1; const duty: routes.validator.AttesterDuty = { @@ -165,7 +165,7 @@ describe("AttestationDutiesService", function () { expect(Object.fromEntries(dutiesService["dutiesByIndexByEpoch"])).toEqual({}); }); - it("Should fetch duties when node is resynced", async function () { + it("Should fetch duties when node is resynced", async () => { // Node is syncing api.node.getSyncingStatus.mockResolvedValue( mockApiResponse({data: {headSlot: 0, syncDistance: 1, isSyncing: true, isOptimistic: false, elOffline: false}}) diff --git a/packages/validator/test/unit/services/block.test.ts b/packages/validator/test/unit/services/block.test.ts index 641ca620a1b5..dc89f1169d92 100644 --- a/packages/validator/test/unit/services/block.test.ts +++ b/packages/validator/test/unit/services/block.test.ts @@ -16,7 +16,7 @@ import {ZERO_HASH_HEX} from "../../utils/types.js"; vi.mock("../../../src/services/validatorStore.js"); -describe("BlockDutiesService", function () { +describe("BlockDutiesService", () => { const api = getApiClientStub(); // @ts-expect-error - Mocked class don't need parameters const validatorStore = vi.mocked(new ValidatorStore()); @@ -36,7 +36,7 @@ describe("BlockDutiesService", function () { }); afterEach(() => controller.abort()); - it("Should produce, sign, and publish a block", async function () { + it("Should produce, sign, and publish a block", async () => { // Reply with some duties const slot = 0; // genesisTime is right now, so test with slot = currentSlot api.validator.getProposerDuties.mockResolvedValue( @@ -111,7 +111,7 @@ describe("BlockDutiesService", function () { ]); }); - it("Should produce, sign, and publish a blinded block", async function () { + it("Should produce, sign, and publish a blinded block", async () => { // Reply with some duties const slot = 0; // genesisTime is right now, so test with slot = currentSlot api.validator.getProposerDuties.mockResolvedValue( diff --git a/packages/validator/test/unit/services/blockDuties.test.ts b/packages/validator/test/unit/services/blockDuties.test.ts index bc4053b704c8..51ced2cd70de 100644 --- a/packages/validator/test/unit/services/blockDuties.test.ts +++ b/packages/validator/test/unit/services/blockDuties.test.ts @@ -13,7 +13,7 @@ import {ClockMock} from "../../utils/clock.js"; import {initValidatorStore} from "../../utils/validatorStore.js"; import {ZERO_HASH_HEX} from "../../utils/types.js"; -describe("BlockDutiesService", function () { +describe("BlockDutiesService", () => { const api = getApiClientStub(); let validatorStore: ValidatorStore; let pubkeys: Uint8Array[]; // Initialize pubkeys in before() so bls is already initialized @@ -30,7 +30,7 @@ describe("BlockDutiesService", function () { }); afterEach(() => controller.abort()); - it("Should fetch and persist block duties", async function () { + it("Should fetch and persist block duties", async () => { // Reply with some duties const slot = 0; // genesisTime is right now, so test with slot = currentSlot const duties: routes.validator.ProposerDutyList = [{slot: slot, validatorIndex: 0, pubkey: pubkeys[0]}]; @@ -106,7 +106,7 @@ describe("BlockDutiesService", function () { expect(notifyBlockProductionFn.mock.calls[1]).toEqual([1, [pubkeys[1]]]); }); - it("Should remove signer from duty", async function () { + it("Should remove signer from duty", async () => { // Reply with some duties const slot = 0; // genesisTime is right now, so test with slot = currentSlot const duties: routes.validator.ProposerDutyList = [ diff --git a/packages/validator/test/unit/services/indicesService.test.ts b/packages/validator/test/unit/services/indicesService.test.ts index 8332bac7cfd6..d4619aa65b94 100644 --- a/packages/validator/test/unit/services/indicesService.test.ts +++ b/packages/validator/test/unit/services/indicesService.test.ts @@ -6,7 +6,7 @@ import {getApiClientStub} from "../../utils/apiStub.js"; import {testLogger} from "../../utils/logger.js"; import {IndicesService} from "../../../src/services/indices.js"; -describe("IndicesService", function () { +describe("IndicesService", () => { const logger = testLogger(); const api = getApiClientStub(); @@ -20,7 +20,7 @@ describe("IndicesService", function () { pubkeys = secretKeys.map((sk) => sk.toPublicKey().toBytes()); }); - it("Should remove pubkey", async function () { + it("Should remove pubkey", async () => { const indicesService = new IndicesService(logger, api, null); const firstValidatorIndex = 0; const secondValidatorIndex = 1; diff --git a/packages/validator/test/unit/services/syncCommitteDuties.test.ts b/packages/validator/test/unit/services/syncCommitteDuties.test.ts index d94926e9b564..27a86d31f901 100644 --- a/packages/validator/test/unit/services/syncCommitteDuties.test.ts +++ b/packages/validator/test/unit/services/syncCommitteDuties.test.ts @@ -20,7 +20,7 @@ import {ClockMock} from "../../utils/clock.js"; import {initValidatorStore} from "../../utils/validatorStore.js"; import {syncCommitteeIndicesToSubnets} from "../../../src/services/utils.js"; -describe("SyncCommitteeDutiesService", function () { +describe("SyncCommitteeDutiesService", () => { const api = getApiClientStub(); let validatorStore: ValidatorStore; @@ -67,7 +67,7 @@ describe("SyncCommitteeDutiesService", function () { controller.abort(); }); - it("Should fetch indexes and duties", async function () { + it("Should fetch indexes and duties", async () => { // Reply with some duties const slot = 1; const duty: routes.validator.SyncDuty = { @@ -127,7 +127,7 @@ describe("SyncCommitteeDutiesService", function () { /** * Reproduce https://github.com/ChainSafe/lodestar/issues/3572 */ - it("should remove redundant duties", async function () { + it("should remove redundant duties", async () => { // Reply with some duties const duty: routes.validator.SyncDuty = { pubkey: pubkeys[0], @@ -195,7 +195,7 @@ describe("SyncCommitteeDutiesService", function () { } as typeof dutiesByIndexByPeriodObj); }); - it("Should remove signer from sync committee duties", async function () { + it("Should remove signer from sync committee duties", async () => { // Reply with some duties const duty1: routes.validator.SyncDuty = { pubkey: pubkeys[0], @@ -264,7 +264,7 @@ describe("SyncCommitteeDutiesService", function () { } as typeof dutiesByIndexByPeriodObjAfterRemoval); }); - it("Should fetch duties when node is resynced", async function () { + it("Should fetch duties when node is resynced", async () => { // Node is syncing api.node.getSyncingStatus.mockResolvedValue( mockApiResponse({data: {headSlot: 0, syncDistance: 1, isSyncing: true, isOptimistic: false, elOffline: false}}) diff --git a/packages/validator/test/unit/services/syncCommittee.test.ts b/packages/validator/test/unit/services/syncCommittee.test.ts index 201bbdc83632..84c7f14d73b1 100644 --- a/packages/validator/test/unit/services/syncCommittee.test.ts +++ b/packages/validator/test/unit/services/syncCommittee.test.ts @@ -21,7 +21,7 @@ vi.mock("../../../src/services/emitter.js"); vi.mock("../../../src/services/chainHeaderTracker.js"); vi.mock("../../../src/services/syncingStatusTracker.js"); -describe("SyncCommitteeService", function () { +describe("SyncCommitteeService", () => { const api = getApiClientStub(); // @ts-expect-error - Mocked class don't need parameters const validatorStore = vi.mocked(new ValidatorStore()); diff --git a/packages/validator/test/unit/services/syncingStatusTracker.test.ts b/packages/validator/test/unit/services/syncingStatusTracker.test.ts index 59029e1b9c51..07364847e345 100644 --- a/packages/validator/test/unit/services/syncingStatusTracker.test.ts +++ b/packages/validator/test/unit/services/syncingStatusTracker.test.ts @@ -4,7 +4,7 @@ import {getMockedLogger} from "../../utils/logger.js"; import {ClockMock} from "../../utils/clock.js"; import {SyncingStatus, SyncingStatusTracker} from "../../../src/services/syncingStatusTracker.js"; -describe("SyncingStatusTracker", function () { +describe("SyncingStatusTracker", () => { const api = getApiClientStub(); const logger = getMockedLogger(); @@ -26,7 +26,7 @@ describe("SyncingStatusTracker", function () { controller.abort(); }); - it("should handle transition from syncing to synced", async function () { + it("should handle transition from syncing to synced", async () => { // Node is syncing const syncing: SyncingStatus = { headSlot: 0, @@ -80,7 +80,7 @@ describe("SyncingStatusTracker", function () { expect(callOnResynced).toHaveBeenCalledOnce(); }); - it("should handle errors when checking syncing status", async function () { + it("should handle errors when checking syncing status", async () => { // Node is offline const error = new Error("ECONNREFUSED"); api.node.getSyncingStatus.mockRejectedValue(error); @@ -92,7 +92,7 @@ describe("SyncingStatusTracker", function () { expect(callOnResynced).not.toHaveBeenCalled(); }); - it("should not call scheduled tasks if already synced", async function () { + it("should not call scheduled tasks if already synced", async () => { // Node is already synced const syncedHead1: SyncingStatus = { headSlot: 1, diff --git a/packages/validator/test/unit/utils/batch.test.ts b/packages/validator/test/unit/utils/batch.test.ts index 821d27c1a43a..455d31e19577 100644 --- a/packages/validator/test/unit/utils/batch.test.ts +++ b/packages/validator/test/unit/utils/batch.test.ts @@ -1,7 +1,7 @@ import {describe, it, expect} from "vitest"; import {batchItems} from "../../../src/util/index.js"; -describe("util / batch", function () { +describe("util / batch", () => { const testCases: {items: string[]; expected: string[][]}[] = [ {items: [], expected: []}, {items: ["1"], expected: [["1"]]}, diff --git a/packages/validator/test/unit/utils/clock.test.ts b/packages/validator/test/unit/utils/clock.test.ts index f1c12e2cf66d..056260d9e515 100644 --- a/packages/validator/test/unit/utils/clock.test.ts +++ b/packages/validator/test/unit/utils/clock.test.ts @@ -5,7 +5,7 @@ import {BeaconConfig} from "@lodestar/config"; import {Clock, getCurrentSlotAround} from "../../../src/util/clock.js"; import {testLogger} from "../../utils/logger.js"; -describe("util / Clock", function () { +describe("util / Clock", () => { const logger = testLogger(); let controller: AbortController; @@ -80,7 +80,7 @@ describe("util / Clock", function () { expect(onEpoch).toHaveBeenNthCalledWith(2, 1, expect.any(AbortSignal)); }); - describe("getCurrentSlot", function () { + describe("getCurrentSlot", () => { const testConfig = {SECONDS_PER_SLOT: 12} as BeaconConfig; const genesisTime = Math.floor(new Date("2021-01-01").getTime() / 1000); @@ -96,7 +96,7 @@ describe("util / Clock", function () { {name: "should return next slot after 12.5s", delta: 12.5}, ]; - it.each(testCase)("$name", async function ({delta}) { + it.each(testCase)("$name", async ({delta}) => { const currentSlot = getCurrentSlotAround(testConfig, genesisTime); vi.advanceTimersByTime(delta * 1000); expect(getCurrentSlotAround(testConfig, genesisTime)).toBe(currentSlot + 1); diff --git a/packages/validator/test/unit/validatorStore.test.ts b/packages/validator/test/unit/validatorStore.test.ts index 3d8d88ee3e64..b029a33e163a 100644 --- a/packages/validator/test/unit/validatorStore.test.ts +++ b/packages/validator/test/unit/validatorStore.test.ts @@ -11,7 +11,7 @@ import {getApiClientStub} from "../utils/apiStub.js"; import {initValidatorStore} from "../utils/validatorStore.js"; import {ValidatorProposerConfig} from "../../src/services/validatorStore.js"; -describe("ValidatorStore", function () { +describe("ValidatorStore", () => { const api = getApiClientStub(); let validatorStore: ValidatorStore; @@ -48,7 +48,7 @@ describe("ValidatorStore", function () { vi.resetAllMocks(); }); - it("Should validate graffiti,feeRecipient etc. from valProposerConfig and ValidatorStore", async function () { + it("Should validate graffiti,feeRecipient etc. from valProposerConfig and ValidatorStore", async () => { //pubkeys[0] values expect(validatorStore.getGraffiti(toHexString(pubkeys[0]))).toBe( valProposerConfig.proposerConfig[toHexString(pubkeys[0])].graffiti From 5adb4ef364e321e5ad0a29b9dd4f504a0a4f8a3b Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 15 Oct 2024 04:50:22 +0100 Subject: [PATCH 158/259] fix: enforce strict timeout for builder to provide bid (#7151) * fix: enforce strict timeout for builder to provide bid * Use math.round --- packages/beacon-node/src/api/impl/validator/index.ts | 4 ++-- packages/beacon-node/src/execution/builder/http.ts | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 6be825b5eb07..17d327c61034 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -89,7 +89,7 @@ import {computeSubnetForCommitteesAtSlot, getPubkeysForIndices, selectBlockProdu export const SYNC_TOLERANCE_EPOCHS = 1; /** - * Cutoff time to wait for execution and builder block production apis to resolve + * Cutoff time to wait from start of the slot for execution and builder block production apis to resolve * Post this time, race execution and builder to pick whatever resolves first * * Empirically the builder block resolves in ~1.5+ seconds, and execution should resolve <1 sec. @@ -637,7 +637,7 @@ export function getValidatorApi( : Promise.reject(new Error("Engine disabled")); const [builder, engine] = await resolveOrRacePromises([builderPromise, enginePromise], { - resolveTimeoutMs: BLOCK_PRODUCTION_RACE_CUTOFF_MS, + resolveTimeoutMs: Math.max(0, BLOCK_PRODUCTION_RACE_CUTOFF_MS - Math.round(chain.clock.secFromSlot(slot) * 1000)), raceTimeoutMs: BLOCK_PRODUCTION_RACE_TIMEOUT_MS, signal: controller.signal, }); diff --git a/packages/beacon-node/src/execution/builder/http.ts b/packages/beacon-node/src/execution/builder/http.ts index 934b874f5ae3..7872c5c17410 100644 --- a/packages/beacon-node/src/execution/builder/http.ts +++ b/packages/beacon-node/src/execution/builder/http.ts @@ -37,6 +37,12 @@ export const defaultExecutionBuilderHttpOpts: ExecutionBuilderHttpOpts = { timeout: 12000, }; +/** + * Duration given to the builder to provide a `SignedBuilderBid` before the deadline + * is reached, aborting the external builder flow in favor of the local build process. + */ +const BUILDER_PROPOSAL_DELAY_TOLERANCE = 1000; + export class ExecutionBuilderHttp implements IExecutionBuilder { readonly api: BuilderApi; readonly config: ChainForkConfig; @@ -115,7 +121,9 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { executionPayloadValue: Wei; blobKzgCommitments?: deneb.BlobKzgCommitments; }> { - const signedBuilderBid = (await this.api.getHeader({slot, parentHash, proposerPubkey})).value(); + const signedBuilderBid = ( + await this.api.getHeader({slot, parentHash, proposerPubkey}, {timeoutMs: BUILDER_PROPOSAL_DELAY_TOLERANCE}) + ).value(); if (!signedBuilderBid) { throw Error("No bid received"); From be0d971386fa5b741c91b5e72052eab76c6511af Mon Sep 17 00:00:00 2001 From: twoeths Date: Tue, 15 Oct 2024 21:37:42 +0700 Subject: [PATCH 159/259] chore: update forkchoice grafana panels (#7161) fix: update forkchoice grafana panels --- dashboards/lodestar_block_processor.json | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/dashboards/lodestar_block_processor.json b/dashboards/lodestar_block_processor.json index 3258efa72fc0..a945916308ab 100644 --- a/dashboards/lodestar_block_processor.json +++ b/dashboards/lodestar_block_processor.json @@ -3985,10 +3985,10 @@ "calcs": [], "displayMode": "list", "placement": "bottom", - "showLegend": false + "showLegend": true }, "tooltip": { - "mode": "single", + "mode": "multi", "sort": "none" }, "tooltipOptions": { @@ -4001,10 +4001,12 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "editorMode": "code", "exemplar": false, "expr": "rate(beacon_fork_choice_find_head_seconds_sum[$rate_interval])/rate(beacon_fork_choice_find_head_seconds_count[$rate_interval])", "interval": "", - "legendFormat": "find head", + "legendFormat": "{{caller}}", + "range": true, "refId": "A" } ], @@ -4103,10 +4105,12 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "editorMode": "code", "exemplar": false, "expr": "beacon_fork_choice_errors_total", "interval": "", "legendFormat": "", + "range": true, "refId": "A" } ], @@ -4189,10 +4193,10 @@ "calcs": [], "displayMode": "list", "placement": "bottom", - "showLegend": true + "showLegend": false }, "tooltip": { - "mode": "single", + "mode": "multi", "sort": "none" }, "tooltipOptions": { @@ -4205,10 +4209,12 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "editorMode": "code", "exemplar": false, "expr": "12 * rate(beacon_fork_choice_find_head_seconds_count[$rate_interval])", "interval": "", - "legendFormat": "updateHead calls", + "legendFormat": "{{caller}}_updateHead_calls", + "range": true, "refId": "A" }, { @@ -4228,11 +4234,13 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "editorMode": "code", "exemplar": false, "expr": "rate(beacon_fork_choice_find_head_seconds_sum[$rate_interval])", "hide": false, "interval": "", - "legendFormat": "usage rate", + "legendFormat": "{{caller}}_usage_rate", + "range": true, "refId": "C" } ], From cf722195b5ebabeb703eb973b2a9b6c70bc32d71 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 15 Oct 2024 15:45:02 +0100 Subject: [PATCH 160/259] chore: print calculated block production cutoff time (#7163) --- packages/beacon-node/src/api/impl/validator/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 17d327c61034..1bf3c4f6f659 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -589,9 +589,12 @@ export function getValidatorApi( }); logger.debug("Produced common block body", loggerContext); + // Calculate cutoff time based on start of the slot + const cutoffMs = Math.max(0, BLOCK_PRODUCTION_RACE_CUTOFF_MS - Math.round(chain.clock.secFromSlot(slot) * 1000)); + logger.verbose("Block production race (builder vs execution) starting", { ...loggerContext, - cutoffMs: BLOCK_PRODUCTION_RACE_CUTOFF_MS, + cutoffMs, timeoutMs: BLOCK_PRODUCTION_RACE_TIMEOUT_MS, }); @@ -637,7 +640,7 @@ export function getValidatorApi( : Promise.reject(new Error("Engine disabled")); const [builder, engine] = await resolveOrRacePromises([builderPromise, enginePromise], { - resolveTimeoutMs: Math.max(0, BLOCK_PRODUCTION_RACE_CUTOFF_MS - Math.round(chain.clock.secFromSlot(slot) * 1000)), + resolveTimeoutMs: cutoffMs, raceTimeoutMs: BLOCK_PRODUCTION_RACE_TIMEOUT_MS, signal: controller.signal, }); From 245d63e5dc368b165107ce0ddc37209da440bfa7 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Wed, 16 Oct 2024 14:44:38 +0200 Subject: [PATCH 161/259] chore: cleanup overrides for the biomejs configuration (#7162) * Clean overrides for unused variables * Fix the naming conventions * Add comments in the biome * Fix code feedback --- biome.jsonc | 188 ++++++------------ packages/api/src/utils/client/httpClient.ts | 1 + packages/api/src/utils/codecs.ts | 3 + packages/api/src/utils/types.ts | 2 +- .../src/db/repositories/checkpointState.ts | 5 +- .../beacon-node/src/network/discv5/utils.ts | 1 + packages/beacon-node/src/util/kzg.ts | 4 + .../test/e2e/eth1/jsonRpcHttpClient.test.ts | 18 +- packages/beacon-node/test/spec/general/bls.ts | 26 +-- .../test/spec/presets/operations.test.ts | 6 +- .../test/spec/utils/runValidSszTest.ts | 1 - packages/beacon-node/test/utils/runEl.ts | 4 +- packages/logger/test/unit/node.node.test.ts | 1 + .../logger/test/unit/winston.node.test.ts | 1 + .../state-transition/test/perf/block/util.ts | 2 - packages/types/src/phase0/validator.ts | 1 + 16 files changed, 107 insertions(+), 157 deletions(-) diff --git a/biome.jsonc b/biome.jsonc index 62d67fb7575f..de0689f2d761 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -71,54 +71,32 @@ "useNumberNamespace": "off", // We prefer to auto-initialize enums "useEnumInitializers": "off", - "noVar": "error", - "useConst": "error", + // Namespaces are deprecated way to organize modules in TS + "noNamespace": "error", "useNamingConvention": { "level": "error", "options": { "strictCase": false, + "requireAscii": true, "conventions": [ + // Skip __dirname and any variable starting with _, for rest check next convention { "selector": { - "kind": "any" - }, - "formats": ["camelCase"] - }, - { - "selector": { - "kind": "classProperty" - }, - "formats": ["camelCase"] - }, - { - "selector": { - "kind": "objectLiteralProperty" - }, - "formats": ["camelCase"] - }, - { - "selector": { - "kind": "classMethod" - }, - "formats": ["camelCase"] - }, - { - "selector": { - "kind": "functionParameter" + "kind": "variable" }, - "formats": ["camelCase"] + "match": "(?:__dirname)|(?:_.*)|(.*)" }, { "selector": { "kind": "variable" }, - "formats": ["camelCase", "CONSTANT_CASE"] + "formats": ["camelCase", "PascalCase", "CONSTANT_CASE"] }, { "selector": { "kind": "typeLike" }, - "formats": ["PascalCase"] + "formats": ["camelCase", "snake_case", "PascalCase", "CONSTANT_CASE"] }, { "selector": { @@ -128,62 +106,62 @@ }, { "selector": { - "kind": "enumMember" + "kind": "objectLiteralProperty" }, - "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + "formats": ["camelCase", "snake_case", "PascalCase", "CONSTANT_CASE"] }, { "selector": { - "kind": "classProperty" + "kind": "objectLiteralMethod" }, - "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + "formats": ["camelCase", "snake_case", "PascalCase", "CONSTANT_CASE"] }, + // Skip any property starting with _ and then check for next convention { "selector": { - "kind": "typeProperty" + "kind": "classProperty" }, - "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + "match": "(?:_.*)|(.*)" }, { "selector": { - "kind": "classMember" + "kind": "classProperty" }, - "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + "formats": ["camelCase", "snake_case", "PascalCase", "CONSTANT_CASE"] }, { "selector": { - "kind": "objectLiteralMethod" + "kind": "typeProperty" }, - "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + "formats": ["camelCase", "snake_case", "PascalCase", "CONSTANT_CASE"] }, { "selector": { "kind": "typeMethod" }, - "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + "formats": ["camelCase", "snake_case", "PascalCase", "CONSTANT_CASE"] }, { "selector": { - "kind": "variable" + "kind": "enumMember" }, - "formats": ["PascalCase", "camelCase", "CONSTANT_CASE"] + "formats": ["camelCase", "snake_case", "PascalCase", "CONSTANT_CASE"] }, { "selector": { - "kind": "importAlias" + "kind": "indexParameter" }, - "formats": ["PascalCase", "camelCase"] + "formats": ["camelCase", "PascalCase"] }, { "selector": { - "kind": "importNamespace" + "kind": "function" }, - "formats": ["PascalCase", "camelCase"] + "formats": ["camelCase", "PascalCase"] } ] } - }, - "noNamespace": "error" + } }, "suspicious": { // `void` as type is useful in our case when used as generic constraint e.g. K extends number | void @@ -246,13 +224,7 @@ "globals": ["BigInt"] }, "overrides": [ - { - "include": ["packages/**/test/perf/**/*.test.ts", "packages/state-transition/test/utils/beforeValueMocha.ts"], - "javascript": { - // These are used by mocha - "globals": ["describe", "it", "before", "after"] - } - }, + // Code using console output { "include": ["packages/cli/src/", "packages/test-utils/src", "packages/flare/src"], "linter": { @@ -263,89 +235,57 @@ } } }, + // All test files { - "include": [ - "**/*.config.js", - "**/*.config.mjs", - "**/*.config.cjs", - "**/*.config.ts", - "scripts/vitest/**/*.ts", - "scripts/vite/**/*.ts", - "**/types/**/*.ts", - "packages/api/src/beacon/routes/*.ts", - "packages/api/src/**/routes.ts", - "packages/api/src/utils/server/handler.ts", - "packages/api/test/unit/client/urlFormat.test.ts", - "packages/beacon-node/src/api/impl/config/constants.ts", - "packages/beacon-node/src/eth1/provider/eth1Provider.ts", - "" - ], - "linter": { - "rules": { - "style": { - "useNamingConvention": { - "level": "off", - "options": { - "strictCase": false - } - } - } - } - } - }, - { - "include": [ - "**/test/**/*.ts", - "packages/*/test/**/*.js", - "packages/api/src/utils/**/*.ts", - "packages/beacon-node/src/db/repositories/checkpointState.ts", - "packages/spec-test-util/src/single.ts" - ], - "linter": { - "rules": { - "suspicious": { - "noExplicitAny": "off" - } - } - } - }, - { - "include": ["packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts"], - "linter": { - "rules": { - "correctness": { - "noUnusedVariables": "off" - } - } - } - }, - { - "include": ["**/test/**/*.ts", "packages/*/test/**/*.js"], + "include": ["**/test/**/*.ts", "packages/spec-test-util/src"], "linter": { "rules": { + "complexity": { + // During tests we often need to use private/protected attributes, which is only possible with literal keys + "useLiteralKeys": "off" + }, "suspicious": { + // During tests it's quicker to define variables with `let` without specifying types + "noImplicitAnyLet": "off", + // During testing we use `any` type for quick assignments + "noExplicitAny": "off", + // Console logging is often used in tests "noConsoleLog": "off" } } } }, + // Dependencies still using mocha { - "include": ["**/perf/**/*.ts"], - "linter": { - "rules": {} + "include": ["packages/**/test/perf/**/*.test.ts", "packages/state-transition/test/utils/beforeValueMocha.ts"], + "javascript": { + // These are used by mocha + "globals": ["describe", "it", "before", "after"] } }, { - "include": ["**/test/**/*.test.ts"], + "include": [ + // These files are using mix cases e.g. `engine_newPayloadV4` + // It's a mix of snake_case and camelCase, which can't validated by biome + "packages/beacon-node/src/db/buckets.ts", + "packages/beacon-node/src/execution/engine/mock.ts", + "packages/beacon-node/src/execution/engine/types.ts", + "packages/beacon-node/src/eth1/provider/eth1Provider.ts", + "packages/validator/src/buckets.ts", + "packages/prover/src/types.ts", + "prover/src/utils/process.ts", + "prover/src/verified_requests/**/*.ts", + "packages/types/src/utils/**/*.ts", + // This file is using snake_case function names + "packages/beacon-node/test/spec/bls/bls.ts" + ], "linter": { "rules": { - "complexity": { - // During tests we often need to use private/protected attributes, which is only possible with literal keys - "useLiteralKeys": "off" - }, - "suspicious": { - // During tests it's quicker to define variables with `let` without specifying types - "noImplicitAnyLet": "off" + "style": { + "useNamingConvention": { + "level": "off", + "options": {} + } } } } diff --git a/packages/api/src/utils/client/httpClient.ts b/packages/api/src/utils/client/httpClient.ts index 721a150f7fcd..33b93e3a9d41 100644 --- a/packages/api/src/utils/client/httpClient.ts +++ b/packages/api/src/utils/client/httpClient.ts @@ -196,6 +196,7 @@ export class HttpClient implements IHttpClient { this.logger?.debug("Requesting fallback URL", {routeId, baseUrl: printableUrl, score: this.urlsScore[i]}); } + // biome-ignore lint/style/useNamingConvention: Author preferred this format const i_ = i; // Keep local copy of i variable to index urlScore after requestWithBody() resolves const urlInit = this.urlsInits[i]; diff --git a/packages/api/src/utils/codecs.ts b/packages/api/src/utils/codecs.ts index db96daf0ce50..c075d8592a46 100644 --- a/packages/api/src/utils/codecs.ts +++ b/packages/api/src/utils/codecs.ts @@ -19,8 +19,11 @@ export type EmptyRequest = Record; export type EmptyResponseData = void; export type EmptyMeta = void; +// biome-ignore lint/suspicious/noExplicitAny: We can not use `unknown` type here export type AnyEndpoint = Endpoint; +// biome-ignore lint/suspicious/noExplicitAny: We can not use `unknown` type here export type EmptyRequestEndpoint = Endpoint; +// biome-ignore lint/suspicious/noExplicitAny: We can not use `unknown` type here export type EmptyResponseEndpoint = Endpoint; /** Shortcut for routes that have no params, query */ diff --git a/packages/api/src/utils/types.ts b/packages/api/src/utils/types.ts index abe2f358320d..aef18b47d940 100644 --- a/packages/api/src/utils/types.ts +++ b/packages/api/src/utils/types.ts @@ -6,7 +6,7 @@ import {WireFormat} from "./wireFormat.js"; export type HasOnlyOptionalProps = { [K in keyof T]-?: object extends Pick ? never : K; -} extends {[_ in keyof T]: never} +} extends {[K2 in keyof T]: never} ? true : false; diff --git a/packages/beacon-node/src/db/repositories/checkpointState.ts b/packages/beacon-node/src/db/repositories/checkpointState.ts index cb111a497f87..7bace3f3f3fc 100644 --- a/packages/beacon-node/src/db/repositories/checkpointState.ts +++ b/packages/beacon-node/src/db/repositories/checkpointState.ts @@ -11,9 +11,10 @@ import {Bucket, getBucketNameByValue} from "../buckets.js"; export class CheckpointStateRepository extends Repository { constructor(config: ChainForkConfig, db: Db) { // Pick some type but won't be used. Casted to any because no type can match `BeaconStateAllForks` - const type = ssz.phase0.BeaconState as any; + const type = ssz.phase0.BeaconState; const bucket = Bucket.allForks_checkpointState; - super(config, db, bucket, type, getBucketNameByValue(bucket)); + // biome-ignore lint/suspicious/noExplicitAny: The type is complex to specify a proper override + super(config, db, bucket, type as any, getBucketNameByValue(bucket)); } getId(): Uint8Array { diff --git a/packages/beacon-node/src/network/discv5/utils.ts b/packages/beacon-node/src/network/discv5/utils.ts index e5707b483281..699675dfbe38 100644 --- a/packages/beacon-node/src/network/discv5/utils.ts +++ b/packages/beacon-node/src/network/discv5/utils.ts @@ -5,6 +5,7 @@ import {ENRKey} from "../metadata.js"; export enum ENRRelevance { no_tcp = "no_tcp", no_eth2 = "no_eth2", + // biome-ignore lint/style/useNamingConvention: Need to use the this name for network convention unknown_forkDigest = "unknown_forkDigest", relevant = "relevant", } diff --git a/packages/beacon-node/src/util/kzg.ts b/packages/beacon-node/src/util/kzg.ts index e89d4e0dfc99..42224d1ebaa6 100644 --- a/packages/beacon-node/src/util/kzg.ts +++ b/packages/beacon-node/src/util/kzg.ts @@ -86,7 +86,9 @@ export function loadEthereumTrustedSetup(mode: TrustedFileMode = TrustedFileMode } export interface TrustedSetupJSON { + // biome-ignore lint/style/useNamingConvention: Need to be consistent with KZG pattern setup_G1: string[]; + // biome-ignore lint/style/useNamingConvention: Need to be consistent with KZG pattern setup_G2: string[]; } @@ -120,7 +122,9 @@ export function trustedSetupJsonToBin(data: TrustedSetupJSON): TrustedSetupBin { export function trustedSetupBinToJson(bytes: TrustedSetupBin): TrustedSetupJSON { const data: TrustedSetupJSON = { + // biome-ignore lint/style/useNamingConvention: Need to be consistent with KZG pattern setup_G1: [], + // biome-ignore lint/style/useNamingConvention: Need to be consistent with KZG pattern setup_G2: [], }; diff --git a/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts b/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts index bc41b5f1c546..91131a89f379 100644 --- a/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts +++ b/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts @@ -41,13 +41,13 @@ describe("eth1 / jsonRpcHttpClient", () => { { id: "Bad port", url: `http://localhost:${port + 1}`, - requestListener: (req, res) => res.end(), + requestListener: (_req, res) => res.end(), error: "", errorCode: "ECONNREFUSED", }, { id: "Not a JSON RPC endpoint", - requestListener: (req, res) => { + requestListener: (_req, res) => { res.setHeader("Content-Type", "text/html"); res.end(""); }, @@ -55,7 +55,7 @@ describe("eth1 / jsonRpcHttpClient", () => { }, { id: "Endpoint returns HTTP error", - requestListener: (req, res) => { + requestListener: (_req, res) => { res.statusCode = 404; res.end(); }, @@ -63,7 +63,7 @@ describe("eth1 / jsonRpcHttpClient", () => { }, { id: "RPC payload with error", - requestListener: (req, res) => { + requestListener: (_req, res) => { res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({jsonrpc: "2.0", id: 83, error: noMethodError})); }, @@ -71,7 +71,7 @@ describe("eth1 / jsonRpcHttpClient", () => { }, { id: "RPC payload with non-spec error: error has no message", - requestListener: (req, res) => { + requestListener: (_req, res) => { res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({jsonrpc: "2.0", id: 83, error: {code: noMethodError.code}})); }, @@ -79,7 +79,7 @@ describe("eth1 / jsonRpcHttpClient", () => { }, { id: "RPC payload with non-spec error: error is a string", - requestListener: (req, res) => { + requestListener: (_req, res) => { res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({jsonrpc: "2.0", id: 83, error: notInSpecError})); }, @@ -87,7 +87,7 @@ describe("eth1 / jsonRpcHttpClient", () => { }, { id: "RPC payload with no result", - requestListener: (req, res) => { + requestListener: (_req, res) => { res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({jsonrpc: "2.0", id: 83})); }, @@ -226,7 +226,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", () => { it("should retry 404", async () => { let requestCount = 0; - const server = http.createServer((req, res) => { + const server = http.createServer((_req, res) => { requestCount++; res.statusCode = 404; res.end(); @@ -317,7 +317,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", () => { it("should not retry payload error", async () => { let requestCount = 0; - const server = http.createServer((req, res) => { + const server = http.createServer((_req, res) => { requestCount++; res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify({jsonrpc: "2.0", id: 83, error: noMethodError})); diff --git a/packages/beacon-node/test/spec/general/bls.ts b/packages/beacon-node/test/spec/general/bls.ts index dfebe945b069..128b5b4f5613 100644 --- a/packages/beacon-node/test/spec/general/bls.ts +++ b/packages/beacon-node/test/spec/general/bls.ts @@ -5,8 +5,8 @@ import { Signature, aggregateSerializedPublicKeys, aggregateSignatures, - aggregateVerify, - fastAggregateVerify, + aggregateVerify as BLSAggregateVerify, + fastAggregateVerify as BLSFastAggregateVerify, verify as _verify, } from "@chainsafe/blst"; import {InputType} from "@lodestar/spec-test-util"; @@ -14,10 +14,10 @@ import {TestRunnerFn} from "../utils/types.js"; const testFnByType: Record any> = { aggregate, - aggregate_verify, - eth_aggregate_pubkeys, - eth_fast_aggregate_verify, - fast_aggregate_verify, + aggregate_verify: aggregateVerify, + eth_aggregate_pubkeys: ethAggregatePubkeys, + eth_fast_aggregate_verify: ethFastAggregateVerify, + fast_aggregate_verify: fastAggregateVerify, sign, verify, }; @@ -86,10 +86,10 @@ function aggregate(input: string[]): string | null { * output: bool -- true (VALID) or false (INVALID) * ``` */ -function aggregate_verify(input: {pubkeys: string[]; messages: string[]; signature: string}): boolean { +function aggregateVerify(input: {pubkeys: string[]; messages: string[]; signature: string}): boolean { const {pubkeys, messages, signature} = input; try { - return aggregateVerify( + return BLSAggregateVerify( messages.map(fromHexString), pubkeys.map((pk) => PublicKey.fromHex(pk)), Signature.fromHex(signature) @@ -105,7 +105,7 @@ function aggregate_verify(input: {pubkeys: string[]; messages: string[]; signatu * output: BLS Signature -- expected output, single BLS signature or empty. * ``` */ -function eth_aggregate_pubkeys(input: string[]): string | null { +function ethAggregatePubkeys(input: string[]): string | null { // Don't add this checks in the source as beacon nodes check the pubkeys for inf when onboarding for (const pk of input) { if (pk === G1_POINT_AT_INFINITY) return null; @@ -127,7 +127,7 @@ function eth_aggregate_pubkeys(input: string[]): string | null { * output: bool -- true (VALID) or false (INVALID) * ``` */ -function eth_fast_aggregate_verify(input: {pubkeys: string[]; message: string; signature: string}): boolean { +function ethFastAggregateVerify(input: {pubkeys: string[]; message: string; signature: string}): boolean { const {pubkeys, message, signature} = input; if (pubkeys.length === 0 && signature === G2_POINT_AT_INFINITY) { @@ -140,7 +140,7 @@ function eth_fast_aggregate_verify(input: {pubkeys: string[]; message: string; s } try { - return fastAggregateVerify( + return BLSFastAggregateVerify( fromHexString(message), pubkeys.map((hex) => PublicKey.fromHex(hex)), Signature.fromHex(signature) @@ -159,10 +159,10 @@ function eth_fast_aggregate_verify(input: {pubkeys: string[]; message: string; s * output: bool -- true (VALID) or false (INVALID) * ``` */ -function fast_aggregate_verify(input: {pubkeys: string[]; message: string; signature: string}): boolean | null { +function fastAggregateVerify(input: {pubkeys: string[]; message: string; signature: string}): boolean | null { const {pubkeys, message, signature} = input; try { - return fastAggregateVerify( + return BLSFastAggregateVerify( fromHexString(message), pubkeys.map((hex) => PublicKey.fromHex(hex, true)), Signature.fromHex(signature, true) diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index 1ab8c19da5ef..b6a479ee3794 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -21,7 +21,7 @@ import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; // Define above to re-use in sync_aggregate and sync_aggregate_random -const sync_aggregate: BlockProcessFn = ( +const syncAggregate: BlockProcessFn = ( state, testCase: {sync_aggregate: altair.SyncAggregate} ) => { @@ -60,8 +60,8 @@ const operationFns: Record> = blockFns.processProposerSlashing(fork, state, testCase.proposer_slashing); }, - sync_aggregate, - sync_aggregate_random: sync_aggregate, + sync_aggregate: syncAggregate, + sync_aggregate_random: syncAggregate, voluntary_exit: (state, testCase: {voluntary_exit: phase0.SignedVoluntaryExit}) => { const fork = state.config.getForkSeq(state.slot); diff --git a/packages/beacon-node/test/spec/utils/runValidSszTest.ts b/packages/beacon-node/test/spec/utils/runValidSszTest.ts index 748a7770b19c..a8d3060af08d 100644 --- a/packages/beacon-node/test/spec/utils/runValidSszTest.ts +++ b/packages/beacon-node/test/spec/utils/runValidSszTest.ts @@ -83,7 +83,6 @@ export function runValidSszTest(type: Type, testData: ValidTestCaseData if (type.isBasic) { console.log("ROOTS Basic", toHexString(type.serialize(testDataValue))); } else { - // biome-ignore lint/complexity/useLiteralKeys: The `getRoots` is a protected attribute const roots = (type as CompositeType)["getRoots"](testDataValue); console.log( "ROOTS Composite", diff --git a/packages/beacon-node/test/utils/runEl.ts b/packages/beacon-node/test/utils/runEl.ts index 8a2da7104510..9a407f91d414 100644 --- a/packages/beacon-node/test/utils/runEl.ts +++ b/packages/beacon-node/test/utils/runEl.ts @@ -179,8 +179,8 @@ async function startELProcess(args: { return tearDownCallBack; } -async function waitForELOffline(ENGINE_PORT: string): Promise { - const port = parseInt(ENGINE_PORT); +async function waitForELOffline(enginePort: string): Promise { + const port = parseInt(enginePort); for (let i = 0; i < 60; i++) { console.log("Waiting for EL offline..."); diff --git a/packages/logger/test/unit/node.node.test.ts b/packages/logger/test/unit/node.node.test.ts index da1245fa37f1..b7c882a1e3bd 100644 --- a/packages/logger/test/unit/node.node.test.ts +++ b/packages/logger/test/unit/node.node.test.ts @@ -6,6 +6,7 @@ import {formatsTestCases} from "../fixtures/loggerFormats.js"; // Node.js maps `process.stdout` to `console._stdout`. // spy does not work on `process.stdout` directly. +// biome-ignore lint/style/useNamingConvention: Need property name _stdout for testing type TestConsole = typeof console & {_stdout: {write: Mock}}; describe("node logger", () => { diff --git a/packages/logger/test/unit/winston.node.test.ts b/packages/logger/test/unit/winston.node.test.ts index 6763cc667afd..e4cfca2b041a 100644 --- a/packages/logger/test/unit/winston.node.test.ts +++ b/packages/logger/test/unit/winston.node.test.ts @@ -8,6 +8,7 @@ import {readFileWhenExists} from "../utils/files.js"; // Node.js maps `process.stdout` to `console._stdout`. // spy does not work on `process.stdout` directly. +// biome-ignore lint/style/useNamingConvention: Need property name _stdout for testing type TestConsole = typeof console & {_stdout: {write: Mock}}; describe("winston logger", () => { diff --git a/packages/state-transition/test/perf/block/util.ts b/packages/state-transition/test/perf/block/util.ts index 441c67deb198..baa86dcac6a5 100644 --- a/packages/state-transition/test/perf/block/util.ts +++ b/packages/state-transition/test/perf/block/util.ts @@ -206,9 +206,7 @@ function getDeposits(preState: CachedBeaconStateAllForks, count: number): phase0 // Fill depositRootViewDU up to depositCount // Instead of actually filling it, just mutate the length to allow .set() - // biome-ignore lint/complexity/useLiteralKeys: It is a protected attribute depositRootViewDU["_length"] = depositCount + count; - // biome-ignore lint/complexity/useLiteralKeys: It is a protected attribute depositRootViewDU["dirtyLength"] = true; for (let i = 0; i < count; i++) { diff --git a/packages/types/src/phase0/validator.ts b/packages/types/src/phase0/validator.ts index a6ec0fb18103..aaff2deaeb27 100644 --- a/packages/types/src/phase0/validator.ts +++ b/packages/types/src/phase0/validator.ts @@ -34,6 +34,7 @@ export class ValidatorNodeStructType extends ContainerNodeStructType Date: Wed, 16 Oct 2024 16:24:33 +0100 Subject: [PATCH 162/259] fix: add logger to builder http client (#7168) --- packages/beacon-node/src/execution/builder/http.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/src/execution/builder/http.ts b/packages/beacon-node/src/execution/builder/http.ts index 7872c5c17410..7bc47e354c6c 100644 --- a/packages/beacon-node/src/execution/builder/http.ts +++ b/packages/beacon-node/src/execution/builder/http.ts @@ -68,7 +68,7 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { headers: opts.userAgent ? {"User-Agent": opts.userAgent} : undefined, }, }, - {config, metrics: metrics?.builderHttpClient} + {config, metrics: metrics?.builderHttpClient, logger} ); logger?.info("External builder", {url: toPrintableUrl(baseUrl)}); this.config = config; From de0d6ab89b575ad20c593acf20d7c97d2c884ab1 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 16 Oct 2024 16:25:21 +0100 Subject: [PATCH 163/259] chore: fix builder api panels in block production dashboard (#7167) --- dashboards/lodestar_block_production.json | 282 +++++++++++----------- 1 file changed, 142 insertions(+), 140 deletions(-) diff --git a/dashboards/lodestar_block_production.json b/dashboards/lodestar_block_production.json index 58c7ba3f3684..3ec4a164f748 100644 --- a/dashboards/lodestar_block_production.json +++ b/dashboards/lodestar_block_production.json @@ -90,6 +90,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -252,7 +253,6 @@ } ], "title": "Full block production avg time with steps", - "transformations": [], "type": "timeseries" }, { @@ -266,6 +266,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -428,7 +429,6 @@ } ], "title": "Blinded block production avg time with steps", - "transformations": [], "type": "timeseries" }, { @@ -442,6 +442,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -599,6 +600,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -683,6 +685,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -822,7 +825,8 @@ }, "showValue": "never", "tooltip": { - "show": true, + "mode": "single", + "showColorScale": false, "yHistogram": false }, "yAxis": { @@ -831,7 +835,7 @@ "unit": "s" } }, - "pluginVersion": "10.1.1", + "pluginVersion": "10.4.1", "reverseYBuckets": false, "targets": [ { @@ -874,6 +878,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -1028,145 +1033,159 @@ "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "fill": 1, - "fillGradient": 1, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 3, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "unit": "none" + }, + "overrides": [] + }, "gridPos": { "h": 8, "w": 12, "x": 12, "y": 25 }, - "hiddenSeries": false, "id": 378, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": false, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "10.1.1", - "pointradius": 0.5, - "points": true, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.1", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "editorMode": "code", "exemplar": false, - "expr": "12 * rate(lodestar_api_rest_response_time_seconds_count{operationId=~\"produceBlindedBlock|publishBlindedBlock|registerValidator\"}[$rate_interval])", + "expr": "12 * rate(lodestar_builder_http_client_request_time_seconds_count[$rate_interval])", "hide": false, "interval": "", - "legendFormat": "{{operationId}}", + "legendFormat": "{{routeId}}", + "range": true, "refId": "D" } ], - "thresholds": [], - "timeRegions": [], "title": "Builder API queries / slot", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:580", - "format": "none", - "logBase": 2, - "show": true - }, - { - "$$hashKey": "object:581", - "format": "short", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "fieldConfig": { "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], "unit": "s" }, "overrides": [] }, - "fill": 1, - "fillGradient": 1, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 33 }, - "hiddenSeries": false, "id": 376, - "legend": { - "avg": false, - "current": false, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": false, - "linewidth": 1, - "nullPointMode": "null", "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "10.1.1", - "pointradius": 0.5, - "points": true, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "10.4.1", "targets": [ { "datasource": { @@ -1175,45 +1194,16 @@ }, "editorMode": "code", "exemplar": false, - "expr": "rate(lodestar_api_rest_response_time_seconds_sum{operationId=~\"produceBlindedBlock|publishBlindedBlock|registerValidator\"}[$rate_interval])\n/\nrate(lodestar_api_rest_response_time_seconds_count{operationId=~\"produceBlindedBlock|publishBlindedBlock|registerValidator\"}[$rate_interval])", + "expr": "rate(lodestar_builder_http_client_request_time_seconds_sum[$rate_interval])\n/\nrate(lodestar_builder_http_client_request_time_seconds_count[$rate_interval])", "hide": false, "interval": "", - "legendFormat": "{{operationId}}", + "legendFormat": "{{routeId}}", "range": true, "refId": "B" } ], - "thresholds": [], - "timeRegions": [], - "title": "Builder API response times", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:87", - "format": "s", - "logBase": 2, - "show": true - }, - { - "$$hashKey": "object:88", - "format": "s", - "logBase": 1, - "show": false - } - ], - "yaxis": { - "align": false - } + "title": "Builder API request times", + "type": "timeseries" }, { "datasource": { @@ -1226,6 +1216,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -1328,6 +1319,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -1436,6 +1428,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -1540,10 +1533,12 @@ "fields": "", "values": false }, + "showPercentChange": false, "text": {}, - "textMode": "auto" + "textMode": "auto", + "wideLayout": true }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.4.1", "targets": [ { "exemplar": false, @@ -1567,6 +1562,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -1580,6 +1576,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1683,6 +1680,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -1766,6 +1764,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -1903,7 +1902,8 @@ "layout": "auto" }, "tooltip": { - "show": true, + "mode": "single", + "showColorScale": false, "yHistogram": false }, "yAxis": { @@ -1911,7 +1911,7 @@ "reverse": false } }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.4.1", "targets": [ { "datasource": { @@ -1981,7 +1981,8 @@ "layout": "auto" }, "tooltip": { - "show": true, + "mode": "single", + "showColorScale": false, "yHistogram": false }, "yAxis": { @@ -1989,7 +1990,7 @@ "reverse": false } }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.4.1", "targets": [ { "datasource": { @@ -2018,6 +2019,7 @@ "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", @@ -2031,6 +2033,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2055,7 +2058,7 @@ "h": 8, "w": 12, "x": 0, - "y": 65 + "y": 73 }, "id": 539, "options": { @@ -2100,8 +2103,7 @@ } ], "refresh": "10s", - "schemaVersion": 38, - "style": "dark", + "schemaVersion": 39, "tags": [ "lodestar" ], From 1d24ed5e674b9ffe968114b18f7f2fa0cae8b8d1 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 16 Oct 2024 16:36:03 +0100 Subject: [PATCH 164/259] fix: update electra BuilderBid container (#7169) --- packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts | 1 - packages/types/src/electra/sszTypes.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index 8d90fb6c5b1a..2b85a09e816e 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -293,7 +293,6 @@ export async function produceBlockBody( throw Error(`Missing blobsBundle response from getPayload at fork=${fork}`); } - // validate blindedBlobsBundle if (this.opts.sanityCheckExecutionEngineBlobs) { validateBlobsAndKzgCommitments(executionPayload, blobsBundle); } diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index d73c33edd523..079af08352ec 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -235,7 +235,7 @@ export const SignedBlindedBeaconBlock = new ContainerType( export const BuilderBid = new ContainerType( { header: ExecutionPayloadHeader, // Modified in ELECTRA - blindedBlobsBundle: denebSsz.BlobKzgCommitments, + blobKzgCommitments: denebSsz.BlobKzgCommitments, executionRequests: ExecutionRequests, // New in ELECTRA value: UintBn256, pubkey: BLSPubkey, From be3af65820f176c97ffddf42e7a7c012a4edcf92 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Wed, 16 Oct 2024 19:00:28 -0700 Subject: [PATCH 165/259] chore: fix and add workaround on params e2e tests --- .../test/spec/presets/operations.test.ts | 3 +-- .../test/e2e/ensure-config-is-synced.test.ts | 22 ++++++++++++++++--- .../src/block/processDeposit.ts | 4 ++-- .../src/block/processDepositRequest.ts | 6 +---- .../src/block/processOperations.ts | 2 +- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index b6a479ee3794..4c90831ef155 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -92,8 +92,7 @@ const operationFns: Record> = }, deposit_request: (state, testCase: {deposit_request: electra.DepositRequest}) => { - const fork = state.config.getForkSeq(state.slot); - blockFns.processDepositRequest(fork, state as CachedBeaconStateElectra, testCase.deposit_request); + blockFns.processDepositRequest(state as CachedBeaconStateElectra, testCase.deposit_request); }, consolidation_request: (state, testCase: {consolidation_request: electra.ConsolidationRequest}) => { diff --git a/packages/params/test/e2e/ensure-config-is-synced.test.ts b/packages/params/test/e2e/ensure-config-is-synced.test.ts index 2322b2e1ff10..c54b0d4d44f8 100644 --- a/packages/params/test/e2e/ensure-config-is-synced.test.ts +++ b/packages/params/test/e2e/ensure-config-is-synced.test.ts @@ -8,7 +8,13 @@ import {loadConfigYaml} from "../yaml.js"; // Not e2e, but slow. Run with e2e tests /** https://github.com/ethereum/consensus-specs/releases */ -const specConfigCommit = "v1.5.0-alpha.3"; +const specConfigCommit = "v1.5.0-alpha.8"; +/** + * Fields that we filter from local config when doing comparison. + * Ideally this should be empty as it is not spec compliant + * For `MAX_BLOBS_PER_BLOCK`, see https://github.com/ChainSafe/lodestar/issues/7172 + */ +const ignoredLocalPresetFields: (keyof BeaconPreset)[] = ["MAX_BLOBS_PER_BLOCK"]; describe("Ensure config is synced", () => { vi.setConfig({testTimeout: 60 * 1000}); @@ -25,12 +31,22 @@ describe("Ensure config is synced", () => { }); function assertCorrectPreset(localPreset: BeaconPreset, remotePreset: BeaconPreset): void { + const filteredLocalPreset: Partial = Object.keys(localPreset) + .filter((key) => !ignoredLocalPresetFields.includes(key as keyof BeaconPreset)) + .reduce( + (acc, key) => { + acc[key as keyof BeaconPreset] = localPreset[key as keyof BeaconPreset]; + return acc; + }, + {} as Partial + ); + // Check each key for better debuggability for (const key of Object.keys(remotePreset) as (keyof BeaconPreset)[]) { - expect(localPreset[key]).toBe(remotePreset[key]); + expect(filteredLocalPreset[key]).toBe(remotePreset[key]); } - expect(localPreset).toEqual(remotePreset); + expect(filteredLocalPreset).toEqual(remotePreset); } async function downloadRemoteConfig(preset: "mainnet" | "minimal", commit: string): Promise { diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 50622d81a2dd..b7e9827c4cd7 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -55,11 +55,11 @@ export function applyDeposit( state: CachedBeaconStateAllForks, deposit: DepositData | DepositRequest ): void { - const {config, epochCtx} = state; + const {config, epochCtx, validators} = state; const {pubkey, withdrawalCredentials, amount, signature} = deposit; const cachedIndex = epochCtx.getValidatorIndex(pubkey); - const isNewValidator = cachedIndex === null || !Number.isSafeInteger(cachedIndex); + const isNewValidator = cachedIndex === null || !Number.isSafeInteger(cachedIndex) || cachedIndex >= validators.length; if (fork < ForkSeq.electra) { if (isNewValidator) { diff --git a/packages/state-transition/src/block/processDepositRequest.ts b/packages/state-transition/src/block/processDepositRequest.ts index a349c372d51b..7c6ea4928f54 100644 --- a/packages/state-transition/src/block/processDepositRequest.ts +++ b/packages/state-transition/src/block/processDepositRequest.ts @@ -3,11 +3,7 @@ import {ForkSeq, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateElectra} from "../types.js"; -export function processDepositRequest( - fork: ForkSeq, - state: CachedBeaconStateElectra, - depositRequest: electra.DepositRequest -): void { +export function processDepositRequest(state: CachedBeaconStateElectra, depositRequest: electra.DepositRequest): void { if (state.depositRequestsStartIndex === UNSET_DEPOSIT_REQUESTS_START_INDEX) { state.depositRequestsStartIndex = BigInt(depositRequest.index); } diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index bb52af14ba32..d611581584c1 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -68,7 +68,7 @@ export function processOperations( const bodyElectra = body as electra.BeaconBlockBody; for (const depositRequest of bodyElectra.executionRequests.deposits) { - processDepositRequest(fork, stateElectra, depositRequest); + processDepositRequest(stateElectra, depositRequest); } for (const elWithdrawalRequest of bodyElectra.executionRequests.withdrawals) { From 223e051a81603d248b47558011bac3867e2df645 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Thu, 17 Oct 2024 08:10:57 -0700 Subject: [PATCH 166/259] fix: update field naming to match engine api spec --- packages/beacon-node/src/execution/engine/types.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index d8dcde1ee014..52ddb8548629 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -116,7 +116,7 @@ type ExecutionPayloadRpcWithValue = { // even though CL tracks this as executionPayloadValue, EL returns this as blockValue blockValue: QUANTITY; blobsBundle?: BlobsBundleRpc; - requests?: ExecutionRequestsRpc; + executionRequests?: ExecutionRequestsRpc; shouldOverrideBuilder?: boolean; }; type ExecutionPayloadResponse = ExecutionPayloadRpc | ExecutionPayloadRpcWithValue; @@ -266,7 +266,9 @@ export function parseExecutionPayload( executionPayloadValue = quantityToBigint(response.blockValue); data = response.executionPayload; blobsBundle = response.blobsBundle ? parseBlobsBundle(response.blobsBundle) : undefined; - executionRequests = response.requests ? deserializeExecutionRequests(response.requests) : undefined; + executionRequests = response.executionRequests + ? deserializeExecutionRequests(response.executionRequests) + : undefined; shouldOverrideBuilder = response.shouldOverrideBuilder ?? false; } else { data = response; From b1b56233fb54ee759fb6a9fa032d07d7de112ee3 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sat, 19 Oct 2024 09:29:48 +0100 Subject: [PATCH 167/259] fix: return `el_offline` as `true` in syncing status response if auth failed (#7175) --- packages/beacon-node/src/sync/sync.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/sync/sync.ts b/packages/beacon-node/src/sync/sync.ts index 1e03431adbbb..94eea73e1ef8 100644 --- a/packages/beacon-node/src/sync/sync.ts +++ b/packages/beacon-node/src/sync/sync.ts @@ -88,7 +88,9 @@ export class BeaconSync implements IBeaconSync { getSyncStatus(): SyncingStatus { const currentSlot = this.chain.clock.currentSlot; - const elOffline = this.chain.executionEngine.state === ExecutionEngineState.OFFLINE; + const elOffline = + this.chain.executionEngine.state === ExecutionEngineState.OFFLINE || + this.chain.executionEngine.state === ExecutionEngineState.AUTH_FAILED; // If we are pre/at genesis, signal ready if (currentSlot <= GENESIS_SLOT) { From e6c1c5b3e38a29ab2cd056a3ec08ab31afaea81f Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 21 Oct 2024 08:53:28 +0100 Subject: [PATCH 168/259] chore: update block proposal errors dashboard panel (#7179) --- dashboards/lodestar_block_production.json | 2 +- packages/api/src/beacon/routes/beacon/block.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dashboards/lodestar_block_production.json b/dashboards/lodestar_block_production.json index 3ec4a164f748..444adccaa59e 100644 --- a/dashboards/lodestar_block_production.json +++ b/dashboards/lodestar_block_production.json @@ -746,7 +746,7 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "rate(lodestar_api_rest_errors_total{operationId=~\"produceBlockV2|produceBlindedBlock|publishBlock|publishBlindedBlock\"}[$rate_interval])", + "expr": "rate(lodestar_api_rest_errors_total{operationId=~\"produceBlockV3|publishBlockV2|publishBlindedBlockV2\"}[$rate_interval])", "legendFormat": "{{operationId}}", "range": true, "refId": "A" diff --git a/packages/api/src/beacon/routes/beacon/block.ts b/packages/api/src/beacon/routes/beacon/block.ts index 04d42cdab81e..cd3cae9fd7ff 100644 --- a/packages/api/src/beacon/routes/beacon/block.ts +++ b/packages/api/src/beacon/routes/beacon/block.ts @@ -499,7 +499,6 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions Date: Mon, 21 Oct 2024 11:10:23 +0200 Subject: [PATCH 169/259] feat: add strategy support for state archives (#7170) * Add strategy support for state-archives * Comment new strategy temporaily * Fix types * Fix unit tests * Fix unit tests * Hide new option * Rename ArchiveMode.Full to ArchiveMode.Frequency * Rename ArchiveMode to StateArchiveMode * Update the code as per feedback * Fix cli package import --- .../src/chain/archiver/archiver.ts | 166 +++++++++++++++++ .../beacon-node/src/chain/archiver/index.ts | 172 +----------------- .../src/chain/archiver/interface.ts | 47 +++++ .../frequencyStateArchiveStrategy.ts} | 31 ++-- packages/beacon-node/src/chain/chain.ts | 2 +- packages/beacon-node/src/chain/options.ts | 6 +- packages/beacon-node/src/node/options.ts | 4 +- .../produceBlock/produceBlockBody.test.ts | 3 +- .../perf/chain/verifyImportBlocks.test.ts | 3 +- .../unit/chain/archive/stateArchiver.test.ts | 2 +- .../test/utils/networkWithMockDb.ts | 2 + .../src/options/beaconNodeOptions/chain.ts | 17 +- .../unit/options/beaconNodeOptions.test.ts | 4 +- 13 files changed, 261 insertions(+), 198 deletions(-) create mode 100644 packages/beacon-node/src/chain/archiver/archiver.ts create mode 100644 packages/beacon-node/src/chain/archiver/interface.ts rename packages/beacon-node/src/chain/archiver/{archiveStates.ts => strategies/frequencyStateArchiveStrategy.ts} (84%) diff --git a/packages/beacon-node/src/chain/archiver/archiver.ts b/packages/beacon-node/src/chain/archiver/archiver.ts new file mode 100644 index 000000000000..2d79f584ea79 --- /dev/null +++ b/packages/beacon-node/src/chain/archiver/archiver.ts @@ -0,0 +1,166 @@ +import {Logger} from "@lodestar/utils"; +import {CheckpointWithHex} from "@lodestar/fork-choice"; +import {IBeaconDb} from "../../db/index.js"; +import {JobItemQueue} from "../../util/queue/index.js"; +import {IBeaconChain} from "../interface.js"; +import {ChainEvent} from "../emitter.js"; +import {Metrics} from "../../metrics/metrics.js"; +import {FrequencyStateArchiveStrategy} from "./strategies/frequencyStateArchiveStrategy.js"; +import {archiveBlocks} from "./archiveBlocks.js"; +import {StateArchiveMode, ArchiverOpts, StateArchiveStrategy} from "./interface.js"; + +export const DEFAULT_STATE_ARCHIVE_MODE = StateArchiveMode.Frequency; + +export const PROCESS_FINALIZED_CHECKPOINT_QUEUE_LEN = 256; + +/** + * Used for running tasks that depends on some events or are executed + * periodically. + */ +export class Archiver { + private stateArchiveMode: StateArchiveMode; + private jobQueue: JobItemQueue<[CheckpointWithHex], void>; + + private prevFinalized: CheckpointWithHex; + private readonly statesArchiverStrategy: StateArchiveStrategy; + private archiveBlobEpochs?: number; + + constructor( + private readonly db: IBeaconDb, + private readonly chain: IBeaconChain, + private readonly logger: Logger, + signal: AbortSignal, + opts: ArchiverOpts, + private readonly metrics?: Metrics | null + ) { + if (opts.stateArchiveMode === StateArchiveMode.Frequency) { + this.statesArchiverStrategy = new FrequencyStateArchiveStrategy(chain.regen, db, logger, opts, chain.bufferPool); + } else { + throw new Error(`State archive strategy "${opts.stateArchiveMode}" currently not supported.`); + } + + this.stateArchiveMode = opts.stateArchiveMode; + this.archiveBlobEpochs = opts.archiveBlobEpochs; + this.prevFinalized = chain.forkChoice.getFinalizedCheckpoint(); + this.jobQueue = new JobItemQueue<[CheckpointWithHex], void>(this.processFinalizedCheckpoint, { + maxLength: PROCESS_FINALIZED_CHECKPOINT_QUEUE_LEN, + signal, + }); + + if (!opts.disableArchiveOnCheckpoint) { + this.chain.emitter.on(ChainEvent.forkChoiceFinalized, this.onFinalizedCheckpoint); + this.chain.emitter.on(ChainEvent.checkpoint, this.onCheckpoint); + + signal.addEventListener( + "abort", + () => { + this.chain.emitter.off(ChainEvent.forkChoiceFinalized, this.onFinalizedCheckpoint); + this.chain.emitter.off(ChainEvent.checkpoint, this.onCheckpoint); + }, + {once: true} + ); + } + } + + /** Archive latest finalized state */ + async persistToDisk(): Promise { + return this.statesArchiverStrategy.maybeArchiveState(this.chain.forkChoice.getFinalizedCheckpoint()); + } + + private onFinalizedCheckpoint = async (finalized: CheckpointWithHex): Promise => { + return this.jobQueue.push(finalized); + }; + + private onCheckpoint = (): void => { + const headStateRoot = this.chain.forkChoice.getHead().stateRoot; + this.chain.regen.pruneOnCheckpoint( + this.chain.forkChoice.getFinalizedCheckpoint().epoch, + this.chain.forkChoice.getJustifiedCheckpoint().epoch, + headStateRoot + ); + + this.statesArchiverStrategy.onCheckpoint(headStateRoot, this.metrics).catch((err) => { + this.logger.error("Error during state archive", {stateArchiveMode: this.stateArchiveMode}, err); + }); + }; + + private processFinalizedCheckpoint = async (finalized: CheckpointWithHex): Promise => { + try { + const finalizedEpoch = finalized.epoch; + this.logger.verbose("Start processing finalized checkpoint", {epoch: finalizedEpoch, rootHex: finalized.rootHex}); + await archiveBlocks( + this.chain.config, + this.db, + this.chain.forkChoice, + this.chain.lightClientServer, + this.logger, + finalized, + this.chain.clock.currentEpoch, + this.archiveBlobEpochs + ); + this.prevFinalized = finalized; + + await this.statesArchiverStrategy.onFinalizedCheckpoint(finalized, this.metrics); + + // should be after ArchiveBlocksTask to handle restart cleanly + await this.statesArchiverStrategy.maybeArchiveState(finalized, this.metrics); + + this.chain.regen.pruneOnFinalized(finalizedEpoch); + + // tasks rely on extended fork choice + const prunedBlocks = this.chain.forkChoice.prune(finalized.rootHex); + await this.updateBackfillRange(finalized); + + this.logger.verbose("Finish processing finalized checkpoint", { + epoch: finalizedEpoch, + rootHex: finalized.rootHex, + prunedBlocks: prunedBlocks.length, + }); + } catch (e) { + this.logger.error("Error processing finalized checkpoint", {epoch: finalized.epoch}, e as Error); + } + }; + + /** + * Backfill sync relies on verified connected ranges (which are represented as key,value + * with a verified jump from a key back to value). Since the node could have progressed + * ahead from, we need to save the forward progress of this node as another backfill + * range entry, that backfill sync will use to jump back if this node is restarted + * for any reason. + * The current backfill has its own backfill entry from anchor slot to last backfilled + * slot. And this would create the entry from the current finalized slot to the anchor + * slot. + */ + private updateBackfillRange = async (finalized: CheckpointWithHex): Promise => { + try { + // Mark the sequence in backfill db from finalized block's slot till anchor slot as + // filled. + const finalizedBlockFC = this.chain.forkChoice.getBlockHex(finalized.rootHex); + if (finalizedBlockFC && finalizedBlockFC.slot > this.chain.anchorStateLatestBlockSlot) { + await this.db.backfilledRanges.put(finalizedBlockFC.slot, this.chain.anchorStateLatestBlockSlot); + + // Clear previously marked sequence till anchorStateLatestBlockSlot, without + // touching backfill sync process sequence which are at + // <=anchorStateLatestBlockSlot i.e. clear >anchorStateLatestBlockSlot + // and < currentSlot + const filteredSeqs = await this.db.backfilledRanges.entries({ + gt: this.chain.anchorStateLatestBlockSlot, + lt: finalizedBlockFC.slot, + }); + this.logger.debug("updated backfilledRanges", { + key: finalizedBlockFC.slot, + value: this.chain.anchorStateLatestBlockSlot, + }); + if (filteredSeqs.length > 0) { + await this.db.backfilledRanges.batchDelete(filteredSeqs.map((entry) => entry.key)); + this.logger.debug( + `Forward Sync - cleaned up backfilledRanges between ${finalizedBlockFC.slot},${this.chain.anchorStateLatestBlockSlot}`, + {seqs: JSON.stringify(filteredSeqs)} + ); + } + } + } catch (e) { + this.logger.error("Error updating backfilledRanges on finalization", {epoch: finalized.epoch}, e as Error); + } + }; +} diff --git a/packages/beacon-node/src/chain/archiver/index.ts b/packages/beacon-node/src/chain/archiver/index.ts index 45169b2fa802..dbcafbe458a6 100644 --- a/packages/beacon-node/src/chain/archiver/index.ts +++ b/packages/beacon-node/src/chain/archiver/index.ts @@ -1,170 +1,2 @@ -import {Logger} from "@lodestar/utils"; -import {CheckpointWithHex} from "@lodestar/fork-choice"; -import {IBeaconDb} from "../../db/index.js"; -import {JobItemQueue} from "../../util/queue/index.js"; -import {IBeaconChain} from "../interface.js"; -import {ChainEvent} from "../emitter.js"; -import {Metrics} from "../../metrics/metrics.js"; -import {StatesArchiver, StatesArchiverOpts} from "./archiveStates.js"; -import {archiveBlocks} from "./archiveBlocks.js"; - -const PROCESS_FINALIZED_CHECKPOINT_QUEUE_LEN = 256; - -export type ArchiverOpts = StatesArchiverOpts & { - disableArchiveOnCheckpoint?: boolean; - archiveBlobEpochs?: number; -}; - -type ProposalStats = { - total: number; - finalized: number; - orphaned: number; - missed: number; -}; - -export type FinalizedStats = { - allValidators: ProposalStats; - attachedValidators: ProposalStats; - finalizedCanonicalCheckpointsCount: number; - finalizedFoundCheckpointsInStateCache: number; - finalizedAttachedValidatorsCount: number; -}; - -/** - * Used for running tasks that depends on some events or are executed - * periodically. - */ -export class Archiver { - private jobQueue: JobItemQueue<[CheckpointWithHex], void>; - - private prevFinalized: CheckpointWithHex; - private readonly statesArchiver: StatesArchiver; - private archiveBlobEpochs?: number; - - constructor( - private readonly db: IBeaconDb, - private readonly chain: IBeaconChain, - private readonly logger: Logger, - signal: AbortSignal, - opts: ArchiverOpts, - private readonly metrics?: Metrics | null - ) { - this.archiveBlobEpochs = opts.archiveBlobEpochs; - this.statesArchiver = new StatesArchiver(chain.regen, db, logger, opts, chain.bufferPool); - this.prevFinalized = chain.forkChoice.getFinalizedCheckpoint(); - this.jobQueue = new JobItemQueue<[CheckpointWithHex], void>(this.processFinalizedCheckpoint, { - maxLength: PROCESS_FINALIZED_CHECKPOINT_QUEUE_LEN, - signal, - }); - - if (!opts.disableArchiveOnCheckpoint) { - this.chain.emitter.on(ChainEvent.forkChoiceFinalized, this.onFinalizedCheckpoint); - this.chain.emitter.on(ChainEvent.checkpoint, this.onCheckpoint); - - signal.addEventListener( - "abort", - () => { - this.chain.emitter.off(ChainEvent.forkChoiceFinalized, this.onFinalizedCheckpoint); - this.chain.emitter.off(ChainEvent.checkpoint, this.onCheckpoint); - }, - {once: true} - ); - } - } - - /** Archive latest finalized state */ - async persistToDisk(): Promise { - await this.statesArchiver.archiveState(this.chain.forkChoice.getFinalizedCheckpoint()); - } - - private onFinalizedCheckpoint = async (finalized: CheckpointWithHex): Promise => { - return this.jobQueue.push(finalized); - }; - - private onCheckpoint = (): void => { - const headStateRoot = this.chain.forkChoice.getHead().stateRoot; - this.chain.regen.pruneOnCheckpoint( - this.chain.forkChoice.getFinalizedCheckpoint().epoch, - this.chain.forkChoice.getJustifiedCheckpoint().epoch, - headStateRoot - ); - }; - - private processFinalizedCheckpoint = async (finalized: CheckpointWithHex): Promise => { - try { - const finalizedEpoch = finalized.epoch; - this.logger.verbose("Start processing finalized checkpoint", {epoch: finalizedEpoch, rootHex: finalized.rootHex}); - await archiveBlocks( - this.chain.config, - this.db, - this.chain.forkChoice, - this.chain.lightClientServer, - this.logger, - finalized, - this.chain.clock.currentEpoch, - this.archiveBlobEpochs - ); - this.prevFinalized = finalized; - - // should be after ArchiveBlocksTask to handle restart cleanly - await this.statesArchiver.maybeArchiveState(finalized, this.metrics); - - this.chain.regen.pruneOnFinalized(finalizedEpoch); - - // tasks rely on extended fork choice - const prunedBlocks = this.chain.forkChoice.prune(finalized.rootHex); - await this.updateBackfillRange(finalized); - - this.logger.verbose("Finish processing finalized checkpoint", { - epoch: finalizedEpoch, - rootHex: finalized.rootHex, - prunedBlocks: prunedBlocks.length, - }); - } catch (e) { - this.logger.error("Error processing finalized checkpoint", {epoch: finalized.epoch}, e as Error); - } - }; - - /** - * Backfill sync relies on verified connected ranges (which are represented as key,value - * with a verified jump from a key back to value). Since the node could have progressed - * ahead from, we need to save the forward progress of this node as another backfill - * range entry, that backfill sync will use to jump back if this node is restarted - * for any reason. - * The current backfill has its own backfill entry from anchor slot to last backfilled - * slot. And this would create the entry from the current finalized slot to the anchor - * slot. - */ - private updateBackfillRange = async (finalized: CheckpointWithHex): Promise => { - try { - // Mark the sequence in backfill db from finalized block's slot till anchor slot as - // filled. - const finalizedBlockFC = this.chain.forkChoice.getBlockHex(finalized.rootHex); - if (finalizedBlockFC && finalizedBlockFC.slot > this.chain.anchorStateLatestBlockSlot) { - await this.db.backfilledRanges.put(finalizedBlockFC.slot, this.chain.anchorStateLatestBlockSlot); - - // Clear previously marked sequence till anchorStateLatestBlockSlot, without - // touching backfill sync process sequence which are at - // <=anchorStateLatestBlockSlot i.e. clear >anchorStateLatestBlockSlot - // and < currentSlot - const filteredSeqs = await this.db.backfilledRanges.entries({ - gt: this.chain.anchorStateLatestBlockSlot, - lt: finalizedBlockFC.slot, - }); - this.logger.debug("updated backfilledRanges", { - key: finalizedBlockFC.slot, - value: this.chain.anchorStateLatestBlockSlot, - }); - if (filteredSeqs.length > 0) { - await this.db.backfilledRanges.batchDelete(filteredSeqs.map((entry) => entry.key)); - this.logger.debug( - `Forward Sync - cleaned up backfilledRanges between ${finalizedBlockFC.slot},${this.chain.anchorStateLatestBlockSlot}`, - {seqs: JSON.stringify(filteredSeqs)} - ); - } - } - } catch (e) { - this.logger.error("Error updating backfilledRanges on finalization", {epoch: finalized.epoch}, e as Error); - } - }; -} +export * from "./archiver.js"; +export * from "./interface.js"; diff --git a/packages/beacon-node/src/chain/archiver/interface.ts b/packages/beacon-node/src/chain/archiver/interface.ts new file mode 100644 index 000000000000..48c930c78cd3 --- /dev/null +++ b/packages/beacon-node/src/chain/archiver/interface.ts @@ -0,0 +1,47 @@ +import {CheckpointWithHex} from "@lodestar/fork-choice"; +import {Metrics} from "../../metrics/metrics.js"; +import {RootHex} from "@lodestar/types"; + +export enum StateArchiveMode { + Frequency = "frequency", + // New strategy to be implemented + // WIP: https://github.com/ChainSafe/lodestar/pull/7005 + // Differential = "diff", +} + +export interface StatesArchiverOpts { + /** + * Minimum number of epochs between archived states + */ + archiveStateEpochFrequency: number; + /** + * Strategy to store archive states + */ + stateArchiveMode: StateArchiveMode; +} + +export type ArchiverOpts = StatesArchiverOpts & { + disableArchiveOnCheckpoint?: boolean; + archiveBlobEpochs?: number; +}; + +export type ProposalStats = { + total: number; + finalized: number; + orphaned: number; + missed: number; +}; + +export type FinalizedStats = { + allValidators: ProposalStats; + attachedValidators: ProposalStats; + finalizedCanonicalCheckpointsCount: number; + finalizedFoundCheckpointsInStateCache: number; + finalizedAttachedValidatorsCount: number; +}; + +export interface StateArchiveStrategy { + onCheckpoint(stateRoot: RootHex, metrics?: Metrics | null): Promise; + onFinalizedCheckpoint(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise; + maybeArchiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise; +} diff --git a/packages/beacon-node/src/chain/archiver/archiveStates.ts b/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts similarity index 84% rename from packages/beacon-node/src/chain/archiver/archiveStates.ts rename to packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts index 8fd9081ab243..a701da5b22ec 100644 --- a/packages/beacon-node/src/chain/archiver/archiveStates.ts +++ b/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts @@ -1,34 +1,28 @@ import {Logger} from "@lodestar/utils"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {Slot, Epoch} from "@lodestar/types"; +import {Slot, Epoch, RootHex} from "@lodestar/types"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {CheckpointWithHex} from "@lodestar/fork-choice"; -import {IBeaconDb} from "../../db/index.js"; -import {IStateRegenerator} from "../regen/interface.js"; -import {getStateSlotFromBytes} from "../../util/multifork.js"; -import {serializeState} from "../serializeState.js"; -import {AllocSource, BufferPool} from "../../util/bufferPool.js"; -import {Metrics} from "../../metrics/metrics.js"; +import {IBeaconDb} from "../../../db/index.js"; +import {IStateRegenerator} from "../../regen/interface.js"; +import {getStateSlotFromBytes} from "../../../util/multifork.js"; +import {serializeState} from "../../serializeState.js"; +import {AllocSource, BufferPool} from "../../../util/bufferPool.js"; +import {Metrics} from "../../../metrics/metrics.js"; +import {StateArchiveStrategy, StatesArchiverOpts} from "../interface.js"; /** * Minimum number of epochs between single temp archived states * These states will be pruned once a new state is persisted */ -const PERSIST_TEMP_STATE_EVERY_EPOCHS = 32; - -export interface StatesArchiverOpts { - /** - * Minimum number of epochs between archived states - */ - archiveStateEpochFrequency: number; -} +export const PERSIST_TEMP_STATE_EVERY_EPOCHS = 32; /** * Archives finalized states from active bucket to archive bucket. * * Only the new finalized state is stored to disk */ -export class StatesArchiver { +export class FrequencyStateArchiveStrategy implements StateArchiveStrategy { constructor( private readonly regen: IStateRegenerator, private readonly db: IBeaconDb, @@ -37,6 +31,9 @@ export class StatesArchiver { private readonly bufferPool?: BufferPool | null ) {} + async onFinalizedCheckpoint(_finalized: CheckpointWithHex, _metrics?: Metrics | null): Promise {} + async onCheckpoint(_stateRoot: RootHex, _metrics?: Metrics | null): Promise {} + /** * Persist states every some epochs to * - Minimize disk space, storing the least states possible @@ -87,7 +84,7 @@ export class StatesArchiver { * Archives finalized states from active bucket to archive bucket. * Only the new finalized state is stored to disk */ - async archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise { + private async archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise { // starting from Mar 2024, the finalized state could be from disk or in memory const finalizedStateOrBytes = await this.regen.getCheckpointStateOrBytes(finalized); const {rootHex} = finalized; diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 195b8736b2c3..144b73f0c01d 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -77,7 +77,7 @@ import { OpPool, } from "./opPools/index.js"; import {LightClientServer} from "./lightClient/index.js"; -import {Archiver} from "./archiver/index.js"; +import {Archiver} from "./archiver/archiver.js"; import {PrepareNextSlotScheduler} from "./prepareNextSlot.js"; import {ReprocessController} from "./reprocess.js"; import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js"; diff --git a/packages/beacon-node/src/chain/options.ts b/packages/beacon-node/src/chain/options.ts index bc2b73256272..cf83c4432984 100644 --- a/packages/beacon-node/src/chain/options.ts +++ b/packages/beacon-node/src/chain/options.ts @@ -1,12 +1,15 @@ import {SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY} from "@lodestar/params"; import {defaultOptions as defaultValidatorOptions} from "@lodestar/validator"; -import {ArchiverOpts} from "./archiver/index.js"; +import {ArchiverOpts} from "./archiver/interface.js"; import {ForkChoiceOpts} from "./forkChoice/index.js"; import {LightClientServerOpts} from "./lightClient/index.js"; import {ShufflingCacheOpts} from "./shufflingCache.js"; import {DEFAULT_MAX_BLOCK_STATES, FIFOBlockStateCacheOpts} from "./stateCache/fifoBlockStateCache.js"; import {PersistentCheckpointStateCacheOpts} from "./stateCache/persistentCheckpointsCache.js"; import {DEFAULT_MAX_CP_STATE_EPOCHS_IN_MEMORY} from "./stateCache/persistentCheckpointsCache.js"; +import {DEFAULT_STATE_ARCHIVE_MODE} from "./archiver/archiver.js"; +export {StateArchiveMode} from "./archiver/interface.js"; +export {DEFAULT_STATE_ARCHIVE_MODE} from "./archiver/archiver.js"; export type IChainOptions = BlockProcessOpts & PoolOpts & @@ -102,6 +105,7 @@ export const defaultChainOptions: IChainOptions = { suggestedFeeRecipient: defaultValidatorOptions.suggestedFeeRecipient, assertCorrectProgressiveBalances: false, archiveStateEpochFrequency: 1024, + stateArchiveMode: DEFAULT_STATE_ARCHIVE_MODE, emitPayloadAttributes: false, // for gossip block validation, it's unlikely we see a reorg with 32 slots // for attestation validation, having this value ensures we don't have to regen states most of the time diff --git a/packages/beacon-node/src/node/options.ts b/packages/beacon-node/src/node/options.ts index 475a4debee63..e587e58ec127 100644 --- a/packages/beacon-node/src/node/options.ts +++ b/packages/beacon-node/src/node/options.ts @@ -1,5 +1,5 @@ import {defaultApiOptions, ApiOptions} from "../api/options.js"; -import {defaultChainOptions, IChainOptions} from "../chain/options.js"; +import {defaultChainOptions, IChainOptions, StateArchiveMode, DEFAULT_STATE_ARCHIVE_MODE} from "../chain/options.js"; import {defaultDbOptions, DatabaseOptions} from "../db/options.js"; import {defaultEth1Options, Eth1Options} from "../eth1/options.js"; import {defaultMetricsOptions, MetricsOptions} from "../metrics/options.js"; @@ -18,7 +18,7 @@ import { export {allNamespaces} from "../api/rest/index.js"; // Re-export to use as default values in CLI args -export {defaultExecutionEngineHttpOpts, defaultExecutionBuilderHttpOpts}; +export {defaultExecutionEngineHttpOpts, defaultExecutionBuilderHttpOpts, StateArchiveMode, DEFAULT_STATE_ARCHIVE_MODE}; export interface IBeaconNodeOptions { api: ApiOptions; diff --git a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts index fdd6f60f5a47..c08cf64fc974 100644 --- a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts +++ b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts @@ -10,7 +10,7 @@ import {BeaconChain} from "../../../../src/chain/index.js"; import {BlockType, produceBlockBody} from "../../../../src/chain/produceBlock/produceBlockBody.js"; import {Eth1ForBlockProductionDisabled} from "../../../../src/eth1/index.js"; import {ExecutionEngineDisabled} from "../../../../src/execution/engine/index.js"; -import {BeaconDb} from "../../../../src/index.js"; +import {StateArchiveMode, BeaconDb} from "../../../../src/index.js"; import {testLogger} from "../../../utils/logger.js"; const logger = testLogger(); @@ -36,6 +36,7 @@ describe("produceBlockBody", () => { skipCreateStateCacheIfAvailable: true, archiveStateEpochFrequency: 1024, minSameMessageSignatureSetsToBatch: 32, + stateArchiveMode: StateArchiveMode.Frequency, }, { config: state.config, diff --git a/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts b/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts index cd4d61b173c7..6f1cf2ef3da6 100644 --- a/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts +++ b/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts @@ -12,7 +12,7 @@ import {ExecutionEngineDisabled} from "../../../src/execution/engine/index.js"; import {Eth1ForBlockProductionDisabled} from "../../../src/eth1/index.js"; import {testLogger} from "../../utils/logger.js"; import {linspace} from "../../../src/util/numpy.js"; -import {BeaconDb} from "../../../src/index.js"; +import {StateArchiveMode, BeaconDb} from "../../../src/index.js"; import {getBlockInput, AttestationImportOpt, BlockSource} from "../../../src/chain/blocks/types.js"; // Define this params in `packages/state-transition/test/perf/params.ts` @@ -85,6 +85,7 @@ describe.skip("verify+import blocks - range sync perf test", () => { skipCreateStateCacheIfAvailable: true, archiveStateEpochFrequency: 1024, minSameMessageSignatureSetsToBatch: 32, + stateArchiveMode: StateArchiveMode.Frequency, }, { config: state.config, diff --git a/packages/beacon-node/test/unit/chain/archive/stateArchiver.test.ts b/packages/beacon-node/test/unit/chain/archive/stateArchiver.test.ts index fe21fd64af96..cbfba0a362df 100644 --- a/packages/beacon-node/test/unit/chain/archive/stateArchiver.test.ts +++ b/packages/beacon-node/test/unit/chain/archive/stateArchiver.test.ts @@ -1,6 +1,6 @@ import {describe, it, expect} from "vitest"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {computeStateSlotsToDelete} from "../../../../src/chain/archiver/archiveStates.js"; +import {computeStateSlotsToDelete} from "../../../../src/chain/archiver/strategies/frequencyStateArchiveStrategy.js"; describe("state archiver task", () => { describe("computeStateSlotsToDelete", () => { diff --git a/packages/beacon-node/test/utils/networkWithMockDb.ts b/packages/beacon-node/test/utils/networkWithMockDb.ts index b1c4293588d2..84c3821bb22c 100644 --- a/packages/beacon-node/test/utils/networkWithMockDb.ts +++ b/packages/beacon-node/test/utils/networkWithMockDb.ts @@ -12,6 +12,7 @@ import {createCachedBeaconStateTest} from "./cachedBeaconState.js"; import {ClockStatic} from "./clock.js"; import {testLogger} from "./logger.js"; import {generateState} from "./state.js"; +import {StateArchiveMode} from "../../src/index.js"; export type NetworkForTestOpts = { startSlot?: number; @@ -54,6 +55,7 @@ export async function getNetworkForTest( disableLightClientServerOnImportBlockHead: true, disablePrepareNextSlot: true, minSameMessageSignatureSetsToBatch: 32, + stateArchiveMode: StateArchiveMode.Frequency, }, { config: beaconConfig, diff --git a/packages/cli/src/options/beaconNodeOptions/chain.ts b/packages/cli/src/options/beaconNodeOptions/chain.ts index 78ffd47da8f4..c5f907804a83 100644 --- a/packages/cli/src/options/beaconNodeOptions/chain.ts +++ b/packages/cli/src/options/beaconNodeOptions/chain.ts @@ -1,5 +1,5 @@ import * as path from "node:path"; -import {defaultOptions, IBeaconNodeOptions} from "@lodestar/beacon-node"; +import {StateArchiveMode, defaultOptions, IBeaconNodeOptions, DEFAULT_STATE_ARCHIVE_MODE} from "@lodestar/beacon-node"; import {CliCommandOptions} from "@lodestar/utils"; export type ChainArgs = { @@ -22,12 +22,13 @@ export type ChainArgs = { "chain.maxSkipSlots"?: number; "chain.trustedSetup"?: string; "safe-slots-to-import-optimistically": number; - "chain.archiveStateEpochFrequency": number; emitPayloadAttributes?: boolean; broadcastValidationStrictness?: string; "chain.minSameMessageSignatureSetsToBatch"?: number; "chain.maxShufflingCacheEpochs"?: number; + "chain.archiveStateEpochFrequency": number; "chain.archiveBlobEpochs"?: number; + "chain.stateArchiveMode": StateArchiveMode; "chain.nHistoricalStates"?: boolean; "chain.nHistoricalStatesFileDataStore"?: boolean; "chain.maxBlockStates"?: number; @@ -54,13 +55,14 @@ export function parseArgs(args: ChainArgs): IBeaconNodeOptions["chain"] { maxSkipSlots: args["chain.maxSkipSlots"], trustedSetup: args["chain.trustedSetup"], safeSlotsToImportOptimistically: args["safe-slots-to-import-optimistically"], - archiveStateEpochFrequency: args["chain.archiveStateEpochFrequency"], emitPayloadAttributes: args.emitPayloadAttributes, broadcastValidationStrictness: args.broadcastValidationStrictness, minSameMessageSignatureSetsToBatch: args["chain.minSameMessageSignatureSetsToBatch"] ?? defaultOptions.chain.minSameMessageSignatureSetsToBatch, maxShufflingCacheEpochs: args["chain.maxShufflingCacheEpochs"] ?? defaultOptions.chain.maxShufflingCacheEpochs, + archiveStateEpochFrequency: args["chain.archiveStateEpochFrequency"], archiveBlobEpochs: args["chain.archiveBlobEpochs"], + stateArchiveMode: args["chain.stateArchiveMode"] ?? defaultOptions.chain.stateArchiveMode, nHistoricalStates: args["chain.nHistoricalStates"] ?? defaultOptions.chain.nHistoricalStates, nHistoricalStatesFileDataStore: args["chain.nHistoricalStatesFileDataStore"] ?? defaultOptions.chain.nHistoricalStatesFileDataStore, @@ -210,6 +212,15 @@ Will double processing times. Use only for debugging purposes.", group: "chain", }, + "chain.stateArchiveMode": { + hidden: true, + choices: Object.values(StateArchiveMode), + description: `Strategy to manage archive states, only support ${DEFAULT_STATE_ARCHIVE_MODE} at this time`, + default: defaultOptions.chain.stateArchiveMode, + type: "string", + group: "chain", + }, + broadcastValidationStrictness: { // TODO: hide the option till validations fully implemented hidden: true, diff --git a/packages/cli/test/unit/options/beaconNodeOptions.test.ts b/packages/cli/test/unit/options/beaconNodeOptions.test.ts index 879b5bfa2fc9..8d295197b541 100644 --- a/packages/cli/test/unit/options/beaconNodeOptions.test.ts +++ b/packages/cli/test/unit/options/beaconNodeOptions.test.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import {describe, it, expect} from "vitest"; -import {IBeaconNodeOptions} from "@lodestar/beacon-node"; +import {StateArchiveMode, IBeaconNodeOptions} from "@lodestar/beacon-node"; import {RecursivePartial} from "@lodestar/utils"; import {parseBeaconNodeArgs, BeaconNodeArgs} from "../../../src/options/beaconNodeOptions/index.js"; import {getTestdirPath} from "../../utils.js"; @@ -43,6 +43,7 @@ describe("options / beaconNodeOptions", () => { "chain.nHistoricalStatesFileDataStore": true, "chain.maxBlockStates": 100, "chain.maxCPStateEpochsInMemory": 100, + "chain.stateArchiveMode": StateArchiveMode.Frequency, emitPayloadAttributes: false, eth1: true, @@ -147,6 +148,7 @@ describe("options / beaconNodeOptions", () => { minSameMessageSignatureSetsToBatch: 32, maxShufflingCacheEpochs: 100, archiveBlobEpochs: 10000, + stateArchiveMode: StateArchiveMode.Frequency, nHistoricalStates: true, nHistoricalStatesFileDataStore: true, maxBlockStates: 100, From e01142b1f886127a1fb0146b83b7d5131a816a14 Mon Sep 17 00:00:00 2001 From: twoeths Date: Mon, 21 Oct 2024 20:49:08 +0700 Subject: [PATCH 170/259] chore: ssz 0.18.0 (#7181) --- packages/api/package.json | 2 +- packages/beacon-node/package.json | 2 +- packages/cli/package.json | 2 +- packages/config/package.json | 2 +- packages/db/package.json | 2 +- packages/fork-choice/package.json | 2 +- packages/light-client/package.json | 2 +- packages/state-transition/package.json | 2 +- packages/types/package.json | 2 +- packages/validator/package.json | 2 +- yarn.lock | 8 ++++---- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/api/package.json b/packages/api/package.json index 58566a0b23f6..1758f1fe47cf 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -71,7 +71,7 @@ }, "dependencies": { "@chainsafe/persistent-merkle-tree": "^0.8.0", - "@chainsafe/ssz": "^0.17.1", + "@chainsafe/ssz": "^0.18.0", "@lodestar/config": "^1.22.0", "@lodestar/params": "^1.22.0", "@lodestar/types": "^1.22.0", diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index e3d095b6f1e0..40b24a199a0a 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -102,7 +102,7 @@ "@chainsafe/libp2p-noise": "^16.0.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/prometheus-gc-stats": "^1.0.0", - "@chainsafe/ssz": "^0.17.1", + "@chainsafe/ssz": "^0.18.0", "@chainsafe/threads": "^1.11.1", "@chainsafe/pubkey-index-map": "2.0.0", "@ethersproject/abi": "^5.7.0", diff --git a/packages/cli/package.json b/packages/cli/package.json index 67d0dfd332cc..871113b84739 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -57,7 +57,7 @@ "@chainsafe/discv5": "^10.0.1", "@chainsafe/enr": "^4.0.1", "@chainsafe/persistent-merkle-tree": "^0.8.0", - "@chainsafe/ssz": "^0.17.1", + "@chainsafe/ssz": "^0.18.0", "@chainsafe/threads": "^1.11.1", "@libp2p/crypto": "^5.0.4", "@libp2p/interface": "^2.1.2", diff --git a/packages/config/package.json b/packages/config/package.json index 434000db2a0f..1c2888be0f18 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -64,7 +64,7 @@ "blockchain" ], "dependencies": { - "@chainsafe/ssz": "^0.17.1", + "@chainsafe/ssz": "^0.18.0", "@lodestar/params": "^1.22.0", "@lodestar/utils": "^1.22.0", "@lodestar/types": "^1.22.0" diff --git a/packages/db/package.json b/packages/db/package.json index 2a10d36766bf..2b2098a9d6c1 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -35,7 +35,7 @@ "check-readme": "typescript-docs-verifier" }, "dependencies": { - "@chainsafe/ssz": "^0.17.1", + "@chainsafe/ssz": "^0.18.0", "@lodestar/config": "^1.22.0", "@lodestar/utils": "^1.22.0", "classic-level": "^1.4.1", diff --git a/packages/fork-choice/package.json b/packages/fork-choice/package.json index 2197ad90a9fd..9a6838bfcf3e 100644 --- a/packages/fork-choice/package.json +++ b/packages/fork-choice/package.json @@ -36,7 +36,7 @@ "check-readme": "typescript-docs-verifier" }, "dependencies": { - "@chainsafe/ssz": "^0.17.1", + "@chainsafe/ssz": "^0.18.0", "@lodestar/config": "^1.22.0", "@lodestar/params": "^1.22.0", "@lodestar/state-transition": "^1.22.0", diff --git a/packages/light-client/package.json b/packages/light-client/package.json index a503d6bc510e..54ab479f2d88 100644 --- a/packages/light-client/package.json +++ b/packages/light-client/package.json @@ -76,7 +76,7 @@ "@chainsafe/bls": "7.1.3", "@chainsafe/blst": "^0.2.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", - "@chainsafe/ssz": "^0.17.1", + "@chainsafe/ssz": "^0.18.0", "@lodestar/api": "^1.22.0", "@lodestar/config": "^1.22.0", "@lodestar/params": "^1.22.0", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index a01d835bae95..4e66cd6c09ac 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -62,7 +62,7 @@ "@chainsafe/blst": "^2.0.3", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/persistent-ts": "^0.19.1", - "@chainsafe/ssz": "^0.17.1", + "@chainsafe/ssz": "^0.18.0", "@chainsafe/swap-or-not-shuffle": "^0.0.2", "@lodestar/config": "^1.22.0", "@lodestar/params": "^1.22.0", diff --git a/packages/types/package.json b/packages/types/package.json index 1c020b409071..89474e8597a1 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -73,7 +73,7 @@ }, "types": "lib/index.d.ts", "dependencies": { - "@chainsafe/ssz": "^0.17.1", + "@chainsafe/ssz": "^0.18.0", "@lodestar/params": "^1.22.0", "ethereum-cryptography": "^2.0.0" }, diff --git a/packages/validator/package.json b/packages/validator/package.json index 932eedac1dba..266e37dca56b 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -46,7 +46,7 @@ ], "dependencies": { "@chainsafe/blst": "^2.0.3", - "@chainsafe/ssz": "^0.17.1", + "@chainsafe/ssz": "^0.18.0", "@lodestar/api": "^1.22.0", "@lodestar/config": "^1.22.0", "@lodestar/db": "^1.22.0", diff --git a/yarn.lock b/yarn.lock index 32c923a514e9..538043fce1ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -649,10 +649,10 @@ "@chainsafe/as-sha256" "^0.4.1" "@chainsafe/persistent-merkle-tree" "^0.6.1" -"@chainsafe/ssz@^0.17.1": - version "0.17.1" - resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.17.1.tgz#7986afbcad5e6971006d596fdb7dfa34bc195131" - integrity sha512-1ay46QqYcVTBvUnDXTPTi5WTiENu7tIxpZGMDpUWps1/nYBmh/We/UoCF/jO+o/fkcDD3p8xQPlHbcCfy+jyjA== +"@chainsafe/ssz@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.18.0.tgz#773d40df9dff3b6a2a4c6685d9797abceb9d36f7" + integrity sha512-1ikTjk3JK6+fsGWiT5IvQU0AP6gF3fDzGmPfkKthbcbgTUR8fjB83Ywp9ko/ZoiDGfrSFkATgT4hvRzclu0IAA== dependencies: "@chainsafe/as-sha256" "0.5.0" "@chainsafe/persistent-merkle-tree" "0.8.0" From 0e4ea98aea3a73ca4524369b6ee11ef0aed817a9 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 21 Oct 2024 14:51:05 +0100 Subject: [PATCH 171/259] feat: add ssz support to builder api (#7180) * feat: add ssz support to builder api * Rephrase comment --- packages/api/src/builder/routes.ts | 22 ++++++++++++---- .../beacon-node/src/execution/builder/http.ts | 25 +++++++++++++++---- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/packages/api/src/builder/routes.ts b/packages/api/src/builder/routes.ts index 018110e5eded..a203a93b8afe 100644 --- a/packages/api/src/builder/routes.ts +++ b/packages/api/src/builder/routes.ts @@ -78,9 +78,6 @@ export type Endpoints = { >; }; -// NOTE: Builder API does not support SSZ as per spec, need to keep routes as JSON-only for now -// See https://github.com/ethereum/builder-specs/issues/53 for more details - export function getDefinitions(config: ChainForkConfig): RouteDefinitions { return { status: { @@ -125,7 +122,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = config.getForkName(signedBlindedBlock.message.slot); return { @@ -141,11 +138,26 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { + const fork = config.getForkName(signedBlindedBlock.message.slot); + return { + body: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.serialize(signedBlindedBlock), + headers: { + [MetaHeader.Version]: fork, + }, + }; + }, + parseReqSsz: ({body, headers}) => { + const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); + return { + signedBlindedBlock: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.deserialize(body), + }; + }, schema: { body: Schema.Object, headers: {[MetaHeader.Version]: Schema.String}, }, - }), + }, resp: { data: WithVersion((fork: ForkName) => { return isForkBlobs(fork) diff --git a/packages/beacon-node/src/execution/builder/http.ts b/packages/beacon-node/src/execution/builder/http.ts index 87920e833f5d..13f797d1c697 100644 --- a/packages/beacon-node/src/execution/builder/http.ts +++ b/packages/beacon-node/src/execution/builder/http.ts @@ -18,6 +18,7 @@ import {SLOTS_PER_EPOCH, ForkExecution} from "@lodestar/params"; import {toPrintableUrl} from "@lodestar/utils"; import {Metrics} from "../../metrics/metrics.js"; import {IExecutionBuilder} from "./interface.js"; +import {WireFormat} from "@lodestar/api"; export type ExecutionBuilderHttpOpts = { enabled: boolean; @@ -53,6 +54,13 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { faultInspectionWindow: number; allowedFaults: number; + /** + * Determine if SSZ is supported by requesting an SSZ encoded response in the `getHeader` request. + * The builder responding with a SSZ serialized `SignedBuilderBid` indicates support to handle the + * `SignedBlindedBeaconBlock` as SSZ serialized bytes instead of JSON when calling `submitBlindedBlock`. + */ + private sszSupported = false; + constructor( opts: ExecutionBuilderHttpOpts, config: ChainForkConfig, @@ -123,14 +131,18 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { blobKzgCommitments?: deneb.BlobKzgCommitments; executionRequests?: electra.ExecutionRequests; }> { - const signedBuilderBid = ( - await this.api.getHeader({slot, parentHash, proposerPubkey}, {timeoutMs: BUILDER_PROPOSAL_DELAY_TOLERANCE}) - ).value(); + const res = await this.api.getHeader( + {slot, parentHash, proposerPubkey}, + {timeoutMs: BUILDER_PROPOSAL_DELAY_TOLERANCE} + ); + const signedBuilderBid = res.value(); if (!signedBuilderBid) { throw Error("No bid received"); } + this.sszSupported = res.wireFormat() === WireFormat.ssz; + const {header, value: executionPayloadValue} = signedBuilderBid.message; const {blobKzgCommitments} = signedBuilderBid.message as deneb.BuilderBid; const {executionRequests} = signedBuilderBid.message as electra.BuilderBid; @@ -138,9 +150,12 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { } async submitBlindedBlock(signedBlindedBlock: SignedBlindedBeaconBlock): Promise { - const data = (await this.api.submitBlindedBlock({signedBlindedBlock}, {retries: 2})).value(); + const res = await this.api.submitBlindedBlock( + {signedBlindedBlock}, + {retries: 2, requestWireFormat: this.sszSupported ? WireFormat.ssz : WireFormat.json} + ); - const {executionPayload, blobsBundle} = parseExecutionPayloadAndBlobsBundle(data); + const {executionPayload, blobsBundle} = parseExecutionPayloadAndBlobsBundle(res.value()); // for the sake of timely proposals we can skip matching the payload with payloadHeader // if the roots (transactions, withdrawals) don't match, this will likely lead to a block with From e770ebe0abae46f926f8fd122f8f392cb54010fb Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Tue, 22 Oct 2024 15:49:21 +0200 Subject: [PATCH 172/259] chore: add vscode workspace settings (#7173) * Add vscode workspace settings * Update the settings file * Add settings for open-in-github * Update the settings * Add comment in the settings * Update the settings * Use tabaqa extension to override settings * Revert "Use tabaqa extension to override settings" This reverts commit fd02f98f363547079f4302ccae7d34ee8d92782b. * Update the settings file * Update settings * Update .vscode/settings.json Co-authored-by: Nico Flaig --------- Co-authored-by: Nico Flaig --- .gitignore | 2 +- .vscode/settings.json | 22 ++++++++++++++++++++++ biome.jsonc | 3 +++ lodestar.code-workspace | 12 ------------ 4 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 lodestar.code-workspace diff --git a/.gitignore b/.gitignore index 073b21cf322a..52d9bc66e5b6 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,7 @@ validators .tmp .npmrc .vscode/launch.json -.vscode/settings.json +!.vscode/settings.json .vscode/tasks.json # Tests artifacts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000000..fbc0552fe61c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,22 @@ +{ + "window.title": "${activeEditorShort}${separator}${rootName}${separator}${profileName}${separator}[${activeRepositoryBranchName}]", + "editor.defaultFormatter": "esbenp.prettier-vscode", + // For `sysoev.vscode-open-in-github` extension + "openInGitHub.defaultBranch": "unstable", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.biome": "explicit", + }, + "[javascript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[json]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[jsonc]": { + "editor.defaultFormatter": "biomejs.biome" + } +} diff --git a/biome.jsonc b/biome.jsonc index de0689f2d761..212a61d86aa2 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -18,6 +18,9 @@ "ignore": ["**/lib", "**/.nyc_output", "./packages/*/spec-tests", "**/node_modules", "./packages/*/node_modules/**"] }, "organizeImports": { + // TODO: We will enable this settings as soon mono-repo support is provided in biome. + // Currently it didn't recognize local packages in repo and sort those higher than npm packages + // https://github.com/biomejs/biome/issues/2228 "enabled": false }, "linter": { diff --git a/lodestar.code-workspace b/lodestar.code-workspace deleted file mode 100644 index 7030ab8d7270..000000000000 --- a/lodestar.code-workspace +++ /dev/null @@ -1,12 +0,0 @@ -{ - "settings": { - "window.title": "${activeEditorShort}${separator}${rootName}${separator}${profileName}${separator}[${activeRepositoryBranchName}]", - "editor.defaultFormatter": "esbenp.prettier-vscode", - "[javascript]": { - "editor.defaultFormatter": "biomejs.biome" - }, - "[typescript]": { - "editor.defaultFormatter": "biomejs.biome" - }, - } -} From 4722b6618ef4977058b93bc4a8ebc4fdf313c72c Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 22 Oct 2024 15:02:29 +0100 Subject: [PATCH 173/259] chore: separate builder and engine in success + error rates panel (#7190) --- dashboards/lodestar_block_production.json | 65 +++++++++++++++++------ 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/dashboards/lodestar_block_production.json b/dashboards/lodestar_block_production.json index 444adccaa59e..04201c62ae4a 100644 --- a/dashboards/lodestar_block_production.json +++ b/dashboards/lodestar_block_production.json @@ -445,12 +445,12 @@ "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", - "axisLabel": "", + "axisLabel": "builder | engine", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", + "fillOpacity": 30, + "gradientMode": "opacity", "hideFrom": { "legend": false, "tooltip": false, @@ -458,6 +458,9 @@ }, "insertNulls": false, "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, "lineWidth": 1, "pointSize": 5, "scaleDistribution": { @@ -473,19 +476,22 @@ "mode": "off" } }, - "mappings": [] + "fieldMinMax": false, + "mappings": [], + "noValue": "0", + "unit": "none" }, "overrides": [ { "matcher": { "id": "byName", - "options": "total" + "options": "engine success" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -494,13 +500,13 @@ { "matcher": { "id": "byName", - "options": "successes" + "options": "builder success" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -509,13 +515,13 @@ { "matcher": { "id": "byName", - "options": "success" + "options": "engine errors" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -524,13 +530,13 @@ { "matcher": { "id": "byName", - "options": "errors" + "options": "builder errors" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -565,10 +571,11 @@ }, "editorMode": "code", "exemplar": false, - "expr": "rate(beacon_block_production_successes_total[$rate_interval])", + "expr": "rate(beacon_block_production_successes_total{source=\"engine\"}[$rate_interval])", + "format": "time_series", "hide": false, "interval": "", - "legendFormat": "success", + "legendFormat": "engine success", "range": true, "refId": "B" }, @@ -579,11 +586,37 @@ }, "editorMode": "code", "exemplar": false, - "expr": "rate(beacon_block_production_requests_total[$rate_interval])\n-\nrate(beacon_block_production_successes_total[$rate_interval])", + "expr": "rate(beacon_block_production_requests_total{source=\"engine\"}[$rate_interval])\n-\nrate(beacon_block_production_successes_total{source=\"engine\"}[$rate_interval])", "interval": "", - "legendFormat": "errors", + "legendFormat": "engine errors", "range": true, "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "-1 * rate(beacon_block_production_successes_total{source=\"builder\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "builder success", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "-1 *\n(\n rate(beacon_block_production_requests_total{source=\"builder\"}[$rate_interval])\n -\n rate(beacon_block_production_successes_total{source=\"builder\"}[$rate_interval])\n)", + "hide": false, + "instant": false, + "legendFormat": "builder errors", + "range": true, + "refId": "D" } ], "title": "Success + Error rates", From fa969ca6fd12fe8c17a11c5536745a501284293e Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 22 Oct 2024 15:41:21 +0100 Subject: [PATCH 174/259] fix: log as info instead of warn if builder does not provide a bid (#7191) --- .../src/api/impl/validator/index.ts | 20 +++++++++++++------ .../beacon-node/src/execution/builder/http.ts | 13 +++++++++++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 1bf3c4f6f659..b470a58aa198 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -70,6 +70,7 @@ import {validateGossipFnRetryUnknownRoot} from "../../../network/processor/gossi import {SCHEDULER_LOOKAHEAD_FACTOR} from "../../../chain/prepareNextSlot.js"; import {ChainEvent, CheckpointHex, CommonBlockBody} from "../../../chain/index.js"; import {ApiOptions} from "../../options.js"; +import {NoBidReceived} from "../../../execution/builder/http.js"; import {getLodestarClientVersion} from "../../../util/metadata.js"; import {computeSubnetForCommitteesAtSlot, getPubkeysForIndices, selectBlockProductionSource} from "./utils.js"; @@ -661,14 +662,21 @@ export function getValidatorApi( } if (builder.status === "rejected" && isBuilderEnabled) { - logger.warn( - "Builder failed to produce the block", - { + if (builder.reason instanceof NoBidReceived) { + logger.info("Builder did not provide a bid", { ...loggerContext, durationMs: builder.durationMs, - }, - builder.reason - ); + }); + } else { + logger.warn( + "Builder failed to produce the block", + { + ...loggerContext, + durationMs: builder.durationMs, + }, + builder.reason + ); + } } if (builder.status === "rejected" && engine.status === "rejected") { diff --git a/packages/beacon-node/src/execution/builder/http.ts b/packages/beacon-node/src/execution/builder/http.ts index 13f797d1c697..0a6018e5e231 100644 --- a/packages/beacon-node/src/execution/builder/http.ts +++ b/packages/beacon-node/src/execution/builder/http.ts @@ -39,6 +39,17 @@ export const defaultExecutionBuilderHttpOpts: ExecutionBuilderHttpOpts = { timeout: 12000, }; +/** + * Expected error if builder does not provide a bid. Most of the time, this + * is due to `min-bid` setting on the mev-boost side but in rare cases could + * also happen if there are no bids from any of the connected relayers. + */ +export class NoBidReceived extends Error { + constructor() { + super("No bid received"); + } +} + /** * Duration given to the builder to provide a `SignedBuilderBid` before the deadline * is reached, aborting the external builder flow in favor of the local build process. @@ -138,7 +149,7 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { const signedBuilderBid = res.value(); if (!signedBuilderBid) { - throw Error("No bid received"); + throw new NoBidReceived(); } this.sszSupported = res.wireFormat() === WireFormat.ssz; From 717abf35f281df6093a5205bfb4af2a53c2a71ca Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Tue, 22 Oct 2024 12:06:54 -0400 Subject: [PATCH 175/259] chore: portable blst (#7164) * chore: add temp-deps blst * chore: update packages to point to temp-deps * chore: remove temp-deps * chore: use 2.1.0 portable version of blst-ts * chore: fix formatting --- packages/beacon-node/package.json | 2 +- packages/cli/package.json | 2 +- packages/flare/package.json | 2 +- packages/state-transition/package.json | 2 +- packages/test-utils/package.json | 2 +- packages/validator/package.json | 2 +- yarn.lock | 78 +++++++++++++------------- 7 files changed, 45 insertions(+), 45 deletions(-) diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 40b24a199a0a..3213504334e3 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -95,7 +95,7 @@ }, "dependencies": { "@chainsafe/as-sha256": "^0.5.0", - "@chainsafe/blst": "^2.0.3", + "@chainsafe/blst": "^2.1.0", "@chainsafe/discv5": "^10.0.1", "@chainsafe/enr": "^4.0.1", "@chainsafe/libp2p-gossipsub": "^14.1.0", diff --git a/packages/cli/package.json b/packages/cli/package.json index 871113b84739..e1c14f6cd9c3 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -53,7 +53,7 @@ "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", "@chainsafe/bls-keystore": "^3.1.0", - "@chainsafe/blst": "^2.0.3", + "@chainsafe/blst": "^2.1.0", "@chainsafe/discv5": "^10.0.1", "@chainsafe/enr": "^4.0.1", "@chainsafe/persistent-merkle-tree": "^0.8.0", diff --git a/packages/flare/package.json b/packages/flare/package.json index a08e5fe0edc1..f8bd37f5abb5 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -59,7 +59,7 @@ ], "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", - "@chainsafe/blst": "^2.0.3", + "@chainsafe/blst": "^2.1.0", "@lodestar/api": "^1.22.0", "@lodestar/config": "^1.22.0", "@lodestar/params": "^1.22.0", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 4e66cd6c09ac..80a6cf45c28f 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -59,7 +59,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/as-sha256": "^0.5.0", - "@chainsafe/blst": "^2.0.3", + "@chainsafe/blst": "^2.1.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/persistent-ts": "^0.19.1", "@chainsafe/ssz": "^0.18.0", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index b2a589581055..1b18c3b5a33e 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -58,7 +58,7 @@ ], "dependencies": { "@chainsafe/bls-keystore": "^3.1.0", - "@chainsafe/blst": "^2.0.3", + "@chainsafe/blst": "^2.1.0", "@lodestar/params": "^1.22.0", "@lodestar/utils": "^1.22.0", "axios": "^1.3.4", diff --git a/packages/validator/package.json b/packages/validator/package.json index 266e37dca56b..a781d62b0111 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -45,7 +45,7 @@ "blockchain" ], "dependencies": { - "@chainsafe/blst": "^2.0.3", + "@chainsafe/blst": "^2.1.0", "@chainsafe/ssz": "^0.18.0", "@lodestar/api": "^1.22.0", "@lodestar/config": "^1.22.0", diff --git a/yarn.lock b/yarn.lock index 538043fce1ce..8519ed6434bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -399,40 +399,40 @@ "@chainsafe/bls-keygen" "^0.4.0" bls-eth-wasm "^0.4.8" -"@chainsafe/blst-darwin-arm64@2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-arm64/-/blst-darwin-arm64-2.0.3.tgz#28ecbcdbaeaebb1cf07a4e8edeaf7b138bc96f22" - integrity sha512-7LGFMBXhB5eM8zLQgblm471NjqnOhI0dv+OohmgWBwjA3Ph4rxTd0CRorZMiqy770MbiLninnYSWiTbjXLY6eQ== +"@chainsafe/blst-darwin-arm64@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-arm64/-/blst-darwin-arm64-2.1.0.tgz#8871d62dc0402df30adbd6f52fbbd02d59f3c5ff" + integrity sha512-7iPRlSbQxEZ2AblmkFLuhnVPUipvA0UenEaUCaLC1MhGFpSwy5bSrF8Krs/E++GN3p2LVz7ZH3tlDfFL0z1EvQ== -"@chainsafe/blst-darwin-x64@2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-x64/-/blst-darwin-x64-2.0.3.tgz#d50cfd591a5b1698202ee97242e0f28a8c76d2be" - integrity sha512-RRgMLuP8rmd84+ht35Rc/vMDsvK6NZgJlchqis1ve0/Na3550gqVgbVY7Y8YDuW8VpGAslII56rDZNqEl7tVmg== +"@chainsafe/blst-darwin-x64@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-x64/-/blst-darwin-x64-2.1.0.tgz#8fe58d92b72b1b872f8b687a0aad8beda3e09072" + integrity sha512-aeoidOpOYVmRFeHVm1p/Axd6CfqWpr6SIift216/HTDBTiuJCGSJqHzk9RHf7gzkr6WtxO7g/6AtkagZA2VPFg== -"@chainsafe/blst-linux-arm64-gnu@2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-gnu/-/blst-linux-arm64-gnu-2.0.3.tgz#05d0028d757a00126628fa6d498f3c8925dda259" - integrity sha512-zkCTMuv3pnWR2xtfcazt7PlJqnltH9yOHSjFy1U7/izowU1KUSSptcvJi+26i2tI5NNWbHVNCb8CqKbRxOdNTQ== +"@chainsafe/blst-linux-arm64-gnu@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-gnu/-/blst-linux-arm64-gnu-2.1.0.tgz#323789a10679cf81813b1e664ef4187a2e941cff" + integrity sha512-d2zgqoJOqkWg2sZbNR7pv8f+oYPOJmnMu46Uulm6NkW3iYNZIc2KkVjBXGYk7xJ+U8ZEzb7KZ7gRB9315sWBcg== -"@chainsafe/blst-linux-arm64-musl@2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-musl/-/blst-linux-arm64-musl-2.0.3.tgz#c6d924fc346d0e50f77d44dfdfe08a9010eceae3" - integrity sha512-aQA9W7TpqoYjMc6WiLJ1rMdrU+vG7kjaOr1ZdCijlBOVer3OP5qdBD16GfjeqaxIQsmMHzHkBf/isczONZ9sjw== +"@chainsafe/blst-linux-arm64-musl@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-musl/-/blst-linux-arm64-musl-2.1.0.tgz#4a308d6b1f71a57a6ecc6cc0531746f5cd8ae3d0" + integrity sha512-w+KiL8ViLXigZVS++tdCwnMBnbc4HXb8claKOnlCppE1rAeF0Dt186AU2TRpqOop3QoOqckqvsguR9iQwZlTUw== -"@chainsafe/blst-linux-x64-gnu@2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-gnu/-/blst-linux-x64-gnu-2.0.3.tgz#0edc16cab944f9f55529d742e157fcf85455a8ce" - integrity sha512-pZtZ9tVmmqInEqSF8+SJGtVynBw4pDOYNzUVSfpHcwBpyIl3TZzuewCQfh487FcJ52c2vXelpA8MucBuRDiDZg== +"@chainsafe/blst-linux-x64-gnu@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-gnu/-/blst-linux-x64-gnu-2.1.0.tgz#c015f9f25aab10bba7720518ba9dc19bb850dcc3" + integrity sha512-2xdOIkkJTvi+/gUoiPQO+p+2o19pixLsH5BOrwxY+EABLL6wxZ82w5LatV3x27YJTk7PbAlyT36n7CjmzaZ/tw== -"@chainsafe/blst-linux-x64-musl@2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-musl/-/blst-linux-x64-musl-2.0.3.tgz#be61d9f50fe35bb4c8692e90583b998701b0409c" - integrity sha512-w/X5+QjDbJTiqlXkiv0TXnuWdkfMRvoTFJcy3RyM7s1ra1kvoB6JRjJMirUJUoJNcMhzThZqjWPeVVpiCrqrVw== +"@chainsafe/blst-linux-x64-musl@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-musl/-/blst-linux-x64-musl-2.1.0.tgz#da4ac690cc3b59bc21c4578d30502490c044f7fb" + integrity sha512-/ddO38KkTTgTmXBLAubU1fjUWcQy90sdUi0IoRm5RprdpXvTSGZ1m8XrcxwEYkUO+KpnacOuU0UDwerHMJl4DA== -"@chainsafe/blst-win32-x64-msvc@2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-win32-x64-msvc/-/blst-win32-x64-msvc-2.0.3.tgz#e4666de90c9fb4f26667decc6bd3f49e8e5b2e46" - integrity sha512-yHy8cF+PTpuOYiBx962gGH2+c2DY38x2Th7HijlBBFbytW+D/nMka1DTuuyuOVIb/un2aEVf7pVBUgXTbQHEwQ== +"@chainsafe/blst-win32-x64-msvc@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-win32-x64-msvc/-/blst-win32-x64-msvc-2.1.0.tgz#edaff899194caa4e40901af90779721673671631" + integrity sha512-wSRVGoLrluus38fmYYS0ft3VSG2EaeeWvb7yxvrAS8xUsaRFRClYo/3kaEHR3D9B9Nu5wiuWfob6DoM3w9deLw== "@chainsafe/blst@^0.2.0": version "0.2.11" @@ -443,18 +443,18 @@ node-fetch "^2.6.1" node-gyp "^8.4.0" -"@chainsafe/blst@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-2.0.3.tgz#12ae2544cb04a8cade626a6d5263d08432bdda4a" - integrity sha512-VMyqXAwgNtiHWj1ksEnHFxD2pmw+0VqQLCeNFacE5xPfscPcj+EVjmexbYdUTae52SfVx1E0F83kk1xLY5GwPw== +"@chainsafe/blst@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-2.1.0.tgz#1df4fa8e390db5c3cceed673b57468e23b4da36f" + integrity sha512-oY5k4whglgVOkisfujO0s1QgCOp3N/J3GogRbHhuNLrf6KN0zs1C3pKHg66EQhQqWVYnFY2Shx2s71/NFD7y+A== optionalDependencies: - "@chainsafe/blst-darwin-arm64" "2.0.3" - "@chainsafe/blst-darwin-x64" "2.0.3" - "@chainsafe/blst-linux-arm64-gnu" "2.0.3" - "@chainsafe/blst-linux-arm64-musl" "2.0.3" - "@chainsafe/blst-linux-x64-gnu" "2.0.3" - "@chainsafe/blst-linux-x64-musl" "2.0.3" - "@chainsafe/blst-win32-x64-msvc" "2.0.3" + "@chainsafe/blst-darwin-arm64" "2.1.0" + "@chainsafe/blst-darwin-x64" "2.1.0" + "@chainsafe/blst-linux-arm64-gnu" "2.1.0" + "@chainsafe/blst-linux-arm64-musl" "2.1.0" + "@chainsafe/blst-linux-x64-gnu" "2.1.0" + "@chainsafe/blst-linux-x64-musl" "2.1.0" + "@chainsafe/blst-win32-x64-msvc" "2.1.0" "@chainsafe/discv5@^10.0.1": version "10.0.1" From 748966bb5f1335f218d0d24376bfcea135e5855f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 20:37:46 +0100 Subject: [PATCH 176/259] chore(deps): bump mermaid from 10.9.0 to 10.9.3 in /docs (#7192) Bumps [mermaid](https://github.com/mermaid-js/mermaid) from 10.9.0 to 10.9.3. - [Release notes](https://github.com/mermaid-js/mermaid/releases) - [Changelog](https://github.com/mermaid-js/mermaid/blob/develop/CHANGELOG.md) - [Commits](https://github.com/mermaid-js/mermaid/compare/v10.9.0...v10.9.3) --- updated-dependencies: - dependency-name: mermaid dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/yarn.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/yarn.lock b/docs/yarn.lock index dad4d8ef1c07..046829e3530b 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -4352,7 +4352,7 @@ domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" -dompurify@^3.0.5: +"dompurify@^3.0.5 <3.1.7": version "3.1.6" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.1.6.tgz#43c714a94c6a7b8801850f82e756685300a027e2" integrity sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ== @@ -6364,9 +6364,9 @@ merge2@^1.3.0, merge2@^1.4.1: integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== mermaid@^10.4.0: - version "10.9.0" - resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-10.9.0.tgz#4d1272fbe434bd8f3c2c150554dc8a23a9bf9361" - integrity sha512-swZju0hFox/B/qoLKK0rOxxgh8Cf7rJSfAUc1u8fezVihYMvrJAS45GzAxTVf4Q+xn9uMgitBcmWk7nWGXOs/g== + version "10.9.3" + resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-10.9.3.tgz#90bc6f15c33dbe5d9507fed31592cc0d88fee9f7" + integrity sha512-V80X1isSEvAewIL3xhmz/rVmc27CVljcsbWxkxlWJWY/1kQa4XOABqpDl2qQLGKzpKm6WbTfUEKImBlUfFYArw== dependencies: "@braintree/sanitize-url" "^6.0.1" "@types/d3-scale" "^4.0.3" @@ -6377,7 +6377,7 @@ mermaid@^10.4.0: d3-sankey "^0.12.3" dagre-d3-es "7.0.10" dayjs "^1.11.7" - dompurify "^3.0.5" + dompurify "^3.0.5 <3.1.7" elkjs "^0.9.0" katex "^0.16.9" khroma "^2.0.0" From 6de073627459ead9f9c6a5e24aa8e705a10493db Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Fri, 25 Oct 2024 03:19:29 +0200 Subject: [PATCH 177/259] test: enable skipped e2e worker tests (#7195) Enable e2e worker tests --- .../onWorker/dataSerialization.test.ts | 29 +++++++++---------- .../onWorker/{workerEcho.ts => workerEcho.js} | 0 2 files changed, 14 insertions(+), 15 deletions(-) rename packages/beacon-node/test/e2e/network/onWorker/{workerEcho.ts => workerEcho.js} (100%) 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 741fd4b46696..12d9e393af09 100644 --- a/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts +++ b/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts @@ -29,8 +29,7 @@ import {EventDirection} from "../../../../src/util/workerEvents.js"; import {CommitteeSubscription} from "../../../../src/network/subnets/interface.js"; import {EchoWorker, getEchoWorker} from "./workerEchoHandler.js"; -// TODO: Need to find the way to load the echoWorker in the test environment -describe.skip("data serialization through worker boundary", () => { +describe("data serialization through worker boundary", () => { let echoWorker: EchoWorker; beforeAll(async () => { @@ -45,7 +44,7 @@ describe.skip("data serialization through worker boundary", () => { const peerId = validPeerIdStr; const peer = validPeerIdStr; const method = ReqRespMethod.BeaconBlocksByRange; - const bytes = ZERO_HASH; + const bytes = Uint8Array.from(ZERO_HASH); const statusZero = ssz.phase0.Status.defaultValue(); // Defining tests in this notation ensures that any event data is tested and probably safe to send @@ -90,7 +89,7 @@ describe.skip("data serialization through worker boundary", () => { type: BlockInputType.preData, block: ssz.capella.SignedBeaconBlock.defaultValue(), source: BlockSource.gossip, - blockBytes: ZERO_HASH, + blockBytes: Uint8Array.from(ZERO_HASH), }, peer, }, @@ -252,21 +251,21 @@ describe.skip("data serialization through worker boundary", () => { type Resolves> = T extends Promise ? (U extends void ? null : U) : never; function getEmptyBlockInput(): BlockInput { - let resolveAvailability: ((blobs: BlockInputDataBlobs) => void) | null = null; - const availabilityPromise = new Promise((resolveCB) => { - resolveAvailability = resolveCB; - }); - if (resolveAvailability === null) { - throw Error("Promise Constructor was not executed immediately"); - } - const blobsCache = new Map(); - - const cachedData = {fork: ForkName.deneb, blobsCache, availabilityPromise, resolveAvailability} as CachedData; + const cachedData = { + fork: ForkName.deneb, + blobsCache: new Map(), + // Actual promise raise this error when used in `worker.postMessage` + // DataCloneError: # could not be cloned. + availabilityPromise: null, + // Actual function raise this error when used in `worker.postMessage` + // DataCloneError: function () { [native code] } could not be cloned + resolveAvailability: null, + } as unknown as CachedData; return { type: BlockInputType.dataPromise, block: ssz.deneb.SignedBeaconBlock.defaultValue(), source: BlockSource.gossip, - blockBytes: ZERO_HASH, + blockBytes: Uint8Array.from(ZERO_HASH), cachedData, }; } diff --git a/packages/beacon-node/test/e2e/network/onWorker/workerEcho.ts b/packages/beacon-node/test/e2e/network/onWorker/workerEcho.js similarity index 100% rename from packages/beacon-node/test/e2e/network/onWorker/workerEcho.ts rename to packages/beacon-node/test/e2e/network/onWorker/workerEcho.js From bfa7a39e6ecb705430a51ba60592dec62c1ee820 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 25 Oct 2024 21:49:06 +0100 Subject: [PATCH 178/259] fix: remove warning log if validator pubkey not found or invalid (#7198) --- packages/beacon-node/src/api/impl/beacon/state/index.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/state/index.ts b/packages/beacon-node/src/api/impl/beacon/state/index.ts index 8cce896e1087..a1e17b80ea84 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/index.ts @@ -18,8 +18,7 @@ import {filterStateValidatorsByStatus, getStateValidatorIndex, getStateResponse, export function getBeaconStateApi({ chain, config, - logger, -}: Pick): ApplicationMethods { +}: Pick): ApplicationMethods { async function getState( stateId: routes.beacon.StateId ): Promise<{state: BeaconStateAllForks; executionOptimistic: boolean; finalized: boolean}> { @@ -95,8 +94,6 @@ export function getBeaconStateApi({ currentEpoch ); validatorResponses.push(validatorResponse); - } else { - logger.warn(resp.reason, {id}); } } return { @@ -145,8 +142,6 @@ export function getBeaconStateApi({ const index = resp.validatorIndex; const {pubkey, activationEpoch} = state.validators.getReadonly(index); validatorIdentities.push({index, pubkey, activationEpoch}); - } else { - logger.warn(resp.reason, {id}); } } } else { From d8b599a4a54f8ad7c0289f452dbe6f62bc685f33 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 28 Oct 2024 09:16:34 +0000 Subject: [PATCH 179/259] feat: forward blinded block ssz bytes to submitBlindedBlock api (#7185) * feat: forward blinded block ssz bytes to submitBlindedBlock api * Add comment * Add WithOptionalBytes --- packages/api/src/builder/routes.ts | 17 ++++++++++------- packages/api/test/unit/builder/testData.ts | 2 +- .../src/api/impl/beacon/blocks/index.ts | 8 ++++++-- .../beacon-node/src/execution/builder/http.ts | 7 +++++-- .../src/execution/builder/interface.ts | 5 ++++- packages/types/src/types.ts | 6 ++++++ 6 files changed, 32 insertions(+), 13 deletions(-) diff --git a/packages/api/src/builder/routes.ts b/packages/api/src/builder/routes.ts index a203a93b8afe..3911a515e1c6 100644 --- a/packages/api/src/builder/routes.ts +++ b/packages/api/src/builder/routes.ts @@ -8,6 +8,7 @@ import { ExecutionPayloadAndBlobsBundle, SignedBlindedBeaconBlock, SignedBuilderBid, + WithOptionalBytes, } from "@lodestar/types"; import {ForkName, isForkBlobs} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; @@ -71,7 +72,7 @@ export type Endpoints = { submitBlindedBlock: Endpoint< "POST", - {signedBlindedBlock: SignedBlindedBeaconBlock}, + {signedBlindedBlock: WithOptionalBytes}, {body: unknown; headers: {[MetaHeader.Version]: string}}, ExecutionPayload | ExecutionPayloadAndBlobsBundle, VersionMeta @@ -124,9 +125,9 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { - const fork = config.getForkName(signedBlindedBlock.message.slot); + const fork = config.getForkName(signedBlindedBlock.data.message.slot); return { - body: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.toJson(signedBlindedBlock), + body: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.toJson(signedBlindedBlock.data), headers: { [MetaHeader.Version]: fork, }, @@ -135,13 +136,15 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedBlindedBlock: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.fromJson(body), + signedBlindedBlock: {data: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.fromJson(body)}, }; }, writeReqSsz: ({signedBlindedBlock}) => { - const fork = config.getForkName(signedBlindedBlock.message.slot); + const fork = config.getForkName(signedBlindedBlock.data.message.slot); return { - body: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.serialize(signedBlindedBlock), + body: + signedBlindedBlock.bytes ?? + getExecutionForkTypes(fork).SignedBlindedBeaconBlock.serialize(signedBlindedBlock.data), headers: { [MetaHeader.Version]: fork, }, @@ -150,7 +153,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { - signedBlindedBlock: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.deserialize(body), + signedBlindedBlock: {data: getExecutionForkTypes(fork).SignedBlindedBeaconBlock.deserialize(body)}, }; }, schema: { diff --git a/packages/api/test/unit/builder/testData.ts b/packages/api/test/unit/builder/testData.ts index a23823702b6d..a807620258df 100644 --- a/packages/api/test/unit/builder/testData.ts +++ b/packages/api/test/unit/builder/testData.ts @@ -23,7 +23,7 @@ export const testData: GenericServerTestCases = { res: {data: ssz.bellatrix.SignedBuilderBid.defaultValue(), meta: {version: ForkName.bellatrix}}, }, submitBlindedBlock: { - args: {signedBlindedBlock: ssz.deneb.SignedBlindedBeaconBlock.defaultValue()}, + args: {signedBlindedBlock: {data: ssz.deneb.SignedBlindedBeaconBlock.defaultValue()}}, res: {data: ssz.bellatrix.ExecutionPayload.defaultValue(), meta: {version: ForkName.bellatrix}}, }, }; 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 b54e8752a437..2d36505d822a 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -15,6 +15,7 @@ import { SignedBeaconBlock, SignedBeaconBlockOrContents, SignedBlindedBeaconBlock, + WithOptionalBytes, } from "@lodestar/types"; import { BlockSource, @@ -269,7 +270,10 @@ export function getBeaconBlockApi({ const source = ProducedBlockSource.builder; chain.logger.debug("Reconstructing signedBlockOrContents", {slot, blockRoot, source}); - const signedBlockOrContents = await reconstructBuilderBlockOrContents(chain, signedBlindedBlock); + const signedBlockOrContents = await reconstructBuilderBlockOrContents(chain, { + data: signedBlindedBlock, + bytes: context?.sszBytes, + }); // the full block is published by relay and it's possible that the block is already known to us // by gossip @@ -507,7 +511,7 @@ export function getBeaconBlockApi({ async function reconstructBuilderBlockOrContents( chain: ApiModules["chain"], - signedBlindedBlock: SignedBlindedBeaconBlock + signedBlindedBlock: WithOptionalBytes ): Promise { const executionBuilder = chain.executionBuilder; if (!executionBuilder) { diff --git a/packages/beacon-node/src/execution/builder/http.ts b/packages/beacon-node/src/execution/builder/http.ts index 0a6018e5e231..b95cfd6a80b9 100644 --- a/packages/beacon-node/src/execution/builder/http.ts +++ b/packages/beacon-node/src/execution/builder/http.ts @@ -9,6 +9,7 @@ import { SignedBlindedBeaconBlock, ExecutionPayloadHeader, electra, + WithOptionalBytes, } from "@lodestar/types"; import {parseExecutionPayloadAndBlobsBundle, reconstructFullBlockOrContents} from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; @@ -160,7 +161,9 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { return {header, executionPayloadValue, blobKzgCommitments, executionRequests}; } - async submitBlindedBlock(signedBlindedBlock: SignedBlindedBeaconBlock): Promise { + async submitBlindedBlock( + signedBlindedBlock: WithOptionalBytes + ): Promise { const res = await this.api.submitBlindedBlock( {signedBlindedBlock}, {retries: 2, requestWireFormat: this.sszSupported ? WireFormat.ssz : WireFormat.json} @@ -174,6 +177,6 @@ export class ExecutionBuilderHttp implements IExecutionBuilder { // probably need diagonis if this block turns out to be invalid because of some bug // const contents = blobsBundle ? {blobs: blobsBundle.blobs, kzgProofs: blobsBundle.proofs} : null; - return reconstructFullBlockOrContents(signedBlindedBlock, {executionPayload, contents}); + return reconstructFullBlockOrContents(signedBlindedBlock.data, {executionPayload, contents}); } } diff --git a/packages/beacon-node/src/execution/builder/interface.ts b/packages/beacon-node/src/execution/builder/interface.ts index 5a6a4eb82f63..19a935a9bf7e 100644 --- a/packages/beacon-node/src/execution/builder/interface.ts +++ b/packages/beacon-node/src/execution/builder/interface.ts @@ -9,6 +9,7 @@ import { ExecutionPayloadHeader, SignedBlindedBeaconBlock, electra, + WithOptionalBytes, } from "@lodestar/types"; import {ForkExecution} from "@lodestar/params"; @@ -39,5 +40,7 @@ export interface IExecutionBuilder { blobKzgCommitments?: deneb.BlobKzgCommitments; executionRequests?: electra.ExecutionRequests; }>; - submitBlindedBlock(signedBlock: SignedBlindedBeaconBlock): Promise; + submitBlindedBlock( + signedBlindedBlock: WithOptionalBytes + ): Promise; } diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 08fc06ac6cb9..51fa2b12a28e 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -32,6 +32,12 @@ export enum ProducedBlockSource { engine = "engine", } +export type WithOptionalBytes = { + data: T; + /** SSZ serialized `data` bytes */ + bytes?: Uint8Array | null; +}; + export type SlotRootHex = {slot: Slot; root: RootHex}; export type SlotOptionalRoot = {slot: Slot; root?: RootHex}; From 4b08c0ba2dff05606a203c8dc2a46fe575132041 Mon Sep 17 00:00:00 2001 From: Cayman Date: Mon, 28 Oct 2024 10:08:25 -0400 Subject: [PATCH 180/259] chore: revert "chore: upgrade to js-libp2p 2.0 (#7077)" (#7202) Revert "chore: upgrade to js-libp2p 2.0 (#7077)" This reverts commit d37bdb0eb8a6e8deedd019fd6b7b3413f3fcf6d4. --- package.json | 2 +- packages/beacon-node/package.json | 35 +- .../src/network/core/networkCore.ts | 17 +- .../src/network/core/networkCoreWorker.ts | 8 +- .../network/core/networkCoreWorkerHandler.ts | 10 +- .../beacon-node/src/network/core/types.ts | 2 +- .../beacon-node/src/network/discv5/index.ts | 14 +- .../beacon-node/src/network/discv5/types.ts | 2 +- .../beacon-node/src/network/discv5/worker.ts | 13 +- .../src/network/gossip/gossipsub.ts | 4 - packages/beacon-node/src/network/interface.ts | 4 +- .../beacon-node/src/network/libp2p/index.ts | 21 +- packages/beacon-node/src/network/network.ts | 18 +- .../src/network/peers/datastore.ts | 3 +- .../beacon-node/src/network/peers/discover.ts | 10 +- .../src/network/peers/peerManager.ts | 5 +- .../peers/utils/getConnectedPeerIds.ts | 4 +- packages/beacon-node/src/network/util.ts | 4 +- packages/beacon-node/src/node/nodejs.ts | 8 +- packages/beacon-node/src/util/peerId.ts | 2 +- .../beacon-node/test/e2e/network/mdns.test.ts | 16 +- .../e2e/network/peers/peerManager.test.ts | 12 +- .../test/e2e/network/reqrespEncode.test.ts | 2 +- .../test/perf/network/noise/sendData.test.ts | 17 +- .../peers/util/prioritizePeers.test.ts | 6 +- .../unit/network/peers/priorization.test.ts | 9 +- packages/beacon-node/test/utils/network.ts | 15 +- .../test/utils/networkWithMockDb.ts | 6 +- .../beacon-node/test/utils/node/beacon.ts | 12 +- packages/beacon-node/test/utils/peer.ts | 8 +- packages/cli/package.json | 10 +- packages/cli/src/cmds/beacon/handler.ts | 10 +- .../cli/src/cmds/beacon/initPeerIdAndEnr.ts | 54 +- packages/cli/src/cmds/bootnode/handler.ts | 14 +- packages/cli/src/config/peerId.ts | 68 +- packages/cli/test/unit/cmds/beacon.test.ts | 57 +- .../test/unit/cmds/initPeerIdAndEnr.test.ts | 13 +- packages/cli/test/unit/config/peerId.test.ts | 12 +- packages/reqresp/package.json | 6 +- packages/reqresp/test/utils/peer.ts | 5 +- yarn.lock | 816 ++++++++---------- 41 files changed, 600 insertions(+), 754 deletions(-) diff --git a/package.json b/package.json index e6de076cf494..7399b4ba6c1e 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "https-browserify": "^1.0.0", "jsdom": "^23.0.1", "lerna": "^7.3.0", - "libp2p": "2.1.7", + "libp2p": "1.4.3", "mocha": "^10.2.0", "node-gyp": "^9.4.0", "npm-run-all": "^4.1.5", diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 3213504334e3..fcaf5b715216 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -96,10 +96,11 @@ "dependencies": { "@chainsafe/as-sha256": "^0.5.0", "@chainsafe/blst": "^2.1.0", - "@chainsafe/discv5": "^10.0.1", - "@chainsafe/enr": "^4.0.1", - "@chainsafe/libp2p-gossipsub": "^14.1.0", - "@chainsafe/libp2p-noise": "^16.0.0", + "@chainsafe/discv5": "^9.0.0", + "@chainsafe/enr": "^3.0.0", + "@chainsafe/libp2p-gossipsub": "^13.0.0", + "@chainsafe/libp2p-identify": "^1.0.0", + "@chainsafe/libp2p-noise": "^15.0.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/prometheus-gc-stats": "^1.0.0", "@chainsafe/ssz": "^0.18.0", @@ -110,15 +111,15 @@ "@fastify/cors": "^10.0.1", "@fastify/swagger": "^9.0.0", "@fastify/swagger-ui": "^5.0.1", - "@libp2p/bootstrap": "^11.0.4", - "@libp2p/crypto": "^5.0.4", - "@libp2p/identify": "^3.0.4", - "@libp2p/interface": "^2.1.2", - "@libp2p/mdns": "^11.0.4", - "@libp2p/mplex": "^11.0.4", - "@libp2p/peer-id": "^5.0.4", - "@libp2p/prometheus-metrics": "^4.1.2", - "@libp2p/tcp": "10.0.4", + "@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.22.0", "@lodestar/config": "^1.22.0", "@lodestar/db": "^1.22.0", @@ -133,15 +134,15 @@ "@lodestar/validator": "^1.22.0", "@multiformats/multiaddr": "^12.1.3", "c-kzg": "^2.1.2", - "datastore-core": "^10.0.0", - "datastore-level": "^11.0.0", + "datastore-core": "^9.1.1", + "datastore-level": "^10.1.1", "deepmerge": "^4.3.1", "fastify": "^5.0.0", - "interface-datastore": "^8.3.0", + "interface-datastore": "^8.2.7", "it-all": "^3.0.4", "it-pipe": "^3.0.1", "jwt-simple": "0.5.6", - "libp2p": "2.1.7", + "libp2p": "1.4.3", "multiformats": "^11.0.1", "prom-client": "^15.1.0", "qs": "^6.11.1", diff --git a/packages/beacon-node/src/network/core/networkCore.ts b/packages/beacon-node/src/network/core/networkCore.ts index b000d184e0eb..d47fcabd4146 100644 --- a/packages/beacon-node/src/network/core/networkCore.ts +++ b/packages/beacon-node/src/network/core/networkCore.ts @@ -1,4 +1,4 @@ -import {Connection, PrivateKey} from "@libp2p/interface"; +import {Connection, PeerId} from "@libp2p/interface"; import {multiaddr} from "@multiformats/multiaddr"; import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/dist/src/score/peer-score.js"; @@ -55,7 +55,7 @@ type Mods = { export type BaseNetworkInit = { opts: NetworkOptions; config: BeaconConfig; - privateKey: PrivateKey; + peerId: PeerId; peerStoreDir: string | undefined; logger: LoggerNode; metricsRegistry: RegistryMetricCreator | null; @@ -126,7 +126,7 @@ export class NetworkCore implements INetworkCore { static async init({ opts, config, - privateKey, + peerId, peerStoreDir, logger, metricsRegistry, @@ -136,7 +136,7 @@ export class NetworkCore implements INetworkCore { activeValidatorCount, initialStatus, }: BaseNetworkInit): Promise { - const libp2p = await createNodeJsLibp2p(privateKey, opts, { + const libp2p = await createNodeJsLibp2p(peerId, opts, { peerStoreDir, metrics: Boolean(metricsRegistry), metricsRegistry: metricsRegistry ?? undefined, @@ -200,9 +200,8 @@ export class NetworkCore implements INetworkCore { const peerManager = await PeerManager.init( { - privateKey, libp2p, - gossip, + gossip: gossip, reqResp, attnetsService, syncnetsService, @@ -363,11 +362,7 @@ export class NetworkCore implements INetworkCore { } getConnectionsByPeer(): Map { - const m = new Map(); - for (const [k, v] of getConnectionsMap(this.libp2p).entries()) { - m.set(k, v.value); - } - return m; + return getConnectionsMap(this.libp2p); } async getConnectedPeers(): Promise { diff --git a/packages/beacon-node/src/network/core/networkCoreWorker.ts b/packages/beacon-node/src/network/core/networkCoreWorker.ts index 07b6de828b6c..5e4b057402d8 100644 --- a/packages/beacon-node/src/network/core/networkCoreWorker.ts +++ b/packages/beacon-node/src/network/core/networkCoreWorker.ts @@ -3,8 +3,7 @@ import path from "node:path"; import worker from "node:worker_threads"; import type {ModuleThread} from "@chainsafe/threads"; import {expose} from "@chainsafe/threads/worker"; -import {privateKeyFromProtobuf} from "@libp2p/crypto/keys"; -import {peerIdFromPrivateKey} from "@libp2p/peer-id"; +import {createFromProtobuf} from "@libp2p/peer-id-factory"; import {chainConfigFromJson, createBeaconConfig} from "@lodestar/config"; import {getNodeLogger} from "@lodestar/logger/node"; import {RegistryMetricCreator, collectNodeJSMetrics} from "../../metrics/index.js"; @@ -33,8 +32,7 @@ if (!workerData) throw Error("workerData must be defined"); if (!parentPort) throw Error("parentPort must be defined"); const config = createBeaconConfig(chainConfigFromJson(workerData.chainConfigJson), workerData.genesisValidatorsRoot); -const privateKey = privateKeyFromProtobuf(workerData.privateKeyProto); -const peerId = peerIdFromPrivateKey(privateKey); +const peerId = await createFromProtobuf(workerData.peerIdProto); // TODO: Pass options from main thread for logging // TODO: Logging won't be visible in file loggers @@ -94,7 +92,7 @@ if (networkCoreWorkerMetrics) { const core = await NetworkCore.init({ opts: workerData.opts, config, - privateKey, + peerId, peerStoreDir: workerData.peerStoreDir, logger, metricsRegistry: metricsRegister, diff --git a/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts b/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts index e883476b5e65..bd66a21e726b 100644 --- a/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts +++ b/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts @@ -3,8 +3,8 @@ 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 {PrivateKey} from "@libp2p/interface"; -import {privateKeyToProtobuf} from "@libp2p/crypto/keys"; +import {PeerId, Secp256k1PeerId} from "@libp2p/interface"; +import {exportToProtobuf} from "@libp2p/peer-id-factory"; import {routes} from "@lodestar/api"; import {BeaconConfig, chainConfigToJson} from "@lodestar/config"; import type {LoggerNode} from "@lodestar/logger/node"; @@ -44,7 +44,7 @@ export type WorkerNetworkCoreInitModules = { opts: WorkerNetworkCoreOpts; config: BeaconConfig; logger: LoggerNode; - privateKey: PrivateKey; + peerId: PeerId; events: NetworkEventBus; metrics: Metrics | null; getReqRespHandler: GetReqRespHandlerFn; @@ -103,14 +103,14 @@ export class WorkerNetworkCore implements INetworkCore { } static async init(modules: WorkerNetworkCoreInitModules): Promise { - const {opts, config, privateKey} = modules; + const {opts, config, peerId} = modules; const {genesisTime, peerStoreDir, activeValidatorCount, localMultiaddrs, metricsEnabled, initialStatus} = opts; const workerData: NetworkWorkerData = { opts, chainConfigJson: chainConfigToJson(config), genesisValidatorsRoot: config.genesisValidatorsRoot, - privateKeyProto: privateKeyToProtobuf(privateKey), + peerIdProto: exportToProtobuf(peerId as Secp256k1PeerId), localMultiaddrs, metricsEnabled, peerStoreDir, diff --git a/packages/beacon-node/src/network/core/types.ts b/packages/beacon-node/src/network/core/types.ts index d2f56c8fa2f1..4eeaf96e1903 100644 --- a/packages/beacon-node/src/network/core/types.ts +++ b/packages/beacon-node/src/network/core/types.ts @@ -78,7 +78,7 @@ export type NetworkWorkerData = { genesisTime: number; activeValidatorCount: number; initialStatus: phase0.Status; - privateKeyProto: Uint8Array; + peerIdProto: Uint8Array; localMultiaddrs: string[]; metricsEnabled: boolean; peerStoreDir?: string; diff --git a/packages/beacon-node/src/network/discv5/index.ts b/packages/beacon-node/src/network/discv5/index.ts index 34990d404c90..745b3171c38d 100644 --- a/packages/beacon-node/src/network/discv5/index.ts +++ b/packages/beacon-node/src/network/discv5/index.ts @@ -1,8 +1,8 @@ import EventEmitter from "node:events"; -import {privateKeyToProtobuf} from "@libp2p/crypto/keys"; -import {PrivateKey} from "@libp2p/interface"; +import {PeerId, Secp256k1PeerId} from "@libp2p/interface"; import {StrictEventEmitter} from "strict-event-emitter-types"; -import {ENR, ENRData, SignableENR} from "@chainsafe/enr"; +import {exportToProtobuf} from "@libp2p/peer-id-factory"; +import {createPrivateKeyFromPeerId, ENR, ENRData, SignableENR} from "@chainsafe/enr"; import {spawn, Thread, Worker} from "@chainsafe/threads"; import {chainConfigFromJson, chainConfigToJson, BeaconConfig} from "@lodestar/config"; import {LoggerNode} from "@lodestar/logger/node"; @@ -10,7 +10,7 @@ import {NetworkCoreMetrics} from "../core/metrics.js"; import {Discv5WorkerApi, Discv5WorkerData, LodestarDiscv5Opts} from "./types.js"; export type Discv5Opts = { - privateKey: PrivateKey; + peerId: PeerId; discv5: LodestarDiscv5Opts; logger: LoggerNode; config: BeaconConfig; @@ -25,6 +25,7 @@ export type Discv5Events = { * Wrapper class abstracting the details of discv5 worker instantiation and message-passing */ export class Discv5Worker extends (EventEmitter as {new (): StrictEventEmitter}) { + private readonly keypair; private readonly subscription: {unsubscribe: () => void}; private closed = false; @@ -34,13 +35,14 @@ export class Discv5Worker extends (EventEmitter as {new (): StrictEventEmitter this.onDiscovered(enrObj)); } static async init(opts: Discv5Opts): Promise { const workerData: Discv5WorkerData = { enr: opts.discv5.enr, - privateKeyProto: privateKeyToProtobuf(opts.privateKey), + peerIdProto: exportToProtobuf(opts.peerId as Secp256k1PeerId), bindAddrs: opts.discv5.bindAddrs, config: opts.discv5.config ?? {}, bootEnrs: opts.discv5.bootEnrs, @@ -78,7 +80,7 @@ export class Discv5Worker extends (EventEmitter as {new (): StrictEventEmitter { const obj = await this.workerApi.enr(); - return new SignableENR(obj.kvs, obj.seq, this.opts.privateKey.raw); + return new SignableENR(obj.kvs, obj.seq, this.keypair.privateKey); } setEnrValue(key: string, value: Uint8Array): Promise { diff --git a/packages/beacon-node/src/network/discv5/types.ts b/packages/beacon-node/src/network/discv5/types.ts index cbaf2423f87f..63c5cd52b6fe 100644 --- a/packages/beacon-node/src/network/discv5/types.ts +++ b/packages/beacon-node/src/network/discv5/types.ts @@ -31,7 +31,7 @@ export type LodestarDiscv5Opts = { /** discv5 worker constructor data */ export interface Discv5WorkerData { enr: string; - privateKeyProto: Uint8Array; + peerIdProto: Uint8Array; bindAddrs: BindAddrs; config: Discv5Config; bootEnrs: string[]; diff --git a/packages/beacon-node/src/network/discv5/worker.ts b/packages/beacon-node/src/network/discv5/worker.ts index 40eb08f7af92..8e96751d5fe7 100644 --- a/packages/beacon-node/src/network/discv5/worker.ts +++ b/packages/beacon-node/src/network/discv5/worker.ts @@ -1,13 +1,12 @@ import worker from "node:worker_threads"; import path from "node:path"; import fs from "node:fs"; +import {createFromProtobuf} from "@libp2p/peer-id-factory"; import {Multiaddr, multiaddr} from "@multiformats/multiaddr"; import {expose} from "@chainsafe/threads/worker"; import {Observable, Subject} from "@chainsafe/threads/observable"; import {Discv5} from "@chainsafe/discv5"; -import {ENR, ENRData, SignableENR, SignableENRData} from "@chainsafe/enr"; -import {privateKeyFromProtobuf} from "@libp2p/crypto/keys"; -import {peerIdFromPrivateKey} from "@libp2p/peer-id"; +import {createPrivateKeyFromPeerId, ENR, ENRData, SignableENR, SignableENRData} from "@chainsafe/enr"; import {createBeaconConfig} from "@lodestar/config"; import {getNodeLogger} from "@lodestar/logger/node"; import {Gauge} from "@lodestar/utils"; @@ -43,15 +42,15 @@ if (workerData.metrics) { }); } -const privateKey = privateKeyFromProtobuf(workerData.privateKeyProto); -const peerId = peerIdFromPrivateKey(privateKey); +const peerId = await createFromProtobuf(workerData.peerIdProto); +const keypair = createPrivateKeyFromPeerId(peerId); const config = createBeaconConfig(workerData.chainConfig, workerData.genesisValidatorsRoot); // Initialize discv5 const discv5 = Discv5.create({ - enr: SignableENR.decodeTxt(workerData.enr, privateKey.raw), - privateKey, + enr: SignableENR.decodeTxt(workerData.enr, keypair.privateKey), + peerId, bindAddrs: { ip4: (workerData.bindAddrs.ip4 ? multiaddr(workerData.bindAddrs.ip4) : undefined) as Multiaddr, ip6: workerData.bindAddrs.ip6 ? multiaddr(workerData.bindAddrs.ip6) : undefined, diff --git a/packages/beacon-node/src/network/gossip/gossipsub.ts b/packages/beacon-node/src/network/gossip/gossipsub.ts index 83bb913325bf..76e1330cd4a1 100644 --- a/packages/beacon-node/src/network/gossip/gossipsub.ts +++ b/packages/beacon-node/src/network/gossip/gossipsub.ts @@ -135,10 +135,6 @@ export class Eth2Gossipsub extends GossipSub { // if this is false, only publish to mesh peers. If there is not enough GOSSIP_D mesh peers, // publish to some more topic peers to make sure we always publish to at least GOSSIP_D peers floodPublish: !opts?.disableFloodPublish, - // Only send IDONTWANT messages if the message size is larger than this - // This should be large enough to not send IDONTWANT for "small" messages - // See https://github.com/ChainSafe/lodestar/pull/7077#issuecomment-2383679472 - idontwantMinDataSize: 16829, }); this.scoreParams = scoreParams; this.config = config; diff --git a/packages/beacon-node/src/network/interface.ts b/packages/beacon-node/src/network/interface.ts index ccb5ddecb557..8d73379af221 100644 --- a/packages/beacon-node/src/network/interface.ts +++ b/packages/beacon-node/src/network/interface.ts @@ -12,11 +12,10 @@ import { PeerRouting, PeerStore, Upgrader, - PrivateKey, } from "@libp2p/interface"; import type {AddressManager, ConnectionManager, Registrar, TransportManager} from "@libp2p/interface-internal"; import type {Datastore} from "interface-datastore"; -import {Identify} from "@libp2p/identify"; +import {Identify} from "@chainsafe/libp2p-identify"; import { LightClientFinalityUpdate, LightClientOptimisticUpdate, @@ -94,7 +93,6 @@ export interface INetwork extends INetworkCorePublic { export type LodestarComponents = { peerId: PeerId; - privateKey: PrivateKey; nodeInfo: NodeInfo; logger: ComponentLogger; events: TypedEventTarget; diff --git a/packages/beacon-node/src/network/libp2p/index.ts b/packages/beacon-node/src/network/libp2p/index.ts index 7697dbcb49a7..a0d58033cf2f 100644 --- a/packages/beacon-node/src/network/libp2p/index.ts +++ b/packages/beacon-node/src/network/libp2p/index.ts @@ -1,7 +1,8 @@ -import {PrivateKey} from "@libp2p/interface"; +import {PeerId} from "@libp2p/interface"; import {Registry} from "prom-client"; import {ENR} from "@chainsafe/enr"; -import {identify} from "@libp2p/identify"; +// TODO: We should use this fork until https://github.com/libp2p/js-libp2p/pull/2387 +import {identify} from "@chainsafe/libp2p-identify"; import {bootstrap} from "@libp2p/bootstrap"; import {mdns} from "@libp2p/mdns"; import {createLibp2p} from "libp2p"; @@ -33,7 +34,7 @@ export async function getDiscv5Multiaddrs(bootEnrs: string[]): Promise } export async function createNodeJsLibp2p( - privateKey: PrivateKey, + peerId: PeerId, networkOpts: Partial = {}, nodeJsLibp2pOpts: NodeJsLibp2pOpts = {} ): Promise { @@ -64,12 +65,12 @@ export async function createNodeJsLibp2p( } return createLibp2p({ - privateKey, + peerId, addresses: { listen: localMultiaddrs, announce: [], }, - connectionEncrypters: [noise()], + connectionEncryption: [noise()], // Reject connections when the server's connection count gets high transports: [ tcp({ @@ -98,14 +99,15 @@ export async function createNodeJsLibp2p( maxParallelDials: 100, maxPeerAddrsToDial: 4, dialTimeout: 30_000, + + // Rely entirely on lodestar's peer manager to prune connections + //maxConnections: options.maxConnections, + // DOCS: There is no way to turn off autodial other than setting minConnections to 0 + minConnections: 0, // the maximum number of pending connections libp2p will accept before it starts rejecting incoming connections. // make it the same to backlog option above maxIncomingPendingConnections: 5, }, - // rely on lodestar's peer manager to ping peers - connectionMonitor: { - enabled: false, - }, datastore, services: { identify: identify({ @@ -116,7 +118,6 @@ export async function createNodeJsLibp2p( // and passing it here directly causes problems downstream, not to mention is slowwww components: (components: LodestarComponents) => ({ peerId: components.peerId, - privateKey: components.privateKey, nodeInfo: components.nodeInfo, logger: components.logger, events: components.events, diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 73208f497d66..1b3ccaaaf75a 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -1,7 +1,6 @@ -import {PeerId, PrivateKey} from "@libp2p/interface"; +import {PeerId} from "@libp2p/interface"; import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/score"; -import {peerIdFromPrivateKey} from "@libp2p/peer-id"; import {BeaconConfig} from "@lodestar/config"; import {sleep} from "@lodestar/utils"; import {LoggerNode} from "@lodestar/logger/node"; @@ -51,7 +50,7 @@ import {getActiveForks} from "./forks.js"; type NetworkModules = { opts: NetworkOptions; - privateKey: PrivateKey; + peerId: PeerId; config: BeaconConfig; logger: LoggerNode; chain: IBeaconChain; @@ -64,7 +63,7 @@ type NetworkModules = { export type NetworkInitModules = { opts: NetworkOptions; config: BeaconConfig; - privateKey: PrivateKey; + peerId: PeerId; peerStoreDir?: string; logger: LoggerNode; metrics: Metrics | null; @@ -105,7 +104,7 @@ export class Network implements INetwork { private regossipBlsChangesPromise: Promise | null = null; constructor(modules: NetworkModules) { - this.peerId = peerIdFromPrivateKey(modules.privateKey); + this.peerId = modules.peerId; this.config = modules.config; this.logger = modules.logger; this.chain = modules.chain; @@ -135,7 +134,7 @@ export class Network implements INetwork { chain, db, gossipHandlers, - privateKey, + peerId, peerStoreDir, getReqRespHandler, }: NetworkInitModules): Promise { @@ -160,7 +159,7 @@ export class Network implements INetwork { initialStatus, }, config, - privateKey, + peerId, logger, events, metrics, @@ -169,7 +168,7 @@ export class Network implements INetwork { : await NetworkCore.init({ opts, config, - privateKey, + peerId, peerStoreDir, logger, clock: chain.clock, @@ -186,12 +185,11 @@ export class Network implements INetwork { ); const multiaddresses = opts.localMultiaddrs?.join(","); - const peerId = peerIdFromPrivateKey(privateKey); logger.info(`PeerId ${peerIdToString(peerId)}, Multiaddrs ${multiaddresses}`); return new Network({ opts, - privateKey, + peerId, config, logger, chain, diff --git a/packages/beacon-node/src/network/peers/datastore.ts b/packages/beacon-node/src/network/peers/datastore.ts index e0f2001c26ee..88a7a6f5f2d6 100644 --- a/packages/beacon-node/src/network/peers/datastore.ts +++ b/packages/beacon-node/src/network/peers/datastore.ts @@ -1,4 +1,3 @@ -import {AbortOptions} from "@libp2p/interface"; import {BaseDatastore} from "datastore-core"; import {LevelDatastore} from "datastore-level"; import {Key, KeyQuery, Query, Pair} from "interface-datastore"; @@ -58,7 +57,7 @@ export class Eth2PeerDataStore extends BaseDatastore { return this._dbDatastore.close(); } - async put(key: Key, val: Uint8Array, _options?: AbortOptions): Promise { + async put(key: Key, val: Uint8Array): Promise { return this._put(key, val, false); } diff --git a/packages/beacon-node/src/network/peers/discover.ts b/packages/beacon-node/src/network/peers/discover.ts index 0ca67caf74fa..2b03656064e4 100644 --- a/packages/beacon-node/src/network/peers/discover.ts +++ b/packages/beacon-node/src/network/peers/discover.ts @@ -1,5 +1,5 @@ import {Multiaddr} from "@multiformats/multiaddr"; -import type {PeerId, PeerInfo, PrivateKey} from "@libp2p/interface"; +import type {PeerId, PeerInfo} from "@libp2p/interface"; import {ENR} from "@chainsafe/enr"; import {BeaconConfig} from "@lodestar/config"; import {pruneSetToMax, sleep} from "@lodestar/utils"; @@ -27,7 +27,6 @@ export type PeerDiscoveryOpts = { }; export type PeerDiscoveryModules = { - privateKey: PrivateKey; libp2p: Libp2p; peerRpcScores: IPeerRpcScoreStore; metrics: NetworkCoreMetrics | null; @@ -159,7 +158,7 @@ export class PeerDiscovery { static async init(modules: PeerDiscoveryModules, opts: PeerDiscoveryOpts): Promise { const discv5 = await Discv5Worker.init({ discv5: opts.discv5, - privateKey: modules.privateKey, + peerId: modules.libp2p.peerId, metrics: modules.metrics ?? undefined, logger: modules.logger, config: modules.config, @@ -323,7 +322,8 @@ export class PeerDiscovery { if (this.randomNodeQuery.code === QueryStatusCode.Active) { this.randomNodeQuery.count++; } - const peerId = enr.peerId; + // async due to some crypto that's no longer necessary + const peerId = await enr.peerId(); // tcp multiaddr is known to be be present, checked inside the worker const multiaddrTCP = enr.getLocationMultiaddr(ENRKey.tcp); if (!multiaddrTCP) { @@ -472,7 +472,7 @@ export class PeerDiscovery { /** Check if there is 1+ open connection with this peer */ private isPeerConnected(peerIdStr: PeerIdStr): boolean { const connections = getConnectionsMap(this.libp2p).get(peerIdStr); - return Boolean(connections?.value.some((connection) => connection.status === "open")); + return Boolean(connections?.some((connection) => connection.status === "open")); } } diff --git a/packages/beacon-node/src/network/peers/peerManager.ts b/packages/beacon-node/src/network/peers/peerManager.ts index b076285b0d21..b8742789d4fb 100644 --- a/packages/beacon-node/src/network/peers/peerManager.ts +++ b/packages/beacon-node/src/network/peers/peerManager.ts @@ -1,4 +1,4 @@ -import {Connection, PeerId, PrivateKey} from "@libp2p/interface"; +import {Connection, PeerId} from "@libp2p/interface"; import {BitArray} from "@chainsafe/ssz"; import {SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {BeaconConfig} from "@lodestar/config"; @@ -94,7 +94,6 @@ export interface IReqRespBeaconNodePeerManager { } export type PeerManagerModules = { - privateKey: PrivateKey; libp2p: Libp2p; logger: LoggerNode; metrics: NetworkCoreMetrics | null; @@ -689,7 +688,7 @@ export class PeerManager { } for (const connections of getConnectionsMap(this.libp2p).values()) { - const openCnx = connections.value.find((cnx) => cnx.status === "open"); + const openCnx = connections.find((cnx) => cnx.status === "open"); if (openCnx) { const direction = openCnx.direction; peersByDirection.set(direction, 1 + (peersByDirection.get(direction) ?? 0)); diff --git a/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts b/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts index d001c0d8892a..8542df605b06 100644 --- a/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts +++ b/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts @@ -8,7 +8,7 @@ import {getConnectionsMap} from "../../util.js"; export function getConnectedPeerIds(libp2p: Libp2p): PeerId[] { const peerIds: PeerId[] = []; for (const connections of getConnectionsMap(libp2p).values()) { - const openConnection = connections.value.find(isConnectionOpen); + const openConnection = connections.find(isConnectionOpen); if (openConnection) { peerIds.push(openConnection.remotePeer); } @@ -21,7 +21,7 @@ export function getConnectedPeerIds(libp2p: Libp2p): PeerId[] { */ export function hasSomeConnectedPeer(libp2p: Libp2p): boolean { for (const connections of getConnectionsMap(libp2p).values()) { - if (connections.value.some(isConnectionOpen)) { + if (connections.some(isConnectionOpen)) { return true; } } diff --git a/packages/beacon-node/src/network/util.ts b/packages/beacon-node/src/network/util.ts index f1d6b917b5e4..13eb13331f74 100644 --- a/packages/beacon-node/src/network/util.ts +++ b/packages/beacon-node/src/network/util.ts @@ -14,13 +14,13 @@ export function prettyPrintPeerIdStr(id: PeerIdStr): string { * Get the connections map from a connection manager */ // Compat function for efficiency reasons -export function getConnectionsMap(libp2p: Libp2p): Map { +export function getConnectionsMap(libp2p: Libp2p): Map { // biome-ignore lint/complexity/useLiteralKeys: `map` is a private attribute return libp2p.services.components.connectionManager.getConnectionsMap()["map"]; } export function getConnection(libp2p: Libp2p, peerIdStr: string): Connection | undefined { - return getConnectionsMap(libp2p).get(peerIdStr)?.value[0] ?? undefined; + return getConnectionsMap(libp2p).get(peerIdStr)?.[0] ?? undefined; } // https://github.com/ChainSafe/js-libp2p-gossipsub/blob/3475242ed254f7647798ab7f36b21909f6cb61da/src/index.ts#L2009 diff --git a/packages/beacon-node/src/node/nodejs.ts b/packages/beacon-node/src/node/nodejs.ts index 0e51b15e514b..701ab0fde070 100644 --- a/packages/beacon-node/src/node/nodejs.ts +++ b/packages/beacon-node/src/node/nodejs.ts @@ -1,7 +1,7 @@ import {setMaxListeners} from "node:events"; import {Registry} from "prom-client"; -import {PrivateKey} from "@libp2p/interface"; +import {PeerId} from "@libp2p/interface"; import {BeaconConfig} from "@lodestar/config"; import {phase0} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; @@ -49,7 +49,7 @@ export type BeaconNodeInitModules = { db: IBeaconDb; logger: LoggerNode; processShutdownCallback: ProcessShutdownCallback; - privateKey: PrivateKey; + peerId: PeerId; peerStoreDir?: string; anchorState: BeaconStateAllForks; wsCheckpoint?: phase0.Checkpoint; @@ -146,7 +146,7 @@ export class BeaconNode { db, logger, processShutdownCallback, - privateKey, + peerId, peerStoreDir, anchorState, wsCheckpoint, @@ -243,7 +243,7 @@ export class BeaconNode { metrics, chain, db, - privateKey, + peerId, peerStoreDir, getReqRespHandler: getReqRespHandlers({db, chain}), }); diff --git a/packages/beacon-node/src/util/peerId.ts b/packages/beacon-node/src/util/peerId.ts index c62f5416cdfe..2afb9bed390e 100644 --- a/packages/beacon-node/src/util/peerId.ts +++ b/packages/beacon-node/src/util/peerId.ts @@ -12,5 +12,5 @@ export type PeerIdStr = string; export {peerIdFromString}; export function peerIdToString(peerId: PeerId): string { - return base58btc.encode(peerId.toMultihash().bytes).slice(1); + return base58btc.encode(peerId.multihash.bytes).slice(1); } diff --git a/packages/beacon-node/test/e2e/network/mdns.test.ts b/packages/beacon-node/test/e2e/network/mdns.test.ts index 6a1be8094137..f8b55d8afae7 100644 --- a/packages/beacon-node/test/e2e/network/mdns.test.ts +++ b/packages/beacon-node/test/e2e/network/mdns.test.ts @@ -1,8 +1,8 @@ import {describe, it, afterEach, beforeEach, expect, vi} from "vitest"; -import {PrivateKey} from "@libp2p/interface"; +import {PeerId} from "@libp2p/interface"; import {multiaddr} from "@multiformats/multiaddr"; +import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {SignableENR} from "@chainsafe/enr"; -import {generateKeyPair} from "@libp2p/crypto/keys"; import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; @@ -35,9 +35,9 @@ describe.skip("mdns", () => { controller.abort(); }); - async function getOpts(privateKey: PrivateKey): Promise { + async function getOpts(peerId: PeerId): Promise { const bindAddrUdp = `/ip4/0.0.0.0/udp/${port++}`; - const enr = SignableENR.createFromPrivateKey(privateKey); + const enr = SignableENR.createFromPeerId(peerId); enr.setLocationMultiaddr(multiaddr(bindAddrUdp)); return { @@ -81,12 +81,12 @@ describe.skip("mdns", () => { const db = getMockedBeaconDb(); const gossipHandlers = {} as GossipHandlers; - const privateKey = await generateKeyPair("secp256k1"); + const peerId = await createSecp256k1PeerId(); const logger = testLogger(nodeName); - const opts = await getOpts(privateKey); + const opts = await getOpts(peerId); - const modules: Omit = { + const modules: Omit = { config, chain, db, @@ -97,7 +97,7 @@ describe.skip("mdns", () => { const network = await Network.init({ ...modules, - ...(await createNetworkModules(mu, privateKey, {...opts, mdns: true})), + ...(await createNetworkModules(mu, peerId, {...opts, mdns: true})), logger, }); diff --git a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts index b46e151cadb3..d0b94399c01d 100644 --- a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts +++ b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts @@ -1,7 +1,7 @@ import {describe, it, afterEach, expect, vi} from "vitest"; import {Connection} from "@libp2p/interface"; +import {CustomEvent} from "@libp2p/interface"; import {BitArray} from "@chainsafe/ssz"; -import {generateKeyPair} from "@libp2p/crypto/keys"; import {config} from "@lodestar/config/default"; import {altair, phase0, ssz} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; @@ -47,8 +47,7 @@ describe("network / peers / PeerManager", () => { const clock = new Clock({config: beaconConfig, genesisTime: 0, signal: controller.signal}); const status = ssz.phase0.Status.defaultValue(); const statusCache = new LocalStatusCache(status); - const privateKey = await generateKeyPair("secp256k1"); - const libp2p = await createNode("/ip4/127.0.0.1/tcp/0", privateKey); + const libp2p = await createNode("/ip4/127.0.0.1/tcp/0"); afterEachCallbacks.push(async () => { controller.abort(); @@ -69,7 +68,6 @@ describe("network / peers / PeerManager", () => { const peerManager = new PeerManager( { - privateKey, libp2p, reqResp, logger, @@ -160,7 +158,7 @@ describe("network / peers / PeerManager", () => { const {statusCache, libp2p, networkEventBus} = await mockModules(); // Simualate a peer connection, get() should return truthy - getConnectionsMap(libp2p).set(peerId1.toString(), {key: peerId1, value: [libp2pConnectionOutboud]}); + getConnectionsMap(libp2p).set(peerId1.toString(), [libp2pConnectionOutboud]); // Subscribe to `peerConnected` event, which must fire after checking peer relevance const peerConnectedPromise = waitForEvent(networkEventBus, NetworkEvent.peerConnected, 2000); @@ -179,7 +177,7 @@ describe("network / peers / PeerManager", () => { const {statusCache, libp2p, reqResp, peerManager, networkEventBus} = await mockModules(); // Simualate a peer connection, get() should return truthy - getConnectionsMap(libp2p).set(peerId1.toString(), {key: peerId1, value: [libp2pConnectionOutboud]}); + getConnectionsMap(libp2p).set(peerId1.toString(), [libp2pConnectionOutboud]); // Subscribe to `peerConnected` event, which must fire after checking peer relevance const peerConnectedPromise = waitForEvent(networkEventBus, NetworkEvent.peerConnected, 2000); @@ -192,7 +190,7 @@ describe("network / peers / PeerManager", () => { reqResp.sendMetadata.mockResolvedValue(remoteMetadata); // Simualate a peer connection, get() should return truthy - getConnectionsMap(libp2p).set(peerId1.toString(), {key: peerId1, value: [libp2pConnectionOutboud]}); + getConnectionsMap(libp2p).set(peerId1.toString(), [libp2pConnectionOutboud]); libp2p.services.components.events.dispatchEvent( new CustomEvent("connection:open", {detail: libp2pConnectionOutboud}) ); diff --git a/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts b/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts index eb994d2e848c..ae916bdd0ab7 100644 --- a/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts +++ b/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts @@ -40,7 +40,7 @@ describe("reqresp encoder", () => { const libp2p = await createLibp2p({ transports: [tcp()], streamMuxers: [mplex()], - connectionEncrypters: [noise()], + connectionEncryption: [noise()], addresses: { listen: [listen], }, diff --git a/packages/beacon-node/test/perf/network/noise/sendData.test.ts b/packages/beacon-node/test/perf/network/noise/sendData.test.ts index 49e37980a598..35538a417adf 100644 --- a/packages/beacon-node/test/perf/network/noise/sendData.test.ts +++ b/packages/beacon-node/test/perf/network/noise/sendData.test.ts @@ -1,12 +1,11 @@ import {itBench} from "@dapplion/benchmark"; import {duplexPair} from "it-pair/duplex"; +import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {pipe} from "it-pipe"; import drain from "it-drain"; import {defaultLogger} from "@libp2p/logger"; import {noise} from "@chainsafe/libp2p-noise"; import {Uint8ArrayList} from "uint8arraylist"; -import {generateKeyPair} from "@libp2p/crypto/keys"; -import {peerIdFromPrivateKey} from "@libp2p/peer-id"; describe("network / noise / sendData", () => { const numberOfMessages = 1000; @@ -25,17 +24,15 @@ describe("network / noise / sendData", () => { itBench({ id: `send data - ${numberOfMessages} ${messageLength}B messages`, beforeEach: async () => { - const privateKeyA = await generateKeyPair("secp256k1"); - const privateKeyB = await generateKeyPair("secp256k1"); - const peerA = peerIdFromPrivateKey(privateKeyA); - const peerB = peerIdFromPrivateKey(privateKeyB); - const noiseA = noise()({logger: defaultLogger(), privateKey: privateKeyA, peerId: peerA}); - const noiseB = noise()({logger: defaultLogger(), privateKey: privateKeyB, peerId: peerB}); + const peerA = await createSecp256k1PeerId(); + const peerB = await createSecp256k1PeerId(); + const noiseA = noise()({logger: defaultLogger()}); + const noiseB = noise()({logger: defaultLogger()}); const [inboundConnection, outboundConnection] = duplexPair(); const [outbound, inbound] = await Promise.all([ - noiseA.secureOutbound(outboundConnection, {remotePeer: peerB}), - noiseB.secureInbound(inboundConnection, {remotePeer: peerA}), + noiseA.secureOutbound(peerA, outboundConnection, peerB), + noiseB.secureInbound(peerB, inboundConnection, peerA), ]); return {connA: outbound.conn, connB: inbound.conn, data: new Uint8Array(messageLength)}; diff --git a/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts b/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts index 18dca2c670cd..d5a6b4e9cb25 100644 --- a/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts +++ b/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts @@ -1,7 +1,6 @@ import {itBench} from "@dapplion/benchmark"; import {PeerId} from "@libp2p/interface"; -import {generateKeyPair} from "@libp2p/crypto/keys"; -import {peerIdFromPrivateKey} from "@libp2p/peer-id"; +import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {altair, phase0} from "@lodestar/types"; import {defaultNetworkOptions} from "../../../../../src/network/options.js"; @@ -13,8 +12,7 @@ describe("prioritizePeers", () => { before(async () => { for (let i = 0; i < defaultNetworkOptions.maxPeers; i++) { - const pk = await generateKeyPair("secp256k1"); - const peer = peerIdFromPrivateKey(pk); + const peer = await createSecp256k1PeerId(); peer.toString = () => `peer-${i}`; seedPeers.push({ id: peer, diff --git a/packages/beacon-node/test/unit/network/peers/priorization.test.ts b/packages/beacon-node/test/unit/network/peers/priorization.test.ts index e72cc32ce28c..26f8d8c9e535 100644 --- a/packages/beacon-node/test/unit/network/peers/priorization.test.ts +++ b/packages/beacon-node/test/unit/network/peers/priorization.test.ts @@ -1,8 +1,7 @@ import {PeerId} from "@libp2p/interface"; +import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {BitArray} from "@chainsafe/ssz"; import {describe, it, expect} from "vitest"; -import {generateKeyPair} from "@libp2p/crypto/keys"; -import {peerIdFromPrivateKey} from "@libp2p/peer-id"; import {ATTESTATION_SUBNET_COUNT} from "@lodestar/params"; import { ExcessPeerDisconnectReason, @@ -18,8 +17,7 @@ type Result = ReturnType; describe("network / peers / priorization", async () => { const peers: PeerId[] = []; for (let i = 0; i < 8; i++) { - const pk = await generateKeyPair("secp256k1"); - const peer = peerIdFromPrivateKey(pk); + const peer = await createSecp256k1PeerId(); peer.toString = () => `peer-${i}`; peers.push(peer); } @@ -268,8 +266,7 @@ describe("network / peers / priorization", async () => { describe("sortPeersToPrune", async () => { const peers: PeerId[] = []; for (let i = 0; i < 8; i++) { - const pk = await generateKeyPair("secp256k1"); - const peer = peerIdFromPrivateKey(pk); + const peer = await createSecp256k1PeerId(); peer.toString = () => `peer-${i}`; peers.push(peer); } diff --git a/packages/beacon-node/test/utils/network.ts b/packages/beacon-node/test/utils/network.ts index 71bb0bd255da..56c831b269f5 100644 --- a/packages/beacon-node/test/utils/network.ts +++ b/packages/beacon-node/test/utils/network.ts @@ -1,6 +1,6 @@ import {BitArray} from "@chainsafe/ssz"; -import {PrivateKey} from "@libp2p/interface"; -import {generateKeyPair} from "@libp2p/crypto/keys"; +import {PeerId} from "@libp2p/interface"; +import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {INetwork, Network, NetworkEvent} from "../../src/network/index.js"; import {Libp2p} from "../../src/network/interface.js"; @@ -8,17 +8,18 @@ import {createNodeJsLibp2p} from "../../src/network/libp2p/index.js"; import {NetworkOptions, defaultNetworkOptions} from "../../src/network/options.js"; import {PeerIdStr} from "../../src/util/peerId.js"; -export async function createNode(multiaddr: string, privateKey?: PrivateKey): Promise { - return createNodeJsLibp2p(privateKey ?? (await generateKeyPair("secp256k1")), {localMultiaddrs: [multiaddr]}); +export async function createNode(multiaddr: string, inPeerId?: PeerId): Promise { + const peerId = inPeerId || (await createSecp256k1PeerId()); + return createNodeJsLibp2p(peerId, {localMultiaddrs: [multiaddr]}); } export async function createNetworkModules( multiaddr: string, - privateKey?: PrivateKey, + peerId?: PeerId, opts?: Partial -): Promise<{opts: NetworkOptions; privateKey: PrivateKey}> { +): Promise<{opts: NetworkOptions; peerId: PeerId}> { return { - privateKey: privateKey ?? (await generateKeyPair("secp256k1")), + peerId: peerId ?? (await createSecp256k1PeerId()), opts: {...defaultNetworkOptions, ...opts, localMultiaddrs: [multiaddr]}, }; } diff --git a/packages/beacon-node/test/utils/networkWithMockDb.ts b/packages/beacon-node/test/utils/networkWithMockDb.ts index 84c3821bb22c..689d332ebbce 100644 --- a/packages/beacon-node/test/utils/networkWithMockDb.ts +++ b/packages/beacon-node/test/utils/networkWithMockDb.ts @@ -1,4 +1,4 @@ -import {generateKeyPair} from "@libp2p/crypto/keys"; +import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {ChainForkConfig, createBeaconConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; import {BeaconChain} from "../../src/chain/chain.js"; @@ -72,7 +72,7 @@ export async function getNetworkForTest( } ); - const modules: Omit = { + const modules: Omit = { config: beaconConfig, chain, db, @@ -83,7 +83,7 @@ export async function getNetworkForTest( const network = await Network.init({ ...modules, - privateKey: await generateKeyPair("secp256k1"), + peerId: await createSecp256k1PeerId(), opts: { ...defaultNetworkOptions, maxPeers: 1, diff --git a/packages/beacon-node/test/utils/node/beacon.ts b/packages/beacon-node/test/utils/node/beacon.ts index 746c2cde5fd4..0163fa148102 100644 --- a/packages/beacon-node/test/utils/node/beacon.ts +++ b/packages/beacon-node/test/utils/node/beacon.ts @@ -1,7 +1,7 @@ import deepmerge from "deepmerge"; import tmp from "tmp"; -import {PrivateKey} from "@libp2p/interface"; -import {generateKeyPair} from "@libp2p/crypto/keys"; +import {PeerId} from "@libp2p/interface"; +import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {config as minimalConfig} from "@lodestar/config/default"; import {createBeaconConfig, createChainForkConfig, ChainConfig} from "@lodestar/config"; import {RecursivePartial} from "@lodestar/utils"; @@ -26,16 +26,16 @@ export async function getDevBeaconNode( options?: RecursivePartial; validatorCount?: number; logger?: LoggerNode; - privateKey?: PrivateKey; + peerId?: PeerId; peerStoreDir?: string; anchorState?: BeaconStateAllForks; wsCheckpoint?: phase0.Checkpoint; } & InteropStateOpts ): Promise { const {params, validatorCount = 8, peerStoreDir} = opts; - let {options = {}, logger, privateKey} = opts; + let {options = {}, logger, peerId} = opts; - if (!privateKey) privateKey = await generateKeyPair("secp256k1"); + if (!peerId) peerId = await createSecp256k1PeerId(); const tmpDir = tmp.dirSync({unsafeCleanup: true}); const config = createChainForkConfig({...minimalConfig, ...params}); logger = logger ?? testLogger(); @@ -93,7 +93,7 @@ export async function getDevBeaconNode( db, logger, processShutdownCallback: () => {}, - privateKey, + peerId, peerStoreDir, anchorState, wsCheckpoint: opts.wsCheckpoint, diff --git a/packages/beacon-node/test/utils/peer.ts b/packages/beacon-node/test/utils/peer.ts index aeec92bf994e..8bd5c6c67be8 100644 --- a/packages/beacon-node/test/utils/peer.ts +++ b/packages/beacon-node/test/utils/peer.ts @@ -1,6 +1,6 @@ import {PeerId} from "@libp2p/interface"; -import {peerIdFromPrivateKey, peerIdFromPublicKey} from "@libp2p/peer-id"; -import {generateKeyPair, publicKeyFromProtobuf} from "@libp2p/crypto/keys"; +import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; +import {peerIdFromBytes} from "@libp2p/peer-id"; import {peerIdToString} from "../../src/util/peerId.js"; /** @@ -9,11 +9,11 @@ import {peerIdToString} from "../../src/util/peerId.js"; */ export function getValidPeerId(): PeerId { const id = Buffer.from("002508021221039481269fe831799b1a0f1d521c1395b4831514859e4559c44d155eae46f03819", "hex"); - return peerIdFromPublicKey(publicKeyFromProtobuf(id)); + return peerIdFromBytes(id); } export async function getRandPeerIdStr(): Promise { - return peerIdToString(peerIdFromPrivateKey(await generateKeyPair("secp256k1"))); + return peerIdToString(await createSecp256k1PeerId()); } export const validPeerIdStr = peerIdToString(getValidPeerId()); diff --git a/packages/cli/package.json b/packages/cli/package.json index e1c14f6cd9c3..3634ccd84424 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -54,14 +54,14 @@ "@chainsafe/bls-keygen": "^0.4.0", "@chainsafe/bls-keystore": "^3.1.0", "@chainsafe/blst": "^2.1.0", - "@chainsafe/discv5": "^10.0.1", - "@chainsafe/enr": "^4.0.1", + "@chainsafe/discv5": "^9.0.0", + "@chainsafe/enr": "^3.0.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/ssz": "^0.18.0", "@chainsafe/threads": "^1.11.1", - "@libp2p/crypto": "^5.0.4", - "@libp2p/interface": "^2.1.2", - "@libp2p/peer-id": "^5.0.4", + "@libp2p/crypto": "^4.1.0", + "@libp2p/peer-id": "^4.1.0", + "@libp2p/peer-id-factory": "^4.1.0", "@lodestar/api": "^1.22.0", "@lodestar/beacon-node": "^1.22.0", "@lodestar/config": "^1.22.0", diff --git a/packages/cli/src/cmds/beacon/handler.ts b/packages/cli/src/cmds/beacon/handler.ts index 2a0238fede20..ea424e04824a 100644 --- a/packages/cli/src/cmds/beacon/handler.ts +++ b/packages/cli/src/cmds/beacon/handler.ts @@ -24,7 +24,7 @@ import {LogArgs} from "../../options/logOptions.js"; import {BeaconArgs} from "./options.js"; import {getBeaconPaths} from "./paths.js"; import {initBeaconState} from "./initBeaconState.js"; -import {initPrivateKeyAndEnr} from "./initPeerIdAndEnr.js"; +import {initPeerIdAndEnr} from "./initPeerIdAndEnr.js"; const DEFAULT_RETENTION_SSZ_OBJECTS_HOURS = 15 * 24; const HOURS_TO_MS = 3600 * 1000; @@ -34,7 +34,7 @@ const EIGHT_GB = 8 * 1024 * 1024 * 1024; * Runs a beacon node. */ export async function beaconHandler(args: BeaconArgs & GlobalArgs): Promise { - const {config, options, beaconPaths, network, version, commit, privateKey, logger} = await beaconHandlerInit(args); + const {config, options, beaconPaths, network, version, commit, peerId, logger} = await beaconHandlerInit(args); const heapSizeLimit = getHeapStatistics().heap_size_limit; if (heapSizeLimit < EIGHT_GB) { @@ -80,7 +80,7 @@ export async function beaconHandler(args: BeaconArgs & GlobalArgs): Promise { +): Promise<{peerId: PeerId; enr: SignableENR}> { const {persistNetworkIdentity} = args; - const newPrivateKeyAndENR = async (): Promise<{privateKey: PrivateKey; enr: SignableENR}> => { - const privateKey = await generateKeyPair("secp256k1"); - const enr = SignableENR.createFromPrivateKey(privateKey); - return {privateKey, enr}; + const newPeerIdAndENR = async (): Promise<{peerId: PeerId; enr: SignableENR}> => { + const peerId = await createSecp256k1PeerId(); + const enr = SignableENR.createV4(createPrivateKeyFromPeerId(peerId).privateKey); + return {peerId, enr}; }; - const readPersistedPrivateKeyAndENR = async ( + const readPersistedPeerIdAndENR = async ( peerIdFile: string, enrFile: string - ): Promise<{privateKey: PrivateKey; enr: SignableENR; newEnr: boolean}> => { - let privateKey: PrivateKey; + ): Promise<{peerId: PeerId; enr: SignableENR; newEnr: boolean}> => { + let peerId: PeerId; let enr: SignableENR; // attempt to read stored peer id try { - privateKey = readPrivateKey(peerIdFile); + peerId = await readPeerId(peerIdFile); } catch (_e) { logger.warn("Unable to read peerIdFile, creating a new peer id"); - return {...(await newPrivateKeyAndENR()), newEnr: true}; + return {...(await newPeerIdAndENR()), newEnr: true}; } // attempt to read stored enr try { - enr = SignableENR.decodeTxt(fs.readFileSync(enrFile, "utf-8"), privateKey.raw); + enr = SignableENR.decodeTxt(fs.readFileSync(enrFile, "utf-8"), createPrivateKeyFromPeerId(peerId).privateKey); } catch (_e) { logger.warn("Unable to decode stored local ENR, creating a new ENR"); - enr = SignableENR.createFromPrivateKey(privateKey); - return {privateKey, enr, newEnr: true}; + enr = SignableENR.createV4(createPrivateKeyFromPeerId(peerId).privateKey); + return {peerId, enr, newEnr: true}; } // check stored peer id against stored enr - if (!privateKey.equals(enr.peerId)) { + if (!peerId.equals(await enr.peerId())) { logger.warn("Stored local ENR doesn't match peerIdFile, creating a new ENR"); - enr = SignableENR.createFromPrivateKey(privateKey); - return {privateKey, enr, newEnr: true}; + enr = SignableENR.createV4(createPrivateKeyFromPeerId(peerId).privateKey); + return {peerId, enr, newEnr: true}; } - return {privateKey, enr, newEnr: false}; + return {peerId, enr, newEnr: false}; }; if (persistNetworkIdentity) { const enrFile = path.join(beaconDir, "enr"); const peerIdFile = path.join(beaconDir, "peer-id.json"); - const {privateKey, enr, newEnr} = await readPersistedPrivateKeyAndENR(peerIdFile, enrFile); + const {peerId, enr, newEnr} = await readPersistedPeerIdAndENR(peerIdFile, enrFile); overwriteEnrWithCliArgs(enr, args, logger, {newEnr, bootnode}); // Re-persist peer-id and enr - writeFile600Perm(peerIdFile, exportToJSON(privateKey)); + writeFile600Perm(peerIdFile, exportToJSON(peerId)); writeFile600Perm(enrFile, enr.encodeTxt()); - return {privateKey, enr}; + return {peerId, enr}; } - const {privateKey, enr} = await newPrivateKeyAndENR(); + const {peerId, enr} = await newPeerIdAndENR(); overwriteEnrWithCliArgs(enr, args, logger, {newEnr: true, bootnode}); - return {privateKey, enr}; + return {peerId, enr}; } diff --git a/packages/cli/src/cmds/bootnode/handler.ts b/packages/cli/src/cmds/bootnode/handler.ts index 9c093eed1272..8a262d8f12b7 100644 --- a/packages/cli/src/cmds/bootnode/handler.ts +++ b/packages/cli/src/cmds/bootnode/handler.ts @@ -10,7 +10,7 @@ import {getBeaconConfigFromArgs} from "../../config/index.js"; import {getNetworkBootnodes, isKnownNetworkName, readBootnodes} from "../../networks/index.js"; import {onGracefulShutdown, mkdir, writeFile600Perm} from "../../util/index.js"; import {getVersionData} from "../../util/version.js"; -import {initPrivateKeyAndEnr} from "../beacon/initPeerIdAndEnr.js"; +import {initPeerIdAndEnr} from "../beacon/initPeerIdAndEnr.js"; import {parseArgs as parseMetricsArgs} from "../../options/beaconNodeOptions/metrics.js"; import {parseArgs as parseNetworkArgs} from "../../options/beaconNodeOptions/network.js"; import {getBeaconPaths} from "../beacon/paths.js"; @@ -22,7 +22,7 @@ import {BootnodeArgs} from "./options.js"; * Runs a bootnode. */ export async function bootnodeHandler(args: BootnodeArgs & GlobalArgs): Promise { - const {discv5Args, metricsArgs, bootnodeDir, network, version, commit, privateKey, enr, logger} = + const {discv5Args, metricsArgs, bootnodeDir, network, version, commit, peerId, enr, logger} = await bootnodeHandlerInit(args); const abortController = new AbortController(); @@ -34,7 +34,7 @@ export async function bootnodeHandler(args: BootnodeArgs & GlobalArgs): Promise< ip4: enr.getLocationMultiaddr("udp4")?.toString(), ip6: enr.getLocationMultiaddr("udp6")?.toString(), }); - logger.info("Identity", {peerId: enr.peerId.toString(), nodeId: enr.nodeId}); + logger.info("Identity", {peerId: peerId.toString(), nodeId: enr.nodeId}); logger.info("ENR", {enr: enr.encodeTxt()}); // bootnode setup @@ -53,7 +53,7 @@ export async function bootnodeHandler(args: BootnodeArgs & GlobalArgs): Promise< const discv5 = Discv5.create({ enr, - privateKey, + peerId, bindAddrs: { ip4: (bindAddrs.ip4 ? multiaddr(bindAddrs.ip4) : undefined) as Multiaddr, ip6: bindAddrs.ip6 ? multiaddr(bindAddrs.ip6) : undefined, @@ -68,7 +68,7 @@ export async function bootnodeHandler(args: BootnodeArgs & GlobalArgs): Promise< logger.info("Adding bootnode", { ip4: bootEnr.getLocationMultiaddr("udp4")?.toString(), ip6: bootEnr.getLocationMultiaddr("udp6")?.toString(), - peerId: bootEnr.peerId.toString(), + peerId: (await bootEnr.peerId()).toString(), nodeId: enr.nodeId, }); discv5.addEnr(bootEnr); @@ -180,7 +180,7 @@ export async function bootnodeHandlerInit(args: BootnodeArgs & GlobalArgs) { ); const logger = initLogger(args, beaconPaths.dataDir, config, "bootnode.log"); - const {privateKey, enr} = await initPrivateKeyAndEnr(args as unknown as BeaconArgs, bootnodeDir, logger, true); + const {peerId, enr} = await initPeerIdAndEnr(args as unknown as BeaconArgs, bootnodeDir, logger, true); - return {discv5Args, metricsArgs, bootnodeDir, network, version, commit, privateKey, enr, logger}; + return {discv5Args, metricsArgs, bootnodeDir, network, version, commit, peerId, enr, logger}; } diff --git a/packages/cli/src/config/peerId.ts b/packages/cli/src/config/peerId.ts index 91390696c2f4..576a99e6980e 100644 --- a/packages/cli/src/config/peerId.ts +++ b/packages/cli/src/config/peerId.ts @@ -1,11 +1,7 @@ -import type {PrivateKey} from "@libp2p/interface"; -import {peerIdFromPrivateKey, peerIdFromString} from "@libp2p/peer-id"; -import { - privateKeyFromProtobuf, - privateKeyToProtobuf, - publicKeyFromProtobuf, - publicKeyToProtobuf, -} from "@libp2p/crypto/keys"; +import type {PeerId} from "@libp2p/interface"; +import {peerIdFromBytes} from "@libp2p/peer-id"; +import {createFromPrivKey, createFromPubKey} from "@libp2p/peer-id-factory"; +import {unmarshalPrivateKey, unmarshalPublicKey} from "@libp2p/crypto/keys"; import {fromString as uint8ArrayFromString} from "uint8arrays/from-string"; import {toString as uint8ArrayToString} from "uint8arrays/to-string"; import {writeFile600Perm, readFile} from "../util/index.js"; @@ -13,38 +9,46 @@ import {writeFile600Perm, readFile} from "../util/index.js"; // Peer id to / from JSON taken from peer-id-factory // See https://github.com/libp2p/js-libp2p-peer-id/pull/9 for more details -// after libp2p 2.0, PeerId no longer contains a private key -// but we retain a semi-backwards-compatible on-disk format -// Note: all properties are required -export type PeerIdJSON = {id: string; pubKey: string; privKey: string}; +async function createFromParts(multihash: Uint8Array, privKey?: Uint8Array, pubKey?: Uint8Array): Promise { + if (privKey != null) { + const key = await unmarshalPrivateKey(privKey); -export function exportToJSON(privateKey: PrivateKey): PeerIdJSON { - const publicKey = privateKey.publicKey; - const peerId = peerIdFromPrivateKey(privateKey); + return createFromPrivKey(key); + } + if (pubKey != null) { + const key = unmarshalPublicKey(pubKey); + + return createFromPubKey(key); + } + + return peerIdFromBytes(multihash); +} + +export type PeerIdJSON = {id: string; pubKey?: string; privKey?: string}; + +export function exportToJSON(peerId: PeerId, excludePrivateKey?: boolean): PeerIdJSON { return { - id: peerId.toString(), - pubKey: uint8ArrayToString(publicKeyToProtobuf(publicKey), "base64pad"), - privKey: uint8ArrayToString(privateKeyToProtobuf(privateKey), "base64pad"), + id: uint8ArrayToString(peerId.toBytes(), "base58btc"), + pubKey: peerId.publicKey != null ? uint8ArrayToString(peerId.publicKey, "base64pad") : undefined, + privKey: + excludePrivateKey === true || peerId.privateKey == null + ? undefined + : uint8ArrayToString(peerId.privateKey, "base64pad"), }; } -export function createFromJSON(obj: PeerIdJSON): PrivateKey { - const privateKey = privateKeyFromProtobuf(uint8ArrayFromString(obj.privKey, "base64pad")); - const publicKey = publicKeyFromProtobuf(uint8ArrayFromString(obj.pubKey, "base64pad")); - const peerId = peerIdFromString(obj.id); - if (!publicKey.equals(privateKey.publicKey)) { - throw new Error("Public key does not match private key"); - } - if (!peerId.equals(peerIdFromPrivateKey(privateKey))) { - throw new Error("Peer ID does not match private key"); - } - return privateKey; +export async function createFromJSON(obj: PeerIdJSON): Promise { + return createFromParts( + uint8ArrayFromString(obj.id, "base58btc"), + obj.privKey != null ? uint8ArrayFromString(obj.privKey, "base64pad") : undefined, + obj.pubKey != null ? uint8ArrayFromString(obj.pubKey, "base64pad") : undefined + ); } -export function writePrivateKey(filepath: string, privateKey: PrivateKey): void { - writeFile600Perm(filepath, exportToJSON(privateKey)); +export function writePeerId(filepath: string, peerId: PeerId): void { + writeFile600Perm(filepath, exportToJSON(peerId)); } -export function readPrivateKey(filepath: string): PrivateKey { +export async function readPeerId(filepath: string): Promise { return createFromJSON(readFile(filepath)); } diff --git a/packages/cli/test/unit/cmds/beacon.test.ts b/packages/cli/test/unit/cmds/beacon.test.ts index 74cde026b1ad..6e7b7f389a29 100644 --- a/packages/cli/test/unit/cmds/beacon.test.ts +++ b/packages/cli/test/unit/cmds/beacon.test.ts @@ -1,16 +1,15 @@ import path from "node:path"; import fs from "node:fs"; import {describe, it, expect} from "vitest"; +import {createFromJSON, createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {multiaddr} from "@multiformats/multiaddr"; -import {ENR, SignableENR} from "@chainsafe/enr"; -import {generateKeyPair} from "@libp2p/crypto/keys"; -import {peerIdFromPrivateKey} from "@libp2p/peer-id"; +import {createPrivateKeyFromPeerId, ENR, SignableENR} from "@chainsafe/enr"; import {chainConfig} from "@lodestar/config/default"; import {chainConfigToJson} from "@lodestar/config"; import {LogLevel} from "@lodestar/utils"; -import {createFromJSON, exportToJSON} from "../../../src/config/peerId.js"; +import {exportToJSON} from "../../../src/config/peerId.js"; import {beaconHandlerInit} from "../../../src/cmds/beacon/handler.js"; -import {initPrivateKeyAndEnr, isLocalMultiAddr} from "../../../src/cmds/beacon/initPeerIdAndEnr.js"; +import {initPeerIdAndEnr, isLocalMultiAddr} from "../../../src/cmds/beacon/initPeerIdAndEnr.js"; import {BeaconArgs} from "../../../src/cmds/beacon/options.js"; import {GlobalArgs} from "../../../src/options/globalOptions.js"; import {testFilesDir, testLogger} from "../../utils.js"; @@ -56,26 +55,26 @@ describe("cmds / beacon / args handler", () => { }); it("Create different PeerId every run", async () => { - const {privateKey: pk1} = await runBeaconHandlerInit({}); - const {privateKey: pk2} = await runBeaconHandlerInit({}); + const {peerId: peerId1} = await runBeaconHandlerInit({}); + const {peerId: peerId2} = await runBeaconHandlerInit({}); - expect(pk1.equals(pk2)).toBe(false); + expect(peerId1.toString()).not.toBe(peerId2.toString()); }); it("Re-use existing peer", async () => { - const prevPk = await generateKeyPair("secp256k1"); + const prevPeerId = await createSecp256k1PeerId(); const peerIdFile = path.join(testFilesDir, "peer-id.json"); - fs.writeFileSync(peerIdFile, JSON.stringify(exportToJSON(prevPk))); - const enr = SignableENR.createFromPrivateKey(prevPk); + fs.writeFileSync(peerIdFile, JSON.stringify(exportToJSON(prevPeerId))); + const enr = SignableENR.createV4(createPrivateKeyFromPeerId(prevPeerId).privateKey); const enrFilePath = path.join(testFilesDir, "enr"); fs.writeFileSync(enrFilePath, enr.encodeTxt()); - const {privateKey} = await runBeaconHandlerInit({ + const {peerId} = await runBeaconHandlerInit({ persistNetworkIdentity: true, }); - expect(privateKey.equals(prevPk)).toBe(true); + expect(peerId.toString()).toBe(prevPeerId.toString()); }); it("Set known deposit contract", async () => { @@ -118,48 +117,48 @@ describe("Test isLocalMultiAddr", () => { describe("initPeerIdAndEnr", () => { it("should not reuse peer id, persistNetworkIdentity=false", async () => { - const {privateKey: pk1} = await initPrivateKeyAndEnr( + const {peerId: peerId1} = await initPeerIdAndEnr( {persistNetworkIdentity: false} as BeaconArgs, testFilesDir, testLogger() ); - const {privateKey: pk2} = await initPrivateKeyAndEnr( + const {peerId: peerId2} = await initPeerIdAndEnr( {persistNetworkIdentity: false} as BeaconArgs, testFilesDir, testLogger() ); - expect(pk1.equals(pk2)).toBe(false); + expect(peerId1.toString()).not.toBe(peerId2.toString()); }); it("should reuse peer id, persistNetworkIdentity=true", async () => { - const {privateKey: pk1} = await initPrivateKeyAndEnr( + const {peerId: peerId1} = await initPeerIdAndEnr( {persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger() ); - const {privateKey: pk2} = await initPrivateKeyAndEnr( + const {peerId: peerId2} = await initPeerIdAndEnr( {persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger() ); - expect(pk1.equals(pk2)).toBe(true); + expect(peerId1.toString()).toBe(peerId2.toString()); }); it("should overwrite invalid peer id", async () => { const peerIdFile = path.join(testFilesDir, "peer-id.json"); - const pk1Str = "wrong peer id file content"; - fs.writeFileSync(peerIdFile, pk1Str); - const {privateKey: pk2} = await initPrivateKeyAndEnr( + const peerId1Str = "wrong peer id file content"; + fs.writeFileSync(peerIdFile, peerId1Str); + const {peerId: peerId2} = await initPeerIdAndEnr( {persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger() ); - const filePk = createFromJSON(JSON.parse(fs.readFileSync(peerIdFile, "utf-8"))); + const filePeerId = await createFromJSON(JSON.parse(fs.readFileSync(peerIdFile, "utf-8"))); - expect(pk1Str).not.toBe(peerIdFromPrivateKey(pk2).toString()); - expect(filePk.equals(pk2)).toBe(true); + expect(peerId1Str).not.toBe(peerId2.toString()); + expect(filePeerId.toString()).toBe(peerId2.toString()); }); it("should overwrite invalid enr", async () => { @@ -167,7 +166,7 @@ describe("initPeerIdAndEnr", () => { const invalidEnr = "wrong enr file content"; fs.writeFileSync(enrFilePath, invalidEnr); - await initPrivateKeyAndEnr({persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger()); + await initPeerIdAndEnr({persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger()); const validEnr = fs.readFileSync(enrFilePath, "utf-8"); @@ -175,13 +174,13 @@ describe("initPeerIdAndEnr", () => { }); it("should overwrite enr that doesn't match peer id", async () => { - const otherPk = await generateKeyPair("secp256k1"); - const otherEnr = SignableENR.createFromPrivateKey(otherPk); + const otherPeerId = await createSecp256k1PeerId(); + const otherEnr = SignableENR.createFromPeerId(otherPeerId); const enrFilePath = path.join(testFilesDir, "enr"); const otherEnrStr = otherEnr.encodeTxt(); fs.writeFileSync(enrFilePath, otherEnrStr); - const {enr} = await initPrivateKeyAndEnr({persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger()); + const {enr} = await initPeerIdAndEnr({persistNetworkIdentity: true} as BeaconArgs, testFilesDir, testLogger()); expect(enr.nodeId).not.toBe(otherEnr); }); diff --git a/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts b/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts index 3dd9b48c298d..a207e0c0f59d 100644 --- a/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts +++ b/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts @@ -1,8 +1,7 @@ import fs from "node:fs"; import {describe, it, expect, beforeEach, afterEach} from "vitest"; import tmp from "tmp"; -import {peerIdFromPrivateKey} from "@libp2p/peer-id"; -import {initPrivateKeyAndEnr} from "../../../src/cmds/beacon/initPeerIdAndEnr.js"; +import {initPeerIdAndEnr} from "../../../src/cmds/beacon/initPeerIdAndEnr.js"; import {BeaconArgs} from "../../../src/cmds/beacon/options.js"; import {testLogger} from "../../utils.js"; @@ -18,35 +17,35 @@ describe("initPeerIdAndEnr", () => { }); it("first time should create a new enr and peer id", async () => { - const {enr, privateKey} = await initPrivateKeyAndEnr( + const {enr, peerId} = await initPeerIdAndEnr( {persistNetworkIdentity: true} as unknown as BeaconArgs, tmpDir.name, testLogger(), true ); // "enr peer id doesn't equal the returned peer id" - expect(enr.peerId.toString()).toBe(peerIdFromPrivateKey(privateKey).toString()); + expect((await enr.peerId()).toString()).toBe(peerId.toString()); expect(enr.seq).toBe(BigInt(1)); expect(enr.tcp).toBeUndefined(); expect(enr.tcp6).toBeUndefined(); }); it("second time should use ths existing enr and peer id", async () => { - const run1 = await initPrivateKeyAndEnr( + const run1 = await initPeerIdAndEnr( {persistNetworkIdentity: true} as unknown as BeaconArgs, tmpDir.name, testLogger(), true ); - const run2 = await initPrivateKeyAndEnr( + const run2 = await initPeerIdAndEnr( {persistNetworkIdentity: true} as unknown as BeaconArgs, tmpDir.name, testLogger(), true ); - expect(run1.privateKey.equals(run2.privateKey)).toBe(true); + expect(run1.peerId.toString()).toBe(run2.peerId.toString()); expect(run1.enr.encodeTxt()).toBe(run2.enr.encodeTxt()); }); }); diff --git a/packages/cli/test/unit/config/peerId.test.ts b/packages/cli/test/unit/config/peerId.test.ts index 120a5e931749..c0cdc8cff1a9 100644 --- a/packages/cli/test/unit/config/peerId.test.ts +++ b/packages/cli/test/unit/config/peerId.test.ts @@ -1,16 +1,16 @@ import {describe, it, expect} from "vitest"; -import {generateKeyPair} from "@libp2p/crypto/keys"; +import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {getTestdirPath} from "../../utils.js"; -import {writePrivateKey, readPrivateKey} from "../../../src/config/index.js"; +import {writePeerId, readPeerId} from "../../../src/config/index.js"; describe("config / peerId", () => { const peerIdFilepath = getTestdirPath("./test-peer-id.json"); it("create, write and read PeerId", async () => { - const privateKey = await generateKeyPair("secp256k1"); - writePrivateKey(peerIdFilepath, privateKey); - const pkRead = readPrivateKey(peerIdFilepath); + const peerId = await createSecp256k1PeerId(); + writePeerId(peerIdFilepath, peerId); + const peerIdRead = await readPeerId(peerIdFilepath); - expect(pkRead.toString()).toBe(privateKey.toString()); + expect(peerIdRead.toString()).toBe(peerId.toString()); }); }); diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index d6d4fbd2b5c2..9bd9775ba2c0 100644 --- a/packages/reqresp/package.json +++ b/packages/reqresp/package.json @@ -53,7 +53,7 @@ }, "dependencies": { "@chainsafe/fast-crc32c": "^4.1.1", - "@libp2p/interface": "^2.1.2", + "@libp2p/interface": "^1.3.0", "@lodestar/config": "^1.22.0", "@lodestar/params": "^1.22.0", "@lodestar/utils": "^1.22.0", @@ -67,10 +67,10 @@ "devDependencies": { "@lodestar/logger": "^1.22.0", "@lodestar/types": "^1.22.0", - "libp2p": "2.1.7" + "libp2p": "1.4.3" }, "peerDependencies": { - "libp2p": "~2.1.7" + "libp2p": "~1.4.3" }, "keywords": [ "ethereum", diff --git a/packages/reqresp/test/utils/peer.ts b/packages/reqresp/test/utils/peer.ts index cbc21eca370f..43edaefbafdd 100644 --- a/packages/reqresp/test/utils/peer.ts +++ b/packages/reqresp/test/utils/peer.ts @@ -1,6 +1,5 @@ import {PeerId} from "@libp2p/interface"; -import {peerIdFromPublicKey} from "@libp2p/peer-id"; -import {publicKeyFromProtobuf} from "@libp2p/crypto/keys"; +import {peerIdFromBytes} from "@libp2p/peer-id"; /** * Returns a valid PeerId with opts `bits: 256, keyType: "secp256k1"` @@ -8,5 +7,5 @@ import {publicKeyFromProtobuf} from "@libp2p/crypto/keys"; */ export function getValidPeerId(): PeerId { const id = Buffer.from("002508021221039481269fe831799b1a0f1d521c1395b4831514859e4559c44d155eae46f03819", "hex"); - return peerIdFromPublicKey(publicKeyFromProtobuf(id)); + return peerIdFromBytes(id); } diff --git a/yarn.lock b/yarn.lock index 8519ed6434bf..a9cb9ebe4fdc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -456,14 +456,14 @@ "@chainsafe/blst-linux-x64-musl" "2.1.0" "@chainsafe/blst-win32-x64-msvc" "2.1.0" -"@chainsafe/discv5@^10.0.1": - version "10.0.1" - resolved "https://registry.yarnpkg.com/@chainsafe/discv5/-/discv5-10.0.1.tgz#1aefe3826b19b1f66e76c737a7a49ae7c77d7664" - integrity sha512-YpvqOMOn/sQMHU97lonvRnbtLZQW1Vqjcwtofd0hOJ6ohtxn+Ne7Cos8qCOFkhRHirGG6irHej4akh/BlBscSA== +"@chainsafe/discv5@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/discv5/-/discv5-9.0.0.tgz#05d4d9d671894b41f0fafa8f32c48ae3ed761bd1" + integrity sha512-7s23ziqsHG/KRgkX79qB/w8kuqPrY8aJaF2aRDy9cScJocJ6ZaOnXhEc8Ku1AcSyrvfGp+tY8R4rDABcxRY+Wg== dependencies: - "@chainsafe/enr" "^4.0.1" - "@libp2p/crypto" "^5.0.1" - "@libp2p/interface" "^2.0.1" + "@chainsafe/enr" "^3.0.0" + "@libp2p/crypto" "^4.0.1" + "@libp2p/interface" "^1.1.1" "@multiformats/multiaddr" "^12.1.10" bcrypto "^5.4.0" bigint-buffer "^1.1.5" @@ -472,17 +472,17 @@ rlp "^2.2.6" strict-event-emitter-types "^2.0.0" -"@chainsafe/enr@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@chainsafe/enr/-/enr-4.0.1.tgz#9c9ad8cd84aedc1242d7e7ac99d670c0f8ee3c0d" - integrity sha512-eYGZC6Wq9UNtD5AZLO21w9DctRkEAhMZ/kIa+eggT5lVRcVSI06O7PmSXOSRW6z+Td/9MQKGEDtuyYa1esWlSg== +"@chainsafe/enr@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/enr/-/enr-3.0.0.tgz#71c83d4381d703bbcd19245ce733eb7c779a30ed" + integrity sha512-D8M8sqnvOim0jWlTdr2IhLyVe0GSUgpk+QO6UaLY4pQVdW1myJP8REp7xdbv1193ULVEkJQFTJAZexTOtmu3jw== dependencies: - "@libp2p/crypto" "^5.0.1" - "@libp2p/interface" "^2.0.1" - "@libp2p/peer-id" "^5.0.1" + "@libp2p/crypto" "^4.0.1" + "@libp2p/interface" "^1.1.1" + "@libp2p/peer-id" "^4.0.4" "@multiformats/multiaddr" "^12.1.10" bigint-buffer "^1.1.5" - ethereum-cryptography "^2.2.0" + ethereum-cryptography "^2.1.3" rlp "^2.2.6" uint8-varint "^2.0.2" uint8arrays "^5.0.1" @@ -528,37 +528,54 @@ resolved "https://registry.yarnpkg.com/@chainsafe/is-ip/-/is-ip-2.0.2.tgz#7311e7403f11d8c5cfa48111f56fcecaac37c9f6" integrity sha512-ndGqEMG1W5WkGagaqOZHpPU172AGdxr+LD15sv3WIUvT5oCFUrG1Y0CW/v2Egwj4JXEvSibaIIIqImsm98y1nA== -"@chainsafe/libp2p-gossipsub@^14.1.0": - version "14.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-gossipsub/-/libp2p-gossipsub-14.1.0.tgz#0003a214c2a88b04ab7c256c70ec439717958f09" - integrity sha512-nzFBbHOoRFa/bXUSzmJaXOgHI+EttTldhLJ33yWcM0DxnWhLKychHkCDLoJO3THa1+dnzrDJoxj3N3/V0WoPVw== +"@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" "^5.0.0" - "@libp2p/interface" "^2.0.0" - "@libp2p/interface-internal" "^2.0.0" - "@libp2p/peer-id" "^5.0.0" - "@libp2p/pubsub" "^10.0.0" + "@libp2p/crypto" "^4.0.1" + "@libp2p/interface" "^1.1.2" + "@libp2p/interface-internal" "^1.0.7" + "@libp2p/peer-id" "^4.0.5" + "@libp2p/pubsub" "^9.0.8" "@multiformats/multiaddr" "^12.1.14" denque "^2.1.0" it-length-prefixed "^9.0.4" it-pipe "^3.0.1" it-pushable "^3.2.3" multiformats "^13.0.1" - protons-runtime "^5.5.0" + protons-runtime "5.4.0" uint8arraylist "^2.4.8" uint8arrays "^5.0.1" -"@chainsafe/libp2p-noise@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-noise/-/libp2p-noise-16.0.0.tgz#52bb558490065439b0026950d7d99567da5c2c96" - integrity sha512-8rqr8V1RD2/lVbfL0Bb//N8iPOFof11cUe8v8z8xJT7fUhCAbtCCSM4jbwI4HCnw0MvHLmcpmAfDCFRwcWzoeA== +"@chainsafe/libp2p-identify@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-identify/-/libp2p-identify-1.0.0.tgz#28191e619715a87c140d8b516ee85cb7d39e41e0" + integrity sha512-X+VWUC0xeCFIulE4BU5M8FmTxZ/OKzku+9/1UaX2EG1LcqQkCDrPi6CCODbE0SraqImG4aVHRbiCFWxKEfE8wQ== + dependencies: + "@libp2p/interface" "^1.1.2" + "@libp2p/interface-internal" "^1.0.7" + "@libp2p/peer-id" "^4.0.5" + "@libp2p/peer-record" "^7.0.7" + "@multiformats/multiaddr" "^12.1.10" + "@multiformats/multiaddr-matcher" "^1.1.0" + it-protobuf-stream "^1.1.1" + protons-runtime "^5.0.0" + uint8arraylist "^2.4.7" + uint8arrays "^5.0.0" + wherearewe "^2.0.1" + +"@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" "^5.0.0" - "@libp2p/interface" "^2.0.0" - "@libp2p/peer-id" "^5.0.0" - "@noble/ciphers" "^0.6.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-length-prefixed "^9.0.1" @@ -566,7 +583,7 @@ it-pair "^2.0.6" it-pipe "^3.0.1" it-stream-types "^2.0.1" - protons-runtime "^5.5.0" + protons-runtime "^5.0.0" uint8arraylist "^2.4.3" uint8arrays "^5.0.0" wherearewe "^2.0.1" @@ -1669,277 +1686,247 @@ yargs "16.2.0" yargs-parser "20.2.4" -"@libp2p/bootstrap@^11.0.4": - version "11.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/bootstrap/-/bootstrap-11.0.7.tgz#ecb14834fff03a184a3a7fd211d2ef85b3002fc6" - integrity sha512-PRDMVXf67+ASYTco6APqPy4HF03mQ8UX+BbBZcMAMpnlPsetYfWgQg3YiBe56J+PVQLs0FPsGpfLmAg7PUguQA== +"@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" "^2.1.2" - "@libp2p/interface-internal" "^2.0.7" - "@libp2p/peer-id" "^5.0.4" + "@libp2p/interface" "^1.3.0" + "@libp2p/peer-id" "^4.1.0" "@multiformats/mafmt" "^12.1.6" - "@multiformats/multiaddr" "^12.2.3" + "@multiformats/multiaddr" "^12.2.1" -"@libp2p/crypto@^5.0.0", "@libp2p/crypto@^5.0.1", "@libp2p/crypto@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@libp2p/crypto/-/crypto-5.0.4.tgz#26f24025f3dd2be959360c6b58c94ccadb04ed63" - integrity sha512-v5xsngOlDu8JP3GQDvK+2YYzTELl7/aPfXPbIzKEcy7ON2hu79t1BZMuavjPsr+WWIPNg5yKst6IJfRilzwXRQ== +"@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" "^2.1.2" + "@libp2p/interface" "^1.3.0" "@noble/curves" "^1.4.0" "@noble/hashes" "^1.4.0" asn1js "^3.0.5" multiformats "^13.1.0" protons-runtime "^5.4.0" uint8arraylist "^2.4.8" - uint8arrays "^5.1.0" - -"@libp2p/identify@^3.0.4": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/identify/-/identify-3.0.7.tgz#a7541d6775cf652314bf2209b281b402e8dedc35" - integrity sha512-4Ns/0HN9lvQAox8eaJruKXakOtikduk6kPlz+KYmFMgVE5/kRBRf7h0aK/8cyU9sQPbSZLCaJ3gBWoDrfMIu2w== - dependencies: - "@libp2p/crypto" "^5.0.4" - "@libp2p/interface" "^2.1.2" - "@libp2p/interface-internal" "^2.0.7" - "@libp2p/peer-id" "^5.0.4" - "@libp2p/peer-record" "^8.0.7" - "@libp2p/utils" "^6.1.0" - "@multiformats/multiaddr" "^12.2.3" - "@multiformats/multiaddr-matcher" "^1.2.1" - it-drain "^3.0.7" - it-parallel "^3.0.7" - it-protobuf-stream "^1.1.3" + 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.1.0" + uint8arrays "^5.0.3" wherearewe "^2.0.1" -"@libp2p/interface-internal@^2.0.0", "@libp2p/interface-internal@^2.0.7": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/interface-internal/-/interface-internal-2.0.7.tgz#ceefa71553ce5aec9be793fcc646680f7d289806" - integrity sha512-numJBYHajL7W1BuURkQ4tlZ4sUGNGI3GWkhTmL2fS+LxYS2hUVTxcemHtUZGpcJQ17GiCqq+j4GE3bkBagOb0g== - dependencies: - "@libp2p/interface" "^2.1.2" - "@libp2p/peer-collections" "^6.0.7" - "@multiformats/multiaddr" "^12.2.3" - progress-events "^1.0.0" - uint8arraylist "^2.4.8" - -"@libp2p/interface@^1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@libp2p/interface/-/interface-1.7.0.tgz#b75b6032a6b0d0d5a13e551dcf4d481a8ca9a88f" - integrity sha512-/zFyaIaIGW0aihhsH7/93vQdpWInUzFocxF11RO/029Y6h0SVjs24HHbils+DqaFDTqN+L7oNlBx2rM2MnmTjA== +"@libp2p/interface-internal@^1.0.7", "@libp2p/interface-internal@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@libp2p/interface-internal/-/interface-internal-1.1.1.tgz#ff16b4fee4a3d3e39121e26eeeab42e9257f5f49" + integrity sha512-lLPd7yysXqpb1oiPZAn57w3CQdD33C+mu6pfUuPYI5yWMgwWq8V3XE4IMG1IyHUGEYZAuGglghAH9YQNbtticw== dependencies: - "@multiformats/multiaddr" "^12.2.3" - it-pushable "^3.2.3" - it-stream-types "^2.0.1" - multiformats "^13.1.0" - progress-events "^1.0.0" + "@libp2p/interface" "^1.3.0" + "@libp2p/peer-collections" "^5.1.11" + "@multiformats/multiaddr" "^12.2.1" uint8arraylist "^2.4.8" -"@libp2p/interface@^2.0.0", "@libp2p/interface@^2.0.1", "@libp2p/interface@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@libp2p/interface/-/interface-2.1.2.tgz#7b38047a7d2d35a6a4e0f0f22fbdeeec98b85321" - integrity sha512-uD4NapC+1qGX7RmgC1aehQm3pMs1MpO1DwuhUlAo1M6CyNxfs1Ha9jhg2T+G4u4CAJM6wffZTyPGnKnrR+M8Fw== +"@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.2.3" + "@multiformats/multiaddr" "^12.2.1" it-pushable "^3.2.3" it-stream-types "^2.0.1" multiformats "^13.1.0" progress-events "^1.0.0" uint8arraylist "^2.4.8" -"@libp2p/logger@^4.0.6": - version "4.0.20" - resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-4.0.20.tgz#bcb7fa83f3803d8ec37926747a18108728589c13" - integrity sha512-TTh2dhHsOTAlMPxSa9ncFPHa/0jTt+0AQxwHdlxg/OGLAgc9VRhnrhHUbJZp07Crcw4T/MOfS4KhjlxgqYgJRw== +"@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.7.0" - "@multiformats/multiaddr" "^12.2.3" + "@libp2p/interface" "^1.3.0" + "@multiformats/multiaddr" "^12.2.1" + debug "^4.3.4" interface-datastore "^8.2.11" multiformats "^13.1.0" - weald "^1.0.2" -"@libp2p/logger@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-5.1.0.tgz#d580e2ee89e3f4224129cc12d727b45494aad6e5" - integrity sha512-hmkk1TONYRe+kKs5QTxkayIfj9qicp8hcrJ1Ac9QfTW/jdaUlnqd1uop4QcOD5GV6qNMq+v1qaMFWFYSN9RcPA== +"@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" "^2.1.2" - "@multiformats/multiaddr" "^12.2.3" - interface-datastore "^8.3.0" - multiformats "^13.1.0" - weald "^1.0.2" - -"@libp2p/mdns@^11.0.4": - version "11.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/mdns/-/mdns-11.0.7.tgz#ab968f952085a59d3ea829727e79f631fa049376" - integrity sha512-CW0MbN2bQvSVsZmYT8Ul5a2TOiwhU3aBKyHyCuf5WA70Nu6Lc72YSc+vRT2EIw5Ihb+dbxC/mXrhY1xKdXaWCg== - dependencies: - "@libp2p/interface" "^2.1.2" - "@libp2p/interface-internal" "^2.0.7" - "@libp2p/peer-id" "^5.0.4" - "@libp2p/utils" "^6.1.0" - "@multiformats/multiaddr" "^12.2.3" + "@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@^11.0.4": - version "11.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/mplex/-/mplex-11.0.7.tgz#18f5af4d59bbd9bdf64c9ddda30020c6b674010d" - integrity sha512-q13aTXf6+kEQk67bnlDnXBy8TAU19zxrNrxzwTTW3m9HEyPEKoA1YJuSqZuDjxfP31BbMshs3xxnlXgph5SpUw== +"@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" "^2.1.2" - "@libp2p/utils" "^6.1.0" + "@libp2p/interface" "^1.3.0" + "@libp2p/utils" "^5.3.2" it-pipe "^3.0.1" it-pushable "^3.2.3" it-stream-types "^2.0.1" uint8-varint "^2.0.4" uint8arraylist "^2.4.8" - uint8arrays "^5.1.0" + uint8arrays "^5.0.3" -"@libp2p/multistream-select@^6.0.5": - version "6.0.5" - resolved "https://registry.yarnpkg.com/@libp2p/multistream-select/-/multistream-select-6.0.5.tgz#919c923ac13573a44de6945695f1d1882ba35da4" - integrity sha512-iOMHcF/NzeShmnRLf9KI39bgfxptklbf6Tv9NvBbICfYO/IJB6KDI6bOif5eXXqUqZjHrQJ3jrRppOEwk2HV4g== +"@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" "^2.1.2" + "@libp2p/interface" "^1.3.0" it-length-prefixed "^9.0.4" - it-length-prefixed-stream "^1.1.7" + it-length-prefixed-stream "^1.1.6" it-stream-types "^2.0.1" p-defer "^4.0.1" race-signal "^1.0.2" uint8-varint "^2.0.4" uint8arraylist "^2.4.8" - uint8arrays "^5.1.0" + uint8arrays "^5.0.3" -"@libp2p/peer-collections@^6.0.7": - version "6.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/peer-collections/-/peer-collections-6.0.7.tgz#8347e08aebbdf4a39962bb87e5ae86cc0aadfcb4" - integrity sha512-e3o994iEUvPR58x8Y5iE6lvrkv48oJXp/A1XIxMB4D/kA4OlY5BjDpHpR4nE4+EkzhIbslbMLAfip2FStyjtHg== +"@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/interface" "^2.1.2" - "@libp2p/peer-id" "^5.0.4" - "@libp2p/utils" "^6.1.0" - multiformats "^13.2.2" + "@libp2p/interface" "^1.3.0" + "@libp2p/peer-id" "^4.1.0" -"@libp2p/peer-id@^5.0.0", "@libp2p/peer-id@^5.0.1", "@libp2p/peer-id@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@libp2p/peer-id/-/peer-id-5.0.4.tgz#5a71f449b97098a5b12631b6be898a016a82c6bb" - integrity sha512-CHNbQ4Odlc+YDTtv6BzWdGSaJ1I3Wb6iHNV7YB59v0ivSsd0NzlR31qWpK/ByUAMT+hfzQzR1dK9s3e7zS4/zQ== +"@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.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-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/crypto" "^5.0.4" - "@libp2p/interface" "^2.1.2" + "@libp2p/interface" "^1.3.0" multiformats "^13.1.0" - uint8arrays "^5.1.0" - -"@libp2p/peer-record@^8.0.7": - version "8.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/peer-record/-/peer-record-8.0.7.tgz#a092b2405e1130b8211f8ef15748b453096029d8" - integrity sha512-YsN8R+5O0MQwYQ0UGqERJJVRx7hAU4/nxiby91wzbgdfuL4qVPXHG4k0OAAtxVGLYa0q7KeXBpBG8qoaKhOXMQ== - dependencies: - "@libp2p/crypto" "^5.0.4" - "@libp2p/interface" "^2.1.2" - "@libp2p/peer-id" "^5.0.4" - "@libp2p/utils" "^6.1.0" - "@multiformats/multiaddr" "^12.2.3" - multiformats "^13.2.2" + 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.1.0" - -"@libp2p/peer-store@^11.0.7": - version "11.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/peer-store/-/peer-store-11.0.7.tgz#e9a57d8a0ce1b3d0559a11b7e6633620f4297276" - integrity sha512-h8W/XVYfKTmJhhnh2Mdub23CzPv24l5g1RRwFsEKCkWAe95M/fvDMPTM2ahRUB64qfnFT5X4XNFFyJFMsVtjLA== - dependencies: - "@libp2p/crypto" "^5.0.4" - "@libp2p/interface" "^2.1.2" - "@libp2p/peer-collections" "^6.0.7" - "@libp2p/peer-id" "^5.0.4" - "@libp2p/peer-record" "^8.0.7" - "@multiformats/multiaddr" "^12.2.3" - interface-datastore "^8.3.0" - it-all "^3.0.6" + 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.1.0" + uint8arrays "^5.0.3" -"@libp2p/prometheus-metrics@^4.1.2": - version "4.2.1" - resolved "https://registry.yarnpkg.com/@libp2p/prometheus-metrics/-/prometheus-metrics-4.2.1.tgz#a563e05cac1f67a161824301cacdfd659bc3052c" - integrity sha512-Mt93FWjP1Jz5G/FsG7cf0J4Y1nYs4eQvx1RjtuEghoQcSzD8nSupeMt67YRQG87R/qrs0jdiGtYxmoCoagsIDw== +"@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" "^2.1.2" - it-foreach "^2.1.0" + "@libp2p/interface" "^1.3.0" + it-foreach "^2.0.6" it-stream-types "^2.0.1" - prom-client "^15.1.2" + prom-client "^15.1.1" uint8arraylist "^2.4.8" -"@libp2p/pubsub@^10.0.0": - version "10.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/pubsub/-/pubsub-10.0.7.tgz#1b7e0b7e96b75a8a1f557171ef4d72c17879e5c0" - integrity sha512-XYAYaASilesqxonjhiEENF/jXoT3jcftNYySkiyajrw3rZnLVkfJMRese3lkFqkIZqy7K/7aAtYEDJLeSrJDiQ== - dependencies: - "@libp2p/crypto" "^5.0.4" - "@libp2p/interface" "^2.1.2" - "@libp2p/interface-internal" "^2.0.7" - "@libp2p/peer-collections" "^6.0.7" - "@libp2p/peer-id" "^5.0.4" - "@libp2p/utils" "^6.1.0" +"@libp2p/pubsub@^9.0.8": + 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.1.0" p-queue "^8.0.1" uint8arraylist "^2.4.8" - uint8arrays "^5.1.0" + uint8arrays "^5.0.3" -"@libp2p/tcp@10.0.4": - version "10.0.4" - resolved "https://registry.yarnpkg.com/@libp2p/tcp/-/tcp-10.0.4.tgz#9fdcd4ef5940816d366ee29e7e8150a5a4bd2f11" - integrity sha512-53WIxkKNMHJphTK/VUJvL5jPrkEitZpZqUSA8zN7e02OXwwOC/X3U03xvVFdrjGL32rW524+7I+SrvS+hVdNCw== +"@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" "^2.1.2" - "@libp2p/utils" "^6.0.4" + "@libp2p/interface" "^1.3.0" + "@libp2p/utils" "^5.3.2" "@multiformats/mafmt" "^12.1.6" - "@multiformats/multiaddr" "^12.2.3" + "@multiformats/multiaddr" "^12.2.1" "@types/sinon" "^17.0.3" - progress-events "^1.0.0" - stream-to-it "^1.0.1" + stream-to-it "^1.0.0" -"@libp2p/utils@^6.0.4", "@libp2p/utils@^6.1.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@libp2p/utils/-/utils-6.1.0.tgz#5ccece78a38bec2c2d759136ccc78494838c2b87" - integrity sha512-pxuUI8QgeS06bMZRpy0JnACPhrrCJS5/rVNTcnQK8lV1ag2bjwkGG/359AwjeEolzYQeLrmmqnZyawd1Y74wpw== +"@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/crypto" "^5.0.4" - "@libp2p/interface" "^2.1.2" - "@libp2p/logger" "^5.1.0" - "@multiformats/multiaddr" "^12.2.3" - "@sindresorhus/fnv1a" "^3.1.0" - "@types/murmurhash3js-revisited" "^3.0.3" - any-signal "^4.1.1" + "@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.2" - it-foreach "^2.1.1" - it-pipe "^3.0.1" it-pushable "^3.2.3" it-stream-types "^2.0.1" - murmurhash3js-revisited "^3.0.0" netmask "^2.0.2" p-defer "^4.0.1" - race-event "^1.3.0" + race-event "^1.2.0" race-signal "^1.0.2" uint8arraylist "^2.4.8" - uint8arrays "^5.1.0" "@lukeed/ms@^2.0.2": version "2.0.2" @@ -2006,7 +1993,7 @@ outvariant "^1.2.1" strict-event-emitter "^0.5.1" -"@multiformats/dns@^1.0.3", "@multiformats/dns@^1.0.6": +"@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== @@ -2026,22 +2013,23 @@ dependencies: "@multiformats/multiaddr" "^12.0.0" -"@multiformats/multiaddr-matcher@^1.2.1": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@multiformats/multiaddr-matcher/-/multiaddr-matcher-1.2.4.tgz#affb3c63b5cd83b44156be19583981651373ec2e" - integrity sha512-GgpqzQFL4Mj8t7cLNHC5nuYUuSm0kTtSUyYswiyWwTSUY3XwRAMx0UiFWQg+ETk0u+/IvFaHxfnyEoH3tasvwg== +"@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 "^13.0.0" -"@multiformats/multiaddr@^12.0.0", "@multiformats/multiaddr@^12.1.10", "@multiformats/multiaddr@^12.1.14", "@multiformats/multiaddr@^12.1.3", "@multiformats/multiaddr@^12.2.3": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@multiformats/multiaddr/-/multiaddr-12.3.1.tgz#953ceb4ae3b39125b7b2c721230ea7b398cf49fe" - integrity sha512-yoGODQY4nIj41ENJClucS8FtBoe8w682bzbKldEQr9lSlfdHqAsRC+vpJAOBpiMwPps1tHua4kxrDmvprdhoDQ== +"@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" "@multiformats/dns" "^1.0.3" multiformats "^13.0.0" uint8-varint "^2.0.1" @@ -2112,19 +2100,12 @@ resolved "https://registry.yarnpkg.com/@napi-rs/snappy-win32-x64-msvc/-/snappy-win32-x64-msvc-7.2.2.tgz#4f598d3a5d50904d9f72433819f68b21eaec4f7d" integrity sha512-a43cyx1nK0daw6BZxVcvDEXxKMFLSBSDTAhsFD0VqSKcC7MGUBMaqyoWUcMiI7LBSz4bxUmxDWKfCYzpEmeb3w== -"@noble/ciphers@^0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.6.0.tgz#a3d82c72ce71ba43128e7eb71757b5ecb75b1273" - integrity sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ== - -"@noble/curves@1.4.2", "@noble/curves@~1.4.0": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.2.tgz#40309198c76ed71bc6dbf7ba24e81ceb4d0d1fe9" - integrity sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== - dependencies: - "@noble/hashes" "1.4.0" +"@noble/ciphers@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.4.0.tgz#e3f69e3ce935683dd8dadb636652a5cb5cd5958c" + integrity sha512-xaUaUUDWbHIFSxaQ/pIe+33VG2mfJp6N/KxKLmZr5biWdNznCAmfu24QRhX10BbVAuqOahAoyp0S4M9md6GPDw== -"@noble/curves@^1.1.0": +"@noble/curves@1.3.0", "@noble/curves@^1.1.0", "@noble/curves@~1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== @@ -2143,12 +2124,12 @@ 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.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", "@noble/hashes@~1.4.0": +"@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== @@ -2721,11 +2702,11 @@ integrity sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ== "@puppeteer/browsers@1.4.6", "@puppeteer/browsers@^1.6.0", "@puppeteer/browsers@^2.1.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.4.0.tgz#a0dd0f4e381e53f509109ae83b891db5972750f5" - integrity sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g== + version "2.3.0" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.3.0.tgz#791ea7d80450fea24eb19fb1d70c367ad4e08cae" + integrity sha512-ioXoq9gPxkss4MYhD+SFaU9p1IHFUX0ILAWFPyjGaBdjLsYAlZw6j1iLA0N/m12uVHLFDfSYNF7EQccjinIMDA== dependencies: - debug "^4.3.6" + debug "^4.3.5" extract-zip "^2.0.1" progress "^2.0.3" proxy-agent "^6.4.0" @@ -2889,27 +2870,27 @@ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.0.0.tgz#109fb595021de285f05a7db6806f2f48296fcee7" integrity sha512-gIVaYhUsy+9s58m/ETjSJVKHhKTBMmcRb9cEV5/5dwvfDlfORjKrFsDeDHWRrm6RjcPvCLZFwGJjAjLj1gg4HA== -"@scure/base@~1.1.6": - version "1.1.8" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.8.tgz#8f23646c352f020c83bca750a82789e246d42b50" - integrity sha512-6CyAclxj3Nb0XT7GHK6K4zK6k2xJm6E4Ft0Ohjt4WgegiFUHEtFb2CGzmPmGBwoIhrLsqNLYfLr04Y1GePrzZg== +"@scure/base@~1.1.4": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.5.tgz#1d85d17269fe97694b9c592552dd9e5e33552157" + integrity sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ== -"@scure/bip32@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.4.0.tgz#4e1f1e196abedcef395b33b9674a042524e20d67" - integrity sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg== +"@scure/bip32@1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.3.tgz#a9624991dc8767087c57999a5d79488f48eae6c8" + integrity sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ== dependencies: - "@noble/curves" "~1.4.0" - "@noble/hashes" "~1.4.0" - "@scure/base" "~1.1.6" + "@noble/curves" "~1.3.0" + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.4" -"@scure/bip39@1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.3.0.tgz#0f258c16823ddd00739461ac31398b4e7d6a18c3" - integrity sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== +"@scure/bip39@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.2.tgz#f3426813f4ced11a47489cbcf7294aa963966527" + integrity sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA== dependencies: - "@noble/hashes" "~1.4.0" - "@scure/base" "~1.1.6" + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.4" "@scure/bip39@^1.0.0": version "1.0.0" @@ -2953,11 +2934,6 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== -"@sindresorhus/fnv1a@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/fnv1a/-/fnv1a-3.1.0.tgz#f8e46597298f6fd4c12dc901cdd4e73beb4d24fa" - integrity sha512-KV321z5m/0nuAg83W1dPLy85HpHDk7Sdi4fJbwvacWsEhAh+rZUW4ZfGcXmUIvjZg4ss2bcwNlRhJ7GBEUG08w== - "@sindresorhus/is@^4.0.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" @@ -3272,11 +3248,6 @@ "@types/dns-packet" "*" "@types/node" "*" -"@types/murmurhash3js-revisited@^3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.3.tgz#94e247168a18342477639126da8f01353437e8d0" - integrity sha512-QvlqvYtGBYIDeO8dFdY4djkRubcrc+yTJtBc7n8VZPlJDUS/00A+PssbvERM8f9bYRmcaSEHPZgZojeQj7kzAA== - "@types/mute-stream@^0.0.4": version "0.0.4" resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478" @@ -3365,11 +3336,6 @@ resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz" integrity sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g== -"@types/retry@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.2.tgz#ed279a64fa438bb69f2480eda44937912bb7480a" - integrity sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow== - "@types/sinon@^17.0.3": version "17.0.3" resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-17.0.3.tgz#9aa7e62f0a323b9ead177ed23a36ea757141a5fa" @@ -3752,19 +3718,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-level@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.4.tgz#3ad8d684c51cc9cbc9cf9612a7100b716c414b57" - integrity sha512-eUP/6pbXBkMbXFdx4IH2fVgvB7M0JvR7/lIL33zcs0IBcwjdzSSl31TOJsaCzmKSSDF9h8QYSOJux4Nd4YJqFg== - dependencies: - buffer "^6.0.3" - catering "^2.1.0" - is-buffer "^2.0.5" - level-supports "^4.0.0" - level-transcoder "^1.0.1" - module-error "^1.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" @@ -5396,14 +5349,15 @@ data-urls@^5.0.0: whatwg-mimetype "^4.0.0" whatwg-url "^14.0.0" -datastore-core@10.0.0, datastore-core@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/datastore-core/-/datastore-core-10.0.0.tgz#86abe346338e88c3326fb7aeb90eff3613cf542f" - integrity sha512-/b5KDmSAIFizS/ZzTTU+ZdfOcQc6mRmbc4/EK/WOzbEO5c0KWyjRLsZ3DWwh9wiPu93V7pX1oC+Or61k8UPPsg== +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.6" + err-code "^3.0.1" interface-datastore "^8.0.0" - interface-store "6.0.0" + interface-store "^5.0.0" it-drain "^3.0.5" it-filter "^3.0.4" it-map "^3.0.5" @@ -5413,19 +5367,18 @@ datastore-core@10.0.0, datastore-core@^10.0.0: it-sort "^3.0.4" it-take "^3.0.4" -datastore-level@*, datastore-level@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/datastore-level/-/datastore-level-11.0.0.tgz#c0f7324bd74e15bec01f2911f5740fbf59c344f7" - integrity sha512-ATSEfGoWTAHgDeZaYukeHu0FgyhjW3FKUw3XtcIpfBl4UF2kLNnYRBfzCeH+3RA0QaZvbSWpgYk6Gwf7m1oCtg== +datastore-level@*, datastore-level@^10.1.1: + version "10.1.1" + resolved "https://registry.yarnpkg.com/datastore-level/-/datastore-level-10.1.1.tgz#390dc6ca17dc691947a3e81c984b4b6064812e81" + integrity sha512-4fQPf/6fIXdcC0XZPGMiNuoOmF82Vhdz+LPTmbzR+CbbnCri6eOcFdzBPnDsAAuPOCV6Zld1EhgM2cRArw1+sQ== dependencies: - datastore-core "10.0.0" + datastore-core "^9.0.0" interface-datastore "^8.0.0" - interface-store "6.0.0" - it-filter "^3.0.4" - it-map "^3.0.5" - it-sort "^3.0.4" - it-take "^3.0.4" - level "^8.0.1" + it-filter "^3.0.0" + it-map "^3.0.1" + it-sort "^3.0.1" + it-take "^3.0.1" + level "^8.0.0" dateformat@^3.0.3: version "3.0.3" @@ -5451,13 +5404,6 @@ debug@^4.3.5: dependencies: ms "2.1.2" -debug@^4.3.6: - version "4.3.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" - integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== - dependencies: - ms "^2.1.3" - decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" @@ -6055,15 +6001,15 @@ esutils@^2.0.2: resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz#58f2810f8e020aecb97de8c8c76147600b0b8ccf" - integrity sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg== +ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz#1352270ed3b339fe25af5ceeadcf1b9c8e30768a" + integrity sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA== dependencies: - "@noble/curves" "1.4.2" - "@noble/hashes" "1.4.0" - "@scure/bip32" "1.4.0" - "@scure/bip39" "1.3.0" + "@noble/curves" "1.3.0" + "@noble/hashes" "1.3.3" + "@scure/bip32" "1.3.3" + "@scure/bip39" "1.2.2" ethers@^5.7.1: version "5.7.2" @@ -7450,18 +7396,18 @@ inquirer@^9.1.5: through "^2.3.6" wrap-ansi "^8.1.0" -interface-datastore@^8.0.0, interface-datastore@^8.2.11, interface-datastore@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/interface-datastore/-/interface-datastore-8.3.0.tgz#0ce9a2f0f61f9fbe1c1734c6d10a0265193689f7" - integrity sha512-RM/rTSmRcnoCwGZIHrPm+nlGYVoT4R0lcFvNnDyhdFT4R6BuHHhfFP47UldVEjs98SfxLuMhaNMsyjI918saHw== +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 "6.0.0" + interface-store "^5.0.0" uint8arrays "^5.0.2" -interface-store@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/interface-store/-/interface-store-6.0.0.tgz#8d8277a582f69d819134e125b686e147099a4728" - integrity sha512-HkjsDPsjA7SKkCr+TH1elUQApAAM3X3JPwrz3vFzaf614wI+ZD6GVvwKGZCHYcbSRqeZP/uzVPqezzeISeo5kA== +interface-store@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/interface-store/-/interface-store-5.1.0.tgz#1735cead844fe452d62c307fafbaaa1d261e6ff3" + integrity sha512-mjUwX3XSoreoxCS3sXS3pSRsGnUjl9T06KBqt/T7AgE9Sgp4diH64ZyURJKnj2T5WmCvTbC0Dm+mwQV5hfLSBQ== internal-slot@^1.0.5: version "1.0.5" @@ -7647,11 +7593,6 @@ is-negative-zero@^2.0.2: resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== -is-network-error@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-network-error/-/is-network-error-1.1.0.tgz#d26a760e3770226d11c169052f266a4803d9c997" - integrity sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g== - is-node-process@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134" @@ -7876,11 +7817,6 @@ it-all@^3.0.0, it-all@^3.0.4: resolved "https://registry.yarnpkg.com/it-all/-/it-all-3.0.4.tgz#08f2e3eb3df04fa4525a343dcacfbdf91ffee162" integrity sha512-UMiy0i9DqCHBdWvMbzdYvVGa5/w4t1cc4nchpbnjdLhklglv8mQeEYnii0gvKESJuL1zV32Cqdb33R6/GPfxpQ== -it-all@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/it-all/-/it-all-3.0.6.tgz#30a4f922ae9ca0945b0f720d3478ae6f5b6707ab" - integrity sha512-HXZWbxCgQZJfrv5rXvaVeaayXED8nTKx9tj9fpBhmcUJcedVZshMMMqTj0RG2+scGypb9Ut1zd1ifbf3lA8L+Q== - it-byte-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/it-byte-stream/-/it-byte-stream-1.0.0.tgz#07645e1c94444760bc7abecebf187b83777b0351" @@ -7890,38 +7826,29 @@ it-byte-stream@^1.0.0: it-stream-types "^2.0.1" uint8arraylist "^2.4.1" -it-byte-stream@^1.0.12: - version "1.1.0" - resolved "https://registry.yarnpkg.com/it-byte-stream/-/it-byte-stream-1.1.0.tgz#f5b80b713fb71a34cbff2390b7232b103cf625bb" - integrity sha512-WWponBWdKEa6o2U3NX+wGMY8X1EkWXcQvpC+3CUqKb4ZzK30q3EPqiTjFxLf9tNVgdF/MNAtx/XclpVfgaz9KQ== - dependencies: - it-queueless-pushable "^1.0.0" - it-stream-types "^2.0.1" - uint8arraylist "^2.4.8" - -it-drain@^3.0.3, it-drain@^3.0.5, it-drain@^3.0.7: +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.4: +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.1.0, it-foreach@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/it-foreach/-/it-foreach-2.1.1.tgz#93e311a1057dd0ff7631f914dc9c2c963f27a4b8" - integrity sha512-ID4Gxnavk/LVQLQESAQ9hR6dR63Ih6X+8VdxEktX8rpz2dCGAbZpey/eljTNbMfV2UKXHiu6UsneoNBZuac97g== +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.7: - version "1.2.0" - resolved "https://registry.yarnpkg.com/it-length-prefixed-stream/-/it-length-prefixed-stream-1.2.0.tgz#1f6ad78c60dea3b16364f86a0b78058f4d66a04e" - integrity sha512-vX7dzSl/2UMYYsAr0FQdPNVR5xYEETaeboZ+eXxNBjgARuvxnWA6OedW8lC5/J3ebMTC98JhA3eH76eTijUOsA== +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" @@ -7940,14 +7867,14 @@ it-length-prefixed@^9.0.1, it-length-prefixed@^9.0.4: uint8arraylist "^2.0.0" uint8arrays "^5.0.1" -it-map@^3.0.5: +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.3, it-merge@^3.0.5: +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== @@ -7962,12 +7889,12 @@ it-pair@^2.0.6: it-stream-types "^2.0.1" p-defer "^4.0.0" -it-parallel@^3.0.7: - version "3.0.8" - resolved "https://registry.yarnpkg.com/it-parallel/-/it-parallel-3.0.8.tgz#fb4a5344732ddae9eff7c7b21908aa1f223638d4" - integrity sha512-URLhs6eG4Hdr4OdvgBBPDzOjBeSSmI+Kqex2rv/aAyYClME26RYHirLVhZsZP5M+ZP6M34iRlXk8Wlqtezuqpg== +it-parallel@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/it-parallel/-/it-parallel-3.0.6.tgz#d8f9efa56dac5f960545b3a148d2ca171694d228" + integrity sha512-i7UM7I9LTkDJw3YIqXHFAPZX6CWYzGc+X3irdNrVExI4vPazrJdI7t5OqrSVN8CONXLAunCiqaSV/zZRbQR56A== dependencies: - p-defer "^4.0.1" + p-defer "^4.0.0" it-peekable@^3.0.0: version "3.0.1" @@ -7983,10 +7910,10 @@ it-pipe@^3.0.1: it-pushable "^3.1.2" it-stream-types "^2.0.1" -it-protobuf-stream@^1.1.3: - version "1.1.5" - resolved "https://registry.yarnpkg.com/it-protobuf-stream/-/it-protobuf-stream-1.1.5.tgz#70da43abfb6beaaf7c53262d8cfd176d463b08f0" - integrity sha512-H70idW45As3cEbU4uSoZ9IYHUIV3YM69/2mmXYR7gOlPabWjuyNi3/abK11geiiq3la27Sos/mXr68JljjKtEQ== +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" @@ -7999,14 +7926,6 @@ it-pushable@^3.1.2, it-pushable@^3.2.0, it-pushable@^3.2.3: dependencies: p-defer "^4.0.0" -it-queueless-pushable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/it-queueless-pushable/-/it-queueless-pushable-1.0.0.tgz#917b52964cd6465d6436f923552c407c5ee3d11c" - integrity sha512-HbcAbcuQj7a9EBxiRCZ+77FxWutgs/pY5ZvEyQnylWPGNFojCLAUwhcZjf5OuEQ9+y+vSa7w1GQBe8xJdmIn5A== - dependencies: - p-defer "^4.0.1" - race-signal "^1.0.2" - it-reader@^6.0.1: version "6.0.4" resolved "https://registry.yarnpkg.com/it-reader/-/it-reader-6.0.4.tgz#439cb88225dcd15116be0ffde9e846a928c3871a" @@ -8015,7 +7934,7 @@ it-reader@^6.0.1: it-stream-types "^2.0.1" uint8arraylist "^2.0.0" -it-sort@^3.0.4: +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== @@ -8027,7 +7946,7 @@ 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.4: +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== @@ -8388,15 +8307,6 @@ level@^8.0.0: browser-level "^1.0.1" classic-level "^1.2.0" -level@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/level/-/level-8.0.1.tgz#737161db1bc317193aca4e7b6f436e7e1df64379" - integrity sha512-oPBGkheysuw7DmzFQYyFe8NAia5jFLAgEnkgWnK3OXAuJr8qFT+xBQIwokAZPME2bhPFzS8hlYcL16m8UZrtwQ== - dependencies: - abstract-level "^1.0.4" - browser-level "^1.0.1" - classic-level "^1.2.0" - libnpmaccess@7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-7.0.2.tgz#7f056c8c933dd9c8ba771fa6493556b53c5aac52" @@ -8419,37 +8329,32 @@ libnpmpublish@7.3.0: sigstore "^1.4.0" ssri "^10.0.1" -libp2p@2.1.7: - version "2.1.7" - resolved "https://registry.yarnpkg.com/libp2p/-/libp2p-2.1.7.tgz#e0d921cba459c78c63d783aafea6ead98a75e57f" - integrity sha512-nUxws8eHeI4jREZJFNdif20c8jYnqPkmvioI3y/hICgXchkhcKzgT1E3jEd2CVT+isskr5LnJ1n70aw6bt0m6w== - dependencies: - "@libp2p/crypto" "^5.0.4" - "@libp2p/interface" "^2.1.2" - "@libp2p/interface-internal" "^2.0.7" - "@libp2p/logger" "^5.1.0" - "@libp2p/multistream-select" "^6.0.5" - "@libp2p/peer-collections" "^6.0.7" - "@libp2p/peer-id" "^5.0.4" - "@libp2p/peer-store" "^11.0.7" - "@libp2p/utils" "^6.1.0" - "@multiformats/dns" "^1.0.6" - "@multiformats/multiaddr" "^12.2.3" - "@multiformats/multiaddr-matcher" "^1.2.1" +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 "^10.0.0" - interface-datastore "^8.3.0" - it-byte-stream "^1.0.12" - it-merge "^3.0.5" - it-parallel "^3.0.7" + 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.1.0" - p-defer "^4.0.1" - p-retry "^6.2.0" - progress-events "^1.0.0" - race-event "^1.3.0" - race-signal "^1.0.2" - uint8arrays "^5.1.0" + uint8arrays "^5.0.3" light-my-request@^6.0.0: version "6.0.0" @@ -9272,16 +9177,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -ms@^3.0.0-canary.1: - version "3.0.0-canary.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-3.0.0-canary.1.tgz#c7b34fbce381492fd0b345d1cf56e14d67b77b80" - integrity sha512-kh8ARjh8rMN7Du2igDRO9QJnqCb2xYTJxyQYK7vJJS4TvLLmsbyhiKpSW+t+y26gyOyMd0riphX0GeWKU3ky5g== - msw@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/msw/-/msw-2.3.2.tgz#ea4f45b51f833fa3b2215c4093bcda28dbe25a83" @@ -9323,10 +9223,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@^13.0.0, multiformats@^13.0.1, multiformats@^13.1.0, multiformats@^13.2.2: - version "13.2.2" - resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-13.2.2.tgz#16da153ee8b68d8c9da31b52176e90b3cd8b43ef" - integrity sha512-RWI+nyf0q64vyOxL8LbKtjJMki0sogRL/8axvklNtiTM0iFCVtHwME9w6+0P1/v4dQvsIg8A45oT3ka1t/M/+A== +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" @@ -9339,11 +9239,6 @@ multimatch@5.0.0: arrify "^2.0.1" minimatch "^3.0.4" -murmurhash3js-revisited@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz#6bd36e25de8f73394222adc6e41fa3fac08a5869" - integrity sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g== - mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -10052,15 +9947,6 @@ p-reduce@2.1.0, p-reduce@^2.0.0, p-reduce@^2.1.0: resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== -p-retry@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-6.2.0.tgz#8d6df01af298750009691ce2f9b3ad2d5968f3bd" - integrity sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA== - dependencies: - "@types/retry" "0.12.2" - is-network-error "^1.0.0" - retry "^0.13.1" - p-timeout@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" @@ -10471,10 +10357,10 @@ progress@^2.0.3: resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prom-client@^15.1.0, prom-client@^15.1.2: - version "15.1.3" - resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-15.1.3.tgz#69fa8de93a88bc9783173db5f758dc1c69fa8fc2" - integrity sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g== +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" @@ -10520,10 +10406,10 @@ protocols@^2.0.0, protocols@^2.0.1: resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== -protons-runtime@^5.4.0, protons-runtime@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/protons-runtime/-/protons-runtime-5.5.0.tgz#ea06d9ef843aad77ea5de3e1ebafa81b58c24570" - integrity sha512-EsALjF9QsrEk6gbCx3lmfHxVN0ah7nG3cY7GySD4xf4g8cr7g543zB88Foh897Sr1RQJ9yDCUsoT1i1H/cVUFA== +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: uint8-varint "^2.0.2" uint8arraylist "^2.4.3" @@ -10672,7 +10558,7 @@ 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.3.0: +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== @@ -10968,11 +10854,6 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== -retry@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" - integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== - reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -11659,7 +11540,7 @@ stream-http@^3.2.0: readable-stream "^3.6.0" xtend "^4.0.2" -stream-to-it@^1.0.1: +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== @@ -11895,11 +11776,6 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^9.4.0: - version "9.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.4.0.tgz#17bfcf686288f531db3dea3215510621ccb55954" - integrity sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw== - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -12431,10 +12307,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, uint8arrays@^5.0.2, uint8arrays@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-5.1.0.tgz#14047c9bdf825d025b7391299436e5e50e7270f1" - integrity sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww== +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" @@ -12799,14 +12675,6 @@ wcwidth@^1.0.0, wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -weald@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/weald/-/weald-1.0.2.tgz#a51fb3a8dbf5fa2b71ef09f9a267c86a46742238" - integrity sha512-iG5cIuBwsPe1ZcoGGd4X6QYlepU1vLr4l4oWpzQWqeJPSo9B8bxxyE6xlnj3TCmThtha7gyVL+uuZgUFkPyfDg== - dependencies: - ms "^3.0.0-canary.1" - supports-color "^9.4.0" - web-streams-polyfill@^3.0.3: version "3.2.1" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" From 4c757cbe097615fa18b97e122f7bc5d73a05f5ac Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 28 Oct 2024 15:15:52 +0000 Subject: [PATCH 181/259] feat: add metric to track default validator configuration (#7194) * Add metric to track default validator configuration * Update validator client dashboard * Rename column --- dashboards/lodestar_validator_client.json | 91 ++++++++++++++++++++++- packages/validator/src/metrics.ts | 10 +++ packages/validator/src/validator.ts | 2 + 3 files changed, 100 insertions(+), 3 deletions(-) diff --git a/dashboards/lodestar_validator_client.json b/dashboards/lodestar_validator_client.json index 5e4459d1d1b9..f954f0a04ccd 100644 --- a/dashboards/lodestar_validator_client.json +++ b/dashboards/lodestar_validator_client.json @@ -497,7 +497,7 @@ }, "gridPos": { "h": 3, - "w": 6, + "w": 3, "x": 12, "y": 2 }, @@ -552,8 +552,8 @@ }, "gridPos": { "h": 3, - "w": 6, - "x": 18, + "w": 3, + "x": 15, "y": 2 }, "id": 37, @@ -590,6 +590,91 @@ "title": "Heap used", "type": "stat" }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "center", + "cellOptions": { + "type": "color-text" + }, + "inspect": false + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 2 + }, + "id": 48, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.4.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "vc_default_configuration", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "__name__": true, + "client_name": true, + "group": true, + "host_type": true, + "instance": true, + "job": true, + "network": true, + "scrape_location": true + }, + "includeByName": {}, + "indexByName": {}, + "renameByName": { + "broadcastValidation": "Broadcast validation", + "builderSelection": "Builder selection" + } + } + } + ], + "type": "table" + }, { "datasource": { "type": "prometheus", diff --git a/packages/validator/src/metrics.ts b/packages/validator/src/metrics.ts index ca693056fc54..1f49c038a50d 100644 --- a/packages/validator/src/metrics.ts +++ b/packages/validator/src/metrics.ts @@ -1,3 +1,4 @@ +import {routes} from "@lodestar/api"; import {MetricsRegisterExtra} from "@lodestar/utils"; export enum MessageSource { @@ -38,6 +39,15 @@ export function getMetrics(register: MetricsRegisterExtra, gitData: LodestarGitD .set(gitData, 1); return { + defaultConfiguration: register.gauge<{ + builderSelection: routes.validator.BuilderSelection; + broadcastValidation: routes.beacon.BroadcastValidation; + }>({ + name: "vc_default_configuration", + help: "Default validator configuration", + labelNames: ["builderSelection", "broadcastValidation"], + }), + // Attestation journey: // - Wait for block or 1/3, call prepare attestation // - Get attestation, sign, call publish diff --git a/packages/validator/src/validator.ts b/packages/validator/src/validator.ts index 1d370c35cc33..09a3a80062da 100644 --- a/packages/validator/src/validator.ts +++ b/packages/validator/src/validator.ts @@ -329,6 +329,8 @@ export class Validator { strictFeeRecipientCheck, }); + metrics?.defaultConfiguration.set({builderSelection: defaultBuilderSelection, broadcastValidation}, 1); + // Instantiates block and attestation services and runs them once the chain has been started. return Validator.init(opts, genesis, metrics); } From 3cd2f1603f5ca7e4af4ad4ebf5c2f6e4531bf405 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 28 Oct 2024 18:27:43 +0000 Subject: [PATCH 182/259] refactor: move WithBytes to types package (#7201) --- packages/beacon-node/src/network/interface.ts | 3 +-- packages/beacon-node/src/network/network.ts | 3 ++- .../src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts | 4 ++-- packages/beacon-node/src/network/reqresp/utils/collect.ts | 2 +- .../network/reqresp/utils/collectSequentialBlocksInRange.ts | 3 +-- packages/beacon-node/src/sync/backfill/verify.ts | 3 +-- packages/beacon-node/test/unit/sync/backfill/verify.test.ts | 3 +-- packages/types/src/types.ts | 6 ++++++ 8 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/beacon-node/src/network/interface.ts b/packages/beacon-node/src/network/interface.ts index 8d73379af221..0d48df42b31e 100644 --- a/packages/beacon-node/src/network/interface.ts +++ b/packages/beacon-node/src/network/interface.ts @@ -27,6 +27,7 @@ import { deneb, phase0, SignedAggregateAndProof, + WithBytes, } from "@lodestar/types"; import {PeerIdStr} from "../util/peerId.js"; import {INetworkEventBus} from "./events.js"; @@ -35,8 +36,6 @@ import {GossipType} from "./gossip/interface.js"; import {PendingGossipsubMessage} from "./processor/types.js"; import {PeerAction} from "./peers/index.js"; -export type WithBytes = {data: T; bytes: Uint8Array}; - /** * The architecture of the network looks like so: * - core: diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 1b3ccaaaf75a..15414fcf9138 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -18,6 +18,7 @@ import { LightClientOptimisticUpdate, LightClientUpdate, SignedAggregateAndProof, + WithBytes, } from "@lodestar/types"; import {routes} from "@lodestar/api"; import {ResponseIncoming} from "@lodestar/reqresp"; @@ -28,7 +29,7 @@ import {IBeaconDb} from "../db/interface.js"; import {PeerIdStr, peerIdToString} from "../util/peerId.js"; import {IClock} from "../util/clock.js"; import {NetworkOptions} from "./options.js"; -import {WithBytes, INetwork} from "./interface.js"; +import {INetwork} from "./interface.js"; import {ReqRespMethod} from "./reqresp/index.js"; import {GossipHandlers, GossipTopicMap, GossipType, GossipTypeMap} from "./gossip/index.js"; import {PeerAction, PeerScoreStats} from "./peers/index.js"; diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts index 8c69c21679ba..3d71087c8fd8 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts @@ -1,11 +1,11 @@ import {ChainForkConfig} from "@lodestar/config"; -import {deneb, Epoch, phase0, SignedBeaconBlock, Slot} from "@lodestar/types"; +import {deneb, Epoch, phase0, SignedBeaconBlock, Slot, WithBytes} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import {computeEpochAtSlot} from "@lodestar/state-transition"; import {BlobsSource, BlockInput, BlockSource, getBlockInput, BlockInputDataBlobs} from "../../chain/blocks/types.js"; import {PeerIdStr} from "../../util/peerId.js"; -import {INetwork, WithBytes} from "../interface.js"; +import {INetwork} from "../interface.js"; export async function beaconBlocksMaybeBlobsByRange( config: ChainForkConfig, diff --git a/packages/beacon-node/src/network/reqresp/utils/collect.ts b/packages/beacon-node/src/network/reqresp/utils/collect.ts index 06f3cfc36806..9818b1921f8e 100644 --- a/packages/beacon-node/src/network/reqresp/utils/collect.ts +++ b/packages/beacon-node/src/network/reqresp/utils/collect.ts @@ -1,7 +1,7 @@ import {Type} from "@chainsafe/ssz"; import {ResponseIncoming, RequestErrorCode, RequestError} from "@lodestar/reqresp"; +import {WithBytes} from "@lodestar/types"; import {ResponseTypeGetter} from "../types.js"; -import {WithBytes} from "../../interface.js"; /** * Sink for `*`, from diff --git a/packages/beacon-node/src/network/reqresp/utils/collectSequentialBlocksInRange.ts b/packages/beacon-node/src/network/reqresp/utils/collectSequentialBlocksInRange.ts index c2cf0ad16ea0..2709cb3f64a9 100644 --- a/packages/beacon-node/src/network/reqresp/utils/collectSequentialBlocksInRange.ts +++ b/packages/beacon-node/src/network/reqresp/utils/collectSequentialBlocksInRange.ts @@ -1,7 +1,6 @@ import {ResponseIncoming} from "@lodestar/reqresp"; import {LodestarError} from "@lodestar/utils"; -import {phase0, SignedBeaconBlock} from "@lodestar/types"; -import {WithBytes} from "../../interface.js"; +import {phase0, SignedBeaconBlock, WithBytes} from "@lodestar/types"; import {ReqRespMethod, responseSszTypeByMethod} from "../types.js"; import {sszDeserializeResponse} from "./collect.js"; diff --git a/packages/beacon-node/src/sync/backfill/verify.ts b/packages/beacon-node/src/sync/backfill/verify.ts index 462762a5576f..715cc6621253 100644 --- a/packages/beacon-node/src/sync/backfill/verify.ts +++ b/packages/beacon-node/src/sync/backfill/verify.ts @@ -1,9 +1,8 @@ import {CachedBeaconStateAllForks, ISignatureSet, getBlockProposerSignatureSet} from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; -import {Root, ssz, Slot, SignedBeaconBlock} from "@lodestar/types"; +import {Root, ssz, Slot, SignedBeaconBlock, WithBytes} from "@lodestar/types"; import {GENESIS_SLOT} from "@lodestar/params"; import {IBlsVerifier} from "../../chain/bls/index.js"; -import {WithBytes} from "../../network/interface.js"; import {BackfillSyncError, BackfillSyncErrorCode} from "./errors.js"; export type BackfillBlockHeader = { diff --git a/packages/beacon-node/test/unit/sync/backfill/verify.test.ts b/packages/beacon-node/test/unit/sync/backfill/verify.test.ts index bba1f7c93f19..3197013455e3 100644 --- a/packages/beacon-node/test/unit/sync/backfill/verify.test.ts +++ b/packages/beacon-node/test/unit/sync/backfill/verify.test.ts @@ -4,9 +4,8 @@ import {fileURLToPath} from "node:url"; import {describe, it, expect} from "vitest"; import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; -import {phase0, ssz} from "@lodestar/types"; +import {phase0, ssz, WithBytes} from "@lodestar/types"; import {verifyBlockSequence} from "../../../../src/sync/backfill/verify.js"; -import {WithBytes} from "../../../../src/network/interface.js"; import {ZERO_HASH} from "../../../../src/constants/constants.js"; import {BackfillSyncErrorCode, BackfillSyncError} from "./../../../../src/sync/backfill/errors.js"; diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 51fa2b12a28e..b1919c2f0842 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -32,6 +32,12 @@ export enum ProducedBlockSource { engine = "engine", } +export type WithBytes = { + data: T; + /** SSZ serialized `data` bytes */ + bytes: Uint8Array; +}; + export type WithOptionalBytes = { data: T; /** SSZ serialized `data` bytes */ From e31d535bb59d209827cbab61cb4381dccac90171 Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Tue, 29 Oct 2024 14:48:32 -0400 Subject: [PATCH 183/259] feat: asyncAggregateWithRandomness (#7204) * chore: update blst to 2.2.0 * feat: make aggregateWithRandomness async * feat: update metrics and remove stale comment * fix: metric collection value * feat: remove duplicate/unused metrics from asyncAggregateWithRandomness --- packages/beacon-node/package.json | 2 +- .../src/chain/bls/multithread/index.ts | 2 +- .../src/chain/bls/multithread/jobItem.ts | 18 ++--- .../src/metrics/metrics/lodestar.ts | 5 -- packages/cli/package.json | 2 +- packages/flare/package.json | 2 +- packages/state-transition/package.json | 2 +- packages/test-utils/package.json | 2 +- packages/validator/package.json | 2 +- yarn.lock | 78 +++++++++---------- 10 files changed, 51 insertions(+), 64 deletions(-) diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index fcaf5b715216..450c6e119023 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -95,7 +95,7 @@ }, "dependencies": { "@chainsafe/as-sha256": "^0.5.0", - "@chainsafe/blst": "^2.1.0", + "@chainsafe/blst": "^2.2.0", "@chainsafe/discv5": "^9.0.0", "@chainsafe/enr": "^3.0.0", "@chainsafe/libp2p-gossipsub": "^13.0.0", diff --git a/packages/beacon-node/src/chain/bls/multithread/index.ts b/packages/beacon-node/src/chain/bls/multithread/index.ts index cb18ca86e42f..fc8ea7534ad7 100644 --- a/packages/beacon-node/src/chain/bls/multithread/index.ts +++ b/packages/beacon-node/src/chain/bls/multithread/index.ts @@ -394,7 +394,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier { try { // Note: This can throw, must be handled per-job. // Pubkey and signature aggregation is defered here - workReq = jobItemWorkReq(job, this.metrics); + workReq = await jobItemWorkReq(job, this.metrics); } catch (e) { this.metrics?.blsThreadPool.errorAggregateSignatureSetsCount.inc({type: job.type}); diff --git a/packages/beacon-node/src/chain/bls/multithread/jobItem.ts b/packages/beacon-node/src/chain/bls/multithread/jobItem.ts index 035d56e56df2..63591af5ee77 100644 --- a/packages/beacon-node/src/chain/bls/multithread/jobItem.ts +++ b/packages/beacon-node/src/chain/bls/multithread/jobItem.ts @@ -1,4 +1,4 @@ -import {PublicKey, aggregateWithRandomness} from "@chainsafe/blst"; +import {PublicKey, asyncAggregateWithRandomness} from "@chainsafe/blst"; import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition"; import {VerifySignatureOpts} from "../interface.js"; import {getAggregatedPubkey} from "../utils.js"; @@ -48,7 +48,7 @@ export function jobItemSigSets(job: JobQueueItem): number { * Prepare BlsWorkReq from JobQueueItem * WARNING: May throw with untrusted user input */ -export function jobItemWorkReq(job: JobQueueItem, metrics: Metrics | null): BlsWorkReq { +export async function jobItemWorkReq(job: JobQueueItem, metrics: Metrics | null): Promise { switch (job.type) { case JobQueueItemType.default: return { @@ -61,17 +61,9 @@ export function jobItemWorkReq(job: JobQueueItem, metrics: Metrics | null): BlsW })), }; case JobQueueItemType.sameMessage: { - // This is slow code on main thread (mainly signature deserialization + group check). - // Ideally it can be taken off-thread, but in the mean time, keep track of total time spent here. - // As of July 2024, for a node subscribing to all subnets, with 1 signature per validator per epoch, - // it takes around 2.02 min to perform this operation for a single epoch. - // cpu profile on main thread has 250s idle so this only works until we reach 3M validators - // However, for normal node with only 2 to 7 subnet subscriptions per epoch this works until 27M validators - // and not a problem in the near future - // this is monitored on v1.21.0 https://github.com/ChainSafe/lodestar/pull/6894/files#r1687359225 - const timer = metrics?.blsThreadPool.aggregateWithRandomnessMainThreadDuration.startTimer(); - const {pk, sig} = aggregateWithRandomness(job.sets.map((set) => ({pk: set.publicKey, sig: set.signature}))); - timer?.(); + const {pk, sig} = await asyncAggregateWithRandomness( + job.sets.map((set) => ({pk: set.publicKey, sig: set.signature})) + ); return { opts: job.opts, diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index f15e195faa20..ac2cca319775 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -497,11 +497,6 @@ export function createLodestarMetrics( name: "lodestar_bls_thread_pool_batchable_sig_sets_total", help: "Count of total batchable signature sets", }), - aggregateWithRandomnessMainThreadDuration: register.histogram({ - name: "lodestar_bls_thread_pool_aggregate_with_randomness_main_thread_time_seconds", - help: "Total time performing aggregateWithRandomness on main thread", - buckets: [0.001, 0.005, 0.01, 0.1], - }), pubkeysAggregationMainThreadDuration: register.histogram({ name: "lodestar_bls_thread_pool_pubkeys_aggregation_main_thread_time_seconds", help: "Total time spent aggregating pubkeys on main thread", diff --git a/packages/cli/package.json b/packages/cli/package.json index 3634ccd84424..40a58a43c754 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -53,7 +53,7 @@ "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", "@chainsafe/bls-keystore": "^3.1.0", - "@chainsafe/blst": "^2.1.0", + "@chainsafe/blst": "^2.2.0", "@chainsafe/discv5": "^9.0.0", "@chainsafe/enr": "^3.0.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", diff --git a/packages/flare/package.json b/packages/flare/package.json index f8bd37f5abb5..0c073c431f38 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -59,7 +59,7 @@ ], "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", - "@chainsafe/blst": "^2.1.0", + "@chainsafe/blst": "^2.2.0", "@lodestar/api": "^1.22.0", "@lodestar/config": "^1.22.0", "@lodestar/params": "^1.22.0", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 80a6cf45c28f..a836d742eb8e 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -59,7 +59,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/as-sha256": "^0.5.0", - "@chainsafe/blst": "^2.1.0", + "@chainsafe/blst": "^2.2.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/persistent-ts": "^0.19.1", "@chainsafe/ssz": "^0.18.0", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 1b18c3b5a33e..dbb15817cd2a 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -58,7 +58,7 @@ ], "dependencies": { "@chainsafe/bls-keystore": "^3.1.0", - "@chainsafe/blst": "^2.1.0", + "@chainsafe/blst": "^2.2.0", "@lodestar/params": "^1.22.0", "@lodestar/utils": "^1.22.0", "axios": "^1.3.4", diff --git a/packages/validator/package.json b/packages/validator/package.json index a781d62b0111..7cd6f06a626b 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -45,7 +45,7 @@ "blockchain" ], "dependencies": { - "@chainsafe/blst": "^2.1.0", + "@chainsafe/blst": "^2.2.0", "@chainsafe/ssz": "^0.18.0", "@lodestar/api": "^1.22.0", "@lodestar/config": "^1.22.0", diff --git a/yarn.lock b/yarn.lock index a9cb9ebe4fdc..846335c80676 100644 --- a/yarn.lock +++ b/yarn.lock @@ -399,40 +399,40 @@ "@chainsafe/bls-keygen" "^0.4.0" bls-eth-wasm "^0.4.8" -"@chainsafe/blst-darwin-arm64@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-arm64/-/blst-darwin-arm64-2.1.0.tgz#8871d62dc0402df30adbd6f52fbbd02d59f3c5ff" - integrity sha512-7iPRlSbQxEZ2AblmkFLuhnVPUipvA0UenEaUCaLC1MhGFpSwy5bSrF8Krs/E++GN3p2LVz7ZH3tlDfFL0z1EvQ== +"@chainsafe/blst-darwin-arm64@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-arm64/-/blst-darwin-arm64-2.2.0.tgz#0ab9083805c308106c2f2107df1e6376d9190b1b" + integrity sha512-BOOy2KHbV028cioPWaAMqHdLRKd6/3XyEmUEcQC2E/SpyYLdNcaKiBUYIU4pT9CrWBbJJxX68UI+3vZVg0M8/w== -"@chainsafe/blst-darwin-x64@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-x64/-/blst-darwin-x64-2.1.0.tgz#8fe58d92b72b1b872f8b687a0aad8beda3e09072" - integrity sha512-aeoidOpOYVmRFeHVm1p/Axd6CfqWpr6SIift216/HTDBTiuJCGSJqHzk9RHf7gzkr6WtxO7g/6AtkagZA2VPFg== +"@chainsafe/blst-darwin-x64@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-x64/-/blst-darwin-x64-2.2.0.tgz#231943a7736f3f89d35e03fec890b7809c98ff1a" + integrity sha512-jG64cwIdPT7u/haRrW26tWCpfMfHBQCfGY169mFQifCwO4VEwvaiVBPOh5olFis6LjpcmD+O0jpM8GqrnsmUHQ== -"@chainsafe/blst-linux-arm64-gnu@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-gnu/-/blst-linux-arm64-gnu-2.1.0.tgz#323789a10679cf81813b1e664ef4187a2e941cff" - integrity sha512-d2zgqoJOqkWg2sZbNR7pv8f+oYPOJmnMu46Uulm6NkW3iYNZIc2KkVjBXGYk7xJ+U8ZEzb7KZ7gRB9315sWBcg== +"@chainsafe/blst-linux-arm64-gnu@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-gnu/-/blst-linux-arm64-gnu-2.2.0.tgz#721aeec63e8e02aba3358a0084c095403a5438fa" + integrity sha512-L8xV2uuLn8we76vdzfryS9ePdheuZrmY6yArGUFaF1Uzcwml6V1/VvyPl9/uooo/YfVRIrvF/D+lQfI2GFAnhw== -"@chainsafe/blst-linux-arm64-musl@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-musl/-/blst-linux-arm64-musl-2.1.0.tgz#4a308d6b1f71a57a6ecc6cc0531746f5cd8ae3d0" - integrity sha512-w+KiL8ViLXigZVS++tdCwnMBnbc4HXb8claKOnlCppE1rAeF0Dt186AU2TRpqOop3QoOqckqvsguR9iQwZlTUw== +"@chainsafe/blst-linux-arm64-musl@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-musl/-/blst-linux-arm64-musl-2.2.0.tgz#dbbabaab93156548c86e2b2b3a1d27160b715000" + integrity sha512-0Vn0luxLYVgC3lvWT1MapFHSAoz99PldqjhilXTGv0AcAk/X5LXPH2RC9Dp2KJGqthyUkpbk1j47jUBfBI+BIg== -"@chainsafe/blst-linux-x64-gnu@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-gnu/-/blst-linux-x64-gnu-2.1.0.tgz#c015f9f25aab10bba7720518ba9dc19bb850dcc3" - integrity sha512-2xdOIkkJTvi+/gUoiPQO+p+2o19pixLsH5BOrwxY+EABLL6wxZ82w5LatV3x27YJTk7PbAlyT36n7CjmzaZ/tw== +"@chainsafe/blst-linux-x64-gnu@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-gnu/-/blst-linux-x64-gnu-2.2.0.tgz#9f8ab825621b75227c75bb75d369d3d42e91fa74" + integrity sha512-gEY/z2SDBA7kXtFEI9VNhWTJAIjx16jdeAyCaS2k4ACGurWZaWk+Ee4KniTsr4WieSqeuNTUr7Pdja0Sr4EKNQ== -"@chainsafe/blst-linux-x64-musl@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-musl/-/blst-linux-x64-musl-2.1.0.tgz#da4ac690cc3b59bc21c4578d30502490c044f7fb" - integrity sha512-/ddO38KkTTgTmXBLAubU1fjUWcQy90sdUi0IoRm5RprdpXvTSGZ1m8XrcxwEYkUO+KpnacOuU0UDwerHMJl4DA== +"@chainsafe/blst-linux-x64-musl@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-musl/-/blst-linux-x64-musl-2.2.0.tgz#11e99ac12b0f83cad68da56f4e9cfc4aa403a2e6" + integrity sha512-58GKtiUmtVSuerRzPEcMNQZpICPboBKFnL7+1Wo+PSuajkvbae7tEFrFTtWeMoKIPgOEsPMnk96LF+0yNgavUg== -"@chainsafe/blst-win32-x64-msvc@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-win32-x64-msvc/-/blst-win32-x64-msvc-2.1.0.tgz#edaff899194caa4e40901af90779721673671631" - integrity sha512-wSRVGoLrluus38fmYYS0ft3VSG2EaeeWvb7yxvrAS8xUsaRFRClYo/3kaEHR3D9B9Nu5wiuWfob6DoM3w9deLw== +"@chainsafe/blst-win32-x64-msvc@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-win32-x64-msvc/-/blst-win32-x64-msvc-2.2.0.tgz#f32b164721ff5edc279f6d6cd0fffde0ad2fe16c" + integrity sha512-UFrZshl4dfX5Uh2zeKXAZtrkQ+otczHMON2tsrapQNICWmfHZrzE6pKuBL+9QeGAbgflwpbz7+D5nQRDpiuHxQ== "@chainsafe/blst@^0.2.0": version "0.2.11" @@ -443,18 +443,18 @@ node-fetch "^2.6.1" node-gyp "^8.4.0" -"@chainsafe/blst@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-2.1.0.tgz#1df4fa8e390db5c3cceed673b57468e23b4da36f" - integrity sha512-oY5k4whglgVOkisfujO0s1QgCOp3N/J3GogRbHhuNLrf6KN0zs1C3pKHg66EQhQqWVYnFY2Shx2s71/NFD7y+A== +"@chainsafe/blst@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-2.2.0.tgz#ced8b861b94934e3c1c53e173c3e1205d775d93b" + integrity sha512-VBaQoNE2a9d9+skAjQKv3Suk0yGKqp3mZM0YWYJNPj/Ae/f6lAyeVSgKqo2LrsNQBzD/LqrJLKUY8rJT3vDKLA== optionalDependencies: - "@chainsafe/blst-darwin-arm64" "2.1.0" - "@chainsafe/blst-darwin-x64" "2.1.0" - "@chainsafe/blst-linux-arm64-gnu" "2.1.0" - "@chainsafe/blst-linux-arm64-musl" "2.1.0" - "@chainsafe/blst-linux-x64-gnu" "2.1.0" - "@chainsafe/blst-linux-x64-musl" "2.1.0" - "@chainsafe/blst-win32-x64-msvc" "2.1.0" + "@chainsafe/blst-darwin-arm64" "2.2.0" + "@chainsafe/blst-darwin-x64" "2.2.0" + "@chainsafe/blst-linux-arm64-gnu" "2.2.0" + "@chainsafe/blst-linux-arm64-musl" "2.2.0" + "@chainsafe/blst-linux-x64-gnu" "2.2.0" + "@chainsafe/blst-linux-x64-musl" "2.2.0" + "@chainsafe/blst-win32-x64-msvc" "2.2.0" "@chainsafe/discv5@^9.0.0": version "9.0.0" From 558ec2fdd26329046ab867288a0992057a6e4992 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 29 Oct 2024 20:59:26 +0000 Subject: [PATCH 184/259] feat: track block production selection results and payload values (#7203) * feat: track block production selection source and reason * Rename reason to builder_censorship * Fix metric name * Add metric to track execution payload value * Update metric descriptions * Remove ETH suffix from payload values * Rename metric * Update import path * Return block selection result * Reorder if statements --- .../src/api/impl/validator/index.ts | 81 ++++++++++++++++++- .../src/api/impl/validator/utils.ts | 27 +++++-- .../beacon-node/src/metrics/metrics/beacon.ts | 16 ++++ packages/utils/src/format.ts | 9 ++- 4 files changed, 122 insertions(+), 11 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index b470a58aa198..2b558577c22c 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -47,7 +47,15 @@ import { getValidatorStatus, } from "@lodestar/types"; import {ExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; -import {fromHex, toHex, resolveOrRacePromises, prettyWeiToEth, toRootHex} from "@lodestar/utils"; +import { + fromHex, + toHex, + resolveOrRacePromises, + prettyWeiToEth, + toRootHex, + TimeoutError, + formatWeiToEth, +} from "@lodestar/utils"; import { AttestationError, AttestationErrorCode, @@ -115,6 +123,41 @@ type ProduceFullOrBlindedBlockOrContentsRes = {executionPayloadSource: ProducedB | (ProduceBlindedBlockRes & {executionPayloadBlinded: true}) ); +/** + * Engine block selection reasons tracked in metrics + */ +export enum EngineBlockSelectionReason { + BuilderDisabled = "builder_disabled", + BuilderError = "builder_error", + BuilderTimeout = "builder_timeout", + BuilderPending = "builder_pending", + BuilderNoBid = "builder_no_bid", + BuilderCensorship = "builder_censorship", + BlockValue = "block_value", + EnginePreferred = "engine_preferred", +} + +/** + * Builder block selection reasons tracked in metrics + */ +export enum BuilderBlockSelectionReason { + EngineDisabled = "engine_disabled", + EngineError = "engine_error", + EnginePending = "engine_pending", + BlockValue = "block_value", + BuilderPreferred = "builder_preferred", +} + +export type BlockSelectionResult = + | { + source: ProducedBlockSource.engine; + reason: EngineBlockSelectionReason; + } + | { + source: ProducedBlockSource.builder; + reason: BuilderBlockSelectionReason; + }; + /** * Server implementation for handling validator duties. * See `@lodestar/validator/src/api` for the client implementation). @@ -417,6 +460,7 @@ export function getValidatorApi( metrics?.blockProductionSuccess.inc({source}); metrics?.blockProductionNumAggregated.observe({source}, block.body.attestations.length); + metrics?.blockProductionExecutionPayloadValue.observe({source}, Number(formatWeiToEth(executionPayloadValue))); logger.verbose("Produced blinded block", { slot, executionPayloadValue, @@ -491,6 +535,7 @@ export function getValidatorApi( metrics?.blockProductionSuccess.inc({source}); metrics?.blockProductionNumAggregated.observe({source}, block.body.attestations.length); + metrics?.blockProductionExecutionPayloadValue.observe({source}, Number(formatWeiToEth(executionPayloadValue))); logger.verbose("Produced execution block", { slot, executionPayloadValue, @@ -694,6 +739,11 @@ export function getValidatorApi( ...getBlockValueLogInfo(engine.value), }); + metrics?.blockProductionSelectionResults.inc({ + source: ProducedBlockSource.engine, + reason: EngineBlockSelectionReason.BuilderCensorship, + }); + return {...engine.value, executionPayloadBlinded: false, executionPayloadSource: ProducedBlockSource.engine}; } @@ -704,6 +754,16 @@ export function getValidatorApi( ...getBlockValueLogInfo(builder.value), }); + metrics?.blockProductionSelectionResults.inc({ + source: ProducedBlockSource.builder, + reason: + isEngineEnabled === false + ? BuilderBlockSelectionReason.EngineDisabled + : engine.status === "pending" + ? BuilderBlockSelectionReason.EnginePending + : BuilderBlockSelectionReason.EngineError, + }); + return {...builder.value, executionPayloadBlinded: true, executionPayloadSource: ProducedBlockSource.builder}; } @@ -714,16 +774,33 @@ export function getValidatorApi( ...getBlockValueLogInfo(engine.value), }); + metrics?.blockProductionSelectionResults.inc({ + source: ProducedBlockSource.engine, + reason: + isBuilderEnabled === false + ? EngineBlockSelectionReason.BuilderDisabled + : builder.status === "pending" + ? EngineBlockSelectionReason.BuilderPending + : builder.reason instanceof NoBidReceived + ? EngineBlockSelectionReason.BuilderNoBid + : builder.reason instanceof TimeoutError + ? EngineBlockSelectionReason.BuilderTimeout + : EngineBlockSelectionReason.BuilderError, + }); + return {...engine.value, executionPayloadBlinded: false, executionPayloadSource: ProducedBlockSource.engine}; } if (engine.status === "fulfilled" && builder.status === "fulfilled") { - const executionPayloadSource = selectBlockProductionSource({ + const result = selectBlockProductionSource({ builderBlockValue: builder.value.executionPayloadValue + builder.value.consensusBlockValue, engineBlockValue: engine.value.executionPayloadValue + engine.value.consensusBlockValue, builderBoostFactor, builderSelection, }); + const executionPayloadSource = result.source; + + metrics?.blockProductionSelectionResults.inc(result); logger.info(`Selected ${executionPayloadSource} block`, { ...loggerContext, diff --git a/packages/beacon-node/src/api/impl/validator/utils.ts b/packages/beacon-node/src/api/impl/validator/utils.ts index 418e0a052787..36accf34cfda 100644 --- a/packages/beacon-node/src/api/impl/validator/utils.ts +++ b/packages/beacon-node/src/api/impl/validator/utils.ts @@ -3,6 +3,7 @@ import {ATTESTATION_SUBNET_COUNT} from "@lodestar/params"; import {routes} from "@lodestar/api"; import {BLSPubkey, CommitteeIndex, ProducedBlockSource, Slot, ValidatorIndex} from "@lodestar/types"; import {MAX_BUILDER_BOOST_FACTOR} from "@lodestar/validator"; +import {BlockSelectionResult, BuilderBlockSelectionReason, EngineBlockSelectionReason} from "./index.js"; export function computeSubnetForCommitteesAtSlot( slot: Slot, @@ -54,21 +55,31 @@ export function selectBlockProductionSource({ engineBlockValue: bigint; builderBlockValue: bigint; builderBoostFactor: bigint; -}): ProducedBlockSource { +}): BlockSelectionResult { switch (builderSelection) { case routes.validator.BuilderSelection.ExecutionAlways: case routes.validator.BuilderSelection.ExecutionOnly: - return ProducedBlockSource.engine; + return {source: ProducedBlockSource.engine, reason: EngineBlockSelectionReason.EnginePreferred}; case routes.validator.BuilderSelection.Default: - case routes.validator.BuilderSelection.MaxProfit: - return builderBoostFactor !== MAX_BUILDER_BOOST_FACTOR && - (builderBoostFactor === BigInt(0) || engineBlockValue >= (builderBlockValue * builderBoostFactor) / BigInt(100)) - ? ProducedBlockSource.engine - : ProducedBlockSource.builder; + case routes.validator.BuilderSelection.MaxProfit: { + if (builderBoostFactor === BigInt(0)) { + return {source: ProducedBlockSource.engine, reason: EngineBlockSelectionReason.EnginePreferred}; + } + + if (builderBoostFactor === MAX_BUILDER_BOOST_FACTOR) { + return {source: ProducedBlockSource.builder, reason: BuilderBlockSelectionReason.BuilderPreferred}; + } + + if (engineBlockValue >= (builderBlockValue * builderBoostFactor) / BigInt(100)) { + return {source: ProducedBlockSource.engine, reason: EngineBlockSelectionReason.BlockValue}; + } + + return {source: ProducedBlockSource.builder, reason: BuilderBlockSelectionReason.BlockValue}; + } case routes.validator.BuilderSelection.BuilderAlways: case routes.validator.BuilderSelection.BuilderOnly: - return ProducedBlockSource.builder; + return {source: ProducedBlockSource.builder, reason: BuilderBlockSelectionReason.BuilderPreferred}; } } diff --git a/packages/beacon-node/src/metrics/metrics/beacon.ts b/packages/beacon-node/src/metrics/metrics/beacon.ts index 685fd56674ad..b9a02a3b2059 100644 --- a/packages/beacon-node/src/metrics/metrics/beacon.ts +++ b/packages/beacon-node/src/metrics/metrics/beacon.ts @@ -3,6 +3,11 @@ import {NotReorgedReason} from "@lodestar/fork-choice/lib/forkChoice/interface.j import {UpdateHeadOpt} from "@lodestar/fork-choice"; import {RegistryMetricCreator} from "../utils/registryMetricCreator.js"; import {BlockProductionStep, PayloadPreparationType} from "../../chain/produceBlock/index.js"; +import { + BlockSelectionResult, + BuilderBlockSelectionReason, + EngineBlockSelectionReason, +} from "../../api/impl/validator/index.js"; export type BeaconMetrics = ReturnType; @@ -160,12 +165,23 @@ export function createBeaconMetrics(register: RegistryMetricCreator) { help: "Count of blocks successfully produced", labelNames: ["source"], }), + blockProductionSelectionResults: register.gauge({ + name: "beacon_block_production_selection_results_total", + help: "Count of all block production selection results", + labelNames: ["source", "reason"], + }), blockProductionNumAggregated: register.histogram<{source: ProducedBlockSource}>({ name: "beacon_block_production_num_aggregated_total", help: "Count of all aggregated attestations in our produced block", buckets: [32, 64, 96, 128], labelNames: ["source"], }), + blockProductionExecutionPayloadValue: register.histogram<{source: ProducedBlockSource}>({ + name: "beacon_block_production_execution_payload_value", + help: "Execution payload value denominated in ETH of produced blocks", + buckets: [0.001, 0.005, 0.01, 0.03, 0.05, 0.07, 0.1, 0.3, 0.5, 1], + labelNames: ["source"], + }), blockProductionCaches: { producedBlockRoot: register.gauge({ diff --git a/packages/utils/src/format.ts b/packages/utils/src/format.ts index 5567eb89cc68..b36412072720 100644 --- a/packages/utils/src/format.ts +++ b/packages/utils/src/format.ts @@ -44,11 +44,18 @@ export function formatBigDecimal(numerator: bigint, denominator: bigint, maxDeci // display upto 5 decimal places const MAX_DECIMAL_FACTOR = BigInt("100000"); +/** + * Format wei as ETH, with up to 5 decimals + */ +export function formatWeiToEth(wei: bigint): string { + return formatBigDecimal(wei, ETH_TO_WEI, MAX_DECIMAL_FACTOR); +} + /** * Format wei as ETH, with up to 5 decimals and append ' ETH' */ export function prettyWeiToEth(wei: bigint): string { - return `${formatBigDecimal(wei, ETH_TO_WEI, MAX_DECIMAL_FACTOR)} ETH`; + return `${formatWeiToEth(wei)} ETH`; } /** From 70f67bbfe9d4727b3756e85186912055319ecf6f Mon Sep 17 00:00:00 2001 From: Cayman Date: Tue, 29 Oct 2024 17:02:01 -0400 Subject: [PATCH 185/259] chore: bump package versions to 1.23.0 --- lerna.json | 2 +- packages/api/package.json | 10 ++++----- packages/beacon-node/package.json | 28 +++++++++++++------------- packages/cli/package.json | 26 ++++++++++++------------ packages/config/package.json | 8 ++++---- packages/db/package.json | 8 ++++---- packages/flare/package.json | 14 ++++++------- packages/fork-choice/package.json | 12 +++++------ packages/light-client/package.json | 12 +++++------ packages/logger/package.json | 6 +++--- packages/params/package.json | 2 +- packages/prover/package.json | 18 ++++++++--------- packages/reqresp/package.json | 12 +++++------ packages/spec-test-util/package.json | 4 ++-- packages/state-transition/package.json | 12 +++++------ packages/test-utils/package.json | 6 +++--- packages/types/package.json | 4 ++-- packages/utils/package.json | 2 +- packages/validator/package.json | 18 ++++++++--------- 19 files changed, 102 insertions(+), 102 deletions(-) diff --git a/lerna.json b/lerna.json index 0ffc65fe5402..6d76d7f4a488 100644 --- a/lerna.json +++ b/lerna.json @@ -4,7 +4,7 @@ ], "npmClient": "yarn", "useNx": true, - "version": "1.22.0", + "version": "1.23.0", "stream": true, "command": { "version": { diff --git a/packages/api/package.json b/packages/api/package.json index 1758f1fe47cf..a787147f6f07 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.22.0", + "version": "1.23.0", "type": "module", "exports": { ".": { @@ -72,10 +72,10 @@ "dependencies": { "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/ssz": "^0.18.0", - "@lodestar/config": "^1.22.0", - "@lodestar/params": "^1.22.0", - "@lodestar/types": "^1.22.0", - "@lodestar/utils": "^1.22.0", + "@lodestar/config": "^1.23.0", + "@lodestar/params": "^1.23.0", + "@lodestar/types": "^1.23.0", + "@lodestar/utils": "^1.23.0", "eventsource": "^2.0.2", "qs": "^6.11.1" }, diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 450c6e119023..7e400b69ad3f 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.22.0", + "version": "1.23.0", "type": "module", "exports": { ".": { @@ -103,9 +103,9 @@ "@chainsafe/libp2p-noise": "^15.0.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/prometheus-gc-stats": "^1.0.0", + "@chainsafe/pubkey-index-map": "2.0.0", "@chainsafe/ssz": "^0.18.0", "@chainsafe/threads": "^1.11.1", - "@chainsafe/pubkey-index-map": "2.0.0", "@ethersproject/abi": "^5.7.0", "@fastify/bearer-auth": "^10.0.1", "@fastify/cors": "^10.0.1", @@ -120,18 +120,18 @@ "@libp2p/peer-id-factory": "^4.1.0", "@libp2p/prometheus-metrics": "^3.0.21", "@libp2p/tcp": "9.0.23", - "@lodestar/api": "^1.22.0", - "@lodestar/config": "^1.22.0", - "@lodestar/db": "^1.22.0", - "@lodestar/fork-choice": "^1.22.0", - "@lodestar/light-client": "^1.22.0", - "@lodestar/logger": "^1.22.0", - "@lodestar/params": "^1.22.0", - "@lodestar/reqresp": "^1.22.0", - "@lodestar/state-transition": "^1.22.0", - "@lodestar/types": "^1.22.0", - "@lodestar/utils": "^1.22.0", - "@lodestar/validator": "^1.22.0", + "@lodestar/api": "^1.23.0", + "@lodestar/config": "^1.23.0", + "@lodestar/db": "^1.23.0", + "@lodestar/fork-choice": "^1.23.0", + "@lodestar/light-client": "^1.23.0", + "@lodestar/logger": "^1.23.0", + "@lodestar/params": "^1.23.0", + "@lodestar/reqresp": "^1.23.0", + "@lodestar/state-transition": "^1.23.0", + "@lodestar/types": "^1.23.0", + "@lodestar/utils": "^1.23.0", + "@lodestar/validator": "^1.23.0", "@multiformats/multiaddr": "^12.1.3", "c-kzg": "^2.1.2", "datastore-core": "^9.1.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 40a58a43c754..6f44a6c2926e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@chainsafe/lodestar", - "version": "1.22.0", + "version": "1.23.0", "description": "Command line interface for lodestar", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -62,17 +62,17 @@ "@libp2p/crypto": "^4.1.0", "@libp2p/peer-id": "^4.1.0", "@libp2p/peer-id-factory": "^4.1.0", - "@lodestar/api": "^1.22.0", - "@lodestar/beacon-node": "^1.22.0", - "@lodestar/config": "^1.22.0", - "@lodestar/db": "^1.22.0", - "@lodestar/light-client": "^1.22.0", - "@lodestar/logger": "^1.22.0", - "@lodestar/params": "^1.22.0", - "@lodestar/state-transition": "^1.22.0", - "@lodestar/types": "^1.22.0", - "@lodestar/utils": "^1.22.0", - "@lodestar/validator": "^1.22.0", + "@lodestar/api": "^1.23.0", + "@lodestar/beacon-node": "^1.23.0", + "@lodestar/config": "^1.23.0", + "@lodestar/db": "^1.23.0", + "@lodestar/light-client": "^1.23.0", + "@lodestar/logger": "^1.23.0", + "@lodestar/params": "^1.23.0", + "@lodestar/state-transition": "^1.23.0", + "@lodestar/types": "^1.23.0", + "@lodestar/utils": "^1.23.0", + "@lodestar/validator": "^1.23.0", "@multiformats/multiaddr": "^12.1.3", "deepmerge": "^4.3.1", "ethers": "^6.7.0", @@ -88,7 +88,7 @@ "yargs": "^17.7.1" }, "devDependencies": { - "@lodestar/test-utils": "^1.22.0", + "@lodestar/test-utils": "^1.23.0", "@types/debug": "^4.1.7", "@types/got": "^9.6.12", "@types/inquirer": "^9.0.3", diff --git a/packages/config/package.json b/packages/config/package.json index 1c2888be0f18..aadbf9e004b2 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/config", - "version": "1.22.0", + "version": "1.23.0", "description": "Chain configuration required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -65,8 +65,8 @@ ], "dependencies": { "@chainsafe/ssz": "^0.18.0", - "@lodestar/params": "^1.22.0", - "@lodestar/utils": "^1.22.0", - "@lodestar/types": "^1.22.0" + "@lodestar/params": "^1.23.0", + "@lodestar/types": "^1.23.0", + "@lodestar/utils": "^1.23.0" } } diff --git a/packages/db/package.json b/packages/db/package.json index 2b2098a9d6c1..370caaa5f8c9 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/db", - "version": "1.22.0", + "version": "1.23.0", "description": "DB modules of Lodestar", "author": "ChainSafe Systems", "homepage": "https://github.com/ChainSafe/lodestar#readme", @@ -36,12 +36,12 @@ }, "dependencies": { "@chainsafe/ssz": "^0.18.0", - "@lodestar/config": "^1.22.0", - "@lodestar/utils": "^1.22.0", + "@lodestar/config": "^1.23.0", + "@lodestar/utils": "^1.23.0", "classic-level": "^1.4.1", "it-all": "^3.0.4" }, "devDependencies": { - "@lodestar/logger": "^1.22.0" + "@lodestar/logger": "^1.23.0" } } diff --git a/packages/flare/package.json b/packages/flare/package.json index 0c073c431f38..8239eec52e2a 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/flare", - "version": "1.22.0", + "version": "1.23.0", "description": "Beacon chain debugging tool", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -60,12 +60,12 @@ "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", "@chainsafe/blst": "^2.2.0", - "@lodestar/api": "^1.22.0", - "@lodestar/config": "^1.22.0", - "@lodestar/params": "^1.22.0", - "@lodestar/state-transition": "^1.22.0", - "@lodestar/types": "^1.22.0", - "@lodestar/utils": "^1.22.0", + "@lodestar/api": "^1.23.0", + "@lodestar/config": "^1.23.0", + "@lodestar/params": "^1.23.0", + "@lodestar/state-transition": "^1.23.0", + "@lodestar/types": "^1.23.0", + "@lodestar/utils": "^1.23.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 9a6838bfcf3e..1ee9d043c925 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.22.0", + "version": "1.23.0", "type": "module", "exports": "./lib/index.js", "types": "./lib/index.d.ts", @@ -37,11 +37,11 @@ }, "dependencies": { "@chainsafe/ssz": "^0.18.0", - "@lodestar/config": "^1.22.0", - "@lodestar/params": "^1.22.0", - "@lodestar/state-transition": "^1.22.0", - "@lodestar/types": "^1.22.0", - "@lodestar/utils": "^1.22.0" + "@lodestar/config": "^1.23.0", + "@lodestar/params": "^1.23.0", + "@lodestar/state-transition": "^1.23.0", + "@lodestar/types": "^1.23.0", + "@lodestar/utils": "^1.23.0" }, "keywords": [ "ethereum", diff --git a/packages/light-client/package.json b/packages/light-client/package.json index 54ab479f2d88..c942ff07ed44 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.22.0", + "version": "1.23.0", "type": "module", "exports": { ".": { @@ -77,11 +77,11 @@ "@chainsafe/blst": "^0.2.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/ssz": "^0.18.0", - "@lodestar/api": "^1.22.0", - "@lodestar/config": "^1.22.0", - "@lodestar/params": "^1.22.0", - "@lodestar/types": "^1.22.0", - "@lodestar/utils": "^1.22.0", + "@lodestar/api": "^1.23.0", + "@lodestar/config": "^1.23.0", + "@lodestar/params": "^1.23.0", + "@lodestar/types": "^1.23.0", + "@lodestar/utils": "^1.23.0", "mitt": "^3.0.0" }, "devDependencies": { diff --git a/packages/logger/package.json b/packages/logger/package.json index 3d6ee5a0d874..b9e9beef39be 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.22.0", + "version": "1.23.0", "type": "module", "exports": { ".": { @@ -66,14 +66,14 @@ }, "types": "lib/index.d.ts", "dependencies": { - "@lodestar/utils": "^1.22.0", + "@lodestar/utils": "^1.23.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.22.0", + "@lodestar/test-utils": "^1.23.0", "@types/triple-beam": "^1.3.2", "triple-beam": "^1.3.0" }, diff --git a/packages/params/package.json b/packages/params/package.json index 33b8415170f1..ce78e826ef18 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/params", - "version": "1.22.0", + "version": "1.23.0", "description": "Chain parameters required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", diff --git a/packages/prover/package.json b/packages/prover/package.json index 9bfe7f21e480..eee42f4226c2 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.22.0", + "version": "1.23.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.22.0", - "@lodestar/config": "^1.22.0", - "@lodestar/light-client": "^1.22.0", - "@lodestar/logger": "^1.22.0", - "@lodestar/params": "^1.22.0", - "@lodestar/types": "^1.22.0", - "@lodestar/utils": "^1.22.0", + "@lodestar/api": "^1.23.0", + "@lodestar/config": "^1.23.0", + "@lodestar/light-client": "^1.23.0", + "@lodestar/logger": "^1.23.0", + "@lodestar/params": "^1.23.0", + "@lodestar/types": "^1.23.0", + "@lodestar/utils": "^1.23.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.22.0", + "@lodestar/test-utils": "^1.23.0", "@types/http-proxy": "^1.17.10", "@types/yargs": "^17.0.24", "axios": "^1.3.4", diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index 9bd9775ba2c0..981016a363df 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.22.0", + "version": "1.23.0", "type": "module", "exports": { ".": { @@ -54,9 +54,9 @@ "dependencies": { "@chainsafe/fast-crc32c": "^4.1.1", "@libp2p/interface": "^1.3.0", - "@lodestar/config": "^1.22.0", - "@lodestar/params": "^1.22.0", - "@lodestar/utils": "^1.22.0", + "@lodestar/config": "^1.23.0", + "@lodestar/params": "^1.23.0", + "@lodestar/utils": "^1.23.0", "it-all": "^3.0.4", "it-pipe": "^3.0.1", "snappy": "^7.2.2", @@ -65,8 +65,8 @@ "uint8arraylist": "^2.4.7" }, "devDependencies": { - "@lodestar/logger": "^1.22.0", - "@lodestar/types": "^1.22.0", + "@lodestar/logger": "^1.23.0", + "@lodestar/types": "^1.23.0", "libp2p": "1.4.3" }, "peerDependencies": { diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index 501d13024159..6f58e55d2201 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.22.0", + "version": "1.23.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.22.0", + "@lodestar/utils": "^1.23.0", "axios": "^1.3.4", "rimraf": "^4.4.1", "snappyjs": "^0.7.0", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index a836d742eb8e..1c1d0f0c7754 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.22.0", + "version": "1.23.0", "type": "module", "exports": { ".": { @@ -62,13 +62,13 @@ "@chainsafe/blst": "^2.2.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/persistent-ts": "^0.19.1", + "@chainsafe/pubkey-index-map": "2.0.0", "@chainsafe/ssz": "^0.18.0", "@chainsafe/swap-or-not-shuffle": "^0.0.2", - "@lodestar/config": "^1.22.0", - "@lodestar/params": "^1.22.0", - "@lodestar/types": "^1.22.0", - "@chainsafe/pubkey-index-map": "2.0.0", - "@lodestar/utils": "^1.22.0", + "@lodestar/config": "^1.23.0", + "@lodestar/params": "^1.23.0", + "@lodestar/types": "^1.23.0", + "@lodestar/utils": "^1.23.0", "bigint-buffer": "^1.1.5", "immutable": "^4.3.2" }, diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index dbb15817cd2a..efc9c96ff5b1 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.22.0", + "version": "1.23.0", "description": "Test utilities reused across other packages", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -59,8 +59,8 @@ "dependencies": { "@chainsafe/bls-keystore": "^3.1.0", "@chainsafe/blst": "^2.2.0", - "@lodestar/params": "^1.22.0", - "@lodestar/utils": "^1.22.0", + "@lodestar/params": "^1.23.0", + "@lodestar/utils": "^1.23.0", "axios": "^1.3.4", "testcontainers": "^10.2.1", "tmp": "^0.2.1", diff --git a/packages/types/package.json b/packages/types/package.json index 89474e8597a1..9201ef2f4e88 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.22.0", + "version": "1.23.0", "type": "module", "exports": { ".": { @@ -74,7 +74,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/ssz": "^0.18.0", - "@lodestar/params": "^1.22.0", + "@lodestar/params": "^1.23.0", "ethereum-cryptography": "^2.0.0" }, "keywords": [ diff --git a/packages/utils/package.json b/packages/utils/package.json index 6c8218741e30..9b6f5e797e68 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.22.0", + "version": "1.23.0", "type": "module", "exports": "./lib/index.js", "files": [ diff --git a/packages/validator/package.json b/packages/validator/package.json index 7cd6f06a626b..9cbb560965fd 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/validator", - "version": "1.22.0", + "version": "1.23.0", "description": "A Typescript implementation of the validator client", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -47,17 +47,17 @@ "dependencies": { "@chainsafe/blst": "^2.2.0", "@chainsafe/ssz": "^0.18.0", - "@lodestar/api": "^1.22.0", - "@lodestar/config": "^1.22.0", - "@lodestar/db": "^1.22.0", - "@lodestar/params": "^1.22.0", - "@lodestar/state-transition": "^1.22.0", - "@lodestar/types": "^1.22.0", - "@lodestar/utils": "^1.22.0", + "@lodestar/api": "^1.23.0", + "@lodestar/config": "^1.23.0", + "@lodestar/db": "^1.23.0", + "@lodestar/params": "^1.23.0", + "@lodestar/state-transition": "^1.23.0", + "@lodestar/types": "^1.23.0", + "@lodestar/utils": "^1.23.0", "strict-event-emitter-types": "^2.0.0" }, "devDependencies": { - "@lodestar/test-utils": "^1.22.0", + "@lodestar/test-utils": "^1.23.0", "bigint-buffer": "^1.1.5", "rimraf": "^4.4.1" } From 99c0dcb81bb2a9c238fb1094ea0b4ffeee646547 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 30 Oct 2024 18:13:00 +0000 Subject: [PATCH 186/259] feat: add keymanager endpoint to retrieve proposer config (#7210) * feat: add keymanager endpoint to retrieve proposer config * Do not return empty builder config * Check all builder proposer config values * Fix settings builder config if undefined * Fix builder config parsing * Use ssz type to handle json serialization Default parsing can't handle BigInt * Revert "Use ssz type to handle json serialization" This reverts commit 01fcea702e32e1f97a0aa351b6623d94dc0fbcea. * Fix boost factor json serialization * Remove unused import * Update test data * Update proposer config test --- packages/api/src/keymanager/index.ts | 1 + packages/api/src/keymanager/routes.ts | 33 +++++++++++++++++++ packages/api/test/unit/keymanager/testData.ts | 15 +++++++++ .../cli/src/cmds/validator/keymanager/impl.ts | 18 ++++++++++ packages/cli/src/util/proposerConfig.ts | 13 +++++--- .../validator/parseProposerConfig.test.ts | 3 +- .../validator/src/services/validatorStore.ts | 4 ++- 7 files changed, 79 insertions(+), 8 deletions(-) diff --git a/packages/api/src/keymanager/index.ts b/packages/api/src/keymanager/index.ts index 1ffcaef897eb..44252acce494 100644 --- a/packages/api/src/keymanager/index.ts +++ b/packages/api/src/keymanager/index.ts @@ -18,6 +18,7 @@ export type { GraffitiData, GasLimitData, BuilderBoostFactorData, + ProposerConfigResponse, } from "./routes.js"; export type {ApiClient}; diff --git a/packages/api/src/keymanager/routes.ts b/packages/api/src/keymanager/routes.ts index 0db096d14e83..c31ae5a04454 100644 --- a/packages/api/src/keymanager/routes.ts +++ b/packages/api/src/keymanager/routes.ts @@ -109,6 +109,17 @@ export type SignerDefinition = { export type RemoteSignerDefinition = Pick; +export type ProposerConfigResponse = { + graffiti?: string; + strictFeeRecipientCheck?: boolean; + feeRecipient?: string; + builder?: { + gasLimit?: number; + selection?: string; + boostFactor?: string; + }; +}; + /** * JSON serialized representation of a single keystore in EIP-2335: BLS12-381 Keystore format. * ``` @@ -356,6 +367,15 @@ export type Endpoints = { EmptyMeta >; + getProposerConfig: Endpoint< + // ⏎ + "GET", + {pubkey: PubkeyHex}, + {params: {pubkey: string}}, + ProposerConfigResponse, + EmptyMeta + >; + /** * Create a signed voluntary exit message for an active validator, identified by a public key known to the validator * client. This endpoint returns a `SignedVoluntaryExit` object, which can be used to initiate voluntary exit via the @@ -635,6 +655,19 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({params: {pubkey}}), + parseReq: ({params: {pubkey}}) => ({pubkey}), + schema: { + params: {pubkey: Schema.StringRequired}, + }, + }, + resp: JsonOnlyResponseCodec, + }, + signVoluntaryExit: { url: "/eth/v1/validator/{pubkey}/voluntary_exit", method: "POST", diff --git a/packages/api/test/unit/keymanager/testData.ts b/packages/api/test/unit/keymanager/testData.ts index bd37798c4685..6b17611d1e0b 100644 --- a/packages/api/test/unit/keymanager/testData.ts +++ b/packages/api/test/unit/keymanager/testData.ts @@ -112,4 +112,19 @@ export const testData: GenericServerTestCases = { args: {pubkey: pubkeyRand}, res: undefined, }, + getProposerConfig: { + args: {pubkey: pubkeyRand}, + res: { + data: { + graffiti: graffitiRandUtf8, + strictFeeRecipientCheck: false, + feeRecipient: ethaddressRand, + builder: { + gasLimit: gasLimitRand, + selection: "maxprofit", + boostFactor: builderBoostFactorRand.toString(), + }, + }, + }, + }, }; diff --git a/packages/cli/src/cmds/validator/keymanager/impl.ts b/packages/cli/src/cmds/validator/keymanager/impl.ts index b4233f3162cd..545f2f74f06e 100644 --- a/packages/cli/src/cmds/validator/keymanager/impl.ts +++ b/packages/cli/src/cmds/validator/keymanager/impl.ts @@ -15,6 +15,7 @@ import { GraffitiData, GasLimitData, BuilderBoostFactorData, + ProposerConfigResponse, } from "@lodestar/api/keymanager"; import {KeymanagerApiMethods as Api} from "@lodestar/api/keymanager/server"; import {Interchange, SignerType, Validator} from "@lodestar/validator"; @@ -364,6 +365,23 @@ export class KeymanagerApi implements Api { return {status: 204}; } + async getProposerConfig({pubkey}: {pubkey: PubkeyHex}): ReturnType { + const config = this.validator.validatorStore.getProposerConfig(pubkey); + + const data: ProposerConfigResponse = { + ...config, + builder: config?.builder + ? { + ...config.builder, + // Default JSON serialization can't handle BigInt + boostFactor: config.builder.boostFactor ? config.builder.boostFactor.toString() : undefined, + } + : undefined, + }; + + return {data}; + } + async signVoluntaryExit({pubkey, epoch}: {pubkey: PubkeyHex; epoch?: Epoch}): ReturnType { if (!isValidatePubkeyHex(pubkey)) { throw new ApiError(400, `Invalid pubkey ${pubkey}`); diff --git a/packages/cli/src/util/proposerConfig.ts b/packages/cli/src/util/proposerConfig.ts index 2c12ce8f8524..4cfa6fa71075 100644 --- a/packages/cli/src/util/proposerConfig.ts +++ b/packages/cli/src/util/proposerConfig.ts @@ -88,11 +88,14 @@ function parseProposerConfigSection( overrideConfig?.strictFeeRecipientCheck ?? (strict_fee_recipient_check ? stringtoBool(strict_fee_recipient_check) : undefined), feeRecipient: overrideConfig?.feeRecipient ?? (fee_recipient ? parseFeeRecipient(fee_recipient) : undefined), - builder: { - gasLimit: overrideConfig?.builder?.gasLimit ?? (gas_limit !== undefined ? Number(gas_limit) : undefined), - selection: overrideConfig?.builder?.selection ?? parseBuilderSelection(builderSelection), - boostFactor: overrideConfig?.builder?.boostFactor ?? parseBuilderBoostFactor(boost_factor), - }, + builder: + overrideConfig?.builder || builder + ? { + gasLimit: overrideConfig?.builder?.gasLimit ?? (gas_limit !== undefined ? Number(gas_limit) : undefined), + selection: overrideConfig?.builder?.selection ?? parseBuilderSelection(builderSelection), + boostFactor: overrideConfig?.builder?.boostFactor ?? parseBuilderBoostFactor(boost_factor), + } + : undefined, }; } diff --git a/packages/cli/test/unit/validator/parseProposerConfig.test.ts b/packages/cli/test/unit/validator/parseProposerConfig.test.ts index 83c8c63ef877..40fa57f7feb5 100644 --- a/packages/cli/test/unit/validator/parseProposerConfig.test.ts +++ b/packages/cli/test/unit/validator/parseProposerConfig.test.ts @@ -26,8 +26,7 @@ const testValue = { builder: { gasLimit: 35000000, selection: routes.validator.BuilderSelection.BuilderAlways, - // biome-ignore lint/correctness/noPrecisionLoss: - boostFactor: BigInt(18446744073709551616), + boostFactor: 18446744073709551616n, }, }, }, diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index dfd856b18d13..f959b4e74ff5 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -377,7 +377,9 @@ export class ValidatorStore { graffiti !== undefined || strictFeeRecipientCheck !== undefined || feeRecipient !== undefined || - builder?.gasLimit !== undefined + builder?.gasLimit !== undefined || + builder?.selection !== undefined || + builder?.boostFactor !== undefined ) { proposerConfig = {graffiti, strictFeeRecipientCheck, feeRecipient, builder}; } From 794e5ef488d3d86abb1bb280581b2ea752154314 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 1 Nov 2024 00:19:35 +0000 Subject: [PATCH 187/259] feat: add mekong network option (#7212) --- packages/cli/src/networks/index.ts | 6 +- packages/cli/src/networks/mekong.ts | 130 ++++++++++++++++++ .../config/src/chainConfig/networks/mekong.ts | 44 ++++++ packages/config/src/networks.ts | 9 +- 4 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 packages/cli/src/networks/mekong.ts create mode 100644 packages/config/src/chainConfig/networks/mekong.ts diff --git a/packages/cli/src/networks/index.ts b/packages/cli/src/networks/index.ts index e2fc9dd621b6..13e55685e353 100644 --- a/packages/cli/src/networks/index.ts +++ b/packages/cli/src/networks/index.ts @@ -22,8 +22,9 @@ import * as sepolia from "./sepolia.js"; import * as holesky from "./holesky.js"; import * as chiado from "./chiado.js"; import * as ephemery from "./ephemery.js"; +import * as mekong from "./mekong.js"; -export type NetworkName = "mainnet" | "dev" | "gnosis" | "sepolia" | "holesky" | "chiado" | "ephemery"; +export type NetworkName = "mainnet" | "dev" | "gnosis" | "sepolia" | "holesky" | "chiado" | "ephemery" | "mekong"; export const networkNames: NetworkName[] = [ "mainnet", "gnosis", @@ -31,6 +32,7 @@ export const networkNames: NetworkName[] = [ "holesky", "chiado", "ephemery", + "mekong", // Leave always as last network. The order matters for the --help printout "dev", @@ -70,6 +72,8 @@ export function getNetworkData(network: NetworkName): { return chiado; case "ephemery": return ephemery; + case "mekong": + return mekong; default: throw Error(`Network not supported: ${network}`); } diff --git a/packages/cli/src/networks/mekong.ts b/packages/cli/src/networks/mekong.ts new file mode 100644 index 000000000000..44b45cd8d7ea --- /dev/null +++ b/packages/cli/src/networks/mekong.ts @@ -0,0 +1,130 @@ +export {mekongChainConfig as chainConfig} from "@lodestar/config/networks"; + +export const depositContractDeployBlock = 0; +export const genesisFileUrl = + "https://raw.githubusercontent.com/ethpandaops/mekong-devnets/master/network-configs/devnet-0/metadata/genesis.ssz"; +export const bootnodesFileUrl = + "https://raw.githubusercontent.com/ethpandaops/mekong-devnets/master/network-configs/devnet-0/metadata/bootstrap_nodes.txt"; + +export const bootEnrs = [ + "enr:-Iq4QNDvMuJuQDFx0NERRjcJzjUlpv-MG5ea22uVCNtFbBAbYdQXcL2ylwiZYKVR4ARyHL-ZIFQ45J3UdM3bCVPzTIaGAZLeJx23gmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQJJ3h8aUO3GJHv-bdvHtsQZ2OEisutelYfGjXO4lSg8BYN1ZHCCIzI", + "enr:-LK4QNmKwqyvCkLGM2MC8dnIE5Mg_j3PvEztzwAbRT2rwa97RCjVvEApmk6E6Tcrfae-jicCz646GX0B46Ksgfk9jY4Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQPrLuUBjXUN4pFbO9NX5UmF0TXzRLFxKQYshOmGXadK34N0Y3CCIyiDdWRwgiMo", + "enr:-Mm4QMycpeBzbXonM4_D6rG4OlCj3IiomsrKTAo5Lt4WiNR_UjHbqqzWDL4cU_DiRciLGtYZ7FplIBPo3Cc5sokaStUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82iEYRxdWljgiMpiXNlY3AyNTZrMaECFnLfbU62fXESKwDiGHjuh3Nt43sFPkpBK4RoiK7vLNiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QGLaP2hOFOCRyqpaJgXPQZSbB5QGRsoicY4U7UZx9RlkYLw9DoLXVxZFfPX7PNAszqMvBzN77FbkOjhPg_yPSFMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MADIRxdWljgiMpiXNlY3AyNTZrMaECbGSZZPqxqAcE_F48V2iNmHt6j60wSptDzsW--MalaYOIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMloS1eJUl8kTCumpRa-gPRV_3vHaznwqrkyZEqdNg_gMQZrdAs521F2CMDfb_QClmB1zc9mD-iqd7IHUpSiy-cBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEoSM7S4RxdWljgiMpiXNlY3AyNTZrMaEDG_p92y4TqYPE1uHfYJhEFYJicbhur6M3INxMDntMAdWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QK5ZHmY0IYdyaiCgNVG8PvmN-4iSC7bIDAqT159eQKzbZfC53fnsjyYc0fXhp3g-U8ClnxHIG6wvMeNwK-OuDLUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEjl3-GYRxdWljgiMpiXNlY3AyNTZrMaED1CTZowO74kS-gZr1mcUtOc3X8HuQ8M0Jlm9QN2A5jSmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMF5aX5M4399B7ixyj5srUR3Wcnpa6cfHuRofq5Rej9vGVvFCl1xt1p2PGgqUqxpoMBLM7--bVqPDtcaBBVtBV4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBQvoRxdWljgiMpiXNlY3AyNTZrMaECnjsDyKbztA9AZkfvAuM0M7BHE6LP65VagkNiausnwf2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QE_YVaRRiUZab27Hwu6kLWSkVRuke4Vx7L3dN8PHSuOqY2CjfnntxTeHRAc2_qS-lB8R35nNbu5D0xNdwWtbMfwBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEj26p9YRxdWljgiMpiXNlY3AyNTZrMaECxR5wgxcH2sTg4chkH2XctRjCRU9nBEMu8U0ixvYVOb6Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QAN_kY7-FlY9w3MiRh8Cm3h6SFLSomuWm8ezpAw9IWpvEZmqG_Y8Puq4rABVEqjoebUkiPdJ4km0YQDAP6CCD7wBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEisVoUYRxdWljgiMpiXNlY3AyNTZrMaEDbwUNCVBNIaDjC3soF1-UroKYk8SCzkDENCIM-eo2eQKIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QHlp8QeXe1YLemM0piknoBOVUyV-c-RxRpjoK9Eovv3wVwQV8ur2L4K1if_dyuYDiz-1vQWjdPKHt3t1HeGsxOkBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MnPIRxdWljgiMpiXNlY3AyNTZrMaECCmUZTe-r6wI4Hl1rZoa_KYB5q_2mGhHQpAuJcB7N3PiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJOUCJF0hWpdYKe9DW2b4n9-a9AwRkYbqa29arOanFBjHon2oamjS64Cpw1ayvTFTSwjFF1Ff6Yt9yf6y92cQ9gBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibgchYRxdWljgiMpiXNlY3AyNTZrMaEC2n4usqrewig49bgZaF1taS26cgVf-HiAE8DZ2Bg6QB2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QOkxdUkUVe8ChY2aX88BxuuAipS7LzH0qzqBwRfmYJ3cJVrfWTJll7lsHgE4FIlU2i9rH9wZWr0mqD3O-T7mMb0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEvKb94YRxdWljgiMpiXNlY3AyNTZrMaECEirgYfVhl9O8-apVAF4E19KST_SoQNdYB-dMK481lhCIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBctddDFJHQsWbwhViVGv7QQJrfiSCRbAmSB_vxLvUwoTF_4jgPdicOI25v8Sexde3K7VmoDumAqbfkDjKv59FsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkH7L54RxdWljgiMpiXNlY3AyNTZrMaEDvSYw5ZRCKA9lGJSjIqbWYikww-HYIay9IJuciFbG56SIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QNvGXzTNoMw9yRHgBSAMQ97pKZBqJvRzP_WQacha-WTDFXpm476LP5NZTJqZm949bOjI7UXFtk-Dq_f9qO9wf0MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MG04RxdWljgiMpiXNlY3AyNTZrMaECbNgYXUYuG0NleWcIX13YfwjVvF_BNt8hKk3yFCgrtWyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QLRk9InGH-I_MoWioQ70snhkdwNh_PJd06JXwaeZQSO9ChrhZO_IAnsZP9UKDMjwK4OWvGqhM7XpNRiSYk-LkB0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJB6D4RxdWljgiMpiXNlY3AyNTZrMaECgGQkX-iULENiOedHQ6q9VexGaI8lBQpyoB8IXGbjWGuIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QD2mxNJuYdUWUlMz51UT51LTsoTXoq5PgQ3OWzXgXOfvI3PlOl6pdynkOYbn2xz2S6PG3VhgzGWwaEbgy5-bKY4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82n3IRxdWljgiMpiXNlY3AyNTZrMaECPPNezPrn-hWXsZ0bXCGvjMNhIDVL6_faIpbMcdWGNeyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QHi9wOHG1kwBa5WVLM27nFBbULVWf-b5pRbsNknKKSo7cq0DcB9YFPCO55xrne5ncLuc5tsLVah588kITWoYZ44Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBRjIRxdWljgiMpiXNlY3AyNTZrMaECREuBzwWs5GJch31Gced8RLlNGcAUdzhexoBwket_gaGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QAVF7D6xLmKDFl19COzYWvUFyq7MqWpoWOCZCYHVIu6xL2tMaV7SzCSbCz0BDBy8I909i60MP3ASMSH3qelCaK0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBi-4RxdWljgiMpiXNlY3AyNTZrMaEDxLQPy6TvG7xuZHgovpv2fP1isHNUj6mff_k0XAMEobGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QGs_9j4e0D_v5jC-pKEltiT6fe9lbwgSVwwmRDNaUL_nOxZfmbvp1qOGRRCHBn5lOerol6_ykgmjDQf7R12eXncBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCrsz4RxdWljgiMpiXNlY3AyNTZrMaED36hK9w-REZSBnK1n1b1wpted08g5Zg2NAWfTm29r7UyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QAp_Du2XkinTcMU2LjMaOwb9dLqQpvik72s_ACpEa18KLqj-FDHjSw2iSSkLdMRiej_nRAmIoXPym1ZYWCsuspABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeNaNoRxdWljgiMpiXNlY3AyNTZrMaECe6WEfRco9dWv-lYOOkJ79oC6h1TsGwfE0qwwUyonCsqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QHjDYxMiuCYPV-u3Fd_EbKdKCXOa9UTUJM-2_ArMSXzBM5Hk6Re1uw9cQrWwzrGyZOqe-DhTlo38kOjENUv6wjMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibhIf4RxdWljgiMpiXNlY3AyNTZrMaECTysK1szima_WiGWZmsfCF39hYWJx4vBn3sw-EacZ2RqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QNtcDYVV2m40bIdResWh0ZcMAByENmg9BHvCtJlUUVZ2FheFMVh8JHPT5RYkkYCivlprbA_HRfv2yR5Vd4DKwoIBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCE0SYdtIRxdWljgiMpiXNlY3AyNTZrMaEDhmsIJt_vylwj9vVpe9xSxplR6yLv1-lcGG3t7kt7eQ-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJBF0ITYJn9deemoje7vB2lEOPTw1LcAbR7vDsUtN1X8QS4uBXHegmlxO_xo_eej94y6SpfeUZfsGI8TxXQO9eMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2ObP4RxdWljgiMpiXNlY3AyNTZrMaEDsGgIhgQBTv7AtHdxPxn6muNOSMSBeYTa8R3a6leiQJmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QKORSYhuvgwEULz5YTbKAFoFxIDUSUprw6-XhSWCI-R5dY74fgfmFWlnfQAWbrlxFPEQFlnFrJgoGJZBfx8qX3MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEneYo34RxdWljgiMpiXNlY3AyNTZrMaEDgOCZaXRC9ru0SM0TTN3rH8Z1rRvHZB6tN9pRiw_dH4mIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPALAj30065etXUSLBv1TCpIPjyu5Sc2jS1pq1dLxcWKCA-TZ7agz_iKHUd7qqKDjU8jkKEI6OZx75SD7hCFMdABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsj4zroRxdWljgiMpiXNlY3AyNTZrMaECscmuK1mmVZABEZ06513uRJNsRbPQ-dDRKtwbIDhBSaeIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJ9ivFpkcKKHcCWgwjRRsFnkHDfsCmf-oShjZ8GP1I3fPsfpoc3m5Al7hEWhiggU1D3DfTKDJLUGTWunO_ZpUbQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCr3YYRxdWljgiMpiXNlY3AyNTZrMaEDS30xNn9X05FEDU8E_mQjkmAGvEUHPjsGvM0-hOa2o2uIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBMzcDyzwpm2E5AMBGwyUEe0cmKfqB8M7zt9t8txyFcANxPcFvqW_uFcJsbv9oWLAAurBHxYRsrcjNXa-yzAiCsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEikSL4oRxdWljgiMpiXNlY3AyNTZrMaED0jwFiAei2MqwdAA2Jb2tG09PInLJDHRKHCEBcOWD1iaIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QGYTvW_cBJzsY3az9nseyDY-QGE9W0i65oSYjC6mYcwPUEaygRfuP8apw3cJ-gyn_4LnSFgiZQJulZoWohmHKr8Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtEjL4RxdWljgiMpiXNlY3AyNTZrMaEDTbzFw2ZRCyW6IMOPv0XjGPaF3KwEm8bIoiXS9YiZ_K2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QAGbFeFkhgZj2gytJlzx3un6Fpof5jA1siTpjzZweK5cO2U-NtmUgh7-cZKRY5cKXySnP-IkXxFwsg1Q9yYmC4QBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEgMcixoRxdWljgiMpiXNlY3AyNTZrMaECHpCu_6mFkwl9SZWYGm5np8J3IUCeW_9SB-3QOQe8ZgKIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QEdec6LFcVat6y4WbhoOp3VsdqE140XhMXaFbXLrser2fyFmaTWVwkwqDKwNwCk_ln5U39nf2HUyrli3MOxyQE4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeOpZYRxdWljgiMpiXNlY3AyNTZrMaECtDxrZZAg0FmSmOXOxtiTMnhiVAFbYJ_2LN624_7d_bmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QCwzClelxvQD72WYzAqszuwt4jPbDGnVMiLcSR5K8DUxbYxaT4irgnBmGaroK5BWYoeP2FcOzwy30qZx_eLSqS0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeMtMYRxdWljgiMpiXNlY3AyNTZrMaECxV_FCOTDHqVWw0egWAQawy7pt8vqsxhfXKsZive3jYSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QN7FBq4fhf-r_klVwhkhs0dw1QvNh-R0U64CaNeDT1C5IAYJmi_H_85vfl7EGqenQXM5igA0vT3Xj1GNlrjmv7QBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtGam4RxdWljgiMpiXNlY3AyNTZrMaECgqkFNSwP0y1X5VZcisA_7U5SAba1arLu5hdrY3nqXD-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QDMC6sQ0fBXCzm6-k4XOqcuCn7mKzntt-93j_pN4_J_3PFvXas6ExyaRr17v_omQm9u1VPTI03iBBrr7NnwOoeABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeiA-oRxdWljgiMpiXNlY3AyNTZrMaECqpIvWTdEaaXvjFLP_kLJr4Fa0lWkQTm42SJzc8KOk0OIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJ-oW-TTrAGfJd_iDN9zHFIlyEE6mFzmWvVIPiEvIWHXH4ExBg-vnOKpfFFHlGdCbfEclqaBOZ6D1nx1bLzxjtUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBqxIRxdWljgiMpiXNlY3AyNTZrMaEDIMB7xB2Sj6Y4p5n2h4TdxPzRnxxgTy-a5WAR9P3FKKCIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QG4hIWEcJJi2Gj6Ql-HhfVK2rmkLamUwEu06czdipkPeDro-wnWcBB1zpVd-QcOPzYiExZQb57gPJOD484otj-oBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfXIRYRxdWljgiMpiXNlY3AyNTZrMaEDwjfI--Oeet9BjyOkNbTOBSINLOkdOKZvbreigno_P96Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QEf-tOBH_isvG9Jjwn-itg_Ax461wK8gN53hxoFgjk_5WqZmSEGrFrfmnkIsKtCNH_JkNtqRPpgR4xi7mDDdG7YBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEizulmoRxdWljgiMpiXNlY3AyNTZrMaECsXckk_ngZJ0ZBmAvefKo5POpLi7tgvj6RBlrfIJxtU-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QOTA6CDkXHMJGzzK4Qw0bt2NvjN5hi0GFHM9FShjUkLzNwhAEO4GDqjJCT8_Vxhuz0s2W7RpWGVh3hYGjlvMBacBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEn0Hy14RxdWljgiMpiXNlY3AyNTZrMaEDimNy71F_6PL6FWsPubnH20GDHm1GS7Fe85P_MJ_CqWqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMkLbE9WDjXPLCRYoQ9G0532uDnHk1gzQFvOKz4W1YkzRKbdsFpvxLId4mhgQn27qcvXSCk9nhQM0MQcsVpDzooBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEaPjC2YRxdWljgiMpiXNlY3AyNTZrMaED3p7pPbl4e4vpW1BAjSTKP3GDbyBPFn-OsFqILK_rCAiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMnUw-6zNtXoKfRXPt5BJBO8TkAxU9rdTzltVtPh30WAb2M3LHYjSfb5DyEpAGPGEK6zSiAbMh9YOKGcrmbXMkUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQOJWSIRxdWljgiMpiXNlY3AyNTZrMaEDty9z1mk9zYbD6COhp-s5I-SnBbvIhgvrDQ7Ompd2IXSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QKwleyLEbKns19VjBa_TaUS7QbmHcZ0sFM1MXhXJ_qCJRWzS-h8BLgBkPqOwUpLFTBKFGpblaJF43tgwpI1iVPUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpRbtA4RxdWljgiMpiXNlY3AyNTZrMaECFTMVLpwC7LnVDFb18UGq_c8eSHCyes7YaXB7v_tKXDmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMYOJD6e010NIMR0abp7m23jDDG6Xrr2qvNvy9kq-QrHUN1B_JyL6mEV1NbqsIIiG9BzN1Kd2LIJEk46l7h29eoBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfVSpIRxdWljgiMpiXNlY3AyNTZrMaED1G20YrHlnMEMpJlZ3uRIN1yL3nKzBrlaw6NVJI8pm-qIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QL-Wv0r30Lu1xV6MvcKHtgzbNwfoMFji6dvMxh-Qp8gDDbFl24RZ6iimexWjw0g62ARz-l8dVfDW_MKjt8QY01UBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkr7eV4RxdWljgiMpiXNlY3AyNTZrMaECE4_MnOcmfF4kkp2fvKBc0XiA1mXl327K-tbZi25cAXOIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QGkPvBD9iEoIJ9bL_LBuERaeHRt-u3GMjJT2wK96GTQZBYmG2yWdSLLZY6N28Ah4n02tZj7XDQia88Zyhm1mg18Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp0fSfYRxdWljgiMpiXNlY3AyNTZrMaED2V8OumEq1Xyc-T_D8Rz_uErhd4ExFaA2Y9ggZ2Q-gaqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-MS4QHP454KmJRQ6QvtYPGDVISUWxt9u66kRS4Y2xG-yGNwrQeCXt2CRn3QOz4K0EYT_qJ4escUKK228aW53SAOoCmcEh2F0dG5ldHOIAQAAAAAAAICEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_Gf0iJc2VjcDI1NmsxoQKcmNIRud0TxGGBowMH6KgQuBL1I6QDisI67IqsT1NcFIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QD3QTJHvr_ozW4XhGWtQAA1faQ5qTPlgsh54Fr-UYHmxWBuwd5kvxCRUU2VFrqwU25MSO2UiIH0ni6eFHTEydx8Eh2F0dG5ldHOIAAAAAACAAQCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2s4qJc2VjcDI1NmsxoQMS7AXi54diXAl7JtCOIuqXTgdQLTI7DoAwoUHtT9M12ohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QMrvDNykHH-uY1LkpFdBQG2j7BTWm4Zu_DZKk7yJgDvqQrgR5ebdrkRbP9JWgB4yQ34GnOvRwKpQH6Fm0n7UR1wEh2F0dG5ldHOIMAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3e-OJc2VjcDI1NmsxoQKoG9efdprL9xdFAFWCwTNVy04G6ogkhxrv66lcem3BUIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QLmLjJYXt2stbFs_xSUsGtPU-e5ZRNI7kK_6EXfMcn-wY8Y0kkI2Y1RNNOKdY6CVRz6bFJHRVuN_Ke-Eev-iK2IEh2F0dG5ldHOIBgAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31WCWJc2VjcDI1NmsxoQLu-LLSTeIaXnVTY_AfGhaDvt8EzO9oSTkS7l9mp2FOsYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QIfHbHSR_wT6eNqWLSwZuwX8Vggfimr9UvQ7CqzyTRZ6RpiMH3WgSfRe2vLZ6XHzsWsEBPb8uIEB1bPznK26c1kEh2F0dG5ldHOIAAMAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69VfuJc2VjcDI1NmsxoQMzBsv9977GwLbPePCR2_215ob8vbuLkl7jw4Xjt4iHWYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QM-FMAwX9YAu3dNrWZ7-mR90ETH8Wi7HLNkzxHG91Ay2RZUZ5E2jNgE1nllpGrJ-PrEbx7ZLZam9pyyWuJUwVxsEh2F0dG5ldHOIgAEAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKAJmyJc2VjcDI1NmsxoQNi_YVV1IKWUYr4WtQX0GQlo_smd7RG9Px1Djgm2ddrjohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QNpXfFe6sv4pZr18EAS-MN7-6vR3BQRUFR2BUF8JYgdFfRIubi4CX7MZPxB_TTwa1QIbsJPpIE6xfgjRGTh8A4AEh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIrFV6KJc2VjcDI1NmsxoQONhJoWb2B8LK4SU3rMbJE_qS8fA7HC8pbQ3PYlBcyO8ohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QH1jbdpyatJUXruCSNlE6A-XKzoz-C74lHdONmCY8vjPFNVsHAOzc_tbsR3PkRHevG8PYZ2n7SGIn1MHtIhCy3wEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRzgOJc2VjcDI1NmsxoQJ_PRvNg4wOXMckP_vRbDc0hFtDX82mYxMrdc0sC8Rj6IhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QOItMJJrAKDahrxwk4TR237U9aQO4Zq199oc8GWjkg_BbQJo_YwMuduki7bXZuzp0AnOibhU_J2JxA1j8-PSYVYEh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3H5uJc2VjcDI1NmsxoQOSxZPyLv5s8ai4FD64JwMvhP8PVq8J3BJRrLB5IBeVhYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QOXTwRX2CPb5t10VXqqBWeH4ZKTuuYMRjtTdO_oua67rSYCJxZgXpcvd4qYDO5JuZacRrfL0yNZjrCsGBdbWK_4Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31NHGJc2VjcDI1NmsxoQOWGlZFPoKXBWSVvkFV2HSoBosBZ-8lELgZT-jWuZVMaohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QBbix4UUs0W6RiDVao4AxqL6vmTQ_ZbRDWtb6oZu2qnbTfeu7rI0ryBoC-3wDi6BrlY9VNAX6nNPLBQazJodN9wEh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7uVSJc2VjcDI1NmsxoQMMAOwLh6oGZWR5ix4Rj1zitDGV1u9hn1sssgqhsxmfaohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QAdIwFds5c1XoHY768YHDWQXE88sZq7x--TbIt8DywC-eKf63P59YopC9MhUXtyAjiPEUdFLGsbnZ8hDm-9QCF0Eh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjHhOJc2VjcDI1NmsxoQLoCYpIP0YsPoZhEdgfDFa9_h18rskEBOtgP0wtA8_Ix4hzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QFbvhD3YZ_d-7MDbwVAqQ9mouMZtHBcyJRyQOb9wCJXoISrFHMlXoghcwXMjK4L8jkpW0u0gAVJlj4KsYwv3CB0Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fqkuJc2VjcDI1NmsxoQPI_G4rCR_WldHte9rlywGwk_CMndXwVZL5vD-Uxx7bnYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QC65D5GPZpOqc_N62YzTHPFqPoIYzTlvkK1QcKIMreBLPiQ0S8crFQI4UR2QtHQwrSoST639jPIev9haCeGt-VcDh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3cBaJc2VjcDI1NmsxoQIyVTK8QH8HZRU5yXxq_9O1e-uNbMKCqeQ8Pnz614EAFohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QEb-gSH1pYzes12yGGMW0LS1VTFQWyChZG0hyHI4uzARMOEknslqIOwFYLwFuIQT6Xo57wY8k1lB2bD7F9erWHUDh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GpWiJc2VjcDI1NmsxoQKq3cwFVO4pfId5ZKR8FFLFjljUd0cM9nCJGDsRlD48bohzeW5jbmV0cwaDdGNwgiMog3VkcIIjKA", + "enr:-LK4QJjwmILrkfb7WcNFNW_6y0rIaje53iiPsnl8EXtlSIeDULOfeib1vI4arkRvtVf8e5NDJVNpC4OCsBM7geTQ09oCh2F0dG5ldHOIAAADAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNoYaJc2VjcDI1NmsxoQKjjHUHsAhI8k7Y9I8Jtcd4be186t5cbzK8Pe4rlNFSOIN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QC_SKLTMsQAA6xHhua6He-3tbTjHX5ldGsiD95pSQCFWAiLuRNg00WL-UqqWV213n2PxZUM2t5FKbUo6s6PEEgADh2F0dG5ldHOIAAAAGAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjPAeJc2VjcDI1NmsxoQJ6_2ty7xIQjMxh_BSVBc7wUNK_zavLTT9YyzBBZigwlohzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QEqg0X9eT-UeeQ_2owzG66lxi9Q02nMu_zOWjI_npLCAbzwffvokHJSUiVjTD5LWNnkZybI46Qd3hy8eCfNWHSYDh2F0dG5ldHOIAAAAAAAGAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-6KJc2VjcDI1NmsxoQNGyONNiNXLU_IhDDCDl7yPv6SxYDYW9zGte2S8Z9oI2IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QGztwj48eJUFLgDdAkX3KheH-Fk88PqSZNRULqu9QGbYI-mUoBOkVtEnUMGBTlbSuGuoev_qFrcEyS_R0ngCNXwDh2F0dG5ldHOIAAAAAAAABgCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhC5lURmJc2VjcDI1NmsxoQOUc7rqSZMXu7aOOH-b73MWd4mOIl4e-vxJJfYP0Hh9DIhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-Ly4QJSbkyL6Rmdt6cpVm9IjVOLURMZLygqwRyGQRrK3kio8DAZR0xN4GskcdMzAnGSQ20WiTBmsWBRfTqTAphoCqcMDh2F0dG5ldHOIAAAAAwAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4ByyJc2VjcDI1NmsxoQMw1fNhMLg9Xin7SkEQtLuGTnbN7-Wnw8fS0AJfnZ2BRohzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", + "enr:-Ly4QKLEnEf0XteI_IHP4zwX9eJss6S5nElWxSvNdbN8n7ijb3ETscGrirR30Vg-0i93zxY1XRo7FQ-rOEfvunFsjCUDh2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLymYWaJc2VjcDI1NmsxoQJ-lebNvZ8CGA_XLb8eQ4Lfn1O0877FaxzQ59D4_BZ2nYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QLf2HnD_AIAN9QUqZVRmzHEM97_WLsWL0suneZGjooQMKLrp1SxaGoyMYTSKwM6Y73BeslKSg_cJc957_j91bIADh2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPPX46Jc2VjcDI1NmsxoQPEQ5EUa259oEjbqaISDsur_X0sYukB30oNTL3FilEP4IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QKzWObYxzgx731J5wl23AjvYWKabGQUBQffvKQnvURfEKJB7R1vIIABd1u59-2TrW4nU3qX_DkYV97INFDImH_EDh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJK-Uy2Jc2VjcDI1NmsxoQJj5WlbVgIRjphmVVGJHnBTwVNKXOUDvLZChgx_JMCst4hzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QGseVCdo_fVjvMY_QGqcyve40Xdd0jYrcTyCq8S0EJy_Nx56YGxqjoHUUxKuMa0PU_iSQBQz2FbLFaDG74ek8y0Dh2F0dG5ldHOIAAAAAAAGAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRuLmJc2VjcDI1NmsxoQKhIIw9enpaKZdfmSvFfK9wDtQLpM-qrlHCd0MTDLNqOIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-LK4QPMXekagH7MNlJQqVIPR5NpGthHPcXJnaIzIejWK0narAo3N3Xs_Og_SwJLb_2Y5zjpKkmUEK2jUkPZ1WQAf5AMCh2F0dG5ldHOIDAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKesmW2Jc2VjcDI1NmsxoQLAQnSQdJeqTKVS-030kSAALKOWJbxD3bMTYnf8S97UZYN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QG8F0cB_Zxl0oKIbACCW8IMjQn10VWZkWCITw93BZh_FImJJXs3jhsZ5e10bw5nltAXkedIxHjNPzAMU3m-uNxcDh2F0dG5ldHOIAAAAAAAAGACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO21QqJc2VjcDI1NmsxoQPL1Q4Ri0_WvBK-G_Dkhb1hDnPfuizAn6EJ13TaAi2C84hzeW5jbmV0cwyDdGNwgiMog3VkcIIjKA", + "enr:-MK4QOeEXnB7mMNwk5tTvmn5ZqUIc7aMUTsDW42IRe39czdtRahIYzQU8f7VY-V26WLy6esPh_ah8JFCrHBErSVsiFWGAZLeT7Kzh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjybOJc2VjcDI1NmsxoQJpe2nb80QWjTg8OV7XQGj9_5HbFSPkb1BLSs52_E7TdohzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-MK4QP-QVRYlqxAZEGaK5EBtNFpF2cw68sprwnvPImwIjeJpWiDVvG2gdQYACH099DrRhS0rVvnvjnDiZc9eW_t3jlKGAZLeT8qUh2F0dG5ldHOIAAAAABgAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fSeGJc2VjcDI1NmsxoQMibnTlWZSEQrFdTWtwbGxwgzNfQugREcWXDzMAlubdQIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QC4Qu0GMY0208CpOOXJ_2Z7GbpPfkFHFj72Cz4kt-wu2Q3Hm_BGovRbHLlPrpF8uByVCV2-AtJVRBn84BHVEMnmGAZLeT7aVh2F0dG5ldHOIAAAAAAAAAGCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5dy46Jc2VjcDI1NmsxoQJsE-K2kx_vWKVVnIforrd-kHKsTjB4BPb3WzkSH1Lz1IhzeW5jbmV0cwqDdGNwgiMog3VkcIIjKA", + "enr:-MK4QKOofW71FNRlgsHUOCeV9AQ70UevGamBKDKnleTPROtrXEP6v9FIqo3pl25M2xN40gD4v1a00VlCDoVYkuPJ3_mGAZLeT8UPh2F0dG5ldHOIAAAAgAEAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES34myJc2VjcDI1NmsxoQMLSTJIF8gzlFEwia6qaD5gsKqT3Z23iaICK81VqretZIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QHXxbNuKKho7NcmdtuSBDNdkMi-cm6tC0AMyJTnYsGcobpX5es-NoxB4WY-kG3bFECGrRh2-tEsI7t28wa3YGTSGAZLeT7e7h2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXU2Jc2VjcDI1NmsxoQIKaSq5y43WBT8dVCHB84d2REc3wBX_tRk9-MOgpT1jB4hzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", + "enr:-MK4QIM-1UP2HB0pKx2jHndjWYzodWEtpEA2sosqoXffqsCrLa-SKOPCKr7x0JpeER2afgK3iqU1fs6rz1nUCuvL8FmGAZLeT7XZh2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhMbHVWCJc2VjcDI1NmsxoQObZKwNbXAMbuIQO_8nnSFd93JE_jMUmSd6kznKTfX-hIhzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-MK4QJM_-BhvBXnUBqQDNJcp3MdbKZ_1SIfzFS-3yFpxR5ZXQ0TRzzaBHNZnfjD24uSDNCaXbMlosEyl4ryPy-0XH02GAZLeT8U5h2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAyyGJc2VjcDI1NmsxoQPESmSk4h2lnhyRIa_lxBb1ITF8NfEPHXSFHJXVzS9n5IhzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-MK4QEzKtIksM5EURBpZ0FZ4fXLtecoS1JJ2icOpT2w-owpbO2P2Oug73jhspMuTOf8kK7cC_BN4gK28klfP_TNGo4-GAZLeT7rwh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GdHKJc2VjcDI1NmsxoQJgKsArRY2WPBuUYLZVUSSBpk4H5wh8zq5GrwjsSdRRcohzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", + "enr:-MK4QKz4NtZlKDRz9775jgPwsRePFX3vbw6pQbFqiIJg1J--eGZchwoG1N1nRXy9NjM4Bfi1XWG4E7Mv0Fdj5QCKr6SGAZLeT8A9h2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3mJJeJc2VjcDI1NmsxoQPgcbrdUs4Cl2iqnDEVlxCv5kmdL3PfoVwz7hFsEYkHbohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QOQd4uWnmwJXQgN26AXaxTf3IUWO4YgfBA9tvxuHEsv9dqg8fee11wGxxisvvRyG-JM4E1WqdMovcFH8dEW1r2-GAZLeT7Sgh2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoaVWJc2VjcDI1NmsxoQOpq1Sbb6wDrBz4d7_RAsXS_xLLh3848cZA_vTKkHNuA4hzeW5jbmV0cwWDdGNwgiMog3VkcIIjKA", + "enr:-MK4QFHjVhYt6eNGd-EGuWSx0FNoH0VobqyChYBb8Xf9YzLzPId1emfv9V-w5jEDndmdDOG2bbh6YH_wFfx548bszlGGAZLeT8cPh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES37GeJc2VjcDI1NmsxoQMZXzxzYiYyeZD4z_ByhY1BEBPdf1nAuLjxTpLlxOrRp4hzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-MK4QAqwAW8TghKOjYIWH5a9RXT1yvsUWOazdzP59eRPvJp5Ho1dWc-_NQiNqgKfZe0_7FT0eI1Erl4lqw7HTc0JM_SGAZLeT7ddh2F0dG5ldHOIAAAAAAAAwACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6aWJc2VjcDI1NmsxoQIGmyFT5c3IsH8psIugRpU9MsjD_ftbaIIzrDwOFvys6IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QPohqNkdiuEBihGI2rkBJX3Tk563kpN9zqYjSmiNdcChAldd_byrT5_MjnQ9bi24R2gQ7uxNYr4NH9UhUTZSd9qGAZLeT70Bh2F0dG5ldHOIAAAAAAAABgCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGiDI7CJc2VjcDI1NmsxoQKGVoBF9cfB3GV4M7Zl_-mTjbbWBCi7QW5C05ibiwuA3YhzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", + "enr:-MK4QP2DRiKhUiUsC4wJjJtITJBN2avNjW9egmAu-y4_B_WUQOhJBT2KJLI_9R73J18PuARPeR4eEVg-c-B5e8bfmKCGAZLeT7b3h2F0dG5ldHOIAAAAYAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKA-BqJc2VjcDI1NmsxoQJIWcsdtYM4mgdzTXwmUaMVoUbLIdVNDWweOsUrjI3UwIhzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", + "enr:-MK4QIiJTCxyJYWDZ1QQoOtBuIEuChMzNYGbVB64AxZE6FAnaNznjwz0Nwf5HJyMHRLiSwgxenjyymjMF3WfZZZtnvCGAZLeT7fch2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjdKaJc2VjcDI1NmsxoQNVGjVbnmG_42TCsv_fSh8VDxU6QzLGRoB40-F_zWq104hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QCVT912AAMDsucNOqG-0yf-biSVNaJub9k3ixr4Sg99NQ2AD4MpE3GSE2c4Jv1J0X2ZvTX1ggnYgbTC5x1yDa8qGAZLeT7ich2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2m8KJc2VjcDI1NmsxoQMpHGgKJECJqncISNxicGI89eIBdjm1scnNr7-DmDa6G4hzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-MK4QO-5av0dVBhDrwNoBkMeBt7ZJN0F8NrOOSNi2mq-CRWiTZZG-CqcOp7t9qjuuQhIi-RscfJyHxRW1yvcPyC5ufiGAZLeT8uNh2F0dG5ldHOIAAAAAAMAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7BZaJc2VjcDI1NmsxoQIJMx1m9LIofaV4RCXF5RyzaLZkRq61IaJbu7yRG9lIXIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QF6UfAiGKckerLH-N3EuPpcBqkRXPbXWq-ir9N-kDdBQZxiafoF9I5zcZDhZtlqCF3sVoE9TMi4NQppf-Z1rxYWGAZLeT8dRh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GaKKJc2VjcDI1NmsxoQJFec8UuFmn0tmu07iNakrK600BGlrxHh_sK2f82qYALYhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QDFSrh_p694cIm6RZ4uONpMkEaRcH9LHnrd99glEoGXpIEpmoIa8YCJJr9DrTRfuURml3_mncRXoajg4dmtFweGGAZLeT7xHh2F0dG5ldHOIAAAAAIABAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4xiSJc2VjcDI1NmsxoQOpjekMNl4V9McivNC7eRKkZQi1Lf_WX46aDF-TpMk864hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QLsNKnDBw1Ho_-SEg1MXS5sFVJjA4DWblUE6Y7IXWLiYQ4W0lDsSy7CpEzwyNU7SrXe1-RlSW_5H5LzU_ywsrPeGAZLeT8Twh2F0dG5ldHOIMAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjQ9WJc2VjcDI1NmsxoQIg-vBB9-5OOrarYUzumiirQZ01OeWbUF1Wi-CBEtJRoIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QI4JBnn2NoAAjb5Kb9k0SiniAUnLPLa4rgV39iBDBqIuCYQSXsjXiQguby7QitFRUznZMiVghIiz9p9GjXdgd0CGAZLeT7hbh2F0dG5ldHOIAAAAAAMAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6zuJc2VjcDI1NmsxoQJ5-KR2npQdVUZAd1HdHYts7qDfVeHvJDOCth0prC-ElIhzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", + "enr:-MK4QL4S9A8qoGT_8GCITvPBL7TCx57ULUlq2aPZjjPnmGLweeAft-punq4XjST99Jhh3S5UeugIl3rH9q3RrnDvXkqGAZLeT7mQh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_LaLyJc2VjcDI1NmsxoQNWzuY7G7y9FJlESwsCrG7DMzUrE7ESs1CdBwGC8CmpLohzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", + "enr:-MK4QF4vFBE44lGXPmNR0YdPC1XKgcXVxGi6pNo3SM7SZmtfJiDuypBq3SBlsNkcTG-d0WEyCXtRdhN5l2DMvLKhjgiGAZLeT7cJh2F0dG5ldHOIAAAAGAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4WPmJc2VjcDI1NmsxoQOEFAnO0rF8u_LHcT1hZKPcJKc_pjxxzS8q_jLEXyjYgohzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", + "enr:-MK4QOtmjWv0SLF7-sCbDXTidUu3eDaO5LRH0_1UBBRv3BfZDCW1f0IE9AGsPt8CfzCKZwhLM6qDg9i6Q7QqueoVv2yGAZLeT7x3h2F0dG5ldHOIAAAYAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoREOJc2VjcDI1NmsxoQLd7bMKI1z0ZzOPVmbsJTUZwuh09sEK60PJTBkr8Z5d0YhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QGPZwfQ1VRvztck8puc-l4453wOlE_GDLkZf21oekvenYGRil0bNPZfy99omIYDo_8Lfj-gTjtyMQNhfX-Gxf7KGAZLeT72vh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI9u1yKJc2VjcDI1NmsxoQOqOuh9qoiDqaOA9P3Zqe9Kr6LtA7BGX6HApTOwTw8JEYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QNoB0qr5S04EqGfFd2oC-8zfJ40EpEKX6comkVAhVGpzRcS5miDn3i7vI8xMq4rcP1f9UNmjf5synrMpkjtl2RCGAZLeT7LYh2F0dG5ldHOIAAAAMAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fp9qJc2VjcDI1NmsxoQM00pJ11HAcuKC2lu3qsmrFfinrKyEIJfI5AgaAXKwQqIhzeW5jbmV0cwyDdGNwgiMog3VkcIIjKA", + "enr:-MK4QPsx1H6cUFhgDo8IeVRxPIevJY2m3cdIcfDm67PQlT3SE_GLHiMXbt7OwNcLfDnmadblfze_qnIfLPxLbvlEdVmGAZLeT7FUh2F0dG5ldHOIAAYAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4z1uJc2VjcDI1NmsxoQJ3uZasVkJgtNwojOc12o_OGa95JidVTiTf2ZNg6v1evYhzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-MK4QLLmvX5uDrkBoxlU32GAniNWyfuq5dGdzp54Nr-NXwYBPFffMC8TRPV5qJtXRPCF0TMOfGRGtVUScaGHK7WhYKGGAZLeT7tLh2F0dG5ldHOIAAAAAAAAMACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7dg6Jc2VjcDI1NmsxoQPPUGx-0Q1GggcWhaFjoBRNM1zxb3-GZet_XVsCjQuQfohzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", + "enr:-LK4QHPZyuxlcLUFzQlV14cUrVEnk0R8-v0gI7LyFmrRbNsWGBRcv1bVBr4OsuDsQe7WCXw_MbzIPbRil-l8lqlktUsEh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ9Z7GWJc2VjcDI1NmsxoQLQ5jTn1P7lwT8_jmjdgTbtknYQYN1diCnUJ1meLGDVI4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QKsnDouz3ORWxyOj86zLs9Y6EPzGGmAQvetPJYVi1OA8EgS6iqTMUumFGYlkrhwhlgl--RhVdJnGn6BT4nWbWsIEh2F0dG5ldHOIAAAAAAAAAMCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-E2Jc2VjcDI1NmsxoQPiM0IiXdbtvibXIinl9tTnU2oxUtQVCsSD8C5Fw5kkvIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QBPu32Td8-yRXOiCr6oZ8Kx_U9l2CtrgtTdS7JJSrya7XmYrhR5PLufbQ_qheDZ5220i1GHFejGrUctcKqXL5b0Eh2F0dG5ldHOIAQAAAAAAAICEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GfsCJc2VjcDI1NmsxoQPVIZx2mp-hC6O-8Sc2trinfPTX1ldcVm872npcbECL84N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QCTAUicPEGC27830Tk47FIOJjLLXAucO2JWZBmUpqyRqdqgx7htej1mbSGOwdkvMy2wr1ppQqNNHpg09Nq7atbAEh2F0dG5ldHOIBgAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdH2zWJc2VjcDI1NmsxoQOa8jxBZtnN1XafI2exkfdQfYrCpf5nIN7NJbM8UaAQ4YN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QBD2UExDYapUhx4Gwwmj0sZOOe8b_Z_7LOwvupuKvHH7S3y-i1tM-a9MUzfKp0f05Lnyd1OebLqAe06SpN0RVokEh2F0dG5ldHOIAAAABgAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjWVmJc2VjcDI1NmsxoQNy5g7s97V6c_bliDX29X02VEt7lFtykziQ6yAQz4B7B4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QKNgqPGYJb0gd6sPYicjvhzxX_4fwIs3UoKfv2Km7hAnILqc4HfLG46fwiaCGuGO8HWqhauYJyElmKl95HdkcnYEh2F0dG5ldHOIAAAAAAAADACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXyKJc2VjcDI1NmsxoQMd0ERS9Kijwan6Ok4AnconhbpavC3ChksqpaeMfFUgYIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QHJU03COhJsMUjgIfZgqe5L9X6NTfBprKwmhq7MMi8pUYkWNplTk0mOFZFDCUdxQoAdXWBMghCg_siFW29NdSacEh2F0dG5ldHOIAAAAAIABAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAkzeJc2VjcDI1NmsxoQIKR_4srED3KxIv8t5HgcGDItwksuAZGkuTiy0Sj-nP94N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QIBsXm9oo2rBww1rjpa8gfUFgtC0zfdQOyj9Lds9vhNmUj9HTjeUSr2np5CmDQbpELn2y_5c68yHCk2HikCsbH8Eh2F0dG5ldHOIAAAAAAAAABiEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69nQ6Jc2VjcDI1NmsxoQKkClbynlGIlGlgJrwz_g-4ClmmbQZlLCrQDFwHWhV414N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QLKcBiOOWyItntw97roB2K9giftNayxWd66H5qiat7h1QuopDgg0RGF6_KRuh6jHWIlhUVUX9kIJfTkQYBq9hrUEh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLI-E7uJc2VjcDI1NmsxoQIPizTcMpW9300gIUyA6wzxPJVehLzRGzep9VcRIcZB4IN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QAW64M2-Mtv6f_IJ-wqKuf-uczJxwzIPs4aKFOu0dMKdROuPHYcsDKNHPoOgOvBM2fD6lI2XeIMmPlkHQs7fSbsEh2F0dG5ldHOIAAAAAAAAgAGEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEji72Jc2VjcDI1NmsxoQOwaeQ96C8h5DJ9qnIwi0MD_EW9mWnVqq8YP7A8IhRxf4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QI_7bYzk-6IKSGx0hwXoUp_4SE37TVNrIo05XsYuCwewL1ANoIv1wTlFPiqhSSdUppGEQr7m_dBCMIiE5YvYfZkEh2F0dG5ldHOIAAAAAABgAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_f11yJc2VjcDI1NmsxoQJcyXAkRddQMRW8Wq_uDDaqhfRix2FsTlQpaeNg3cTL6YN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QOcFoKeISpC6WEzMFOs0Fd8g5O3zxHR4YrtOti-Qrm-iHZX7R8Cm-ZlWaBAC_tv-KQ31POPAiVE26QpRgmnERHoEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDiYIuJc2VjcDI1NmsxoQOM0fzW5xagH42YOYCaUR6TlIWaurBsnTa41TOg5IMBRYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QDwhH0TLPcX9EkImgdegz9n4DN9U-u6rx-qA03Idi3WvL1tqnEWB54qSofoLPlpRCk1LEhPcekgUE2IrgfSKAGcEh2F0dG5ldHOIAAAAAAAAwACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjJ-CJc2VjcDI1NmsxoQJJnCea2UoBVZUPpyZPNZ8lCj1sPxtWP7v44pA3bAXFFoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QDWc9ARKxtQzvcfhsSSuOQVBXtJf4uBN5khbopSvlB5mRhqKJD0DoWr1brq0Fu7aXtwxLwz3tmW88gHRyfgNeXsEh2F0dG5ldHOIwAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW3BOJc2VjcDI1NmsxoQP08nTiii_CUneyjjQiQOxlSJRGOBy5RxAltma_eD2kqYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QHzsDl0sImNgHoUUQZHERvokg6bzOIMRqld5y_I3Dq76OcCRlR1B1NNUBZomkckV752vh6xwgh_nuU8gC5vhkqAEh2F0dG5ldHOIAAAAAAAMAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fxziJc2VjcDI1NmsxoQIcnSoMB5m__EkBOblmx6pFVb2gWMgytvG0DCK-7Dc454N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QLaDD0Ce92HbHN_Odx8gOLWetZBBkdObRIK_tGnbyAMZF1D0lOmSazEXtqb_gcYyYWloH2aLvUiIhFyfBcqdFKgEh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNp5mJc2VjcDI1NmsxoQLthQWPCxwf6ElsjcoeDy7xWTVy0oyZGsWLyWJhT0AVZoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QNbU3sIX2x1pEdOMlHnyTnf_qKCftwHH7PtruMWDcQ2FeYxji2tu79tZy2slCZYcHC3Kt2yY6YNA8xuXmny-qf0Eh2F0dG5ldHOIAAAAAAAYAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs75jmJc2VjcDI1NmsxoQO3hlCHVZ2KkCuU3J0cmy32kyeaygleHpvTj1e43JJLJIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QP45lW8RQIrJrUYu8JaBbdHsFCL7c5cTwnbsf1v_I6M-R1Ugjq2j77Fzzpj7eE1omCrXkq9NGuN02EqnhAG0BYMEh2F0dG5ldHOIAAAAABgAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjX6-Jc2VjcDI1NmsxoQKmt4RKybkmaCeLp5hZ4ubq8aOrMujHCsZQGkEIfQX63YN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QPm1dSEh4ejPKAgCUmVW8YfTCnot8TBcjPl_9DUK9x8pHAMdgLBG4dQYU1cVy0VkdQ-y7PrCWuS2HVGVWgXs-w0Eh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRrmKJc2VjcDI1NmsxoQJ3YV-wCUUU6e7D41mVpE6Pl2IxB6u4Xp3RiuVW72jrKoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QCcjOXE6AFoUfRAPy2ADwoHrKA8e1AEvONG_TfeNEA0lFQCgrffj14h3aZtqzRSmDx4kdmz9Aq4xI_OERsFSwsIEh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjnAqJc2VjcDI1NmsxoQLrpyFMatvbIPm9lThrW9SdBdscw1Ctj4OL4Cg71wC1SIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QODfmZ3HU4QHVggOpxp1HVczob3ce9UwTGhSxE5tiQLCH0TATU2t4i_WEaicUJMRJi66Bmeb8c9rEoGvTLdmOSEEh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5deB6Jc2VjcDI1NmsxoQNj36dwUn-Vk4qn0H6Pe4qhOYluSopCikb6fF2Kh-26JYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QAaQ9jSV48tiTtHzL1aocXbrJnt0r1uSituGZCTjl8mINNxn5Z_Brf9J9oThAK7U67uO9ChPzEarhfhvTGO677MEh2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4YuJc2VjcDI1NmsxoQKdiOidyLx2IMQyrI-L-a169keDHUmAjMZ3_8vurIiHF4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QM8rHJc9l75ns1i9tuZyux2m9CtFi7zh9Rjh6t38OhCGTLE_Nq8ZMyg0oy5ktpkIoIp6v5T2DVrmx_P6iDbtHrwEh2F0dG5ldHOIADAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJgq582Jc2VjcDI1NmsxoQMXBD2dqEKFbP0hIM624HswH20R-LlZIQIuTsB9nIygh4N0Y3CCIyiDdWRwgiMo", +]; diff --git a/packages/config/src/chainConfig/networks/mekong.ts b/packages/config/src/chainConfig/networks/mekong.ts new file mode 100644 index 000000000000..d7f2d15cb525 --- /dev/null +++ b/packages/config/src/chainConfig/networks/mekong.ts @@ -0,0 +1,44 @@ +import {fromHex as b} from "@lodestar/utils"; +import {ChainConfig} from "../types.js"; +import {chainConfig as mainnet} from "../configs/mainnet.js"; + +// Mekong beacon chain config: +// https://github.com/ethpandaops/mekong-devnets/blob/master/network-configs/devnet-0/metadata/config.yaml + +export const mekongChainConfig: ChainConfig = { + ...mainnet, + + CONFIG_NAME: "mekong", + + // Genesis + // --------------------------------------------------------------- + MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 100000, + MIN_GENESIS_TIME: 1730372340, + GENESIS_FORK_VERSION: b("0x10000000"), + GENESIS_DELAY: 60, + + // Forking + // --------------------------------------------------------------- + // # Altair + ALTAIR_FORK_VERSION: b("0x20000000"), + ALTAIR_FORK_EPOCH: 0, + // # Merge + BELLATRIX_FORK_VERSION: b("0x30000000"), + BELLATRIX_FORK_EPOCH: 0, + TERMINAL_TOTAL_DIFFICULTY: BigInt("0"), + // Capella + CAPELLA_FORK_VERSION: b("0x40000000"), + CAPELLA_FORK_EPOCH: 0, + // Deneb + DENEB_FORK_VERSION: b("0x50637624"), + DENEB_FORK_EPOCH: 0, + // Electra + ELECTRA_FORK_VERSION: b("0x60637624"), + ELECTRA_FORK_EPOCH: 256, + + // Deposit contract + // --------------------------------------------------------------- + DEPOSIT_CHAIN_ID: 7078815900, + DEPOSIT_NETWORK_ID: 7078815900, + DEPOSIT_CONTRACT_ADDRESS: b("0x4242424242424242424242424242424242424242"), +}; diff --git a/packages/config/src/networks.ts b/packages/config/src/networks.ts index 819c02b995b0..df39ae15d09e 100644 --- a/packages/config/src/networks.ts +++ b/packages/config/src/networks.ts @@ -5,6 +5,7 @@ import {sepoliaChainConfig} from "./chainConfig/networks/sepolia.js"; import {holeskyChainConfig} from "./chainConfig/networks/holesky.js"; import {chiadoChainConfig} from "./chainConfig/networks/chiado.js"; import {ephemeryChainConfig} from "./chainConfig/networks/ephemery.js"; +import {mekongChainConfig} from "./chainConfig/networks/mekong.js"; export { mainnetChainConfig, @@ -13,9 +14,10 @@ export { holeskyChainConfig, chiadoChainConfig, ephemeryChainConfig, + mekongChainConfig, }; -export type NetworkName = "mainnet" | "gnosis" | "sepolia" | "holesky" | "chiado" | "ephemery"; +export type NetworkName = "mainnet" | "gnosis" | "sepolia" | "holesky" | "chiado" | "ephemery" | "mekong"; export const networksChainConfig: Record = { mainnet: mainnetChainConfig, gnosis: gnosisChainConfig, @@ -23,6 +25,7 @@ export const networksChainConfig: Record = { holesky: holeskyChainConfig, chiado: chiadoChainConfig, ephemery: ephemeryChainConfig, + mekong: mekongChainConfig, }; export type GenesisData = { @@ -55,4 +58,8 @@ export const genesisData: Record = { genesisTime: ephemeryChainConfig.MIN_GENESIS_TIME + ephemeryChainConfig.GENESIS_DELAY, genesisValidatorsRoot: "0x0000000000000000000000000000000000000000000000000000000000000000", }, + mekong: { + genesisTime: 1730372340, + genesisValidatorsRoot: "0x9838240bca889c52818d7502179b393a828f61f15119d9027827c36caeb67db7", + }, }; From 06b4c2d3241752b676f1673a62cd2a695761c806 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Fri, 1 Nov 2024 17:14:21 +0100 Subject: [PATCH 188/259] chore: fix import order with biome syntax (#7211) Fix import order --- biome.jsonc | 5 +- packages/api/src/beacon/client/debug.ts | 2 +- .../api/src/beacon/routes/beacon/block.ts | 18 +-- .../api/src/beacon/routes/beacon/index.ts | 4 +- packages/api/src/beacon/routes/beacon/pool.ts | 8 +- .../api/src/beacon/routes/beacon/rewards.ts | 4 +- .../api/src/beacon/routes/beacon/state.ts | 4 +- packages/api/src/beacon/routes/config.ts | 2 +- packages/api/src/beacon/routes/debug.ts | 6 +- packages/api/src/beacon/routes/events.ts | 24 ++-- packages/api/src/beacon/routes/lightclient.ts | 16 +-- packages/api/src/beacon/routes/lodestar.ts | 4 +- packages/api/src/beacon/routes/node.ts | 4 +- packages/api/src/beacon/routes/proof.ts | 4 +- packages/api/src/beacon/routes/validator.ts | 24 ++-- packages/api/src/beacon/server/events.ts | 2 +- packages/api/src/beacon/server/index.ts | 2 +- packages/api/src/builder/index.ts | 2 +- packages/api/src/builder/routes.ts | 18 +-- packages/api/src/builder/server/index.ts | 4 +- packages/api/src/keymanager/index.ts | 2 +- packages/api/src/keymanager/routes.ts | 6 +- packages/api/src/keymanager/server/index.ts | 4 +- packages/api/src/utils/client/httpClient.ts | 6 +- packages/api/src/utils/codecs.ts | 4 +- packages/api/src/utils/metadata.ts | 4 +- packages/api/src/utils/server/handler.ts | 4 +- packages/api/src/utils/server/route.ts | 2 +- .../beacon/genericServerTest/beacon.test.ts | 4 +- .../beacon/genericServerTest/config.test.ts | 4 +- .../beacon/genericServerTest/debug.test.ts | 16 +-- .../beacon/genericServerTest/events.test.ts | 8 +- .../genericServerTest/lightclient.test.ts | 4 +- .../beacon/genericServerTest/node.test.ts | 4 +- .../beacon/genericServerTest/proofs.test.ts | 4 +- .../genericServerTest/validator.test.ts | 4 +- .../api/test/unit/beacon/oapiSpec.test.ts | 4 +- .../api/test/unit/beacon/testData/config.ts | 2 +- .../api/test/unit/beacon/testData/events.ts | 2 +- .../test/unit/beacon/testData/lightclient.ts | 2 +- .../test/unit/beacon/testData/validator.ts | 2 +- .../api/test/unit/builder/builder.test.ts | 4 +- .../api/test/unit/builder/oapiSpec.test.ts | 2 +- packages/api/test/unit/builder/testData.ts | 2 +- packages/api/test/unit/client/fetch.test.ts | 2 +- .../api/test/unit/client/httpClient.test.ts | 18 +-- .../unit/client/httpClientOptions.test.ts | 2 +- .../api/test/unit/client/urlFormat.test.ts | 6 +- .../test/unit/keymanager/keymanager.test.ts | 4 +- .../api/test/unit/keymanager/oapiSpec.test.ts | 2 +- packages/api/test/unit/utils/headers.test.ts | 2 +- packages/api/test/unit/utils/serdes.test.ts | 2 +- packages/api/test/utils/checkAgainstSpec.ts | 6 +- packages/api/test/utils/genericServerTest.ts | 8 +- packages/api/test/utils/utils.ts | 6 +- packages/beacon-node/src/api/impl/api.ts | 2 +- .../src/api/impl/beacon/blocks/index.ts | 28 ++--- .../src/api/impl/beacon/blocks/utils.ts | 8 +- .../beacon-node/src/api/impl/beacon/index.ts | 2 +- .../src/api/impl/beacon/pool/index.ts | 16 +-- .../src/api/impl/beacon/state/index.ts | 4 +- .../src/api/impl/beacon/state/utils.ts | 4 +- .../src/api/impl/config/constants.ts | 58 ++++----- .../beacon-node/src/api/impl/config/index.ts | 2 +- .../beacon-node/src/api/impl/debug/index.ts | 6 +- .../src/api/impl/lightclient/index.ts | 6 +- .../src/api/impl/lodestar/index.ts | 10 +- .../beacon-node/src/api/impl/node/index.ts | 2 +- .../beacon-node/src/api/impl/proof/index.ts | 8 +- packages/beacon-node/src/api/impl/types.ts | 4 +- .../src/api/impl/validator/index.ts | 84 ++++++------- .../src/api/impl/validator/utils.ts | 4 +- packages/beacon-node/src/api/options.ts | 2 +- packages/beacon-node/src/api/rest/base.ts | 6 +- packages/beacon-node/src/api/rest/index.ts | 4 +- .../src/chain/archiver/archiveBlocks.ts | 8 +- .../src/chain/archiver/archiver.ts | 10 +- .../src/chain/archiver/interface.ts | 2 +- .../frequencyStateArchiveStrategy.ts | 12 +- .../beacon-node/src/chain/balancesCache.ts | 4 +- .../src/chain/beaconProposerCache.ts | 2 +- .../src/chain/blocks/importBlock.ts | 20 ++-- .../beacon-node/src/chain/blocks/index.ts | 10 +- .../beacon-node/src/chain/blocks/types.ts | 8 +- .../src/chain/blocks/utils/checkpoint.ts | 2 +- .../src/chain/blocks/verifyBlock.ts | 22 ++-- .../blocks/verifyBlocksDataAvailability.ts | 10 +- .../blocks/verifyBlocksExecutionPayloads.ts | 38 +++--- .../chain/blocks/verifyBlocksSanityChecks.ts | 2 +- .../chain/blocks/verifyBlocksSignatures.ts | 4 +- .../blocks/verifyBlocksStateTransitionOnly.ts | 8 +- .../src/chain/bls/multithread/index.ts | 18 +-- .../src/chain/bls/multithread/jobItem.ts | 4 +- .../src/chain/bls/multithread/worker.ts | 6 +- packages/beacon-node/src/chain/chain.ts | 112 +++++++++--------- packages/beacon-node/src/chain/emitter.ts | 2 +- .../src/chain/errors/attestationError.ts | 2 +- .../src/chain/errors/blobSidecarError.ts | 2 +- .../src/chain/errors/blockError.ts | 2 +- .../src/chain/errors/syncCommitteeError.ts | 2 +- .../beacon-node/src/chain/forkChoice/index.ts | 12 +- .../beacon-node/src/chain/genesis/genesis.ts | 20 ++-- .../src/chain/genesis/interface.ts | 2 +- .../historicalState/getHistoricalState.ts | 2 +- .../src/chain/historicalState/index.ts | 2 +- .../src/chain/historicalState/worker.ts | 10 +- packages/beacon-node/src/chain/initState.ts | 6 +- packages/beacon-node/src/chain/interface.ts | 78 ++++++------ .../src/chain/lightClient/index.ts | 68 +++++------ .../src/chain/lightClient/proofs.ts | 6 +- .../opPools/aggregatedAttestationPool.ts | 38 +++--- .../src/chain/opPools/attestationPool.ts | 8 +- .../beacon-node/src/chain/opPools/opPool.ts | 24 ++-- .../chain/opPools/syncCommitteeMessagePool.ts | 4 +- .../opPools/syncContributionAndProofPool.ts | 4 +- packages/beacon-node/src/chain/options.ts | 2 +- .../beacon-node/src/chain/prepareNextSlot.ts | 20 ++-- .../chain/produceBlock/produceBlockBody.ts | 56 ++++----- .../beacon-node/src/chain/regen/errors.ts | 2 +- .../beacon-node/src/chain/regen/interface.ts | 4 +- .../beacon-node/src/chain/regen/queued.ts | 10 +- packages/beacon-node/src/chain/regen/regen.ts | 22 ++-- packages/beacon-node/src/chain/reprocess.ts | 2 +- .../src/chain/rewards/attestationsRewards.ts | 6 +- .../src/chain/rewards/blockRewards.ts | 4 +- .../src/chain/rewards/syncCommitteeRewards.ts | 4 +- .../chain/seenCache/seenAttestationData.ts | 2 +- .../src/chain/seenCache/seenCommittee.ts | 2 +- .../chain/seenCache/seenGossipBlockInput.ts | 14 +-- .../chain/stateCache/blockStateCacheImpl.ts | 4 +- .../chain/stateCache/fifoBlockStateCache.ts | 4 +- .../stateCache/inMemoryCheckpointsCache.ts | 6 +- .../stateCache/persistentCheckpointsCache.ts | 16 +-- .../beacon-node/src/chain/stateCache/types.ts | 2 +- .../src/chain/validation/aggregateAndProof.ts | 8 +- .../src/chain/validation/attestation.ts | 52 ++++---- .../src/chain/validation/attesterSlashing.ts | 6 +- .../src/chain/validation/blobSidecar.ts | 12 +- .../beacon-node/src/chain/validation/block.ts | 10 +- .../chain/validation/blsToExecutionChange.ts | 8 +- .../validation/lightClientFinalityUpdate.ts | 6 +- .../validation/lightClientOptimisticUpdate.ts | 6 +- .../src/chain/validation/proposerSlashing.ts | 4 +- .../signatureSets/aggregateAndProof.ts | 8 +- .../signatureSets/contributionAndProof.ts | 4 +- .../signatureSets/selectionProof.ts | 6 +- .../validation/signatureSets/syncCommittee.ts | 4 +- .../syncCommitteeContribution.ts | 4 +- .../syncCommitteeSelectionProof.ts | 4 +- .../src/chain/validation/syncCommittee.ts | 2 +- .../syncCommitteeContributionAndProof.ts | 8 +- .../src/chain/validation/voluntaryExit.ts | 4 +- packages/beacon-node/src/db/beacon.ts | 20 ++-- packages/beacon-node/src/db/interface.ts | 18 +-- .../src/db/repositories/attesterSlashing.ts | 2 +- .../src/db/repositories/backfilledRanges.ts | 2 +- .../src/db/repositories/blobSidecars.ts | 2 +- .../db/repositories/blobSidecarsArchive.ts | 2 +- .../src/db/repositories/blockArchive.ts | 8 +- .../src/db/repositories/blockArchiveIndex.ts | 4 +- .../db/repositories/blsToExecutionChange.ts | 2 +- .../src/db/repositories/depositDataRoot.ts | 4 +- .../src/db/repositories/depositEvent.ts | 2 +- .../src/db/repositories/eth1Data.ts | 4 +- .../db/repositories/lightclientBestUpdate.ts | 2 +- .../lightclientCheckpointHeader.ts | 2 +- .../src/db/repositories/proposerSlashing.ts | 2 +- .../src/db/repositories/stateArchive.ts | 4 +- .../src/db/repositories/stateArchiveIndex.ts | 2 +- .../src/db/repositories/voluntaryExit.ts | 2 +- .../src/db/single/preGenesisState.ts | 2 +- .../preGenesisStateLastProcessedBlock.ts | 2 +- .../src/eth1/eth1DepositDataTracker.ts | 12 +- .../beacon-node/src/eth1/eth1DepositsCache.ts | 10 +- .../src/eth1/eth1MergeBlockTracker.ts | 6 +- packages/beacon-node/src/eth1/index.ts | 2 +- packages/beacon-node/src/eth1/interface.ts | 2 +- .../src/eth1/provider/eth1Provider.ts | 14 +-- .../src/eth1/provider/jsonRpcHttpClient.ts | 2 +- .../beacon-node/src/eth1/provider/utils.ts | 2 +- packages/beacon-node/src/eth1/stream.ts | 6 +- .../beacon-node/src/eth1/utils/deposits.ts | 10 +- .../beacon-node/src/eth1/utils/eth1Data.ts | 2 +- .../beacon-node/src/eth1/utils/eth1Vote.ts | 4 +- .../beacon-node/src/execution/builder/http.ts | 26 ++-- .../src/execution/builder/interface.ts | 16 +-- .../beacon-node/src/execution/engine/http.ts | 30 ++--- .../beacon-node/src/execution/engine/index.ts | 6 +- .../src/execution/engine/interface.ts | 6 +- .../beacon-node/src/execution/engine/mock.ts | 22 ++-- .../src/execution/engine/payloadIdCache.ts | 2 +- .../beacon-node/src/execution/engine/types.ts | 14 +-- .../beacon-node/src/execution/engine/utils.ts | 6 +- packages/beacon-node/src/metrics/metrics.ts | 14 +-- .../beacon-node/src/metrics/metrics/beacon.ts | 8 +- .../src/metrics/metrics/lodestar.ts | 6 +- .../beacon-node/src/metrics/nodeJsMetrics.ts | 2 +- .../beacon-node/src/metrics/server/http.ts | 4 +- .../src/metrics/utils/avgMinMax.ts | 2 +- .../beacon-node/src/metrics/utils/gauge.ts | 2 +- .../metrics/utils/registryMetricCreator.ts | 2 +- .../src/metrics/validatorMonitor.ts | 14 +-- .../beacon-node/src/monitoring/service.ts | 6 +- packages/beacon-node/src/monitoring/system.ts | 2 +- .../src/network/core/networkCore.ts | 46 +++---- .../src/network/core/networkCoreWorker.ts | 8 +- .../beacon-node/src/network/core/types.ts | 4 +- .../beacon-node/src/network/discv5/index.ts | 8 +- .../beacon-node/src/network/discv5/worker.ts | 16 +-- packages/beacon-node/src/network/events.ts | 6 +- packages/beacon-node/src/network/forks.ts | 2 +- .../src/network/gossip/encoding.ts | 10 +- .../src/network/gossip/gossipsub.ts | 24 ++-- .../src/network/gossip/interface.ts | 22 ++-- .../src/network/gossip/scoringParameters.ts | 6 +- .../beacon-node/src/network/gossip/topic.ts | 6 +- packages/beacon-node/src/network/interface.ts | 22 ++-- .../beacon-node/src/network/libp2p/index.ts | 12 +- packages/beacon-node/src/network/metadata.ts | 4 +- packages/beacon-node/src/network/network.ts | 52 ++++---- packages/beacon-node/src/network/options.ts | 2 +- .../src/network/peers/datastore.ts | 2 +- .../beacon-node/src/network/peers/discover.ts | 14 +-- .../src/network/peers/peerManager.ts | 30 ++--- .../src/network/peers/peersData.ts | 2 +- .../peers/utils/enrSubnetsDeserialize.ts | 2 +- .../network/peers/utils/prioritizePeers.ts | 4 +- .../network/processor/extractSlotRootFns.ts | 2 +- .../src/network/processor/gossipHandlers.ts | 60 +++++----- .../network/processor/gossipQueues/index.ts | 4 +- .../network/processor/gossipQueues/linear.ts | 2 +- .../network/processor/gossipValidatorFn.ts | 10 +- .../src/network/processor/index.ts | 18 +-- .../src/network/processor/types.ts | 2 +- .../src/network/reqresp/ReqRespBeaconNode.ts | 8 +- .../reqresp/beaconBlocksMaybeBlobsByRange.ts | 4 +- .../reqresp/beaconBlocksMaybeBlobsByRoot.ts | 14 +-- .../reqresp/handlers/beaconBlocksByRange.ts | 2 +- .../reqresp/handlers/blobSidecarsByRange.ts | 6 +- .../reqresp/handlers/blobSidecarsByRoot.ts | 4 +- .../src/network/reqresp/handlers/index.ts | 4 +- .../reqresp/handlers/lightClientBootstrap.ts | 6 +- .../handlers/lightClientFinalityUpdate.ts | 4 +- .../handlers/lightClientOptimisticUpdate.ts | 4 +- .../handlers/lightClientUpdatesByRange.ts | 8 +- .../src/network/reqresp/handlers/status.ts | 2 +- .../src/network/reqresp/protocols.ts | 4 +- .../src/network/reqresp/rateLimit.ts | 4 +- .../src/network/reqresp/utils/collect.ts | 2 +- .../utils/collectSequentialBlocksInRange.ts | 2 +- .../src/network/subnets/attnetsService.ts | 14 +-- .../src/network/subnets/interface.ts | 2 +- .../src/network/subnets/syncnetsService.ts | 4 +- packages/beacon-node/src/node/nodejs.ts | 26 ++-- packages/beacon-node/src/node/notifier.ts | 10 +- packages/beacon-node/src/node/options.ts | 24 ++-- .../src/node/utils/interop/deposits.ts | 8 +- .../src/node/utils/interop/state.ts | 4 +- packages/beacon-node/src/node/utils/state.ts | 2 +- .../beacon-node/src/sync/backfill/backfill.ts | 12 +- .../beacon-node/src/sync/backfill/errors.ts | 2 +- .../beacon-node/src/sync/backfill/verify.ts | 4 +- packages/beacon-node/src/sync/interface.ts | 10 +- packages/beacon-node/src/sync/range/batch.ts | 6 +- packages/beacon-node/src/sync/range/chain.ts | 16 +-- packages/beacon-node/src/sync/range/range.ts | 14 +-- .../src/sync/range/utils/hashBlocks.ts | 2 +- packages/beacon-node/src/sync/sync.ts | 18 +-- packages/beacon-node/src/sync/unknownBlock.ts | 18 +-- .../src/sync/utils/pendingBlocksTree.ts | 2 +- .../src/sync/utils/remoteSyncType.ts | 2 +- packages/beacon-node/src/util/blobs.ts | 4 +- packages/beacon-node/src/util/clock.ts | 6 +- packages/beacon-node/src/util/kzg.ts | 2 +- packages/beacon-node/src/util/multifork.ts | 2 +- packages/beacon-node/src/util/peerId.ts | 2 +- .../beacon-node/src/util/queue/fnQueue.ts | 2 +- .../beacon-node/src/util/queue/itemQueue.ts | 4 +- packages/beacon-node/src/util/sszBytes.ts | 2 +- .../api/impl/beacon/block/endpoint.test.ts | 10 +- .../api/impl/beacon/node/endpoints.test.ts | 8 +- .../api/impl/beacon/state/endpoint.test.ts | 8 +- .../test/e2e/api/impl/config.test.ts | 6 +- .../e2e/api/impl/lightclient/endpoint.test.ts | 16 +-- .../test/e2e/api/lodestar/lodestar.test.ts | 16 +-- .../test/e2e/chain/bls/multithread.test.ts | 4 +- .../test/e2e/chain/lightclient.test.ts | 16 +-- .../test/e2e/chain/proposerBoostReorg.test.ts | 14 +-- .../stateCache/nHistoricalStates.test.ts | 18 +-- .../beacon/repositories/blockArchive.test.ts | 2 +- .../e2e/doppelganger/doppelganger.test.ts | 12 +- .../e2e/eth1/eth1ForBlockProduction.test.ts | 12 +- .../e2e/eth1/eth1MergeBlockTracker.test.ts | 8 +- .../test/e2e/eth1/eth1Provider.test.ts | 8 +- .../test/e2e/eth1/jsonRpcHttpClient.test.ts | 4 +- .../beacon-node/test/e2e/eth1/stream.test.ts | 8 +- .../test/e2e/interop/genesisState.test.ts | 4 +- .../test/e2e/network/gossipsub.test.ts | 8 +- .../beacon-node/test/e2e/network/mdns.test.ts | 18 +-- .../test/e2e/network/network.test.ts | 4 +- .../onWorker/dataSerialization.test.ts | 28 ++--- .../e2e/network/onWorker/workerEchoHandler.ts | 2 +- .../e2e/network/peers/peerManager.test.ts | 24 ++-- .../test/e2e/network/reqresp.test.ts | 12 +- .../test/e2e/network/reqrespEncode.test.ts | 20 ++-- .../test/e2e/sync/finalizedSync.test.ts | 18 +-- .../test/e2e/sync/unknownBlockSync.test.ts | 20 ++-- packages/beacon-node/test/globalSetup.ts | 2 +- .../test/memory/unfinalizedPubkey2Index.ts | 4 +- packages/beacon-node/test/mocks/clock.ts | 2 +- packages/beacon-node/test/mocks/loggerMock.ts | 2 +- .../test/mocks/mockedBeaconChain.ts | 20 ++-- .../beacon-node/test/mocks/mockedBeaconDb.ts | 12 +- .../beacon-node/test/mocks/mockedNetwork.ts | 4 +- packages/beacon-node/test/mocks/regenMocks.ts | 2 +- .../beacon-node/test/mocks/shufflingMock.ts | 2 +- .../beacon-node/test/perf/bls/bls.test.ts | 2 +- .../opPools/aggregatedAttestationPool.test.ts | 6 +- .../test/perf/chain/opPools/opPool.test.ts | 2 +- .../produceBlock/produceBlockBody.test.ts | 4 +- .../seenCache/seenAggregateAndProof.test.ts | 2 +- .../inMemoryCheckpointsCache.test.ts | 4 +- .../updateUnfinalizedPubkeys.test.ts | 10 +- .../perf/chain/validation/attestation.test.ts | 4 +- .../perf/chain/verifyImportBlocks.test.ts | 12 +- .../test/perf/eth1/pickEth1Vote.test.ts | 4 +- .../test/perf/misc/bytesHex.test.ts | 2 +- .../perf/network/gossip/fastMsgIdFn.test.ts | 4 +- .../test/perf/network/noise/sendData.test.ts | 8 +- .../peers/enrSubnetsDeserialize.test.ts | 4 +- .../peers/util/prioritizePeers.test.ts | 2 +- .../test/perf/util/bitArray.test.ts | 2 +- packages/beacon-node/test/setupPreset.ts | 2 +- .../test/sim/electra-interop.test.ts | 24 ++-- .../beacon-node/test/sim/mergemock.test.ts | 18 +-- packages/beacon-node/test/spec/bls/bls.ts | 2 +- .../beacon-node/test/spec/bls/index.test.ts | 2 +- .../beacon-node/test/spec/downloadTests.ts | 2 +- packages/beacon-node/test/spec/general/bls.ts | 8 +- .../test/spec/general/index.test.ts | 4 +- .../test/spec/general/ssz_generic.ts | 4 +- .../test/spec/general/ssz_generic_types.ts | 10 +- .../spec/presets/epoch_processing.test.ts | 12 +- .../test/spec/presets/finality.test.ts | 6 +- .../test/spec/presets/fork.test.ts | 12 +- .../test/spec/presets/fork_choice.test.ts | 56 ++++----- .../test/spec/presets/genesis.test.ts | 12 +- .../light_client/single_merkle_proof.ts | 6 +- .../test/spec/presets/light_client/sync.ts | 12 +- .../presets/light_client/update_ranking.ts | 6 +- .../test/spec/presets/merkle.test.ts | 10 +- .../test/spec/presets/operations.test.ts | 10 +- .../test/spec/presets/rewards.test.ts | 8 +- .../test/spec/presets/sanity.test.ts | 6 +- .../test/spec/presets/shuffling.test.ts | 4 +- .../test/spec/presets/ssz_static.test.ts | 8 +- .../test/spec/presets/transition.test.ts | 10 +- .../test/spec/utils/expectEqualBeaconState.ts | 4 +- .../replaceUintTypeWithUintBigintType.ts | 6 +- .../test/spec/utils/runValidSszTest.ts | 4 +- .../test/spec/utils/specTestIterator.ts | 2 +- .../test/spec/utils/sszTestCaseParser.ts | 6 +- .../network/gossip/scoringParameters.test.ts | 6 +- .../unit-mainnet/network/subnets/util.test.ts | 2 +- .../test/unit/api/impl/beacon/beacon.test.ts | 4 +- .../beacon/blocks/getBlockHeaders.test.ts | 6 +- .../unit/api/impl/beacon/state/utils.test.ts | 2 +- .../test/unit/api/impl/config/config.test.ts | 2 +- .../test/unit/api/impl/events/events.test.ts | 4 +- .../test/unit/api/impl/swaggerUI.test.ts | 2 +- .../impl/validator/duties/proposer.test.ts | 12 +- .../validator/produceAttestationData.test.ts | 6 +- .../api/impl/validator/produceBlockV2.test.ts | 18 +-- .../api/impl/validator/produceBlockV3.test.ts | 12 +- .../unit/api/impl/validator/utils.test.ts | 4 +- .../unit/chain/archive/blockArchiver.test.ts | 12 +- .../unit/chain/archive/nonCheckpoint.test.ts | 2 +- .../unit/chain/archive/stateArchiver.test.ts | 2 +- .../test/unit/chain/beaconProposerCache.ts | 2 +- .../rejectFirstInvalidResolveAllValid.test.ts | 2 +- .../blocks/verifyBlocksSanityChecks.test.ts | 10 +- .../test/unit/chain/bls/bls.test.ts | 4 +- .../test/unit/chain/bls/utils.test.ts | 2 +- .../unit/chain/forkChoice/forkChoice.test.ts | 8 +- .../test/unit/chain/genesis/genesis.test.ts | 10 +- .../test/unit/chain/lightclient/proof.test.ts | 6 +- .../upgradeLightClientHeader.test.ts | 6 +- .../opPools/aggregatedAttestationPool.test.ts | 22 ++-- .../chain/opPools/attestationPool.test.ts | 6 +- .../unit/chain/opPools/syncCommittee.test.ts | 4 +- .../opPools/syncCommitteeContribution.test.ts | 10 +- .../test/unit/chain/prepareNextSlot.test.ts | 12 +- .../test/unit/chain/reprocess.test.ts | 2 +- .../unit/chain/rewards/blockRewards.test.ts | 8 +- .../chain/seenCache/aggregateAndProof.test.ts | 4 +- .../seenCache/seenAttestationData.test.ts | 2 +- .../seenCache/seenGossipBlockInput.test.ts | 4 +- .../chain/seenCache/syncCommittee.test.ts | 4 +- .../test/unit/chain/shufflingCache.test.ts | 2 +- .../stateCache/blockStateCacheImpl.test.ts | 6 +- .../stateCache/fifoBlockStateCache.test.ts | 4 +- .../inMemoryCheckpointsCache.test.ts | 4 +- .../persistentCheckpointsCache.test.ts | 14 +-- .../validation/aggregateAndProof.test.ts | 8 +- ...hufflingForAttestationVerification.test.ts | 8 +- .../attestation/validateAttestation.test.ts | 2 +- ...idateGossipAttestationsSameAttData.test.ts | 2 +- .../chain/validation/attesterSlashing.test.ts | 8 +- .../test/unit/chain/validation/block.test.ts | 4 +- .../validation/blsToExecutionChange.test.ts | 20 ++-- .../lightClientFinalityUpdate.test.ts | 6 +- .../lightClientOptimisticUpdate.test.ts | 6 +- .../chain/validation/proposerSlashing.test.ts | 6 +- .../chain/validation/syncCommittee.test.ts | 12 +- .../chain/validation/voluntaryExit.test.ts | 16 +-- .../db/api/repositories/blockArchive.test.ts | 10 +- .../test/unit/db/api/repository.test.ts | 6 +- .../unit/eth1/eth1DepositDataTracker.test.ts | 8 +- .../unit/eth1/eth1MergeBlockTracker.test.ts | 4 +- .../test/unit/eth1/hexEncoding.test.ts | 8 +- .../beacon-node/test/unit/eth1/jwt.test.ts | 4 +- .../unit/eth1/utils/depositContract.test.ts | 4 +- .../test/unit/eth1/utils/deposits.test.ts | 16 +-- .../test/unit/eth1/utils/eth1Data.test.ts | 14 +-- .../unit/eth1/utils/eth1DepositEvent.test.ts | 2 +- .../test/unit/eth1/utils/eth1Vote.test.ts | 12 +- .../utils/groupDepositEventsByBlock.test.ts | 2 +- .../optimizeNextBlockDiffForGenesis.test.ts | 4 +- .../test/unit/execution/engine/utils.test.ts | 8 +- .../test/unit/executionEngine/http.test.ts | 12 +- .../unit/executionEngine/httpRetry.test.ts | 10 +- .../test/unit/metrics/beacon.test.ts | 2 +- .../test/unit/metrics/metrics.test.ts | 2 +- .../test/unit/metrics/server/http.test.ts | 4 +- .../test/unit/metrics/utils.test.ts | 2 +- .../beacon-node/test/unit/metrics/utils.ts | 2 +- .../test/unit/monitoring/clientStats.test.ts | 4 +- .../test/unit/monitoring/properties.test.ts | 2 +- .../test/unit/monitoring/service.test.ts | 10 +- .../beaconBlocksMaybeBlobsByRange.test.ts | 12 +- .../test/unit/network/fork.test.ts | 6 +- .../test/unit/network/gossip/topic.test.ts | 4 +- .../test/unit/network/metadata.test.ts | 4 +- .../test/unit/network/peers/client.test.ts | 4 +- .../test/unit/network/peers/datastore.test.ts | 2 +- .../test/unit/network/peers/discover.test.ts | 4 +- .../unit/network/peers/priorization.test.ts | 8 +- .../test/unit/network/peers/score.test.ts | 8 +- .../peers/utils/assertPeerRelevance.test.ts | 4 +- .../network/peers/utils/enrSubnets.test.ts | 2 +- .../processor/aggregatorTracker.test.ts | 2 +- .../processor/gossipQueues/indexed.test.ts | 2 +- .../processor/gossipQueues/linear.test.ts | 2 +- .../test/unit/network/processorQueues.test.ts | 2 +- .../collectSequentialBlocksInRange.test.ts | 6 +- .../test/unit/network/reqresp/utils.ts | 6 +- .../network/subnets/attnetsService.test.ts | 8 +- .../test/unit/network/subnets/util.test.ts | 4 +- .../test/unit/network/util.test.ts | 4 +- .../test/unit/sync/backfill/verify.test.ts | 8 +- .../test/unit/sync/range/batch.test.ts | 10 +- .../test/unit/sync/range/chain.test.ts | 14 +-- .../unit/sync/range/utils/batches.test.ts | 8 +- .../sync/range/utils/peerBalancer.test.ts | 2 +- .../sync/range/utils/updateChains.test.ts | 4 +- .../test/unit/sync/unknownBlock.test.ts | 18 +-- .../unit/sync/utils/pendingBlocksTree.test.ts | 2 +- .../unit/sync/utils/remoteSyncType.test.ts | 6 +- .../test/unit/util/address.test.ts | 2 +- .../beacon-node/test/unit/util/array.test.ts | 4 +- .../test/unit/util/binarySearch.test.ts | 4 +- .../test/unit/util/bitArray.test.ts | 2 +- .../test/unit/util/bufferPool.test.ts | 2 +- .../beacon-node/test/unit/util/bytes.test.ts | 2 +- .../test/unit/util/chunkify.test.ts | 2 +- .../beacon-node/test/unit/util/clock.test.ts | 4 +- .../test/unit/util/dependentRoot.test.ts | 4 +- .../beacon-node/test/unit/util/error.test.ts | 2 +- .../beacon-node/test/unit/util/file.test.ts | 2 +- .../test/unit/util/graffiti.test.ts | 4 +- .../test/unit/util/itTrigger.test.ts | 2 +- .../beacon-node/test/unit/util/kzg.test.ts | 12 +- .../beacon-node/test/unit/util/map.test.ts | 2 +- .../test/unit/util/metadata.test.ts | 4 +- .../beacon-node/test/unit/util/peerId.test.ts | 2 +- .../beacon-node/test/unit/util/queue.test.ts | 2 +- .../beacon-node/test/unit/util/set.test.ts | 2 +- .../test/unit/util/shuffle.test.ts | 2 +- .../beacon-node/test/unit/util/sortBy.test.ts | 2 +- .../test/unit/util/sszBytes.test.ts | 18 +-- .../beacon-node/test/unit/util/time.test.ts | 2 +- .../test/unit/util/timeSeries.test.ts | 2 +- .../test/unit/util/wrapError.test.ts | 2 +- packages/beacon-node/test/utils/api.ts | 6 +- .../test/utils/cachedBeaconState.ts | 2 +- .../utils/cliTools/kzgTrustedSetupFromJson.ts | 2 +- packages/beacon-node/test/utils/clock.ts | 2 +- packages/beacon-node/test/utils/config.ts | 2 +- packages/beacon-node/test/utils/db.ts | 2 +- packages/beacon-node/test/utils/errors.ts | 2 +- packages/beacon-node/test/utils/logger.ts | 4 +- .../test/utils/networkWithMockDb.ts | 2 +- .../beacon-node/test/utils/node/beacon.ts | 18 +-- .../beacon-node/test/utils/node/simTest.ts | 14 +-- .../beacon-node/test/utils/node/validator.ts | 12 +- packages/beacon-node/test/utils/peer.ts | 2 +- packages/beacon-node/test/utils/runEl.ts | 6 +- packages/beacon-node/test/utils/state.ts | 14 +-- packages/beacon-node/test/utils/testnet.ts | 4 +- .../beacon-node/test/utils/typeGenerator.ts | 2 +- .../utils/validationData/aggregateAndProof.ts | 4 +- .../test/utils/validationData/attestation.ts | 18 +-- packages/cli/src/applyPreset.ts | 2 +- packages/cli/src/cli.ts | 2 +- packages/cli/src/cmds/beacon/handler.ts | 22 ++-- packages/cli/src/cmds/beacon/index.ts | 2 +- .../cli/src/cmds/beacon/initBeaconState.ts | 28 ++--- .../cli/src/cmds/beacon/initPeerIdAndEnr.ts | 8 +- packages/cli/src/cmds/beacon/options.ts | 4 +- packages/cli/src/cmds/beacon/paths.ts | 2 +- packages/cli/src/cmds/bootnode/handler.ts | 16 +-- packages/cli/src/cmds/bootnode/index.ts | 2 +- packages/cli/src/cmds/bootnode/options.ts | 4 +- packages/cli/src/cmds/dev/files.ts | 4 +- packages/cli/src/cmds/dev/handler.ts | 12 +- packages/cli/src/cmds/dev/index.ts | 2 +- packages/cli/src/cmds/dev/options.ts | 2 +- packages/cli/src/cmds/index.ts | 4 +- packages/cli/src/cmds/lightclient/handler.ts | 2 +- packages/cli/src/cmds/lightclient/index.ts | 2 +- .../cmds/validator/blsToExecutionChange.ts | 10 +- packages/cli/src/cmds/validator/handler.ts | 30 ++--- packages/cli/src/cmds/validator/import.ts | 6 +- packages/cli/src/cmds/validator/index.ts | 10 +- .../keymanager/decryptKeystoreDefinitions.ts | 6 +- .../keymanager/decryptKeystores/threadPool.ts | 4 +- .../keymanager/decryptKeystores/worker.ts | 4 +- .../cli/src/cmds/validator/keymanager/impl.ts | 20 ++-- .../validator/keymanager/keystoreCache.ts | 2 +- .../validator/keymanager/persistedKeys.ts | 4 +- .../src/cmds/validator/keymanager/server.ts | 2 +- packages/cli/src/cmds/validator/options.ts | 2 +- .../cli/src/cmds/validator/signers/index.ts | 14 +-- .../src/cmds/validator/signers/logSigners.ts | 2 +- .../validator/slashingProtection/export.ts | 10 +- .../validator/slashingProtection/import.ts | 8 +- .../validator/slashingProtection/index.ts | 4 +- .../validator/slashingProtection/utils.ts | 10 +- .../cli/src/cmds/validator/voluntaryExit.ts | 14 +-- packages/cli/src/config/beaconNodeOptions.ts | 4 +- packages/cli/src/config/beaconParams.ts | 14 +-- packages/cli/src/config/peerId.ts | 4 +- packages/cli/src/index.ts | 2 +- packages/cli/src/networks/dev.ts | 4 +- packages/cli/src/networks/index.ts | 20 ++-- .../cli/src/options/beaconNodeOptions/api.ts | 2 +- .../src/options/beaconNodeOptions/builder.ts | 2 +- .../src/options/beaconNodeOptions/chain.ts | 2 +- .../cli/src/options/beaconNodeOptions/eth1.ts | 2 +- .../options/beaconNodeOptions/execution.ts | 2 +- .../src/options/beaconNodeOptions/metrics.ts | 2 +- .../options/beaconNodeOptions/monitoring.ts | 2 +- .../src/options/beaconNodeOptions/network.ts | 4 +- .../cli/src/options/beaconNodeOptions/sync.ts | 2 +- packages/cli/src/options/globalOptions.ts | 2 +- packages/cli/src/options/logOptions.ts | 2 +- packages/cli/src/util/gitData/gitDataPath.ts | 2 +- packages/cli/src/util/gitData/index.ts | 2 +- packages/cli/src/util/logger.ts | 6 +- packages/cli/src/util/proposerConfig.ts | 2 +- .../cli/test/e2e/blsToExecutionchange.test.ts | 4 +- .../cli/test/e2e/importFromFsDirect.test.ts | 4 +- .../cli/test/e2e/importFromFsPreStep.test.ts | 4 +- .../test/e2e/importKeystoresFromApi.test.ts | 10 +- .../test/e2e/importRemoteKeysFromApi.test.ts | 8 +- .../e2e/propserConfigfromKeymanager.test.ts | 6 +- packages/cli/test/e2e/runDevCmd.test.ts | 4 +- packages/cli/test/e2e/validatorList.test.ts | 8 +- packages/cli/test/e2e/voluntaryExit.test.ts | 6 +- .../cli/test/e2e/voluntaryExitFromApi.test.ts | 2 +- .../e2e/voluntaryExitRemoteSigner.test.ts | 10 +- .../cli/test/sim/backupEthProvider.test.ts | 4 +- packages/cli/test/sim/deneb.test.ts | 4 +- packages/cli/test/sim/endpoints.test.ts | 6 +- packages/cli/test/sim/mixedClient.test.ts | 4 +- packages/cli/test/sim/multiFork.test.ts | 14 +-- packages/cli/test/unit/cmds/beacon.test.ts | 12 +- .../test/unit/cmds/initPeerIdAndEnr.test.ts | 2 +- .../keymanager/keystoreCache.test.ts | 8 +- .../unit/config/beaconNodeOptions.test.ts | 2 +- .../cli/test/unit/config/beaconParams.test.ts | 6 +- packages/cli/test/unit/config/peerId.test.ts | 4 +- .../unit/options/beaconNodeOptions.test.ts | 6 +- .../test/unit/options/paramsOptions.test.ts | 4 +- .../cli/test/unit/paths/globalPaths.test.ts | 2 +- .../unit/util/extractJwtHexSecret.test.ts | 2 +- packages/cli/test/unit/util/format.test.ts | 2 +- packages/cli/test/unit/util/gitData.test.ts | 2 +- packages/cli/test/unit/util/logger.test.ts | 2 +- .../test/unit/util/parseBootnodesFile.test.ts | 2 +- packages/cli/test/unit/util/progress.test.ts | 2 +- .../test/unit/util/pruneOldFilesInDir.test.ts | 2 +- .../test/unit/util/stripOffNewlines.test.ts | 2 +- .../decryptKeystoreDefinitions.test.ts | 10 +- packages/cli/test/unit/validator/keys.test.ts | 2 +- .../cli/test/unit/validator/options.test.ts | 2 +- .../validator/parseProposerConfig.test.ts | 2 +- packages/cli/test/utils.ts | 2 +- .../assertions/accountBalanceAssertion.ts | 2 +- .../crucible/assertions/blobsAssertion.ts | 2 +- .../defaults/attestationCountAssertion.ts | 4 +- .../attestationParticipationAssertion.ts | 2 +- .../defaults/connectedPeerCountAssertion.ts | 2 +- .../assertions/defaults/finalizedAssertion.ts | 2 +- .../assertions/defaults/headAssertion.ts | 2 +- .../defaults/inclusionDelayAssertion.ts | 2 +- .../defaults/missedBlocksAssertion.ts | 2 +- .../syncCommitteeParticipationAssertion.ts | 2 +- .../assertions/executionHeadAssertion.ts | 4 +- .../crucible/assertions/forkAssertion.ts | 2 +- .../lighthousePeerScoreAssertion.ts | 2 +- .../crucible/assertions/mergeAssertion.ts | 2 +- .../crucible/assertions/nodeAssertion.ts | 2 +- .../assertions/withdrawalsAssertion.ts | 4 +- .../crucible/clients/beacon/lighthouse.ts | 4 +- .../utils/crucible/clients/beacon/lodestar.ts | 2 +- .../utils/crucible/clients/execution/geth.ts | 2 +- .../utils/crucible/clients/execution/index.ts | 4 +- .../crucible/clients/execution/nethermind.ts | 4 +- .../utils/crucible/clients/validator/index.ts | 4 +- .../crucible/clients/validator/lighthouse.ts | 6 +- .../crucible/clients/validator/lodestar.ts | 2 +- .../utils/crucible/externalSignerServer.ts | 4 +- .../cli/test/utils/crucible/interfaces.ts | 6 +- .../crucible/runner/childProcessRunner.ts | 2 +- .../utils/crucible/runner/dockerRunner.ts | 2 +- .../cli/test/utils/crucible/simulation.ts | 20 ++-- .../test/utils/crucible/simulationTracker.ts | 14 +-- .../utils/crucible/utils/executionGenesis.ts | 2 +- .../cli/test/utils/crucible/utils/index.ts | 2 +- .../cli/test/utils/crucible/utils/keys.ts | 2 +- .../cli/test/utils/crucible/utils/paths.ts | 2 +- .../cli/test/utils/crucible/utils/ports.ts | 6 +- .../cli/test/utils/crucible/utils/syncing.ts | 4 +- .../web3js/blobsEIP4844Transaction.ts | 2 +- .../cli/test/utils/mockBeaconApiServer.ts | 4 +- packages/cli/test/utils/validator.ts | 4 +- packages/config/src/beaconConfig.ts | 4 +- .../config/src/chainConfig/configs/mainnet.ts | 2 +- .../config/src/chainConfig/configs/minimal.ts | 2 +- packages/config/src/chainConfig/default.ts | 2 +- packages/config/src/chainConfig/index.ts | 2 +- packages/config/src/chainConfig/json.ts | 2 +- .../src/chainConfig/networks/ephemery.ts | 2 +- .../config/src/chainConfig/networks/gnosis.ts | 4 +- .../src/chainConfig/networks/holesky.ts | 2 +- .../src/chainConfig/networks/mainnet.ts | 2 +- .../config/src/chainConfig/networks/mekong.ts | 2 +- .../src/chainConfig/networks/sepolia.ts | 2 +- packages/config/src/forkConfig/index.ts | 18 +-- packages/config/src/genesisConfig/index.ts | 6 +- packages/config/src/networks.ts | 8 +- packages/config/test/unit/index.test.ts | 4 +- packages/config/test/unit/json.test.ts | 4 +- packages/db/src/controller/level.ts | 4 +- .../db/test/unit/controller/level.test.ts | 4 +- packages/db/test/unit/schema.test.ts | 2 +- packages/flare/src/cli.ts | 2 +- packages/flare/src/cmds/index.ts | 2 +- packages/flare/src/cmds/selfSlashAttester.ts | 8 +- packages/flare/src/cmds/selfSlashProposer.ts | 8 +- packages/flare/src/index.ts | 2 +- packages/flare/test/unit/utils/format.test.ts | 2 +- packages/fork-choice/src/forkChoice/errors.ts | 2 +- .../fork-choice/src/forkChoice/forkChoice.ts | 44 +++---- .../fork-choice/src/forkChoice/interface.ts | 10 +- packages/fork-choice/src/forkChoice/store.ts | 6 +- .../src/protoArray/computeDeltas.ts | 4 +- .../fork-choice/src/protoArray/interface.ts | 2 +- .../fork-choice/src/protoArray/protoArray.ts | 8 +- .../perf/forkChoice/onAttestation.test.ts | 6 +- .../test/perf/forkChoice/updateHead.test.ts | 2 +- .../fork-choice/test/perf/forkChoice/util.ts | 6 +- .../perf/protoArray/computeDeltas.test.ts | 2 +- .../test/unit/forkChoice/forkChoice.test.ts | 14 +-- .../unit/forkChoice/getProposerHead.test.ts | 10 +- .../test/unit/forkChoice/utils.test.ts | 4 +- .../unit/protoArray/computeDeltas.test.ts | 2 +- .../protoArray/executionStatusUpdates.test.ts | 8 +- .../unit/protoArray/getCommonAncestor.test.ts | 4 +- .../test/unit/protoArray/protoArray.test.ts | 4 +- packages/light-client/src/index.ts | 18 +-- packages/light-client/src/spec/index.ts | 2 +- .../src/spec/processLightClientUpdate.ts | 4 +- packages/light-client/src/spec/utils.ts | 20 ++-- .../src/spec/validateLightClientBootstrap.ts | 4 +- .../src/spec/validateLightClientUpdate.ts | 26 ++-- .../light-client/src/transport/interface.ts | 2 +- packages/light-client/src/transport/rest.ts | 6 +- packages/light-client/src/utils/api.ts | 2 +- packages/light-client/src/utils/domain.ts | 2 +- packages/light-client/src/utils/utils.ts | 2 +- .../src/utils/verifyMerkleBranch.ts | 2 +- packages/light-client/src/validation.ts | 32 ++--- .../test/mocks/BeaconChainLcMock.ts | 2 +- .../test/mocks/LightclientServerApiMock.ts | 8 +- .../unit/isValidLightClientHeader.test.ts | 4 +- .../light-client/test/unit/sync.node.test.ts | 26 ++-- .../test/unit/syncInMemory.test.ts | 6 +- packages/light-client/test/unit/utils.test.ts | 6 +- .../test/unit/utils/chunkify.test.ts | 2 +- .../light-client/test/unit/validation.test.ts | 8 +- .../test/unit/webEsmBundle.browser.test.ts | 6 +- .../light-client/test/utils/naive/update.ts | 8 +- .../test/utils/prepareUpdateNaive.ts | 4 +- packages/light-client/test/utils/server.ts | 6 +- packages/light-client/test/utils/utils.ts | 4 +- packages/logger/src/browser.ts | 4 +- packages/logger/src/interface.ts | 2 +- packages/logger/src/node.ts | 6 +- packages/logger/src/utils/format.ts | 4 +- packages/logger/src/winston.ts | 2 +- .../test/e2e/logger/workerLoggerHandler.ts | 2 +- .../logger/test/e2e/logger/workerLogs.test.ts | 4 +- packages/logger/test/unit/browser.test.ts | 6 +- packages/logger/test/unit/env.node.test.ts | 6 +- packages/logger/test/unit/node.node.test.ts | 2 +- packages/logger/test/unit/utils/json.test.ts | 2 +- .../logger/test/unit/utils/timeFormat.test.ts | 2 +- .../logger/test/unit/winston.node.test.ts | 2 +- packages/params/src/index.ts | 6 +- packages/params/src/setPreset.ts | 2 +- .../test/e2e/ensure-config-is-synced.test.ts | 4 +- .../params/test/e2e/overridePreset.test.ts | 6 +- .../params/test/e2e/overridePresetError.ts | 2 +- packages/params/test/e2e/overridePresetOk.ts | 2 +- packages/params/test/e2e/setPreset.test.ts | 6 +- packages/params/test/e2e/setPresetError.ts | 2 +- packages/params/test/e2e/setPresetOk.ts | 2 +- .../params/test/unit/activePreset.test.ts | 6 +- .../test/unit/applicationDomains.test.ts | 4 +- packages/params/test/unit/forkName.test.ts | 2 +- packages/params/test/yaml.ts | 2 +- packages/prover/src/cli/applyPreset.ts | 2 +- packages/prover/src/cli/cli.ts | 2 +- packages/prover/src/cli/cmds/start/handler.ts | 4 +- packages/prover/src/cli/options.ts | 2 +- packages/prover/src/interfaces.ts | 2 +- .../src/proof_provider/payload_store.ts | 4 +- .../src/proof_provider/proof_provider.ts | 2 +- packages/prover/src/utils/consensus.ts | 2 +- packages/prover/src/utils/evm.ts | 10 +- packages/prover/src/utils/execution.ts | 2 +- .../prover/src/utils/gitData/gitDataPath.ts | 2 +- packages/prover/src/utils/gitData/index.ts | 2 +- packages/prover/src/utils/json_rpc.ts | 10 +- packages/prover/src/utils/process.ts | 10 +- packages/prover/src/utils/validation.ts | 4 +- packages/prover/src/utils/verification.ts | 2 +- .../prover/src/verified_requests/eth_call.ts | 2 +- .../src/verified_requests/eth_getBalance.ts | 2 +- .../verified_requests/eth_getBlockByHash.ts | 2 +- .../verified_requests/eth_getBlockByNumber.ts | 2 +- .../src/verified_requests/eth_getCode.ts | 2 +- .../eth_getTransactionCount.ts | 4 +- packages/prover/src/web3_provider.ts | 2 +- .../prover/src/web3_provider_inspector.ts | 4 +- packages/prover/src/web3_proxy.ts | 6 +- .../prover/test/e2e/cli/cmds/start.test.ts | 10 +- .../test/e2e/web3_batch_request.test.ts | 6 +- .../prover/test/e2e/web3_provider.test.ts | 6 +- packages/prover/test/mocks/request_handler.ts | 12 +- .../unit/proof_provider/orderd_map.test.ts | 2 +- .../unit/proof_provider/payload_store.test.ts | 10 +- .../ethers_provider_type.test.ts | 2 +- .../legacy_provider_type.test.ts | 2 +- .../web3js_provider_type.test.ts | 2 +- .../prover/test/unit/utils/conversion.test.ts | 2 +- .../prover/test/unit/utils/execution.test.ts | 6 +- .../unit/verified_requests/eth_call.test.ts | 6 +- .../verified_requests/eth_estimateGas.test.ts | 8 +- .../verified_requests/eth_getBalance.test.ts | 6 +- .../eth_getBlockByHash.test.ts | 6 +- .../eth_getBlockByNumber.test.ts | 4 +- .../verified_requests/eth_getCode.test.ts | 6 +- .../eth_getTransactionCount.test.ts | 6 +- .../test/unit/web3_provider.node.test.ts | 10 +- .../test/unit/web3_provider_inspector.test.ts | 6 +- packages/reqresp/src/ReqResp.ts | 10 +- .../reqresp/src/encoders/requestDecode.ts | 2 +- .../reqresp/src/encoders/requestEncode.ts | 2 +- .../reqresp/src/encoders/responseDecode.ts | 8 +- .../reqresp/src/encoders/responseEncode.ts | 4 +- .../encodingStrategies/sszSnappy/decode.ts | 4 +- .../sszSnappy/snappyFrames/compress.ts | 2 +- packages/reqresp/src/request/errors.ts | 2 +- packages/reqresp/src/request/index.ts | 12 +- packages/reqresp/src/response/index.ts | 12 +- packages/reqresp/src/utils/collectExactOne.ts | 2 +- .../test/fixtures/encodingStrategies.ts | 4 +- packages/reqresp/test/fixtures/messages.ts | 2 +- packages/reqresp/test/fixtures/protocols.ts | 6 +- packages/reqresp/test/unit/ReqResp.test.ts | 8 +- .../test/unit/encoders/reqestEncode.test.ts | 2 +- .../test/unit/encoders/requestDecode.test.ts | 2 +- .../test/unit/encoders/responseDecode.test.ts | 6 +- .../test/unit/encoders/responseEncode.test.ts | 4 +- .../sszSnappy/decode.test.ts | 4 +- .../sszSnappy/encode.test.ts | 2 +- .../sszSnappy/snappyFrames/uncompress.test.ts | 6 +- .../sszSnappy/utils.test.ts | 2 +- .../unit/rate_limiter/rateLimiterGRCA.test.ts | 2 +- .../reqresp/test/unit/request/index.test.ts | 18 +-- .../reqresp/test/unit/response/index.test.ts | 6 +- .../test/unit/utils/protocolId.test.ts | 2 +- packages/reqresp/test/utils/errors.ts | 2 +- packages/reqresp/test/utils/index.ts | 8 +- packages/spec-test-util/src/downloadTests.ts | 4 +- packages/spec-test-util/src/single.ts | 4 +- packages/spec-test-util/src/sszGeneric.ts | 4 +- .../test/e2e/single/index.test.ts | 4 +- packages/state-transition/src/block/index.ts | 10 +- .../src/block/isValidIndexedAttestation.ts | 2 +- .../src/block/processAttestationPhase0.ts | 6 +- .../src/block/processAttestations.ts | 2 +- .../src/block/processAttestationsAltair.ts | 8 +- .../src/block/processAttesterSlashing.ts | 6 +- .../src/block/processBlockHeader.ts | 2 +- .../src/block/processBlsToExecutionChange.ts | 4 +- .../src/block/processConsolidationRequest.ts | 6 +- .../src/block/processDeposit.ts | 6 +- .../src/block/processDepositRequest.ts | 2 +- .../src/block/processExecutionPayload.ts | 8 +- .../src/block/processOperations.ts | 10 +- .../src/block/processProposerSlashing.ts | 6 +- .../src/block/processRandao.ts | 4 +- .../src/block/processSyncCommittee.ts | 6 +- .../src/block/processVoluntaryExit.ts | 4 +- .../src/block/processWithdrawalRequest.ts | 8 +- .../src/block/processWithdrawals.ts | 10 +- .../src/block/slashValidator.ts | 4 +- .../state-transition/src/cache/epochCache.ts | 68 +++++------ .../src/cache/epochTransitionCache.ts | 24 ++-- .../state-transition/src/cache/pubkeyCache.ts | 2 +- .../state-transition/src/cache/stateCache.ts | 6 +- .../src/cache/syncCommitteeCache.ts | 4 +- packages/state-transition/src/cache/types.ts | 2 +- .../src/epoch/computeUnrealizedCheckpoints.ts | 4 +- .../src/epoch/getAttestationDeltas.ts | 6 +- .../src/epoch/getRewardsAndPenalties.ts | 2 +- packages/state-transition/src/epoch/index.ts | 10 +- .../epoch/processEffectiveBalanceUpdates.ts | 2 +- .../src/epoch/processEth1DataReset.ts | 2 +- .../src/epoch/processHistoricalRootsUpdate.ts | 2 +- .../epoch/processHistoricalSummariesUpdate.ts | 2 +- .../processJustificationAndFinalization.ts | 2 +- .../src/epoch/processPendingDeposits.ts | 4 +- .../src/epoch/processRandaoMixesReset.ts | 2 +- .../src/epoch/processRegistryUpdates.ts | 4 +- .../src/epoch/processSlashings.ts | 2 +- .../src/epoch/processSlashingsReset.ts | 2 +- .../src/epoch/processSyncCommitteeUpdates.ts | 2 +- packages/state-transition/src/metrics.ts | 4 +- .../src/signatureSets/attesterSlashings.ts | 4 +- .../src/signatureSets/blsToExecutionChange.ts | 4 +- .../src/signatureSets/index.ts | 8 +- .../src/signatureSets/indexedAttestation.ts | 4 +- .../src/signatureSets/proposer.ts | 2 +- .../src/signatureSets/proposerSlashings.ts | 2 +- .../src/signatureSets/randao.ts | 6 +- .../src/signatureSets/voluntaryExits.ts | 6 +- packages/state-transition/src/slot/index.ts | 2 +- .../src/slot/upgradeStateToAltair.ts | 10 +- .../src/slot/upgradeStateToBellatrix.ts | 2 +- .../src/slot/upgradeStateToCapella.ts | 2 +- .../src/slot/upgradeStateToDeneb.ts | 2 +- .../src/slot/upgradeStateToElectra.ts | 6 +- .../state-transition/src/stateTransition.ts | 30 ++--- .../state-transition/src/util/aggregator.ts | 6 +- .../state-transition/src/util/attestation.ts | 2 +- .../state-transition/src/util/blindedBlock.ts | 16 +-- .../state-transition/src/util/blockRoot.ts | 10 +- .../src/util/calculateCommitteeAssignments.ts | 2 +- .../src/util/computeAnchorCheckpoint.ts | 2 +- packages/state-transition/src/util/domain.ts | 2 +- packages/state-transition/src/util/electra.ts | 2 +- packages/state-transition/src/util/epoch.ts | 2 +- .../src/util/epochShuffling.ts | 12 +- .../state-transition/src/util/execution.ts | 18 +-- packages/state-transition/src/util/genesis.ts | 14 +-- packages/state-transition/src/util/interop.ts | 2 +- .../src/util/loadState/loadState.ts | 6 +- .../state-transition/src/util/rootCache.ts | 2 +- packages/state-transition/src/util/seed.ts | 6 +- packages/state-transition/src/util/slot.ts | 4 +- .../src/util/syncCommittee.ts | 4 +- .../state-transition/src/util/validator.ts | 4 +- .../src/util/weakSubjectivity.ts | 2 +- .../test/perf/analyzeEpochs.ts | 4 +- .../perf/block/processAttestation.test.ts | 2 +- .../perf/block/processBlockAltair.test.ts | 4 +- .../perf/block/processBlockPhase0.test.ts | 2 +- .../test/perf/block/processEth1Data.test.ts | 2 +- .../perf/block/processWithdrawals.test.ts | 4 +- .../state-transition/test/perf/block/util.ts | 14 +-- .../test/perf/dataStructures/arrayish.test.ts | 2 +- .../test/perf/epoch/epochAltair.test.ts | 32 ++--- .../test/perf/epoch/epochCapella.test.ts | 32 ++--- .../test/perf/epoch/epochPhase0.test.ts | 28 ++--- .../processEffectiveBalanceUpdates.test.ts | 8 +- .../perf/epoch/processRegistryUpdates.test.ts | 4 +- .../epoch/processRewardsAndPenalties.test.ts | 4 +- .../processRewardsAndPenaltiesPhase0.test.ts | 2 +- .../epoch/processSlashingsAllForks.test.ts | 8 +- .../test/perf/epoch/utilPhase0.ts | 2 +- .../test/perf/hashing.test.ts | 4 +- .../test/perf/misc/aggregationBits.test.ts | 2 +- .../test/perf/misc/byteArrayEquals.test.ts | 2 +- .../test/perf/misc/rootEquals.test.ts | 2 +- .../test/perf/sanityCheck.test.ts | 2 +- .../test/perf/slot/slots.test.ts | 2 +- packages/state-transition/test/perf/types.ts | 2 +- packages/state-transition/test/perf/util.ts | 24 ++-- .../test/perf/util/balance.test.ts | 4 +- .../test/perf/util/epochContext.test.ts | 2 +- .../loadState/findModifiedValidators.test.ts | 6 +- .../perf/util/loadState/loadState.test.ts | 6 +- .../test/perf/util/rootCache.test.ts | 4 +- .../test/perf/util/shufflings.test.ts | 6 +- .../test/perf/util/signingRoot.test.ts | 2 +- .../block/isValidIndexedAttestation.test.ts | 4 +- .../unit/block/processWithdrawals.test.ts | 4 +- .../test/unit/cachedBeaconState.test.ts | 12 +- .../test/unit/constants.test.ts | 2 +- .../unit/signatureSets/signatureSets.test.ts | 6 +- .../test/unit/upgradeState.test.ts | 10 +- .../test/unit/util/aggregator.test.ts | 4 +- .../test/unit/util/balance.test.ts | 8 +- .../test/unit/util/cachedBeaconState.test.ts | 2 +- .../test/unit/util/deposit.test.ts | 4 +- .../test/unit/util/epoch.test.ts | 6 +- .../test/unit/util/flags.test.ts | 2 +- .../test/unit/util/loadState.test.ts | 6 +- .../findModifiedInactivityScores.test.ts | 2 +- .../loadState/findModifiedValidators.test.ts | 2 +- .../unit/util/loadState/loadValidator.test.ts | 2 +- .../test/unit/util/misc.test.ts | 4 +- .../test/unit/util/seed.test.ts | 2 +- .../test/unit/util/shuffling.test.ts | 6 +- .../test/unit/util/slashing.test.ts | 2 +- .../test/unit/util/slot.test.ts | 2 +- .../test/unit/util/validator.test.ts | 4 +- .../test/unit/util/weakSubjectivity.test.ts | 4 +- .../state-transition/test/utils/capella.ts | 6 +- packages/state-transition/test/utils/state.ts | 10 +- .../test/utils/testFileCache.ts | 4 +- packages/test-utils/src/childProcess.ts | 4 +- packages/test-utils/src/cli.ts | 4 +- packages/test-utils/src/doubles.ts | 2 +- packages/test-utils/src/externalSigner.ts | 4 +- packages/test-utils/src/http.ts | 2 +- packages/types/src/altair/index.ts | 2 +- packages/types/src/altair/sszTypes.ts | 8 +- packages/types/src/bellatrix/index.ts | 2 +- packages/types/src/bellatrix/sszTypes.ts | 6 +- packages/types/src/capella/index.ts | 2 +- packages/types/src/capella/sszTypes.ts | 10 +- packages/types/src/deneb/index.ts | 2 +- packages/types/src/deneb/sszTypes.ts | 14 +-- packages/types/src/electra/index.ts | 2 +- packages/types/src/electra/sszTypes.ts | 22 ++-- packages/types/src/phase0/index.ts | 2 +- packages/types/src/phase0/sszTypes.ts | 2 +- packages/types/src/primitive/index.ts | 2 +- packages/types/src/primitive/sszTypes.ts | 2 +- packages/types/src/sszTypes.ts | 2 +- packages/types/src/types.ts | 2 +- packages/types/src/utils/executionAddress.ts | 2 +- packages/types/src/utils/typeguards.ts | 18 +-- packages/types/test/constants/blobs.test.ts | 2 +- .../types/test/constants/lightclient.test.ts | 2 +- packages/types/test/unit/blinded.test.ts | 2 +- .../types/test/unit/executionAddress.test.ts | 2 +- .../types/test/unit/phase0/sszTypes.test.ts | 2 +- packages/types/test/unit/ssz.test.ts | 2 +- .../types/test/unit/validatorStatus.test.ts | 4 +- packages/utils/src/bytes.ts | 2 +- packages/utils/src/bytes/index.ts | 8 +- packages/utils/src/command.ts | 2 +- packages/utils/test/perf/bytes.test.ts | 4 +- packages/utils/test/types/metrics.test-d.ts | 2 +- packages/utils/test/unit/assert.test.ts | 2 +- packages/utils/test/unit/base64.test.ts | 4 +- packages/utils/test/unit/bytes.test.ts | 10 +- packages/utils/test/unit/err.test.ts | 4 +- packages/utils/test/unit/format.test.ts | 2 +- packages/utils/test/unit/math.test.ts | 4 +- packages/utils/test/unit/objects.test.ts | 2 +- packages/utils/test/unit/promise.node.test.ts | 2 +- packages/utils/test/unit/promise.test.ts | 4 +- packages/utils/test/unit/promiserace.test.ts | 4 +- packages/utils/test/unit/retry.test.ts | 4 +- packages/utils/test/unit/sleep.test.ts | 4 +- packages/utils/test/unit/timeout.test.ts | 4 +- packages/utils/test/unit/waitFor.test.ts | 4 +- packages/validator/src/genesis.ts | 2 +- .../src/repositories/metaDataRepository.ts | 4 +- .../validator/src/services/attestation.ts | 18 +-- .../src/services/attestationDuties.ts | 12 +- packages/validator/src/services/block.ts | 22 ++-- .../validator/src/services/blockDuties.ts | 8 +- .../src/services/chainHeaderTracker.ts | 4 +- .../src/services/doppelgangerService.ts | 6 +- packages/validator/src/services/emitter.ts | 2 +- .../src/services/externalSignerSync.ts | 2 +- packages/validator/src/services/indices.ts | 4 +- .../src/services/prepareBeaconProposer.ts | 4 +- .../validator/src/services/syncCommittee.ts | 16 +-- .../src/services/syncCommitteeDuties.ts | 12 +- .../src/services/syncingStatusTracker.ts | 4 +- .../validator/src/services/validatorStore.ts | 46 +++---- .../attestationByTargetRepository.ts | 6 +- .../attestationLowerBoundRepository.ts | 4 +- .../slashingProtection/attestation/index.ts | 4 +- .../block/blockBySlotRepository.ts | 6 +- .../src/slashingProtection/block/index.ts | 4 +- .../validator/src/slashingProtection/index.ts | 12 +- .../interchange/formats/completeV4.ts | 2 +- .../interchange/formats/v5.ts | 2 +- .../interchange/parseInterchange.ts | 2 +- .../interchange/serializeInterchange.ts | 2 +- .../src/slashingProtection/interface.ts | 2 +- .../minMaxSurround/distanceStoreRepository.ts | 2 +- .../minMaxSurround/minMaxSurround.ts | 2 +- packages/validator/src/types.ts | 2 +- packages/validator/src/util/clock.ts | 6 +- .../src/util/externalSignerClient.ts | 22 ++-- packages/validator/src/util/params.ts | 2 +- packages/validator/src/validator.ts | 30 ++--- .../validator/test/e2e/web3signer.test.ts | 16 +-- packages/validator/test/spec/downloadTests.ts | 2 +- packages/validator/test/spec/index.test.ts | 10 +- packages/validator/test/spec/spec.test.ts | 8 +- .../test/unit/services/attestation.test.ts | 14 +-- .../unit/services/attestationDuties.test.ts | 18 +-- .../test/unit/services/block.test.ts | 12 +- .../test/unit/services/blockDuties.test.ts | 10 +- .../test/unit/services/doppelganger.test.ts | 10 +- .../unit/services/externalSignerSync.test.ts | 6 +- .../test/unit/services/indicesService.test.ts | 8 +- .../unit/services/syncCommitteDuties.test.ts | 16 +-- .../test/unit/services/syncCommittee.test.ts | 14 +-- .../services/syncingStatusTracker.test.ts | 6 +- .../test/unit/services/utils.test.ts | 2 +- .../interchange/index.test.ts | 2 +- .../minMaxSurround/surroundTests.test.ts | 2 +- .../minMaxSurround/updateSpans.test.ts | 6 +- .../minMaxSurround/utils.ts | 2 +- .../unit/slashingProtection/utils.test.ts | 2 +- .../validator/test/unit/utils/batch.test.ts | 2 +- .../validator/test/unit/utils/clock.test.ts | 4 +- .../test/unit/utils/difference.test.ts | 2 +- .../validator/test/unit/utils/metrics.test.ts | 2 +- .../validator/test/unit/utils/params.test.ts | 8 +- .../test/unit/validatorStore.test.ts | 10 +- packages/validator/test/utils/apiStub.ts | 2 +- packages/validator/test/utils/logger.ts | 2 +- .../validator/test/utils/validatorStore.ts | 2 +- 1068 files changed, 3633 insertions(+), 3636 deletions(-) diff --git a/biome.jsonc b/biome.jsonc index 212a61d86aa2..f50f4ad9c8d1 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -18,10 +18,7 @@ "ignore": ["**/lib", "**/.nyc_output", "./packages/*/spec-tests", "**/node_modules", "./packages/*/node_modules/**"] }, "organizeImports": { - // TODO: We will enable this settings as soon mono-repo support is provided in biome. - // Currently it didn't recognize local packages in repo and sort those higher than npm packages - // https://github.com/biomejs/biome/issues/2228 - "enabled": false + "enabled": true }, "linter": { "enabled": true, diff --git a/packages/api/src/beacon/client/debug.ts b/packages/api/src/beacon/client/debug.ts index 4df3bef12cf8..c0f2514fa3eb 100644 --- a/packages/api/src/beacon/client/debug.ts +++ b/packages/api/src/beacon/client/debug.ts @@ -1,5 +1,5 @@ import {ChainForkConfig} from "@lodestar/config"; -import {ApiClientMethods, createApiClientMethods, IHttpClient} from "../../utils/client/index.js"; +import {ApiClientMethods, IHttpClient, createApiClientMethods} from "../../utils/client/index.js"; import {Endpoints, getDefinitions} from "../routes/debug.js"; export type ApiClient = ApiClientMethods; diff --git a/packages/api/src/beacon/routes/beacon/block.ts b/packages/api/src/beacon/routes/beacon/block.ts index cd3cae9fd7ff..8fadfa1b9002 100644 --- a/packages/api/src/beacon/routes/beacon/block.ts +++ b/packages/api/src/beacon/routes/beacon/block.ts @@ -1,21 +1,23 @@ import {ContainerType, ListCompositeType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; +import {ForkName, ForkPreElectra, ForkPreExecution, isForkBlobs, isForkExecution} from "@lodestar/params"; import { - Slot, - ssz, + BeaconBlockBody, RootHex, - deneb, - isSignedBlockContents, SignedBeaconBlock, - BeaconBlockBody, SignedBeaconBlockOrContents, SignedBlindedBeaconBlock, SignedBlockContents, + Slot, + deneb, + isSignedBlockContents, + ssz, sszTypesFor, } from "@lodestar/types"; -import {ForkName, ForkPreElectra, ForkPreExecution, isForkBlobs, isForkExecution} from "@lodestar/params"; -import {Endpoint, RequestCodec, RouteDefinitions, Schema} from "../../../utils/index.js"; import {EmptyMeta, EmptyResponseCodec, EmptyResponseData, WithVersion} from "../../../utils/codecs.js"; +import {getExecutionForkTypes, toForkName} from "../../../utils/fork.js"; +import {fromHeaders} from "../../../utils/headers.js"; +import {Endpoint, RequestCodec, RouteDefinitions, Schema} from "../../../utils/index.js"; import { ExecutionOptimisticAndFinalizedCodec, ExecutionOptimisticAndFinalizedMeta, @@ -23,8 +25,6 @@ import { ExecutionOptimisticFinalizedAndVersionMeta, MetaHeader, } from "../../../utils/metadata.js"; -import {getExecutionForkTypes, toForkName} from "../../../utils/fork.js"; -import {fromHeaders} from "../../../utils/headers.js"; import {WireFormat} from "../../../utils/wireFormat.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes diff --git a/packages/api/src/beacon/routes/beacon/index.ts b/packages/api/src/beacon/routes/beacon/index.ts index 39d7d995dfb1..5c4a9163a1b7 100644 --- a/packages/api/src/beacon/routes/beacon/index.ts +++ b/packages/api/src/beacon/routes/beacon/index.ts @@ -1,11 +1,11 @@ import {ChainForkConfig} from "@lodestar/config"; import {phase0, ssz} from "@lodestar/types"; +import {EmptyArgs, EmptyMeta, EmptyMetaCodec, EmptyRequest, EmptyRequestCodec} from "../../../utils/codecs.js"; import {Endpoint, RouteDefinitions} from "../../../utils/types.js"; -import {EmptyArgs, EmptyRequestCodec, EmptyMeta, EmptyMetaCodec, EmptyRequest} from "../../../utils/codecs.js"; import * as block from "./block.js"; import * as pool from "./pool.js"; -import * as state from "./state.js"; import * as rewards from "./rewards.js"; +import * as state from "./state.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes diff --git a/packages/api/src/beacon/routes/beacon/pool.ts b/packages/api/src/beacon/routes/beacon/pool.ts index 3f0b8ac74284..4d909c2aac7b 100644 --- a/packages/api/src/beacon/routes/beacon/pool.ts +++ b/packages/api/src/beacon/routes/beacon/pool.ts @@ -1,22 +1,22 @@ import {ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {isForkPostElectra} from "@lodestar/params"; -import {phase0, capella, CommitteeIndex, Slot, ssz, electra, AttesterSlashing} from "@lodestar/types"; -import {Schema, Endpoint, RouteDefinitions} from "../../../utils/index.js"; +import {AttesterSlashing, CommitteeIndex, Slot, capella, electra, phase0, ssz} from "@lodestar/types"; import { ArrayOf, EmptyArgs, - EmptyRequestCodec, EmptyMeta, EmptyMetaCodec, EmptyRequest, + EmptyRequestCodec, EmptyResponseCodec, EmptyResponseData, WithVersion, } from "../../../utils/codecs.js"; -import {MetaHeader, VersionCodec, VersionMeta} from "../../../utils/metadata.js"; import {toForkName} from "../../../utils/fork.js"; import {fromHeaders} from "../../../utils/headers.js"; +import {Endpoint, RouteDefinitions, Schema} from "../../../utils/index.js"; +import {MetaHeader, VersionCodec, VersionMeta} from "../../../utils/metadata.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes diff --git a/packages/api/src/beacon/routes/beacon/rewards.ts b/packages/api/src/beacon/routes/beacon/rewards.ts index d41b5ef705f0..3acb09955cb4 100644 --- a/packages/api/src/beacon/routes/beacon/rewards.ts +++ b/packages/api/src/beacon/routes/beacon/rewards.ts @@ -2,10 +2,10 @@ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {Epoch, ssz} from "@lodestar/types"; -import {Schema, Endpoint, RouteDefinitions} from "../../../utils/index.js"; -import {fromValidatorIdsStr, toValidatorIdsStr} from "../../../utils/serdes.js"; import {ArrayOf, JsonOnlyReq} from "../../../utils/codecs.js"; +import {Endpoint, RouteDefinitions, Schema} from "../../../utils/index.js"; import {ExecutionOptimisticAndFinalizedCodec, ExecutionOptimisticAndFinalizedMeta} from "../../../utils/metadata.js"; +import {fromValidatorIdsStr, toValidatorIdsStr} from "../../../utils/serdes.js"; import {BlockArgs} from "./block.js"; import {ValidatorId} from "./state.js"; diff --git a/packages/api/src/beacon/routes/beacon/state.ts b/packages/api/src/beacon/routes/beacon/state.ts index 4127bb1ce793..d1284558f98f 100644 --- a/packages/api/src/beacon/routes/beacon/state.ts +++ b/packages/api/src/beacon/routes/beacon/state.ts @@ -1,9 +1,9 @@ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; -import {phase0, CommitteeIndex, Slot, Epoch, ssz, RootHex, StringType, ValidatorStatus} from "@lodestar/types"; -import {Endpoint, RequestCodec, RouteDefinitions, Schema} from "../../../utils/index.js"; +import {CommitteeIndex, Epoch, RootHex, Slot, StringType, ValidatorStatus, phase0, ssz} from "@lodestar/types"; import {ArrayOf, JsonOnlyReq} from "../../../utils/codecs.js"; +import {Endpoint, RequestCodec, RouteDefinitions, Schema} from "../../../utils/index.js"; import {ExecutionOptimisticAndFinalizedCodec, ExecutionOptimisticAndFinalizedMeta} from "../../../utils/metadata.js"; import {fromValidatorIdsStr, toValidatorIdsStr} from "../../../utils/serdes.js"; import {WireFormat} from "../../../utils/wireFormat.js"; diff --git a/packages/api/src/beacon/routes/config.ts b/packages/api/src/beacon/routes/config.ts index afce0898908c..cd76c2bf41b2 100644 --- a/packages/api/src/beacon/routes/config.ts +++ b/packages/api/src/beacon/routes/config.ts @@ -4,10 +4,10 @@ import {ssz} from "@lodestar/types"; import { ArrayOf, EmptyArgs, - EmptyRequestCodec, EmptyMeta, EmptyMetaCodec, EmptyRequest, + EmptyRequestCodec, JsonOnlyResp, } from "../../utils/codecs.js"; import {Endpoint, RouteDefinitions} from "../../utils/index.js"; diff --git a/packages/api/src/beacon/routes/debug.ts b/packages/api/src/beacon/routes/debug.ts index 349684f62ccd..9afc96d5a637 100644 --- a/packages/api/src/beacon/routes/debug.ts +++ b/packages/api/src/beacon/routes/debug.ts @@ -1,22 +1,22 @@ import {ContainerType, Type, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; -import {ssz, StringType, BeaconState} from "@lodestar/types"; +import {BeaconState, StringType, ssz} from "@lodestar/types"; import { ArrayOf, EmptyArgs, - EmptyRequestCodec, EmptyMeta, EmptyMetaCodec, EmptyRequest, + EmptyRequestCodec, WithVersion, } from "../../utils/codecs.js"; import { ExecutionOptimisticFinalizedAndVersionCodec, ExecutionOptimisticFinalizedAndVersionMeta, } from "../../utils/metadata.js"; +import {Schema} from "../../utils/schema.js"; import {Endpoint, RouteDefinitions} from "../../utils/types.js"; import {WireFormat} from "../../utils/wireFormat.js"; -import {Schema} from "../../utils/schema.js"; import {StateArgs} from "./beacon/state.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes diff --git a/packages/api/src/beacon/routes/events.ts b/packages/api/src/beacon/routes/events.ts index 5fa218bc02f3..81bd6e7a7f5e 100644 --- a/packages/api/src/beacon/routes/events.ts +++ b/packages/api/src/beacon/routes/events.ts @@ -1,27 +1,27 @@ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; +import {ForkName} from "@lodestar/params"; import { + Attestation, + AttesterSlashing, Epoch, - phase0, - capella, + LightClientFinalityUpdate, + LightClientOptimisticUpdate, + RootHex, + SSEPayloadAttributes, Slot, - ssz, StringType, - RootHex, - altair, UintNum64, - LightClientOptimisticUpdate, - LightClientFinalityUpdate, - SSEPayloadAttributes, - Attestation, - AttesterSlashing, + altair, + capella, + phase0, + ssz, sszTypesFor, } from "@lodestar/types"; -import {ForkName} from "@lodestar/params"; -import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import {EmptyMeta, EmptyResponseCodec, EmptyResponseData} from "../../utils/codecs.js"; import {getExecutionForkTypes, getLightClientForkTypes} from "../../utils/fork.js"; +import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import {VersionType} from "../../utils/metadata.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes diff --git a/packages/api/src/beacon/routes/lightclient.ts b/packages/api/src/beacon/routes/lightclient.ts index bac73b43ddb2..d3e60a69bae9 100644 --- a/packages/api/src/beacon/routes/lightclient.ts +++ b/packages/api/src/beacon/routes/lightclient.ts @@ -1,27 +1,27 @@ import {ListCompositeType, ValueOf} from "@chainsafe/ssz"; +import {BeaconConfig, ChainForkConfig, createBeaconConfig} from "@lodestar/config"; +import {NetworkName, genesisData} from "@lodestar/config/networks"; +import {ForkName, ZERO_HASH} from "@lodestar/params"; import { LightClientBootstrap, LightClientFinalityUpdate, LightClientOptimisticUpdate, LightClientUpdate, - ssz, SyncPeriod, + ssz, } from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; -import {ForkName, ZERO_HASH} from "@lodestar/params"; -import {BeaconConfig, ChainForkConfig, createBeaconConfig} from "@lodestar/config"; -import {genesisData, NetworkName} from "@lodestar/config/networks"; -import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; -import {MetaHeader, VersionCodec, VersionMeta} from "../../utils/metadata.js"; -import {getLightClientForkTypes, toForkName} from "../../utils/fork.js"; import { EmptyArgs, - EmptyRequestCodec, EmptyMeta, EmptyMetaCodec, EmptyRequest, + EmptyRequestCodec, WithVersion, } from "../../utils/codecs.js"; +import {getLightClientForkTypes, toForkName} from "../../utils/fork.js"; +import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; +import {MetaHeader, VersionCodec, VersionMeta} from "../../utils/metadata.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes diff --git a/packages/api/src/beacon/routes/lodestar.ts b/packages/api/src/beacon/routes/lodestar.ts index 1d3c62ca2082..81191efd2696 100644 --- a/packages/api/src/beacon/routes/lodestar.ts +++ b/packages/api/src/beacon/routes/lodestar.ts @@ -1,15 +1,15 @@ import {ChainForkConfig} from "@lodestar/config"; import {Epoch, RootHex, Slot} from "@lodestar/types"; -import {Schema, Endpoint, RouteDefinitions} from "../../utils/index.js"; import { EmptyArgs, - EmptyRequestCodec, EmptyMeta, EmptyRequest, + EmptyRequestCodec, EmptyResponseCodec, EmptyResponseData, JsonOnlyResponseCodec, } from "../../utils/codecs.js"; +import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import {FilterGetPeers, NodePeer, PeerDirection, PeerState} from "./node.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes diff --git a/packages/api/src/beacon/routes/node.ts b/packages/api/src/beacon/routes/node.ts index c7a6c2e36361..e98c0f42ec56 100644 --- a/packages/api/src/beacon/routes/node.ts +++ b/packages/api/src/beacon/routes/node.ts @@ -1,19 +1,19 @@ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {ssz, stringType} from "@lodestar/types"; -import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import { ArrayOf, EmptyArgs, - EmptyRequestCodec, EmptyMeta, EmptyMetaCodec, EmptyRequest, + EmptyRequestCodec, EmptyResponseCodec, EmptyResponseData, JsonOnlyResponseCodec, } from "../../utils/codecs.js"; import {HttpStatusCode} from "../../utils/httpStatusCode.js"; +import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import {WireFormat} from "../../utils/wireFormat.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes diff --git a/packages/api/src/beacon/routes/proof.ts b/packages/api/src/beacon/routes/proof.ts index 0c6d5a058cea..63f6765e3873 100644 --- a/packages/api/src/beacon/routes/proof.ts +++ b/packages/api/src/beacon/routes/proof.ts @@ -1,10 +1,10 @@ import {CompactMultiProof, ProofType} from "@chainsafe/persistent-merkle-tree"; import {ByteListType, ContainerType} from "@chainsafe/ssz"; -import {fromHex, toHex} from "@lodestar/utils"; import {ChainForkConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; -import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; +import {fromHex, toHex} from "@lodestar/utils"; import {ArrayOf} from "../../utils/codecs.js"; +import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import {VersionCodec, VersionMeta} from "../../utils/metadata.js"; export const CompactMultiProofType = new ContainerType({ diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index cf30d5748a46..313459f4db97 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -2,27 +2,24 @@ import {ContainerType, Type, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {isForkBlobs, isForkPostElectra} from "@lodestar/params"; import { - altair, + Attestation, BLSSignature, + BeaconBlockOrContents, + BlindedBeaconBlock, CommitteeIndex, Epoch, - phase0, + ProducedBlockSource, Root, Slot, - ssz, UintBn64, ValidatorIndex, - ProducedBlockSource, - stringType, - BeaconBlockOrContents, - BlindedBeaconBlock, - Attestation, + altair, + phase0, + ssz, sszTypesFor, + stringType, } from "@lodestar/types"; import {fromHex, toHex, toRootHex} from "@lodestar/utils"; -import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; -import {fromGraffitiHex, toBoolean, toGraffitiHex} from "../../utils/serdes.js"; -import {getExecutionForkTypes, toForkName} from "../../utils/fork.js"; import { ArrayOf, EmptyMeta, @@ -33,6 +30,9 @@ import { WithMeta, WithVersion, } from "../../utils/codecs.js"; +import {getExecutionForkTypes, toForkName} from "../../utils/fork.js"; +import {fromHeaders} from "../../utils/headers.js"; +import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import { ExecutionOptimisticAndDependentRootCodec, ExecutionOptimisticAndDependentRootMeta, @@ -43,7 +43,7 @@ import { VersionMeta, VersionType, } from "../../utils/metadata.js"; -import {fromHeaders} from "../../utils/headers.js"; +import {fromGraffitiHex, toBoolean, toGraffitiHex} from "../../utils/serdes.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes diff --git a/packages/api/src/beacon/server/events.ts b/packages/api/src/beacon/server/events.ts index b9027ab1879d..a68edb6c4146 100644 --- a/packages/api/src/beacon/server/events.ts +++ b/packages/api/src/beacon/server/events.ts @@ -1,6 +1,6 @@ import {ChainForkConfig} from "@lodestar/config"; import {ApiError, ApplicationMethods, FastifyRoutes, createFastifyRoutes} from "../../utils/server/index.js"; -import {Endpoints, getDefinitions, eventTypes, getEventSerdes} from "../routes/events.js"; +import {Endpoints, eventTypes, getDefinitions, getEventSerdes} from "../routes/events.js"; export function getRoutes(config: ChainForkConfig, methods: ApplicationMethods): FastifyRoutes { const eventSerdes = getEventSerdes(config); diff --git a/packages/api/src/beacon/server/index.ts b/packages/api/src/beacon/server/index.ts index 304f4d42be17..cc5005aa2740 100644 --- a/packages/api/src/beacon/server/index.ts +++ b/packages/api/src/beacon/server/index.ts @@ -1,5 +1,5 @@ -import type {FastifyInstance} from "fastify"; import {ChainForkConfig} from "@lodestar/config"; +import type {FastifyInstance} from "fastify"; import {ApplicationMethods, FastifyRoute} from "../../utils/server/index.js"; import {Endpoints} from "../routes/index.js"; diff --git a/packages/api/src/builder/index.ts b/packages/api/src/builder/index.ts index d1d9d31a17ab..9497cd5e95ba 100644 --- a/packages/api/src/builder/index.ts +++ b/packages/api/src/builder/index.ts @@ -1,7 +1,7 @@ import {ChainForkConfig} from "@lodestar/config"; import {HttpClient, HttpClientModules, HttpClientOptions, IHttpClient} from "../utils/client/httpClient.js"; -import {Endpoints} from "./routes.js"; import type {ApiClient} from "./client.js"; +import {Endpoints} from "./routes.js"; import * as builder from "./client.js"; diff --git a/packages/api/src/builder/routes.ts b/packages/api/src/builder/routes.ts index 3911a515e1c6..91042539f96b 100644 --- a/packages/api/src/builder/routes.ts +++ b/packages/api/src/builder/routes.ts @@ -1,27 +1,25 @@ +import {ChainForkConfig} from "@lodestar/config"; +import {ForkName, isForkBlobs} from "@lodestar/params"; import { - ssz, - bellatrix, - Slot, - Root, BLSPubkey, ExecutionPayload, ExecutionPayloadAndBlobsBundle, + Root, SignedBlindedBeaconBlock, SignedBuilderBid, + Slot, WithOptionalBytes, + bellatrix, + ssz, } from "@lodestar/types"; -import {ForkName, isForkBlobs} from "@lodestar/params"; -import {ChainForkConfig} from "@lodestar/config"; import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; -import {Endpoint, RouteDefinitions, Schema} from "../utils/index.js"; -import {MetaHeader, VersionCodec, VersionMeta} from "../utils/metadata.js"; import { ArrayOf, EmptyArgs, - EmptyRequestCodec, EmptyMeta, EmptyRequest, + EmptyRequestCodec, EmptyResponseCodec, EmptyResponseData, JsonOnlyReq, @@ -29,6 +27,8 @@ import { } from "../utils/codecs.js"; import {getBlobsForkTypes, getExecutionForkTypes, toForkName} from "../utils/fork.js"; import {fromHeaders} from "../utils/headers.js"; +import {Endpoint, RouteDefinitions, Schema} from "../utils/index.js"; +import {MetaHeader, VersionCodec, VersionMeta} from "../utils/metadata.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes diff --git a/packages/api/src/builder/server/index.ts b/packages/api/src/builder/server/index.ts index 888d6bb64bec..5e59e5d9807b 100644 --- a/packages/api/src/builder/server/index.ts +++ b/packages/api/src/builder/server/index.ts @@ -1,8 +1,8 @@ -import type {FastifyInstance} from "fastify"; import {ChainForkConfig} from "@lodestar/config"; +import type {FastifyInstance} from "fastify"; +import {AnyEndpoint} from "../../utils/codecs.js"; import {ApplicationMethods, FastifyRoute, FastifyRoutes, createFastifyRoutes} from "../../utils/server/index.js"; import {Endpoints, getDefinitions} from "../routes.js"; -import {AnyEndpoint} from "../../utils/codecs.js"; export type BuilderApiMethods = ApplicationMethods; diff --git a/packages/api/src/keymanager/index.ts b/packages/api/src/keymanager/index.ts index 44252acce494..24e7e08da444 100644 --- a/packages/api/src/keymanager/index.ts +++ b/packages/api/src/keymanager/index.ts @@ -1,5 +1,5 @@ import {ChainForkConfig} from "@lodestar/config"; -import {IHttpClient, HttpClient, HttpClientModules, HttpClientOptions} from "../utils/client/index.js"; +import {HttpClient, HttpClientModules, HttpClientOptions, IHttpClient} from "../utils/client/index.js"; import type {ApiClient} from "./client.js"; import * as keymanager from "./client.js"; diff --git a/packages/api/src/keymanager/routes.ts b/packages/api/src/keymanager/routes.ts index c31ae5a04454..05eddeefd604 100644 --- a/packages/api/src/keymanager/routes.ts +++ b/packages/api/src/keymanager/routes.ts @@ -1,19 +1,19 @@ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {Epoch, phase0, ssz, stringType} from "@lodestar/types"; -import {Schema, Endpoint, RouteDefinitions} from "../utils/index.js"; -import {WireFormat} from "../utils/wireFormat.js"; import { EmptyArgs, - EmptyRequestCodec, EmptyMeta, EmptyMetaCodec, EmptyRequest, + EmptyRequestCodec, EmptyResponseCodec, EmptyResponseData, JsonOnlyReq, JsonOnlyResponseCodec, } from "../utils/codecs.js"; +import {Endpoint, RouteDefinitions, Schema} from "../utils/index.js"; +import {WireFormat} from "../utils/wireFormat.js"; export enum ImportStatus { /** Keystore successfully decrypted and imported to keymanager permanent storage */ diff --git a/packages/api/src/keymanager/server/index.ts b/packages/api/src/keymanager/server/index.ts index f4d0e75f971e..065bcb5ac5d8 100644 --- a/packages/api/src/keymanager/server/index.ts +++ b/packages/api/src/keymanager/server/index.ts @@ -1,8 +1,8 @@ -import type {FastifyInstance} from "fastify"; import {ChainForkConfig} from "@lodestar/config"; +import type {FastifyInstance} from "fastify"; +import {AnyEndpoint} from "../../utils/codecs.js"; import {ApplicationMethods, FastifyRoute, FastifyRoutes, createFastifyRoutes} from "../../utils/server/index.js"; import {Endpoints, getDefinitions} from "../routes.js"; -import {AnyEndpoint} from "../../utils/codecs.js"; export type KeymanagerApiMethods = ApplicationMethods; diff --git a/packages/api/src/utils/client/httpClient.ts b/packages/api/src/utils/client/httpClient.ts index 33b93e3a9d41..85585e8f40f7 100644 --- a/packages/api/src/utils/client/httpClient.ts +++ b/packages/api/src/utils/client/httpClient.ts @@ -1,8 +1,10 @@ import {ErrorAborted, Logger, MapDef, TimeoutError, isValidHttpUrl, retry, toPrintableUrl} from "@lodestar/utils"; import {mergeHeaders} from "../headers.js"; +import {HttpStatusCode} from "../httpStatusCode.js"; import {Endpoint} from "../types.js"; import {WireFormat} from "../wireFormat.js"; -import {HttpStatusCode} from "../httpStatusCode.js"; +import {fetch, isFetchError} from "./fetch.js"; +import {Metrics} from "./metrics.js"; import { ApiRequestInit, ApiRequestInitRequired, @@ -13,8 +15,6 @@ import { createApiRequest, } from "./request.js"; import {ApiResponse} from "./response.js"; -import {Metrics} from "./metrics.js"; -import {fetch, isFetchError} from "./fetch.js"; /** A higher default timeout, validator will set its own shorter timeoutMs */ const DEFAULT_TIMEOUT_MS = 60_000; diff --git a/packages/api/src/utils/codecs.ts b/packages/api/src/utils/codecs.ts index c075d8592a46..fad6396af085 100644 --- a/packages/api/src/utils/codecs.ts +++ b/packages/api/src/utils/codecs.ts @@ -2,12 +2,12 @@ import {ArrayType, ListBasicType, ListCompositeType, Type, isBasicType, isCompos import {ForkName} from "@lodestar/params"; import {objectToExpectedCase} from "@lodestar/utils"; import { - RequestWithoutBodyCodec, + Endpoint, RequestWithBodyCodec, + RequestWithoutBodyCodec, ResponseCodec, ResponseDataCodec, ResponseMetadataCodec, - Endpoint, SszRequestMethods, } from "./types.js"; import {WireFormat} from "./wireFormat.js"; diff --git a/packages/api/src/utils/metadata.ts b/packages/api/src/utils/metadata.ts index 2ee9b2f51f0e..6186c06a7047 100644 --- a/packages/api/src/utils/metadata.ts +++ b/packages/api/src/utils/metadata.ts @@ -1,10 +1,10 @@ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ForkName} from "@lodestar/params"; import {StringType, ssz, stringType} from "@lodestar/types"; -import {ResponseMetadataCodec} from "./types.js"; -import {toBoolean} from "./serdes.js"; import {toForkName} from "./fork.js"; import {HttpHeader} from "./headers.js"; +import {toBoolean} from "./serdes.js"; +import {ResponseMetadataCodec} from "./types.js"; export const VersionType = new ContainerType({ /** diff --git a/packages/api/src/utils/server/handler.ts b/packages/api/src/utils/server/handler.ts index 035f4328141a..b444d263cf09 100644 --- a/packages/api/src/utils/server/handler.ts +++ b/packages/api/src/utils/server/handler.ts @@ -2,15 +2,15 @@ import type * as fastify from "fastify"; import {HttpHeader, MediaType, SUPPORTED_MEDIA_TYPES, parseAcceptHeader, parseContentTypeHeader} from "../headers.js"; import { Endpoint, - RequestData, JsonRequestData, JsonRequestMethods, + RequestData, RequestWithBodyCodec, + RequestWithoutBodyCodec, RouteDefinition, SszRequestData, SszRequestMethods, isRequestWithoutBody, - RequestWithoutBodyCodec, } from "../types.js"; import {WireFormat, fromWireFormat, getWireFormat} from "../wireFormat.js"; import {ApiError} from "./error.js"; diff --git a/packages/api/src/utils/server/route.ts b/packages/api/src/utils/server/route.ts index aa04a1f11cf7..26bf07b6790e 100644 --- a/packages/api/src/utils/server/route.ts +++ b/packages/api/src/utils/server/route.ts @@ -1,5 +1,5 @@ -import type * as fastify from "fastify"; import {mapValues} from "@lodestar/utils"; +import type * as fastify from "fastify"; import {getFastifySchema} from "../schema.js"; import {Endpoint, RouteDefinition, RouteDefinitions} from "../types.js"; import {toColonNotationPath} from "../urlFormat.js"; diff --git a/packages/api/test/unit/beacon/genericServerTest/beacon.test.ts b/packages/api/test/unit/beacon/genericServerTest/beacon.test.ts index f8c13b33afb6..5f2c2d4d50e7 100644 --- a/packages/api/test/unit/beacon/genericServerTest/beacon.test.ts +++ b/packages/api/test/unit/beacon/genericServerTest/beacon.test.ts @@ -1,7 +1,7 @@ -import {describe} from "vitest"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {Endpoints} from "../../../../src/beacon/routes/beacon/index.js"; +import {describe} from "vitest"; import {getClient} from "../../../../src/beacon/client/beacon.js"; +import {Endpoints} from "../../../../src/beacon/routes/beacon/index.js"; import {getRoutes} from "../../../../src/beacon/server/beacon.js"; import {runGenericServerTest} from "../../../utils/genericServerTest.js"; import {testData} from "../testData/beacon.js"; diff --git a/packages/api/test/unit/beacon/genericServerTest/config.test.ts b/packages/api/test/unit/beacon/genericServerTest/config.test.ts index 91075f96d1e3..a66eb1768e2c 100644 --- a/packages/api/test/unit/beacon/genericServerTest/config.test.ts +++ b/packages/api/test/unit/beacon/genericServerTest/config.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; import {config} from "@lodestar/config/default"; -import {Endpoints, getDefinitions} from "../../../../src/beacon/routes/config.js"; +import {describe, expect, it} from "vitest"; import {getClient} from "../../../../src/beacon/client/config.js"; +import {Endpoints, getDefinitions} from "../../../../src/beacon/routes/config.js"; import {getRoutes} from "../../../../src/beacon/server/config.js"; import {runGenericServerTest} from "../../../utils/genericServerTest.js"; import {testData} from "../testData/config.js"; diff --git a/packages/api/test/unit/beacon/genericServerTest/debug.test.ts b/packages/api/test/unit/beacon/genericServerTest/debug.test.ts index f329382dbe46..d6140fa20512 100644 --- a/packages/api/test/unit/beacon/genericServerTest/debug.test.ts +++ b/packages/api/test/unit/beacon/genericServerTest/debug.test.ts @@ -1,19 +1,19 @@ -import {describe, it, expect, beforeAll, afterAll, vi} from "vitest"; import {toHexString} from "@chainsafe/ssz"; -import {FastifyInstance} from "fastify"; +import {config} from "@lodestar/config/default"; import {ForkName} from "@lodestar/params"; import {ssz} from "@lodestar/types"; -import {config} from "@lodestar/config/default"; -import {Endpoints, getDefinitions} from "../../../../src/beacon/routes/debug.js"; +import {FastifyInstance} from "fastify"; +import {afterAll, beforeAll, describe, expect, it, vi} from "vitest"; import {getClient} from "../../../../src/beacon/client/debug.js"; +import {Endpoints, getDefinitions} from "../../../../src/beacon/routes/debug.js"; import {getRoutes} from "../../../../src/beacon/server/debug.js"; -import {runGenericServerTest} from "../../../utils/genericServerTest.js"; -import {getMockApi, getTestServer} from "../../../utils/utils.js"; import {HttpClient} from "../../../../src/utils/client/httpClient.js"; -import {testData} from "../testData/debug.js"; -import {FastifyRoute} from "../../../../src/utils/server/index.js"; import {AnyEndpoint} from "../../../../src/utils/codecs.js"; +import {FastifyRoute} from "../../../../src/utils/server/index.js"; import {WireFormat} from "../../../../src/utils/wireFormat.js"; +import {runGenericServerTest} from "../../../utils/genericServerTest.js"; +import {getMockApi, getTestServer} from "../../../utils/utils.js"; +import {testData} from "../testData/debug.js"; describe("beacon / debug", () => { // Extend timeout since states are very big diff --git a/packages/api/test/unit/beacon/genericServerTest/events.test.ts b/packages/api/test/unit/beacon/genericServerTest/events.test.ts index 16123ec624e8..c0480c8368c9 100644 --- a/packages/api/test/unit/beacon/genericServerTest/events.test.ts +++ b/packages/api/test/unit/beacon/genericServerTest/events.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect, beforeEach, afterEach, beforeAll, afterAll} from "vitest"; -import {FastifyInstance} from "fastify"; -import {sleep} from "@lodestar/utils"; import {config} from "@lodestar/config/default"; -import {Endpoints, getDefinitions, EventType, BeaconEvent} from "../../../../src/beacon/routes/events.js"; +import {sleep} from "@lodestar/utils"; +import {FastifyInstance} from "fastify"; +import {afterAll, afterEach, beforeAll, beforeEach, describe, expect, it} from "vitest"; import {getClient} from "../../../../src/beacon/client/events.js"; +import {BeaconEvent, Endpoints, EventType, getDefinitions} from "../../../../src/beacon/routes/events.js"; import {getRoutes} from "../../../../src/beacon/server/events.js"; import {getMockApi, getTestServer} from "../../../utils/utils.js"; import {eventTestData} from "../testData/events.js"; diff --git a/packages/api/test/unit/beacon/genericServerTest/lightclient.test.ts b/packages/api/test/unit/beacon/genericServerTest/lightclient.test.ts index 5bf8b7827161..84c06d2a0d17 100644 --- a/packages/api/test/unit/beacon/genericServerTest/lightclient.test.ts +++ b/packages/api/test/unit/beacon/genericServerTest/lightclient.test.ts @@ -1,7 +1,7 @@ -import {describe} from "vitest"; import {config} from "@lodestar/config/default"; -import {Endpoints} from "../../../../src/beacon/routes/lightclient.js"; +import {describe} from "vitest"; import {getClient} from "../../../../src/beacon/client/lightclient.js"; +import {Endpoints} from "../../../../src/beacon/routes/lightclient.js"; import {getRoutes} from "../../../../src/beacon/server/lightclient.js"; import {runGenericServerTest} from "../../../utils/genericServerTest.js"; import {testData} from "../testData/lightclient.js"; diff --git a/packages/api/test/unit/beacon/genericServerTest/node.test.ts b/packages/api/test/unit/beacon/genericServerTest/node.test.ts index 0affaf014c4a..c54737b387ae 100644 --- a/packages/api/test/unit/beacon/genericServerTest/node.test.ts +++ b/packages/api/test/unit/beacon/genericServerTest/node.test.ts @@ -1,7 +1,7 @@ -import {describe} from "vitest"; import {config} from "@lodestar/config/default"; -import {Endpoints} from "../../../../src/beacon/routes/node.js"; +import {describe} from "vitest"; import {getClient} from "../../../../src/beacon/client/node.js"; +import {Endpoints} from "../../../../src/beacon/routes/node.js"; import {getRoutes} from "../../../../src/beacon/server/node.js"; import {runGenericServerTest} from "../../../utils/genericServerTest.js"; import {testData} from "../testData/node.js"; diff --git a/packages/api/test/unit/beacon/genericServerTest/proofs.test.ts b/packages/api/test/unit/beacon/genericServerTest/proofs.test.ts index d31137886e2f..518c3f70381d 100644 --- a/packages/api/test/unit/beacon/genericServerTest/proofs.test.ts +++ b/packages/api/test/unit/beacon/genericServerTest/proofs.test.ts @@ -1,7 +1,7 @@ -import {describe} from "vitest"; import {config} from "@lodestar/config/default"; -import {Endpoints} from "../../../../src/beacon/routes/proof.js"; +import {describe} from "vitest"; import {getClient} from "../../../../src/beacon/client/proof.js"; +import {Endpoints} from "../../../../src/beacon/routes/proof.js"; import {getRoutes} from "../../../../src/beacon/server/proof.js"; import {runGenericServerTest} from "../../../utils/genericServerTest.js"; import {testData} from "../testData/proofs.js"; diff --git a/packages/api/test/unit/beacon/genericServerTest/validator.test.ts b/packages/api/test/unit/beacon/genericServerTest/validator.test.ts index 0aed65cd6f17..650bc6c8f9a2 100644 --- a/packages/api/test/unit/beacon/genericServerTest/validator.test.ts +++ b/packages/api/test/unit/beacon/genericServerTest/validator.test.ts @@ -1,7 +1,7 @@ -import {describe} from "vitest"; import {config} from "@lodestar/config/default"; -import {Endpoints} from "../../../../src/beacon/routes/validator.js"; +import {describe} from "vitest"; import {getClient} from "../../../../src/beacon/client/validator.js"; +import {Endpoints} from "../../../../src/beacon/routes/validator.js"; import {getRoutes} from "../../../../src/beacon/server/validator.js"; import {runGenericServerTest} from "../../../utils/genericServerTest.js"; import {testData} from "../testData/validator.js"; diff --git a/packages/api/test/unit/beacon/oapiSpec.test.ts b/packages/api/test/unit/beacon/oapiSpec.test.ts index f6a38505e264..a3033355c984 100644 --- a/packages/api/test/unit/beacon/oapiSpec.test.ts +++ b/packages/api/test/unit/beacon/oapiSpec.test.ts @@ -1,11 +1,11 @@ import path from "node:path"; import {fileURLToPath} from "node:url"; -import {describe, it, beforeAll, expect} from "vitest"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {OpenApiFile} from "../../utils/parseOpenApiSpec.js"; +import {beforeAll, describe, expect, it} from "vitest"; import {routes} from "../../../src/beacon/index.js"; import {IgnoredProperty, runTestCheckAgainstSpec} from "../../utils/checkAgainstSpec.js"; import {fetchOpenApiSpec} from "../../utils/fetchOpenApiSpec.js"; +import {OpenApiFile} from "../../utils/parseOpenApiSpec.js"; // Import all testData and merge below import {testData as beaconTestData} from "./testData/beacon.js"; import {testData as configTestData} from "./testData/config.js"; diff --git a/packages/api/test/unit/beacon/testData/config.ts b/packages/api/test/unit/beacon/testData/config.ts index dddc90ae6b25..ab0437650df7 100644 --- a/packages/api/test/unit/beacon/testData/config.ts +++ b/packages/api/test/unit/beacon/testData/config.ts @@ -1,7 +1,7 @@ -import {ssz} from "@lodestar/types"; import {chainConfigToJson} from "@lodestar/config"; import {chainConfig} from "@lodestar/config/default"; import {activePreset, presetToJson} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; import {Endpoints} from "../../../../src/beacon/routes/config.js"; import {GenericServerTestCases} from "../../../utils/genericServerTest.js"; diff --git a/packages/api/test/unit/beacon/testData/events.ts b/packages/api/test/unit/beacon/testData/events.ts index 3d2ffb708965..c9ba39d24efe 100644 --- a/packages/api/test/unit/beacon/testData/events.ts +++ b/packages/api/test/unit/beacon/testData/events.ts @@ -1,5 +1,5 @@ -import {ssz} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; import {Endpoints, EventData, EventType, blobSidecarSSE} from "../../../../src/beacon/routes/events.js"; import {GenericServerTestCases} from "../../../utils/genericServerTest.js"; diff --git a/packages/api/test/unit/beacon/testData/lightclient.ts b/packages/api/test/unit/beacon/testData/lightclient.ts index f405d514fc5d..715f823a1d29 100644 --- a/packages/api/test/unit/beacon/testData/lightclient.ts +++ b/packages/api/test/unit/beacon/testData/lightclient.ts @@ -1,6 +1,6 @@ import {toHexString} from "@chainsafe/ssz"; -import {ssz} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; import {Endpoints} from "../../../../src/beacon/routes/lightclient.js"; import {GenericServerTestCases} from "../../../utils/genericServerTest.js"; diff --git a/packages/api/test/unit/beacon/testData/validator.ts b/packages/api/test/unit/beacon/testData/validator.ts index d4fae4bfe290..327100cedab1 100644 --- a/packages/api/test/unit/beacon/testData/validator.ts +++ b/packages/api/test/unit/beacon/testData/validator.ts @@ -1,5 +1,5 @@ import {ForkName} from "@lodestar/params"; -import {ssz, ProducedBlockSource} from "@lodestar/types"; +import {ProducedBlockSource, ssz} from "@lodestar/types"; import {BuilderSelection, Endpoints} from "../../../../src/beacon/routes/validator.js"; import {GenericServerTestCases} from "../../../utils/genericServerTest.js"; diff --git a/packages/api/test/unit/builder/builder.test.ts b/packages/api/test/unit/builder/builder.test.ts index d2e25916069e..00a38563a100 100644 --- a/packages/api/test/unit/builder/builder.test.ts +++ b/packages/api/test/unit/builder/builder.test.ts @@ -1,7 +1,7 @@ -import {describe} from "vitest"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {Endpoints} from "../../../src/builder/routes.js"; +import {describe} from "vitest"; import {getClient} from "../../../src/builder/client.js"; +import {Endpoints} from "../../../src/builder/routes.js"; import {getRoutes} from "../../../src/builder/server/index.js"; import {runGenericServerTest} from "../../utils/genericServerTest.js"; import {testData} from "./testData.js"; diff --git a/packages/api/test/unit/builder/oapiSpec.test.ts b/packages/api/test/unit/builder/oapiSpec.test.ts index d972b64905e5..8f567a5c0e1e 100644 --- a/packages/api/test/unit/builder/oapiSpec.test.ts +++ b/packages/api/test/unit/builder/oapiSpec.test.ts @@ -2,10 +2,10 @@ import path from "node:path"; import {fileURLToPath} from "node:url"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {OpenApiFile} from "../../utils/parseOpenApiSpec.js"; import {getDefinitions} from "../../../src/builder/routes.js"; import {runTestCheckAgainstSpec} from "../../utils/checkAgainstSpec.js"; import {fetchOpenApiSpec} from "../../utils/fetchOpenApiSpec.js"; +import {OpenApiFile} from "../../utils/parseOpenApiSpec.js"; import {testData} from "./testData.js"; // Global variable __dirname no longer available in ES6 modules. diff --git a/packages/api/test/unit/builder/testData.ts b/packages/api/test/unit/builder/testData.ts index a807620258df..ad0ce95f5a8b 100644 --- a/packages/api/test/unit/builder/testData.ts +++ b/packages/api/test/unit/builder/testData.ts @@ -1,6 +1,6 @@ import {fromHexString} from "@chainsafe/ssz"; -import {ssz} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; import {Endpoints} from "../../../src/builder/routes.js"; import {GenericServerTestCases} from "../../utils/genericServerTest.js"; diff --git a/packages/api/test/unit/client/fetch.test.ts b/packages/api/test/unit/client/fetch.test.ts index 1faf7d979a02..067e97e4ba6a 100644 --- a/packages/api/test/unit/client/fetch.test.ts +++ b/packages/api/test/unit/client/fetch.test.ts @@ -1,6 +1,6 @@ import crypto from "node:crypto"; import http from "node:http"; -import {describe, it, expect, afterEach} from "vitest"; +import {afterEach, describe, expect, it} from "vitest"; import {FetchError, FetchErrorType, fetch} from "../../../src/utils/client/fetch.js"; describe("FetchError", () => { diff --git a/packages/api/test/unit/client/httpClient.test.ts b/packages/api/test/unit/client/httpClient.test.ts index 577b860c4cca..aa689967f7b4 100644 --- a/packages/api/test/unit/client/httpClient.test.ts +++ b/packages/api/test/unit/client/httpClient.test.ts @@ -1,26 +1,26 @@ import {IncomingMessage} from "node:http"; -import {describe, it, afterEach, expect, vi} from "vitest"; -import {RouteOptions, fastify} from "fastify"; import {BooleanType, ContainerType, UintNumberType, ValueOf} from "@chainsafe/ssz"; import {ErrorAborted, TimeoutError, toBase64} from "@lodestar/utils"; +import {RouteOptions, fastify} from "fastify"; +import {afterEach, describe, expect, it, vi} from "vitest"; +import {WireFormat} from "../../../src/index.js"; +import {addSszContentTypeParser} from "../../../src/server/index.js"; import {HttpClient, RouteDefinitionExtra} from "../../../src/utils/client/index.js"; -import {HttpStatusCode} from "../../../src/utils/httpStatusCode.js"; import { AnyEndpoint, EmptyArgs, - EmptyRequestCodec, EmptyMeta, EmptyRequest, + EmptyRequestCodec, EmptyResponseCodec, + EmptyResponseData, JsonOnlyReq, JsonOnlyResponseCodec, - EmptyResponseData, } from "../../../src/utils/codecs.js"; -import {compileRouteUrlFormatter} from "../../../src/utils/urlFormat.js"; -import {Endpoint, Schema} from "../../../src/utils/index.js"; -import {WireFormat} from "../../../src/index.js"; import {HttpHeader, MediaType} from "../../../src/utils/headers.js"; -import {addSszContentTypeParser} from "../../../src/server/index.js"; +import {HttpStatusCode} from "../../../src/utils/httpStatusCode.js"; +import {Endpoint, Schema} from "../../../src/utils/index.js"; +import {compileRouteUrlFormatter} from "../../../src/utils/urlFormat.js"; /* eslint-disable @typescript-eslint/return-await */ diff --git a/packages/api/test/unit/client/httpClientOptions.test.ts b/packages/api/test/unit/client/httpClientOptions.test.ts index 9bc7ab2bfaf8..b2eb374e26c9 100644 --- a/packages/api/test/unit/client/httpClientOptions.test.ts +++ b/packages/api/test/unit/client/httpClientOptions.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {HttpClient} from "../../../src/index.js"; describe("HTTPClient options", () => { diff --git a/packages/api/test/unit/client/urlFormat.test.ts b/packages/api/test/unit/client/urlFormat.test.ts index 5132044b7631..a97a2dfe94a1 100644 --- a/packages/api/test/unit/client/urlFormat.test.ts +++ b/packages/api/test/unit/client/urlFormat.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import { - compileRouteUrlFormatter, - toColonNotationPath, Token, TokenType, + compileRouteUrlFormatter, + toColonNotationPath, urlToTokens, } from "../../../src/utils/urlFormat.js"; diff --git a/packages/api/test/unit/keymanager/keymanager.test.ts b/packages/api/test/unit/keymanager/keymanager.test.ts index 42e6a3dbf511..64778dcab7fc 100644 --- a/packages/api/test/unit/keymanager/keymanager.test.ts +++ b/packages/api/test/unit/keymanager/keymanager.test.ts @@ -1,7 +1,7 @@ -import {describe} from "vitest"; import {config} from "@lodestar/config/default"; -import {Endpoints} from "../../../src/keymanager/routes.js"; +import {describe} from "vitest"; import {getClient} from "../../../src/keymanager/client.js"; +import {Endpoints} from "../../../src/keymanager/routes.js"; import {getRoutes} from "../../../src/keymanager/server/index.js"; import {runGenericServerTest} from "../../utils/genericServerTest.js"; import {testData} from "./testData.js"; diff --git a/packages/api/test/unit/keymanager/oapiSpec.test.ts b/packages/api/test/unit/keymanager/oapiSpec.test.ts index aab4e1823ab0..d3817598029b 100644 --- a/packages/api/test/unit/keymanager/oapiSpec.test.ts +++ b/packages/api/test/unit/keymanager/oapiSpec.test.ts @@ -1,10 +1,10 @@ import path from "node:path"; import {fileURLToPath} from "node:url"; import {config} from "@lodestar/config/default"; -import {OpenApiFile} from "../../utils/parseOpenApiSpec.js"; import {getDefinitions} from "../../../src/keymanager/routes.js"; import {runTestCheckAgainstSpec} from "../../utils/checkAgainstSpec.js"; import {fetchOpenApiSpec} from "../../utils/fetchOpenApiSpec.js"; +import {OpenApiFile} from "../../utils/parseOpenApiSpec.js"; import {testData} from "./testData.js"; // Global variable __dirname no longer available in ES6 modules. diff --git a/packages/api/test/unit/utils/headers.test.ts b/packages/api/test/unit/utils/headers.test.ts index 3416335b0dcd..a96a36233505 100644 --- a/packages/api/test/unit/utils/headers.test.ts +++ b/packages/api/test/unit/utils/headers.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {MediaType, SUPPORTED_MEDIA_TYPES, mergeHeaders, parseAcceptHeader} from "../../../src/utils/headers.js"; describe("utils / headers", () => { diff --git a/packages/api/test/unit/utils/serdes.test.ts b/packages/api/test/unit/utils/serdes.test.ts index 5b55ef66805e..e9e178782bb2 100644 --- a/packages/api/test/unit/utils/serdes.test.ts +++ b/packages/api/test/unit/utils/serdes.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {fromGraffitiHex, toGraffitiHex} from "../../../src/utils/serdes.js"; describe("utils / serdes", () => { diff --git a/packages/api/test/utils/checkAgainstSpec.ts b/packages/api/test/utils/checkAgainstSpec.ts index a3f943ad4816..be076dfeb381 100644 --- a/packages/api/test/utils/checkAgainstSpec.ts +++ b/packages/api/test/utils/checkAgainstSpec.ts @@ -1,9 +1,9 @@ import Ajv, {ErrorObject} from "ajv"; -import {expect, describe, beforeAll, it} from "vitest"; -import {WireFormat} from "../../src/utils/wireFormat.js"; +import {beforeAll, describe, expect, it} from "vitest"; import {Endpoint, RequestWithBodyCodec, RouteDefinitions, isRequestWithoutBody} from "../../src/utils/types.js"; -import {applyRecursively, JsonSchema, OpenApiJson, parseOpenApiSpec} from "./parseOpenApiSpec.js"; +import {WireFormat} from "../../src/utils/wireFormat.js"; import {GenericServerTestCases} from "./genericServerTest.js"; +import {JsonSchema, OpenApiJson, applyRecursively, parseOpenApiSpec} from "./parseOpenApiSpec.js"; const ajv = new Ajv({ strict: true, diff --git a/packages/api/test/utils/genericServerTest.ts b/packages/api/test/utils/genericServerTest.ts index 1c01bb449306..3223ff5ca5a5 100644 --- a/packages/api/test/utils/genericServerTest.ts +++ b/packages/api/test/utils/genericServerTest.ts @@ -1,10 +1,10 @@ -import {it, expect, describe, beforeAll, afterAll, MockInstance} from "vitest"; -import {FastifyInstance} from "fastify"; import {ChainForkConfig} from "@lodestar/config"; +import {FastifyInstance} from "fastify"; +import {MockInstance, afterAll, beforeAll, describe, expect, it} from "vitest"; +import {ApiClientMethods, ApiRequestInit, HttpClient, IHttpClient} from "../../src/utils/client/index.js"; import {Endpoint} from "../../src/utils/index.js"; -import {WireFormat} from "../../src/utils/wireFormat.js"; import {ApplicationMethods, ApplicationResponse, FastifyRoutes} from "../../src/utils/server/index.js"; -import {ApiClientMethods, ApiRequestInit, HttpClient, IHttpClient} from "../../src/utils/client/index.js"; +import {WireFormat} from "../../src/utils/wireFormat.js"; import {getMockApi, getTestServer} from "./utils.js"; export type GenericServerTestCases> = { diff --git a/packages/api/test/utils/utils.ts b/packages/api/test/utils/utils.ts index d3ecbc964435..26302db60792 100644 --- a/packages/api/test/utils/utils.ts +++ b/packages/api/test/utils/utils.ts @@ -1,7 +1,7 @@ -import {MockedObject, vi} from "vitest"; -import {parse as parseQueryString} from "qs"; -import {FastifyInstance, fastify} from "fastify"; import {mapValues} from "@lodestar/utils"; +import {FastifyInstance, fastify} from "fastify"; +import {parse as parseQueryString} from "qs"; +import {MockedObject, vi} from "vitest"; import {Endpoint} from "../../src/utils/index.js"; import {ApplicationMethods, addSszContentTypeParser} from "../../src/utils/server/index.js"; diff --git a/packages/beacon-node/src/api/impl/api.ts b/packages/beacon-node/src/api/impl/api.ts index 3647feed2d7c..65d79112f50c 100644 --- a/packages/beacon-node/src/api/impl/api.ts +++ b/packages/beacon-node/src/api/impl/api.ts @@ -1,6 +1,5 @@ import {BeaconApiMethods} from "@lodestar/api/beacon/server"; import {ApiOptions} from "../options.js"; -import {ApiModules} from "./types.js"; import {getBeaconApi} from "./beacon/index.js"; import {getConfigApi} from "./config/index.js"; import {getDebugApi} from "./debug/index.js"; @@ -9,6 +8,7 @@ import {getLightclientApi} from "./lightclient/index.js"; import {getLodestarApi} from "./lodestar/index.js"; import {getNodeApi} from "./node/index.js"; import {getProofApi} from "./proof/index.js"; +import {ApiModules} from "./types.js"; import {getValidatorApi} from "./validator/index.js"; export function getApi(opts: ApiOptions, modules: ApiModules): BeaconApiMethods { 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 2d36505d822a..bda72bc3b997 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -1,40 +1,40 @@ import {routes} from "@lodestar/api"; import {ApiError, ApplicationMethods} from "@lodestar/api/server"; +import {ForkExecution, SLOTS_PER_HISTORICAL_ROOT, isForkExecution, isForkPostElectra} from "@lodestar/params"; import { computeEpochAtSlot, computeTimeAtSlot, reconstructFullBlockOrContents, signedBeaconBlockToBlinded, } from "@lodestar/state-transition"; -import {ForkExecution, SLOTS_PER_HISTORICAL_ROOT, isForkExecution, isForkPostElectra} from "@lodestar/params"; -import {sleep, fromHex, toRootHex} from "@lodestar/utils"; import { - deneb, - isSignedBlockContents, ProducedBlockSource, SignedBeaconBlock, SignedBeaconBlockOrContents, SignedBlindedBeaconBlock, WithOptionalBytes, + deneb, + isSignedBlockContents, } from "@lodestar/types"; +import {fromHex, sleep, toRootHex} from "@lodestar/utils"; import { - BlockSource, - getBlockInput, - ImportBlockOpts, - BlockInput, BlobsSource, + BlockInput, BlockInputDataBlobs, + BlockSource, + ImportBlockOpts, + getBlockInput, } from "../../../../chain/blocks/types.js"; -import {promiseAllMaybeAsync} from "../../../../util/promises.js"; -import {isOptimisticBlock} from "../../../../util/forkChoice.js"; -import {computeBlobSidecars} from "../../../../util/blobs.js"; +import {verifyBlocksInEpoch} from "../../../../chain/blocks/verifyBlock.js"; +import {BeaconChain} from "../../../../chain/chain.js"; import {BlockError, BlockErrorCode, BlockGossipError} from "../../../../chain/errors/index.js"; +import {validateGossipBlock} from "../../../../chain/validation/block.js"; import {OpSource} from "../../../../metrics/validatorMonitor.js"; import {NetworkEvent} from "../../../../network/index.js"; +import {computeBlobSidecars} from "../../../../util/blobs.js"; +import {isOptimisticBlock} from "../../../../util/forkChoice.js"; +import {promiseAllMaybeAsync} from "../../../../util/promises.js"; import {ApiModules} from "../../types.js"; -import {validateGossipBlock} from "../../../../chain/validation/block.js"; -import {verifyBlocksInEpoch} from "../../../../chain/blocks/verifyBlock.js"; -import {BeaconChain} from "../../../../chain/chain.js"; import {getBlockResponse, toBeaconHeaderResponse} from "./utils.js"; type PublishBlockOpts = ImportBlockOpts; diff --git a/packages/beacon-node/src/api/impl/beacon/blocks/utils.ts b/packages/beacon-node/src/api/impl/beacon/blocks/utils.ts index 44152ff4b8a9..b1030c6de58b 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/utils.ts @@ -1,12 +1,12 @@ import {routes} from "@lodestar/api"; -import {blockToHeader} from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; -import {RootHex, SignedBeaconBlock, Slot} from "@lodestar/types"; import {IForkChoice} from "@lodestar/fork-choice"; -import {GENESIS_SLOT} from "../../../../constants/index.js"; -import {ApiError, ValidationError} from "../../errors.js"; +import {blockToHeader} from "@lodestar/state-transition"; +import {RootHex, SignedBeaconBlock, Slot} from "@lodestar/types"; import {IBeaconChain} from "../../../../chain/interface.js"; +import {GENESIS_SLOT} from "../../../../constants/index.js"; import {rootHexRegex} from "../../../../eth1/provider/utils.js"; +import {ApiError, ValidationError} from "../../errors.js"; export function toBeaconHeaderResponse( config: ChainForkConfig, diff --git a/packages/beacon-node/src/api/impl/beacon/index.ts b/packages/beacon-node/src/api/impl/beacon/index.ts index 2e75dc76782c..0003e9c97878 100644 --- a/packages/beacon-node/src/api/impl/beacon/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/index.ts @@ -3,8 +3,8 @@ import {ApplicationMethods} from "@lodestar/api/server"; import {ApiModules} from "../types.js"; import {getBeaconBlockApi} from "./blocks/index.js"; import {getBeaconPoolApi} from "./pool/index.js"; -import {getBeaconStateApi} from "./state/index.js"; import {getBeaconRewardsApi} from "./rewards/index.js"; +import {getBeaconStateApi} from "./state/index.js"; export function getBeaconApi( modules: Pick diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index 9343dd67a399..45fb763d9540 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -1,22 +1,22 @@ import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; -import {Attestation, Epoch, isElectraAttestation, ssz} from "@lodestar/types"; import {ForkName, SYNC_COMMITTEE_SUBNET_SIZE, isForkPostElectra} from "@lodestar/params"; -import {validateApiAttestation} from "../../../../chain/validation/index.js"; -import {validateApiAttesterSlashing} from "../../../../chain/validation/attesterSlashing.js"; -import {validateApiProposerSlashing} from "../../../../chain/validation/proposerSlashing.js"; -import {validateApiVoluntaryExit} from "../../../../chain/validation/voluntaryExit.js"; -import {validateApiBlsToExecutionChange} from "../../../../chain/validation/blsToExecutionChange.js"; -import {validateApiSyncCommittee} from "../../../../chain/validation/syncCommittee.js"; -import {ApiModules} from "../../types.js"; +import {Attestation, Epoch, isElectraAttestation, ssz} from "@lodestar/types"; import { AttestationError, AttestationErrorCode, GossipAction, SyncCommitteeError, } from "../../../../chain/errors/index.js"; +import {validateApiAttesterSlashing} from "../../../../chain/validation/attesterSlashing.js"; +import {validateApiBlsToExecutionChange} from "../../../../chain/validation/blsToExecutionChange.js"; +import {validateApiAttestation} from "../../../../chain/validation/index.js"; +import {validateApiProposerSlashing} from "../../../../chain/validation/proposerSlashing.js"; +import {validateApiSyncCommittee} from "../../../../chain/validation/syncCommittee.js"; +import {validateApiVoluntaryExit} from "../../../../chain/validation/voluntaryExit.js"; import {validateGossipFnRetryUnknownRoot} from "../../../../network/processor/gossipHandlers.js"; import {ApiError, FailureList, IndexedError} from "../../errors.js"; +import {ApiModules} from "../../types.js"; export function getBeaconPoolApi({ chain, diff --git a/packages/beacon-node/src/api/impl/beacon/state/index.ts b/packages/beacon-node/src/api/impl/beacon/state/index.ts index a1e17b80ea84..916507cc56fc 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/index.ts @@ -1,5 +1,6 @@ import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; +import {EPOCHS_PER_HISTORICAL_VECTOR} from "@lodestar/params"; import { BeaconStateAllForks, CachedBeaconStateAltair, @@ -8,12 +9,11 @@ import { getCurrentEpoch, getRandaoMix, } from "@lodestar/state-transition"; -import {EPOCHS_PER_HISTORICAL_VECTOR} from "@lodestar/params"; import {getValidatorStatus} from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; import {ApiError} from "../../errors.js"; import {ApiModules} from "../../types.js"; -import {filterStateValidatorsByStatus, getStateValidatorIndex, getStateResponse, toValidatorResponse} from "./utils.js"; +import {filterStateValidatorsByStatus, getStateResponse, getStateValidatorIndex, toValidatorResponse} from "./utils.js"; export function getBeaconStateApi({ chain, diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index 392262a563be..f23fd52f0286 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -1,10 +1,10 @@ import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {routes} from "@lodestar/api"; +import {CheckpointWithHex, IForkChoice} from "@lodestar/fork-choice"; import {GENESIS_SLOT} from "@lodestar/params"; import {BeaconStateAllForks} from "@lodestar/state-transition"; -import {BLSPubkey, Epoch, getValidatorStatus, phase0, RootHex, Slot, ValidatorIndex} from "@lodestar/types"; +import {BLSPubkey, Epoch, RootHex, Slot, ValidatorIndex, getValidatorStatus, phase0} from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; -import {CheckpointWithHex, IForkChoice} from "@lodestar/fork-choice"; import {IBeaconChain} from "../../../../chain/index.js"; import {ApiError, ValidationError} from "../../errors.js"; diff --git a/packages/beacon-node/src/api/impl/config/constants.ts b/packages/beacon-node/src/api/impl/config/constants.ts index e951da35bdd2..c55cfe7008f4 100644 --- a/packages/beacon-node/src/api/impl/config/constants.ts +++ b/packages/beacon-node/src/api/impl/config/constants.ts @@ -1,44 +1,44 @@ import { - GENESIS_SLOT, - GENESIS_EPOCH, - FAR_FUTURE_EPOCH, + ATTESTATION_SUBNET_COUNT, BASE_REWARDS_PER_EPOCH, - DEPOSIT_CONTRACT_TREE_DEPTH, - JUSTIFICATION_BITS_LENGTH, + BLOB_TX_TYPE, BLS_WITHDRAWAL_PREFIX, - ETH1_ADDRESS_WITHDRAWAL_PREFIX, - DOMAIN_BEACON_PROPOSER, + COMPOUNDING_WITHDRAWAL_PREFIX, + DEPOSIT_CONTRACT_TREE_DEPTH, + DOMAIN_AGGREGATE_AND_PROOF, + DOMAIN_APPLICATION_BUILDER, DOMAIN_BEACON_ATTESTER, - DOMAIN_RANDAO, + DOMAIN_BEACON_PROPOSER, + DOMAIN_BLS_TO_EXECUTION_CHANGE, + DOMAIN_CONTRIBUTION_AND_PROOF, DOMAIN_DEPOSIT, - DOMAIN_VOLUNTARY_EXIT, + DOMAIN_RANDAO, DOMAIN_SELECTION_PROOF, - DOMAIN_AGGREGATE_AND_PROOF, DOMAIN_SYNC_COMMITTEE, DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF, - DOMAIN_CONTRIBUTION_AND_PROOF, - DOMAIN_BLS_TO_EXECUTION_CHANGE, - DOMAIN_APPLICATION_BUILDER, - TIMELY_SOURCE_FLAG_INDEX, - TIMELY_TARGET_FLAG_INDEX, - TIMELY_HEAD_FLAG_INDEX, - TIMELY_SOURCE_WEIGHT, - TIMELY_TARGET_WEIGHT, - TIMELY_HEAD_WEIGHT, - SYNC_REWARD_WEIGHT, + DOMAIN_VOLUNTARY_EXIT, + EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION, + ETH1_ADDRESS_WITHDRAWAL_PREFIX, + FAR_FUTURE_EPOCH, + FULL_EXIT_REQUEST_AMOUNT, + GENESIS_EPOCH, + GENESIS_SLOT, + JUSTIFICATION_BITS_LENGTH, PROPOSER_WEIGHT, - WEIGHT_DENOMINATOR, - TARGET_AGGREGATORS_PER_COMMITTEE, RANDOM_SUBNETS_PER_VALIDATOR, - EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION, - ATTESTATION_SUBNET_COUNT, - TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE, SYNC_COMMITTEE_SUBNET_COUNT, - BLOB_TX_TYPE, - VERSIONED_HASH_VERSION_KZG, - COMPOUNDING_WITHDRAWAL_PREFIX, + SYNC_REWARD_WEIGHT, + TARGET_AGGREGATORS_PER_COMMITTEE, + TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE, + TIMELY_HEAD_FLAG_INDEX, + TIMELY_HEAD_WEIGHT, + TIMELY_SOURCE_FLAG_INDEX, + TIMELY_SOURCE_WEIGHT, + TIMELY_TARGET_FLAG_INDEX, + TIMELY_TARGET_WEIGHT, UNSET_DEPOSIT_REQUESTS_START_INDEX, - FULL_EXIT_REQUEST_AMOUNT, + VERSIONED_HASH_VERSION_KZG, + WEIGHT_DENOMINATOR, } from "@lodestar/params"; /** diff --git a/packages/beacon-node/src/api/impl/config/index.ts b/packages/beacon-node/src/api/impl/config/index.ts index 9b8694aa5914..f9d3924430ad 100644 --- a/packages/beacon-node/src/api/impl/config/index.ts +++ b/packages/beacon-node/src/api/impl/config/index.ts @@ -1,6 +1,6 @@ import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; -import {chainConfigToJson, ChainConfig, specValuesToJson} from "@lodestar/config"; +import {ChainConfig, chainConfigToJson, specValuesToJson} from "@lodestar/config"; import {activePreset, presetToJson} from "@lodestar/params"; import {ApiModules} from "../types.js"; import {specConstants} from "./constants.js"; diff --git a/packages/beacon-node/src/api/impl/debug/index.ts b/packages/beacon-node/src/api/impl/debug/index.ts index e5b6450b206f..e6c104272237 100644 --- a/packages/beacon-node/src/api/impl/debug/index.ts +++ b/packages/beacon-node/src/api/impl/debug/index.ts @@ -1,12 +1,12 @@ import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; import {ExecutionStatus} from "@lodestar/fork-choice"; -import {BeaconState} from "@lodestar/types"; import {ZERO_HASH_HEX} from "@lodestar/params"; -import {getStateResponseWithRegen} from "../beacon/state/utils.js"; -import {ApiModules} from "../types.js"; +import {BeaconState} from "@lodestar/types"; import {isOptimisticBlock} from "../../../util/forkChoice.js"; import {getStateSlotFromBytes} from "../../../util/multifork.js"; +import {getStateResponseWithRegen} from "../beacon/state/utils.js"; +import {ApiModules} from "../types.js"; export function getDebugApi({ chain, diff --git a/packages/beacon-node/src/api/impl/lightclient/index.ts b/packages/beacon-node/src/api/impl/lightclient/index.ts index 0dd366accf68..850a8312978c 100644 --- a/packages/beacon-node/src/api/impl/lightclient/index.ts +++ b/packages/beacon-node/src/api/impl/lightclient/index.ts @@ -1,9 +1,9 @@ -import {fromHex} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; -import {MAX_REQUEST_LIGHT_CLIENT_UPDATES, MAX_REQUEST_LIGHT_CLIENT_COMMITTEE_HASHES} from "@lodestar/params"; -import {ApiModules} from "../types.js"; +import {MAX_REQUEST_LIGHT_CLIENT_COMMITTEE_HASHES, MAX_REQUEST_LIGHT_CLIENT_UPDATES} from "@lodestar/params"; +import {fromHex} from "@lodestar/utils"; import {assertLightClientServer} from "../../../node/utils/lightclient.js"; +import {ApiModules} from "../types.js"; // TODO: Import from lightclient/server package export function getLightclientApi({ diff --git a/packages/beacon-node/src/api/impl/lodestar/index.ts b/packages/beacon-node/src/api/impl/lodestar/index.ts index f89959ad9da6..10787194f5f5 100644 --- a/packages/beacon-node/src/api/impl/lodestar/index.ts +++ b/packages/beacon-node/src/api/impl/lodestar/index.ts @@ -2,18 +2,18 @@ import fs from "node:fs"; import path from "node:path"; import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; +import {ChainForkConfig} from "@lodestar/config"; import {Repository} from "@lodestar/db"; -import {toHex, toRootHex} from "@lodestar/utils"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {getLatestWeakSubjectivityCheckpointEpoch} from "@lodestar/state-transition"; -import {ChainForkConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {toHex, toRootHex} from "@lodestar/utils"; import {BeaconChain} from "../../../chain/index.js"; import {QueuedStateRegenerator, RegenRequest} from "../../../chain/regen/index.js"; -import {GossipType} from "../../../network/index.js"; import {IBeaconDb} from "../../../db/interface.js"; -import {ApiModules} from "../types.js"; +import {GossipType} from "../../../network/index.js"; import {profileNodeJS, writeHeapSnapshot} from "../../../util/profile.js"; +import {ApiModules} from "../types.js"; export function getLodestarApi({ chain, diff --git a/packages/beacon-node/src/api/impl/node/index.ts b/packages/beacon-node/src/api/impl/node/index.ts index bd1fb85522de..0d476df32303 100644 --- a/packages/beacon-node/src/api/impl/node/index.ts +++ b/packages/beacon-node/src/api/impl/node/index.ts @@ -1,8 +1,8 @@ import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; +import {ApiOptions} from "../../options.js"; import {ApiError} from "../errors.js"; import {ApiModules} from "../types.js"; -import {ApiOptions} from "../../options.js"; export function getNodeApi( opts: ApiOptions, diff --git a/packages/beacon-node/src/api/impl/proof/index.ts b/packages/beacon-node/src/api/impl/proof/index.ts index 9e1a33940225..7b61e280015f 100644 --- a/packages/beacon-node/src/api/impl/proof/index.ts +++ b/packages/beacon-node/src/api/impl/proof/index.ts @@ -1,10 +1,10 @@ -import {CompactMultiProof, createProof, ProofType} from "@chainsafe/persistent-merkle-tree"; +import {CompactMultiProof, ProofType, createProof} from "@chainsafe/persistent-merkle-tree"; import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; -import {ApiModules} from "../types.js"; -import {getStateResponse} from "../beacon/state/utils.js"; -import {getBlockResponse} from "../beacon/blocks/utils.js"; import {ApiOptions} from "../../options.js"; +import {getBlockResponse} from "../beacon/blocks/utils.js"; +import {getStateResponse} from "../beacon/state/utils.js"; +import {ApiModules} from "../types.js"; export function getProofApi( opts: ApiOptions, diff --git a/packages/beacon-node/src/api/impl/types.ts b/packages/beacon-node/src/api/impl/types.ts index 6b14e79ef998..4b2649acc556 100644 --- a/packages/beacon-node/src/api/impl/types.ts +++ b/packages/beacon-node/src/api/impl/types.ts @@ -3,9 +3,9 @@ import {Logger} from "@lodestar/utils"; import {IBeaconChain} from "../../chain/index.js"; import {IBeaconDb} from "../../db/index.js"; -import {IBeaconSync} from "../../sync/index.js"; -import {INetwork} from "../../network/index.js"; import {Metrics} from "../../metrics/index.js"; +import {INetwork} from "../../network/index.js"; +import {IBeaconSync} from "../../sync/index.js"; export type ApiModules = { config: ChainForkConfig; diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 2b558577c22c..b15644a8087e 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -1,61 +1,61 @@ import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; +import {DataAvailabilityStatus, ExecutionStatus} from "@lodestar/fork-choice"; import { - CachedBeaconStateAllForks, - computeStartSlotAtEpoch, - calculateCommitteeAssignments, - proposerShufflingDecisionRoot, - attesterShufflingDecisionRoot, - getBlockRootAtSlot, - computeEpochAtSlot, - getCurrentSlot, - beaconBlockToBlinded, - createCachedBeaconState, - loadState, -} from "@lodestar/state-transition"; -import { + ForkBlobs, + ForkExecution, + ForkPreBlobs, + ForkSeq, GENESIS_SLOT, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT, SYNC_COMMITTEE_SUBNET_SIZE, isForkBlobs, isForkExecution, - ForkSeq, - ForkPreBlobs, - ForkBlobs, - ForkExecution, isForkPostElectra, } from "@lodestar/params"; -import {MAX_BUILDER_BOOST_FACTOR} from "@lodestar/validator"; import { + CachedBeaconStateAllForks, + attesterShufflingDecisionRoot, + beaconBlockToBlinded, + calculateCommitteeAssignments, + computeEpochAtSlot, + computeStartSlotAtEpoch, + createCachedBeaconState, + getBlockRootAtSlot, + getCurrentSlot, + loadState, + proposerShufflingDecisionRoot, +} from "@lodestar/state-transition"; +import { + BLSSignature, + BeaconBlock, + BlindedBeaconBlock, + BlockContents, + Epoch, + ProducedBlockSource, Root, Slot, ValidatorIndex, - ssz, - Epoch, - ProducedBlockSource, + Wei, bellatrix, - BLSSignature, + getValidatorStatus, isBlindedBeaconBlock, isBlockContents, phase0, - Wei, - BeaconBlock, - BlockContents, - BlindedBeaconBlock, - getValidatorStatus, + ssz, } from "@lodestar/types"; -import {ExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; import { + TimeoutError, + formatWeiToEth, fromHex, - toHex, - resolveOrRacePromises, prettyWeiToEth, + resolveOrRacePromises, + toHex, toRootHex, - TimeoutError, - formatWeiToEth, } from "@lodestar/utils"; +import {MAX_BUILDER_BOOST_FACTOR} from "@lodestar/validator"; import { AttestationError, AttestationErrorCode, @@ -63,23 +63,23 @@ import { SyncCommitteeError, SyncCommitteeErrorCode, } from "../../../chain/errors/index.js"; +import {ChainEvent, CheckpointHex, CommonBlockBody} from "../../../chain/index.js"; +import {SCHEDULER_LOOKAHEAD_FACTOR} from "../../../chain/prepareNextSlot.js"; +import {RegenCaller} from "../../../chain/regen/index.js"; import {validateApiAggregateAndProof} from "../../../chain/validation/index.js"; +import {validateSyncCommitteeGossipContributionAndProof} from "../../../chain/validation/syncCommitteeContributionAndProof.js"; import {ZERO_HASH} from "../../../constants/index.js"; +import {NoBidReceived} from "../../../execution/builder/http.js"; +import {validateGossipFnRetryUnknownRoot} from "../../../network/processor/gossipHandlers.js"; +import {CommitteeSubscription} from "../../../network/subnets/index.js"; import {SyncState} from "../../../sync/index.js"; import {isOptimisticBlock} from "../../../util/forkChoice.js"; import {getDefaultGraffiti, toGraffitiBuffer} from "../../../util/graffiti.js"; +import {getLodestarClientVersion} from "../../../util/metadata.js"; +import {ApiOptions} from "../../options.js"; +import {getStateResponseWithRegen} from "../beacon/state/utils.js"; import {ApiError, NodeIsSyncing, OnlySupportedByDVT} from "../errors.js"; -import {validateSyncCommitteeGossipContributionAndProof} from "../../../chain/validation/syncCommitteeContributionAndProof.js"; -import {CommitteeSubscription} from "../../../network/subnets/index.js"; import {ApiModules} from "../types.js"; -import {RegenCaller} from "../../../chain/regen/index.js"; -import {getStateResponseWithRegen} from "../beacon/state/utils.js"; -import {validateGossipFnRetryUnknownRoot} from "../../../network/processor/gossipHandlers.js"; -import {SCHEDULER_LOOKAHEAD_FACTOR} from "../../../chain/prepareNextSlot.js"; -import {ChainEvent, CheckpointHex, CommonBlockBody} from "../../../chain/index.js"; -import {ApiOptions} from "../../options.js"; -import {NoBidReceived} from "../../../execution/builder/http.js"; -import {getLodestarClientVersion} from "../../../util/metadata.js"; import {computeSubnetForCommitteesAtSlot, getPubkeysForIndices, selectBlockProductionSource} from "./utils.js"; /** diff --git a/packages/beacon-node/src/api/impl/validator/utils.ts b/packages/beacon-node/src/api/impl/validator/utils.ts index 36accf34cfda..b8e5aa525f25 100644 --- a/packages/beacon-node/src/api/impl/validator/utils.ts +++ b/packages/beacon-node/src/api/impl/validator/utils.ts @@ -1,6 +1,6 @@ -import {BeaconStateAllForks, computeSlotsSinceEpochStart} from "@lodestar/state-transition"; -import {ATTESTATION_SUBNET_COUNT} from "@lodestar/params"; import {routes} from "@lodestar/api"; +import {ATTESTATION_SUBNET_COUNT} from "@lodestar/params"; +import {BeaconStateAllForks, computeSlotsSinceEpochStart} from "@lodestar/state-transition"; import {BLSPubkey, CommitteeIndex, ProducedBlockSource, Slot, ValidatorIndex} from "@lodestar/types"; import {MAX_BUILDER_BOOST_FACTOR} from "@lodestar/validator"; import {BlockSelectionResult, BuilderBlockSelectionReason, EngineBlockSelectionReason} from "./index.js"; diff --git a/packages/beacon-node/src/api/options.ts b/packages/beacon-node/src/api/options.ts index 811621ba97bf..02d0c9c6cdf6 100644 --- a/packages/beacon-node/src/api/options.ts +++ b/packages/beacon-node/src/api/options.ts @@ -1,4 +1,4 @@ -import {beaconRestApiServerOpts, BeaconRestApiServerOpts} from "./rest/index.js"; +import {BeaconRestApiServerOpts, beaconRestApiServerOpts} from "./rest/index.js"; export type ApiOptions = { maxGindicesInProof?: number; diff --git a/packages/beacon-node/src/api/rest/base.ts b/packages/beacon-node/src/api/rest/base.ts index 276583dc7281..efa01b032230 100644 --- a/packages/beacon-node/src/api/rest/base.ts +++ b/packages/beacon-node/src/api/rest/base.ts @@ -1,9 +1,9 @@ -import {parse as parseQueryString} from "qs"; -import {FastifyInstance, FastifyRequest, fastify, errorCodes} from "fastify"; -import {fastifyCors} from "@fastify/cors"; import bearerAuthPlugin from "@fastify/bearer-auth"; +import {fastifyCors} from "@fastify/cors"; import {addSszContentTypeParser} from "@lodestar/api/server"; import {ErrorAborted, Gauge, Histogram, Logger} from "@lodestar/utils"; +import {FastifyInstance, FastifyRequest, errorCodes, fastify} from "fastify"; +import {parse as parseQueryString} from "qs"; import {isLocalhostIP} from "../../util/ip.js"; import {ApiError, FailureList, IndexedError, NodeIsSyncing} from "../impl/errors.js"; import {HttpActiveSocketsTracker, SocketMetrics} from "./activeSockets.js"; diff --git a/packages/beacon-node/src/api/rest/index.ts b/packages/beacon-node/src/api/rest/index.ts index 6beaf061588c..1d31080327e6 100644 --- a/packages/beacon-node/src/api/rest/index.ts +++ b/packages/beacon-node/src/api/rest/index.ts @@ -1,10 +1,10 @@ import {Endpoints} from "@lodestar/api"; import {BeaconApiMethods} from "@lodestar/api/beacon/server"; import {registerRoutes} from "@lodestar/api/beacon/server"; -import {ErrorAborted, Logger} from "@lodestar/utils"; import {ChainForkConfig} from "@lodestar/config"; +import {ErrorAborted, Logger} from "@lodestar/utils"; import {NodeIsSyncing} from "../impl/errors.js"; -import {RestApiServer, RestApiServerModules, RestApiServerMetrics, RestApiServerOpts} from "./base.js"; +import {RestApiServer, RestApiServerMetrics, RestApiServerModules, RestApiServerOpts} from "./base.js"; import {registerSwaggerUIRoutes} from "./swaggerUI.js"; export {allNamespaces} from "@lodestar/api"; diff --git a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts index 8e1ac456579a..69c7dedfc560 100644 --- a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts +++ b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts @@ -1,10 +1,10 @@ -import {Epoch, Slot, RootHex} from "@lodestar/types"; +import {ChainForkConfig} from "@lodestar/config"; +import {KeyValue} from "@lodestar/db"; import {IForkChoice} from "@lodestar/fork-choice"; -import {Logger, fromHex, toRootHex} from "@lodestar/utils"; import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {KeyValue} from "@lodestar/db"; -import {ChainForkConfig} from "@lodestar/config"; +import {Epoch, RootHex, Slot} from "@lodestar/types"; +import {Logger, fromHex, toRootHex} from "@lodestar/utils"; import {IBeaconDb} from "../../db/index.js"; import {BlockArchiveBatchPutBinaryItem} from "../../db/repositories/index.js"; import {LightClientServer} from "../lightClient/index.js"; diff --git a/packages/beacon-node/src/chain/archiver/archiver.ts b/packages/beacon-node/src/chain/archiver/archiver.ts index 2d79f584ea79..6d5be3445eb2 100644 --- a/packages/beacon-node/src/chain/archiver/archiver.ts +++ b/packages/beacon-node/src/chain/archiver/archiver.ts @@ -1,13 +1,13 @@ -import {Logger} from "@lodestar/utils"; import {CheckpointWithHex} from "@lodestar/fork-choice"; +import {Logger} from "@lodestar/utils"; import {IBeaconDb} from "../../db/index.js"; +import {Metrics} from "../../metrics/metrics.js"; import {JobItemQueue} from "../../util/queue/index.js"; -import {IBeaconChain} from "../interface.js"; import {ChainEvent} from "../emitter.js"; -import {Metrics} from "../../metrics/metrics.js"; -import {FrequencyStateArchiveStrategy} from "./strategies/frequencyStateArchiveStrategy.js"; +import {IBeaconChain} from "../interface.js"; import {archiveBlocks} from "./archiveBlocks.js"; -import {StateArchiveMode, ArchiverOpts, StateArchiveStrategy} from "./interface.js"; +import {ArchiverOpts, StateArchiveMode, StateArchiveStrategy} from "./interface.js"; +import {FrequencyStateArchiveStrategy} from "./strategies/frequencyStateArchiveStrategy.js"; export const DEFAULT_STATE_ARCHIVE_MODE = StateArchiveMode.Frequency; diff --git a/packages/beacon-node/src/chain/archiver/interface.ts b/packages/beacon-node/src/chain/archiver/interface.ts index 48c930c78cd3..283fef579024 100644 --- a/packages/beacon-node/src/chain/archiver/interface.ts +++ b/packages/beacon-node/src/chain/archiver/interface.ts @@ -1,6 +1,6 @@ import {CheckpointWithHex} from "@lodestar/fork-choice"; -import {Metrics} from "../../metrics/metrics.js"; import {RootHex} from "@lodestar/types"; +import {Metrics} from "../../metrics/metrics.js"; export enum StateArchiveMode { Frequency = "frequency", diff --git a/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts b/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts index a701da5b22ec..6ae592ce7c63 100644 --- a/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts +++ b/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts @@ -1,14 +1,14 @@ -import {Logger} from "@lodestar/utils"; +import {CheckpointWithHex} from "@lodestar/fork-choice"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {Slot, Epoch, RootHex} from "@lodestar/types"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {CheckpointWithHex} from "@lodestar/fork-choice"; +import {Epoch, RootHex, Slot} from "@lodestar/types"; +import {Logger} from "@lodestar/utils"; import {IBeaconDb} from "../../../db/index.js"; -import {IStateRegenerator} from "../../regen/interface.js"; +import {Metrics} from "../../../metrics/metrics.js"; +import {AllocSource, BufferPool} from "../../../util/bufferPool.js"; import {getStateSlotFromBytes} from "../../../util/multifork.js"; +import {IStateRegenerator} from "../../regen/interface.js"; import {serializeState} from "../../serializeState.js"; -import {AllocSource, BufferPool} from "../../../util/bufferPool.js"; -import {Metrics} from "../../../metrics/metrics.js"; import {StateArchiveStrategy, StatesArchiverOpts} from "../interface.js"; /** diff --git a/packages/beacon-node/src/chain/balancesCache.ts b/packages/beacon-node/src/chain/balancesCache.ts index d29a6998f600..8fe09df4c275 100644 --- a/packages/beacon-node/src/chain/balancesCache.ts +++ b/packages/beacon-node/src/chain/balancesCache.ts @@ -1,11 +1,11 @@ +import {CheckpointWithHex} from "@lodestar/fork-choice"; import { CachedBeaconStateAllForks, - computeStartSlotAtEpoch, EffectiveBalanceIncrements, + computeStartSlotAtEpoch, getBlockRootAtSlot, getEffectiveBalanceIncrementsZeroInactive, } from "@lodestar/state-transition"; -import {CheckpointWithHex} from "@lodestar/fork-choice"; import {Epoch, RootHex} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; diff --git a/packages/beacon-node/src/chain/beaconProposerCache.ts b/packages/beacon-node/src/chain/beaconProposerCache.ts index f8638aa64bf7..dd46821e6d57 100644 --- a/packages/beacon-node/src/chain/beaconProposerCache.ts +++ b/packages/beacon-node/src/chain/beaconProposerCache.ts @@ -1,5 +1,5 @@ -import {Epoch} from "@lodestar/types"; import {routes} from "@lodestar/api"; +import {Epoch} from "@lodestar/types"; import {MapDef} from "@lodestar/utils"; import {Metrics} from "../metrics/index.js"; diff --git a/packages/beacon-node/src/chain/blocks/importBlock.ts b/packages/beacon-node/src/chain/blocks/importBlock.ts index 596f01f391a4..6b23112b03fe 100644 --- a/packages/beacon-node/src/chain/blocks/importBlock.ts +++ b/packages/beacon-node/src/chain/blocks/importBlock.ts @@ -1,26 +1,26 @@ -import {capella, ssz, altair, BeaconBlock} from "@lodestar/types"; +import {routes} from "@lodestar/api"; +import {AncestorStatus, EpochDifference, ForkChoiceError, ForkChoiceErrorCode} from "@lodestar/fork-choice"; import {ForkLightClient, ForkSeq, INTERVALS_PER_SLOT, MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params"; import { CachedBeaconStateAltair, + RootCache, computeEpochAtSlot, computeStartSlotAtEpoch, isStateValidatorsNodesPopulated, - RootCache, } from "@lodestar/state-transition"; -import {routes} from "@lodestar/api"; -import {ForkChoiceError, ForkChoiceErrorCode, EpochDifference, AncestorStatus} from "@lodestar/fork-choice"; +import {BeaconBlock, altair, capella, ssz} from "@lodestar/types"; import {isErrorAborted, toHex, toRootHex} from "@lodestar/utils"; import {ZERO_HASH_HEX} from "../../constants/index.js"; -import {toCheckpointHex} from "../stateCache/index.js"; +import {kzgCommitmentToVersionedHash} from "../../util/blobs.js"; +import {callInNextEventLoop} from "../../util/eventLoop.js"; import {isOptimisticBlock} from "../../util/forkChoice.js"; import {isQueueErrorAborted} from "../../util/queue/index.js"; -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 {ChainEvent, ReorgEventData} from "../emitter.js"; import {ForkchoiceCaller} from "../forkChoice/index.js"; -import {FullyVerifiedBlock, ImportBlockOpts, AttestationImportOpt, BlockInputType} from "./types.js"; +import {REPROCESS_MIN_TIME_TO_NEXT_SLOT_SEC} from "../reprocess.js"; +import {toCheckpointHex} from "../stateCache/index.js"; +import {AttestationImportOpt, BlockInputType, FullyVerifiedBlock, ImportBlockOpts} from "./types.js"; import {getCheckpointFromState} from "./utils/checkpoint.js"; import {writeBlockInputToDb} from "./writeBlockInputToDb.js"; diff --git a/packages/beacon-node/src/chain/blocks/index.ts b/packages/beacon-node/src/chain/blocks/index.ts index f64e4b1f3813..6e8eed428a4b 100644 --- a/packages/beacon-node/src/chain/blocks/index.ts +++ b/packages/beacon-node/src/chain/blocks/index.ts @@ -1,14 +1,14 @@ -import {isErrorAborted, toRootHex} from "@lodestar/utils"; import {SignedBeaconBlock} from "@lodestar/types"; -import {JobItemQueue, isQueueErrorAborted} from "../../util/queue/index.js"; +import {isErrorAborted, toRootHex} from "@lodestar/utils"; import {Metrics} from "../../metrics/metrics.js"; +import {JobItemQueue, isQueueErrorAborted} from "../../util/queue/index.js"; +import type {BeaconChain} from "../chain.js"; import {BlockError, BlockErrorCode, isBlockErrorAborted} from "../errors/index.js"; import {BlockProcessOpts} from "../options.js"; -import type {BeaconChain} from "../chain.js"; -import {verifyBlocksInEpoch} from "./verifyBlock.js"; import {importBlock} from "./importBlock.js"; -import {assertLinearChainSegment} from "./utils/chainSegment.js"; import {BlockInput, FullyVerifiedBlock, ImportBlockOpts} from "./types.js"; +import {assertLinearChainSegment} from "./utils/chainSegment.js"; +import {verifyBlocksInEpoch} from "./verifyBlock.js"; import {verifyBlocksSanityChecks} from "./verifyBlocksSanityChecks.js"; import {removeEagerlyPersistedBlockInputs} from "./writeBlockInputToDb.js"; export {type ImportBlockOpts, AttestationImportOpt} from "./types.js"; diff --git a/packages/beacon-node/src/chain/blocks/types.ts b/packages/beacon-node/src/chain/blocks/types.ts index 8b793932e951..2b7186e91112 100644 --- a/packages/beacon-node/src/chain/blocks/types.ts +++ b/packages/beacon-node/src/chain/blocks/types.ts @@ -1,8 +1,8 @@ -import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition"; -import {MaybeValidExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; -import {deneb, Slot, RootHex, SignedBeaconBlock} from "@lodestar/types"; -import {ForkSeq, ForkBlobs} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; +import {DataAvailabilityStatus, MaybeValidExecutionStatus} from "@lodestar/fork-choice"; +import {ForkBlobs, ForkSeq} from "@lodestar/params"; +import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition"; +import {RootHex, SignedBeaconBlock, Slot, deneb} from "@lodestar/types"; export enum BlockInputType { // preData is preDeneb diff --git a/packages/beacon-node/src/chain/blocks/utils/checkpoint.ts b/packages/beacon-node/src/chain/blocks/utils/checkpoint.ts index 2ff77600b2b8..855a1b19e741 100644 --- a/packages/beacon-node/src/chain/blocks/utils/checkpoint.ts +++ b/packages/beacon-node/src/chain/blocks/utils/checkpoint.ts @@ -1,5 +1,5 @@ -import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; import {ZERO_HASH} from "../../../constants/index.js"; diff --git a/packages/beacon-node/src/chain/blocks/verifyBlock.ts b/packages/beacon-node/src/chain/blocks/verifyBlock.ts index 4d21342bd8cc..47a9a9060572 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlock.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlock.ts @@ -1,26 +1,26 @@ +import {ChainForkConfig} from "@lodestar/config"; +import {DataAvailabilityStatus, ExecutionStatus, ProtoBlock} from "@lodestar/fork-choice"; +import {ForkName} from "@lodestar/params"; import { CachedBeaconStateAllForks, + DataAvailableStatus, computeEpochAtSlot, isStateValidatorsNodesPopulated, - DataAvailableStatus, } from "@lodestar/state-transition"; import {bellatrix, deneb} from "@lodestar/types"; -import {ForkName} from "@lodestar/params"; -import {ProtoBlock, ExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; -import {ChainForkConfig} from "@lodestar/config"; import {Logger, toRootHex} from "@lodestar/utils"; +import type {BeaconChain} from "../chain.js"; import {BlockError, BlockErrorCode} from "../errors/index.js"; import {BlockProcessOpts} from "../options.js"; import {RegenCaller} from "../regen/index.js"; -import type {BeaconChain} from "../chain.js"; -import {BlockInput, ImportBlockOpts, BlockInputType} from "./types.js"; -import {POS_PANDA_MERGE_TRANSITION_BANNER} from "./utils/pandaMergeTransitionBanner.js"; -import {CAPELLA_OWL_BANNER} from "./utils/ownBanner.js"; +import {BlockInput, BlockInputType, ImportBlockOpts} from "./types.js"; import {DENEB_BLOWFISH_BANNER} from "./utils/blowfishBanner.js"; -import {verifyBlocksStateTransitionOnly} from "./verifyBlocksStateTransitionOnly.js"; -import {verifyBlocksSignatures} from "./verifyBlocksSignatures.js"; -import {verifyBlocksExecutionPayload, SegmentExecStatus} from "./verifyBlocksExecutionPayloads.js"; +import {CAPELLA_OWL_BANNER} from "./utils/ownBanner.js"; +import {POS_PANDA_MERGE_TRANSITION_BANNER} from "./utils/pandaMergeTransitionBanner.js"; import {verifyBlocksDataAvailability} from "./verifyBlocksDataAvailability.js"; +import {SegmentExecStatus, verifyBlocksExecutionPayload} from "./verifyBlocksExecutionPayloads.js"; +import {verifyBlocksSignatures} from "./verifyBlocksSignatures.js"; +import {verifyBlocksStateTransitionOnly} from "./verifyBlocksStateTransitionOnly.js"; import {writeBlockInputToDb} from "./writeBlockInputToDb.js"; /** diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts index 98bfae2c1ce3..1d8c72a46873 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts @@ -1,12 +1,12 @@ -import {computeTimeAtSlot} from "@lodestar/state-transition"; -import {DataAvailabilityStatus} from "@lodestar/fork-choice"; import {ChainForkConfig} from "@lodestar/config"; -import {deneb, UintNum64} from "@lodestar/types"; +import {DataAvailabilityStatus} from "@lodestar/fork-choice"; +import {computeTimeAtSlot} from "@lodestar/state-transition"; +import {UintNum64, deneb} from "@lodestar/types"; import {Logger} from "@lodestar/utils"; +import {Metrics} from "../../metrics/metrics.js"; import {BlockError, BlockErrorCode} from "../errors/index.js"; import {validateBlobSidecars} from "../validation/blobSidecar.js"; -import {Metrics} from "../../metrics/metrics.js"; -import {BlockInput, BlockInputType, ImportBlockOpts, BlobSidecarValidation, getBlockInput} from "./types.js"; +import {BlobSidecarValidation, BlockInput, BlockInputType, ImportBlockOpts, 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 diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts index e641ff9ae6d9..e37442bfde8f 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts @@ -1,32 +1,32 @@ +import {ChainForkConfig} from "@lodestar/config"; +import { + ExecutionStatus, + IForkChoice, + LVHInvalidResponse, + LVHValidResponse, + MaybeValidExecutionStatus, + ProtoBlock, + assertValidTerminalPowBlock, +} from "@lodestar/fork-choice"; +import {ForkSeq, SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY} from "@lodestar/params"; import { CachedBeaconStateAllForks, - isExecutionStateType, isExecutionBlockBodyType, - isMergeTransitionBlock as isMergeTransitionBlockFn, isExecutionEnabled, + isExecutionStateType, + isMergeTransitionBlock as isMergeTransitionBlockFn, } from "@lodestar/state-transition"; -import {bellatrix, Slot, deneb, SignedBeaconBlock, electra} from "@lodestar/types"; -import { - IForkChoice, - assertValidTerminalPowBlock, - ProtoBlock, - ExecutionStatus, - MaybeValidExecutionStatus, - LVHValidResponse, - LVHInvalidResponse, -} from "@lodestar/fork-choice"; -import {ChainForkConfig} from "@lodestar/config"; +import {SignedBeaconBlock, Slot, bellatrix, deneb, electra} from "@lodestar/types"; import {ErrorAborted, Logger, toRootHex} from "@lodestar/utils"; -import {ForkSeq, SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY} from "@lodestar/params"; +import {IEth1ForBlockProduction} from "../../eth1/index.js"; import {IExecutionEngine} from "../../execution/engine/interface.js"; -import {BlockError, BlockErrorCode} from "../errors/index.js"; -import {IClock} from "../../util/clock.js"; -import {kzgCommitmentToVersionedHash} from "../../util/blobs.js"; -import {BlockProcessOpts} from "../options.js"; import {ExecutionPayloadStatus} from "../../execution/engine/interface.js"; -import {IEth1ForBlockProduction} from "../../eth1/index.js"; import {Metrics} from "../../metrics/metrics.js"; +import {kzgCommitmentToVersionedHash} from "../../util/blobs.js"; +import {IClock} from "../../util/clock.js"; +import {BlockError, BlockErrorCode} from "../errors/index.js"; +import {BlockProcessOpts} from "../options.js"; import {ImportBlockOpts} from "./types.js"; export type VerifyBlockExecutionPayloadModules = { diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts index 22b20a55fb67..5115f39ebf47 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts @@ -1,6 +1,6 @@ -import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; +import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {Slot} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {IClock} from "../../util/clock.js"; diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts index e86549cda7d3..d133579f97a5 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts @@ -1,10 +1,10 @@ import {CachedBeaconStateAllForks, getBlockSignatureSets} from "@lodestar/state-transition"; -import {Logger} from "@lodestar/utils"; import {SignedBeaconBlock} from "@lodestar/types"; +import {Logger} from "@lodestar/utils"; import {Metrics} from "../../metrics/metrics.js"; +import {nextEventLoop} from "../../util/eventLoop.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"; /** diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts index 49cd46220008..b2f70d6274b3 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts @@ -1,16 +1,16 @@ import { CachedBeaconStateAllForks, - stateTransition, - ExecutionPayloadStatus, DataAvailableStatus, + ExecutionPayloadStatus, StateHashTreeRootSource, + stateTransition, } from "@lodestar/state-transition"; 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 {BlockError, BlockErrorCode} from "../errors/index.js"; +import {BlockProcessOpts} from "../options.js"; import {BlockInput, ImportBlockOpts} from "./types.js"; /** diff --git a/packages/beacon-node/src/chain/bls/multithread/index.ts b/packages/beacon-node/src/chain/bls/multithread/index.ts index fc8ea7534ad7..4b1867c3793f 100644 --- a/packages/beacon-node/src/chain/bls/multithread/index.ts +++ b/packages/beacon-node/src/chain/bls/multithread/index.ts @@ -1,24 +1,21 @@ /* eslint-disable @typescript-eslint/strict-boolean-expressions */ import path from "node:path"; -import {spawn, Worker} from "@chainsafe/threads"; +import {Worker, spawn} from "@chainsafe/threads"; // `threads` library creates self global variable which breaks `timeout-abort-controller` https://github.com/jacobheun/timeout-abort-controller/issues/9 // Don't add an eslint disable here as a reminder that this has to be fixed eventually // @ts-ignore // biome-ignore lint/suspicious/noGlobalAssign: self = undefined; import {PublicKey} from "@chainsafe/blst"; -import {Logger} from "@lodestar/utils"; import {ISignatureSet} from "@lodestar/state-transition"; -import {QueueError, QueueErrorCode} from "../../../util/queue/index.js"; +import {Logger} from "@lodestar/utils"; import {Metrics} from "../../../metrics/index.js"; -import {IBlsVerifier, VerifySignatureOpts} from "../interface.js"; -import {getAggregatedPubkey, getAggregatedPubkeysCount} from "../utils.js"; -import {verifySignatureSetsMaybeBatch} from "../maybeBatch.js"; import {LinkedList} from "../../../util/array.js"; import {callInNextEventLoop} from "../../../util/eventLoop.js"; -import {BlsWorkReq, BlsWorkResult, WorkerData, WorkResultCode, WorkResultError} from "./types.js"; -import {chunkifyMaximizeChunkSize} from "./utils.js"; -import {defaultPoolSize} from "./poolSize.js"; +import {QueueError, QueueErrorCode} from "../../../util/queue/index.js"; +import {IBlsVerifier, VerifySignatureOpts} from "../interface.js"; +import {verifySignatureSetsMaybeBatch} from "../maybeBatch.js"; +import {getAggregatedPubkey, getAggregatedPubkeysCount} from "../utils.js"; import { JobQueueItem, JobQueueItemSameMessage, @@ -27,6 +24,9 @@ import { jobItemSigSets, jobItemWorkReq, } from "./jobItem.js"; +import {defaultPoolSize} from "./poolSize.js"; +import {BlsWorkReq, BlsWorkResult, WorkResultCode, WorkResultError, WorkerData} from "./types.js"; +import {chunkifyMaximizeChunkSize} from "./utils.js"; // Worker constructor consider the path relative to the current working directory const workerDir = process.env.NODE_ENV === "test" ? "../../../../lib/chain/bls/multithread" : "./"; diff --git a/packages/beacon-node/src/chain/bls/multithread/jobItem.ts b/packages/beacon-node/src/chain/bls/multithread/jobItem.ts index 63591af5ee77..efaaf36fd88f 100644 --- a/packages/beacon-node/src/chain/bls/multithread/jobItem.ts +++ b/packages/beacon-node/src/chain/bls/multithread/jobItem.ts @@ -1,9 +1,9 @@ import {PublicKey, asyncAggregateWithRandomness} from "@chainsafe/blst"; import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition"; +import {Metrics} from "../../../metrics/metrics.js"; +import {LinkedList} from "../../../util/array.js"; import {VerifySignatureOpts} from "../interface.js"; import {getAggregatedPubkey} from "../utils.js"; -import {LinkedList} from "../../../util/array.js"; -import {Metrics} from "../../../metrics/metrics.js"; import {BlsWorkReq} from "./types.js"; export type JobQueueItem = JobQueueItemDefault | JobQueueItemSameMessage; diff --git a/packages/beacon-node/src/chain/bls/multithread/worker.ts b/packages/beacon-node/src/chain/bls/multithread/worker.ts index d2794db2e6bf..7fbd1701950b 100644 --- a/packages/beacon-node/src/chain/bls/multithread/worker.ts +++ b/packages/beacon-node/src/chain/bls/multithread/worker.ts @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/strict-boolean-expressions */ import worker from "node:worker_threads"; -import {expose} from "@chainsafe/threads/worker"; import {PublicKey} from "@chainsafe/blst"; -import {verifySignatureSetsMaybeBatch, SignatureSetDeserialized} from "../maybeBatch.js"; -import {WorkerData, BlsWorkReq, WorkResult, WorkResultCode, SerializedSet, BlsWorkResult} from "./types.js"; +import {expose} from "@chainsafe/threads/worker"; +import {SignatureSetDeserialized, verifySignatureSetsMaybeBatch} from "../maybeBatch.js"; +import {BlsWorkReq, BlsWorkResult, SerializedSet, WorkResult, WorkResultCode, WorkerData} from "./types.js"; import {chunkifyMaximizeChunkSize} from "./utils.js"; /** diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 144b73f0c01d..8b9fa0336283 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -1,106 +1,106 @@ import path from "node:path"; -import {CompositeTypeAny, TreeView, Type} from "@chainsafe/ssz"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; +import {CompositeTypeAny, TreeView, Type} from "@chainsafe/ssz"; +import {BeaconConfig} from "@lodestar/config"; +import {CheckpointWithHex, ExecutionStatus, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice"; +import {ForkSeq, GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; import { BeaconStateAllForks, CachedBeaconStateAllForks, + EffectiveBalanceIncrements, + EpochShuffling, + Index2PubkeyCache, + computeAnchorCheckpoint, + computeEndSlotAtEpoch, computeEpochAtSlot, computeStartSlotAtEpoch, createCachedBeaconState, - EffectiveBalanceIncrements, getEffectiveBalanceIncrementsZeroInactive, isCachedBeaconState, - Index2PubkeyCache, - EpochShuffling, - computeEndSlotAtEpoch, - computeAnchorCheckpoint, } from "@lodestar/state-transition"; -import {BeaconConfig} from "@lodestar/config"; import { - UintNum64, + BeaconBlock, + BlindedBeaconBlock, + BlindedBeaconBlockBody, + Epoch, + ExecutionPayload, Root, - phase0, - Slot, RootHex, - Epoch, + SignedBeaconBlock, + Slot, + UintNum64, ValidatorIndex, - deneb, Wei, bellatrix, + deneb, isBlindedBeaconBlock, - BeaconBlock, - SignedBeaconBlock, - ExecutionPayload, - BlindedBeaconBlock, - BlindedBeaconBlockBody, + phase0, } from "@lodestar/types"; -import {CheckpointWithHex, ExecutionStatus, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice"; -import {ProcessShutdownCallback} from "@lodestar/validator"; import {Logger, fromHex, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toRootHex} from "@lodestar/utils"; -import {ForkSeq, GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ProcessShutdownCallback} from "@lodestar/validator"; import {GENESIS_EPOCH, ZERO_HASH} from "../constants/index.js"; import {IBeaconDb} from "../db/index.js"; -import {Metrics} from "../metrics/index.js"; import {IEth1ForBlockProduction} from "../eth1/index.js"; -import {IExecutionEngine, IExecutionBuilder} from "../execution/index.js"; +import {IExecutionBuilder, IExecutionEngine} from "../execution/index.js"; +import {Metrics} from "../metrics/index.js"; +import {BufferPool} from "../util/bufferPool.js"; import {Clock, ClockEvent, IClock} from "../util/clock.js"; import {ensureDir, writeIfNotExist} from "../util/file.js"; import {isOptimisticBlock} from "../util/forkChoice.js"; -import {BufferPool} from "../util/bufferPool.js"; +import {Archiver} from "./archiver/archiver.js"; +import {CheckpointBalancesCache} from "./balancesCache.js"; +import {BeaconProposerCache} from "./beaconProposerCache.js"; import {BlockProcessor, ImportBlockOpts} from "./blocks/index.js"; -import {ChainEventEmitter, ChainEvent} from "./emitter.js"; +import {BlockInput} from "./blocks/types.js"; +import {BlsMultiThreadWorkerPool, BlsSingleThreadVerifier, IBlsVerifier} from "./bls/index.js"; +import {ChainEvent, ChainEventEmitter} from "./emitter.js"; +import {ForkchoiceCaller, initializeForkChoice} from "./forkChoice/index.js"; +import {HistoricalStateRegen} from "./historicalState/index.js"; import { - IBeaconChain, - ProposerPreparationData, BlockHash, - StateGetOpts, CommonBlockBody, FindHeadFnName, + IBeaconChain, + ProposerPreparationData, + StateGetOpts, } from "./interface.js"; -import {IChainOptions} from "./options.js"; -import {QueuedStateRegenerator, RegenCaller} from "./regen/index.js"; -import {ForkchoiceCaller, initializeForkChoice} from "./forkChoice/index.js"; -import {IBlsVerifier, BlsSingleThreadVerifier, BlsMultiThreadWorkerPool} from "./bls/index.js"; -import { - SeenAttesters, - SeenAggregators, - SeenBlockProposers, - SeenSyncCommitteeMessages, - SeenContributionAndProof, -} from "./seenCache/index.js"; +import {LightClientServer} from "./lightClient/index.js"; import { AggregatedAttestationPool, AttestationPool, + OpPool, SyncCommitteeMessagePool, SyncContributionAndProofPool, - OpPool, } from "./opPools/index.js"; -import {LightClientServer} from "./lightClient/index.js"; -import {Archiver} from "./archiver/archiver.js"; +import {IChainOptions} from "./options.js"; import {PrepareNextSlotScheduler} from "./prepareNextSlot.js"; -import {ReprocessController} from "./reprocess.js"; -import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js"; -import {SeenBlockAttesters} from "./seenCache/seenBlockAttesters.js"; -import {BeaconProposerCache} from "./beaconProposerCache.js"; -import {CheckpointBalancesCache} from "./balancesCache.js"; +import {computeNewStateRoot} from "./produceBlock/computeNewStateRoot.js"; import {AssembledBlockType, BlobsResultType, BlockType} from "./produceBlock/index.js"; import {BlockAttributes, produceBlockBody, produceCommonBlockBody} from "./produceBlock/produceBlockBody.js"; -import {computeNewStateRoot} from "./produceBlock/computeNewStateRoot.js"; -import {BlockInput} from "./blocks/types.js"; -import {SeenAttestationDatas} from "./seenCache/seenAttestationData.js"; -import {HistoricalStateRegen} from "./historicalState/index.js"; +import {QueuedStateRegenerator, RegenCaller} from "./regen/index.js"; +import {ReprocessController} from "./reprocess.js"; +import {AttestationsRewards, computeAttestationsRewards} from "./rewards/attestationsRewards.js"; import {BlockRewards, computeBlockRewards} from "./rewards/blockRewards.js"; +import {SyncCommitteeRewards, computeSyncCommitteeRewards} from "./rewards/syncCommitteeRewards.js"; +import { + SeenAggregators, + SeenAttesters, + SeenBlockProposers, + SeenContributionAndProof, + SeenSyncCommitteeMessages, +} from "./seenCache/index.js"; +import {SeenGossipBlockInput} from "./seenCache/index.js"; +import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js"; +import {SeenAttestationDatas} from "./seenCache/seenAttestationData.js"; +import {SeenBlockAttesters} from "./seenCache/seenBlockAttesters.js"; import {ShufflingCache} from "./shufflingCache.js"; import {BlockStateCacheImpl} from "./stateCache/blockStateCacheImpl.js"; -import {SeenGossipBlockInput} from "./seenCache/index.js"; -import {InMemoryCheckpointStateCache} from "./stateCache/inMemoryCheckpointsCache.js"; -import {FIFOBlockStateCache} from "./stateCache/fifoBlockStateCache.js"; -import {PersistentCheckpointStateCache} from "./stateCache/persistentCheckpointsCache.js"; import {DbCPStateDatastore} from "./stateCache/datastore/db.js"; import {FileCPStateDatastore} from "./stateCache/datastore/file.js"; -import {SyncCommitteeRewards, computeSyncCommitteeRewards} from "./rewards/syncCommitteeRewards.js"; -import {AttestationsRewards, computeAttestationsRewards} from "./rewards/attestationsRewards.js"; +import {FIFOBlockStateCache} from "./stateCache/fifoBlockStateCache.js"; +import {InMemoryCheckpointStateCache} from "./stateCache/inMemoryCheckpointsCache.js"; +import {PersistentCheckpointStateCache} from "./stateCache/persistentCheckpointsCache.js"; /** * Arbitrary constants, blobs and payloads should be consumed immediately in the same slot diff --git a/packages/beacon-node/src/chain/emitter.ts b/packages/beacon-node/src/chain/emitter.ts index 10b6455e48f5..a24c1e37bf92 100644 --- a/packages/beacon-node/src/chain/emitter.ts +++ b/packages/beacon-node/src/chain/emitter.ts @@ -2,9 +2,9 @@ import {EventEmitter} from "node:events"; import {StrictEventEmitter} from "strict-event-emitter-types"; import {routes} from "@lodestar/api"; -import {phase0} from "@lodestar/types"; import {CheckpointWithHex} from "@lodestar/fork-choice"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import {phase0} from "@lodestar/types"; /** * Important chain events that occur during normal chain operation. diff --git a/packages/beacon-node/src/chain/errors/attestationError.ts b/packages/beacon-node/src/chain/errors/attestationError.ts index 9f8e86cea1ab..618a334928ae 100644 --- a/packages/beacon-node/src/chain/errors/attestationError.ts +++ b/packages/beacon-node/src/chain/errors/attestationError.ts @@ -1,4 +1,4 @@ -import {Epoch, Slot, ValidatorIndex, RootHex} from "@lodestar/types"; +import {Epoch, RootHex, Slot, ValidatorIndex} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {GossipActionError} from "./gossipValidation.js"; diff --git a/packages/beacon-node/src/chain/errors/blobSidecarError.ts b/packages/beacon-node/src/chain/errors/blobSidecarError.ts index f38aa883002c..410574594911 100644 --- a/packages/beacon-node/src/chain/errors/blobSidecarError.ts +++ b/packages/beacon-node/src/chain/errors/blobSidecarError.ts @@ -1,4 +1,4 @@ -import {Slot, RootHex, ValidatorIndex} from "@lodestar/types"; +import {RootHex, Slot, ValidatorIndex} from "@lodestar/types"; import {GossipActionError} from "./gossipValidation.js"; export enum BlobSidecarErrorCode { diff --git a/packages/beacon-node/src/chain/errors/blockError.ts b/packages/beacon-node/src/chain/errors/blockError.ts index 6280533c7a68..bc5dd6c33956 100644 --- a/packages/beacon-node/src/chain/errors/blockError.ts +++ b/packages/beacon-node/src/chain/errors/blockError.ts @@ -1,6 +1,6 @@ +import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {RootHex, SignedBeaconBlock, Slot, ValidatorIndex} from "@lodestar/types"; import {LodestarError, toRootHex} from "@lodestar/utils"; -import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {ExecutionPayloadStatus} from "../../execution/engine/interface.js"; import {QueueErrorCode} from "../../util/queue/index.js"; import {GossipActionError} from "./gossipValidation.js"; diff --git a/packages/beacon-node/src/chain/errors/syncCommitteeError.ts b/packages/beacon-node/src/chain/errors/syncCommitteeError.ts index e4a92729cecd..1564a358ec4c 100644 --- a/packages/beacon-node/src/chain/errors/syncCommitteeError.ts +++ b/packages/beacon-node/src/chain/errors/syncCommitteeError.ts @@ -1,4 +1,4 @@ -import {ValidatorIndex, Slot, RootHex} from "@lodestar/types"; +import {RootHex, Slot, ValidatorIndex} from "@lodestar/types"; import {GossipActionError} from "./gossipValidation.js"; export enum SyncCommitteeErrorCode { diff --git a/packages/beacon-node/src/chain/forkChoice/index.ts b/packages/beacon-node/src/chain/forkChoice/index.ts index 839975de4e26..b3f5d11260f2 100644 --- a/packages/beacon-node/src/chain/forkChoice/index.ts +++ b/packages/beacon-node/src/chain/forkChoice/index.ts @@ -1,26 +1,26 @@ -import {Slot} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import { + DataAvailabilityStatus, + ExecutionStatus, ForkChoice, - ProtoArray, ForkChoiceStore, - ExecutionStatus, JustifiedBalancesGetter, + ProtoArray, ForkChoiceOpts as RawForkChoiceOpts, - DataAvailabilityStatus, } from "@lodestar/fork-choice"; import { CachedBeaconStateAllForks, + computeAnchorCheckpoint, getEffectiveBalanceIncrementsZeroInactive, isExecutionStateType, isMergeTransitionComplete, - computeAnchorCheckpoint, } from "@lodestar/state-transition"; +import {Slot} from "@lodestar/types"; import {Logger, toRootHex} from "@lodestar/utils"; +import {GENESIS_SLOT} from "../../constants/index.js"; import {ChainEventEmitter} from "../emitter.js"; import {ChainEvent} from "../emitter.js"; -import {GENESIS_SLOT} from "../../constants/index.js"; export type ForkChoiceOpts = RawForkChoiceOpts & { // for testing only diff --git a/packages/beacon-node/src/chain/genesis/genesis.ts b/packages/beacon-node/src/chain/genesis/genesis.ts index 0c46f920d614..f56b42a3b89e 100644 --- a/packages/beacon-node/src/chain/genesis/genesis.ts +++ b/packages/beacon-node/src/chain/genesis/genesis.ts @@ -1,25 +1,25 @@ -import {toGindex, Tree} from "@chainsafe/persistent-merkle-tree"; -import {GENESIS_EPOCH, GENESIS_SLOT} from "@lodestar/params"; -import {phase0, ssz} from "@lodestar/types"; +import {Tree, toGindex} from "@chainsafe/persistent-merkle-tree"; import {BeaconConfig, ChainForkConfig} from "@lodestar/config"; +import {GENESIS_EPOCH, GENESIS_SLOT} from "@lodestar/params"; import { - getTemporaryBlockHeader, - getGenesisBeaconState, + BeaconStateAllForks, + CachedBeaconStateAllForks, applyDeposits, - applyTimestamp, applyEth1BlockHash, - CachedBeaconStateAllForks, + applyTimestamp, createCachedBeaconState, - BeaconStateAllForks, createEmptyEpochCacheImmutableData, getActiveValidatorIndices, + getGenesisBeaconState, + getTemporaryBlockHeader, } from "@lodestar/state-transition"; +import {phase0, ssz} from "@lodestar/types"; import {Logger} from "@lodestar/utils"; +import {DepositTree} from "../../db/repositories/depositDataRoot.js"; import {IEth1Provider} from "../../eth1/index.js"; import {IEth1StreamParams} from "../../eth1/interface.js"; import {getDepositsAndBlockStreamForGenesis, getDepositsStream} from "../../eth1/stream.js"; -import {DepositTree} from "../../db/repositories/depositDataRoot.js"; -import {IGenesisBuilder, GenesisResult} from "./interface.js"; +import {GenesisResult, IGenesisBuilder} from "./interface.js"; export type GenesisBuilderKwargs = { config: ChainForkConfig; diff --git a/packages/beacon-node/src/chain/genesis/interface.ts b/packages/beacon-node/src/chain/genesis/interface.ts index d1bae335b9ff..79c402cc29cb 100644 --- a/packages/beacon-node/src/chain/genesis/interface.ts +++ b/packages/beacon-node/src/chain/genesis/interface.ts @@ -1,6 +1,6 @@ import {CompositeViewDU, VectorCompositeType} from "@chainsafe/ssz"; -import {ssz} from "@lodestar/types"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import {ssz} from "@lodestar/types"; import {Eth1Block} from "../../eth1/interface.js"; export type GenesisResult = { diff --git a/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts b/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts index a9f254dea3f2..20a53c40d73d 100644 --- a/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts +++ b/packages/beacon-node/src/chain/historicalState/getHistoricalState.ts @@ -1,4 +1,5 @@ import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; +import {BeaconConfig} from "@lodestar/config"; import { BeaconStateAllForks, CachedBeaconStateAllForks, @@ -7,7 +8,6 @@ import { createCachedBeaconState, stateTransition, } from "@lodestar/state-transition"; -import {BeaconConfig} from "@lodestar/config"; import {IBeaconDb} from "../../db/index.js"; import {HistoricalStateRegenMetrics, RegenErrorType} from "./types.js"; diff --git a/packages/beacon-node/src/chain/historicalState/index.ts b/packages/beacon-node/src/chain/historicalState/index.ts index 8688bcf9f372..250a80467951 100644 --- a/packages/beacon-node/src/chain/historicalState/index.ts +++ b/packages/beacon-node/src/chain/historicalState/index.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import {ModuleThread, Thread, spawn, Worker} from "@chainsafe/threads"; +import {ModuleThread, Thread, Worker, spawn} from "@chainsafe/threads"; import {chainConfigToJson} from "@lodestar/config"; import {LoggerNode} from "@lodestar/logger/node"; import { diff --git a/packages/beacon-node/src/chain/historicalState/worker.ts b/packages/beacon-node/src/chain/historicalState/worker.ts index 2ea673d0faff..fabb985c66a5 100644 --- a/packages/beacon-node/src/chain/historicalState/worker.ts +++ b/packages/beacon-node/src/chain/historicalState/worker.ts @@ -1,21 +1,21 @@ import worker from "node:worker_threads"; -import {Transfer, expose} from "@chainsafe/threads/worker"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; -import {createBeaconConfig, chainConfigFromJson} from "@lodestar/config"; +import {Transfer, expose} from "@chainsafe/threads/worker"; +import {chainConfigFromJson, createBeaconConfig} from "@lodestar/config"; +import {LevelDbController} from "@lodestar/db"; import {getNodeLogger} from "@lodestar/logger/node"; import {EpochTransitionStep, StateCloneSource, StateHashTreeRootSource} from "@lodestar/state-transition"; -import {LevelDbController} from "@lodestar/db"; +import {BeaconDb} from "../../db/index.js"; import {RegistryMetricCreator, collectNodeJSMetrics} from "../../metrics/index.js"; import {JobFnQueue} from "../../util/queue/fnQueue.js"; import {QueueMetrics} from "../../util/queue/options.js"; -import {BeaconDb} from "../../db/index.js"; +import {getHistoricalState} from "./getHistoricalState.js"; import { HistoricalStateRegenMetrics, HistoricalStateWorkerApi, HistoricalStateWorkerData, RegenErrorType, } from "./types.js"; -import {getHistoricalState} from "./getHistoricalState.js"; // most of this setup copied from networkCoreWorker.ts diff --git a/packages/beacon-node/src/chain/initState.ts b/packages/beacon-node/src/chain/initState.ts index 2883cdc8388e..ff683867d14b 100644 --- a/packages/beacon-node/src/chain/initState.ts +++ b/packages/beacon-node/src/chain/initState.ts @@ -1,17 +1,17 @@ +import {ChainForkConfig} from "@lodestar/config"; import { - computeEpochAtSlot, BeaconStateAllForks, CachedBeaconStateAllForks, + computeEpochAtSlot, computeStartSlotAtEpoch, } from "@lodestar/state-transition"; import {SignedBeaconBlock} from "@lodestar/types"; -import {ChainForkConfig} from "@lodestar/config"; import {Logger, toHex, toRootHex} from "@lodestar/utils"; import {GENESIS_SLOT} from "../constants/index.js"; import {IBeaconDb} from "../db/index.js"; import {Eth1Provider} from "../eth1/index.js"; -import {Metrics} from "../metrics/index.js"; import {Eth1Options} from "../eth1/options.js"; +import {Metrics} from "../metrics/index.js"; import {GenesisBuilder} from "./genesis/genesis.js"; import {GenesisResult} from "./genesis/interface.js"; diff --git a/packages/beacon-node/src/chain/interface.ts b/packages/beacon-node/src/chain/interface.ts index 3b44ffd594ae..67b011ec0246 100644 --- a/packages/beacon-node/src/chain/interface.ts +++ b/packages/beacon-node/src/chain/interface.ts @@ -1,64 +1,64 @@ -import {CompositeTypeAny, TreeView, Type} from "@chainsafe/ssz"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; +import {CompositeTypeAny, TreeView, Type} from "@chainsafe/ssz"; +import {BeaconConfig} from "@lodestar/config"; +import {CheckpointWithHex, IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import { - UintNum64, + BeaconStateAllForks, + CachedBeaconStateAllForks, + EpochShuffling, + Index2PubkeyCache, +} from "@lodestar/state-transition"; +import { + BeaconBlock, + BlindedBeaconBlock, + Epoch, + ExecutionPayload, Root, - phase0, - Slot, RootHex, - Epoch, + SignedBeaconBlock, + Slot, + UintNum64, ValidatorIndex, - deneb, Wei, - capella, altair, - BeaconBlock, - ExecutionPayload, - SignedBeaconBlock, - BlindedBeaconBlock, + capella, + deneb, + phase0, } from "@lodestar/types"; -import { - BeaconStateAllForks, - CachedBeaconStateAllForks, - EpochShuffling, - Index2PubkeyCache, -} from "@lodestar/state-transition"; -import {BeaconConfig} from "@lodestar/config"; import {Logger} from "@lodestar/utils"; -import {CheckpointWithHex, IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {IEth1ForBlockProduction} from "../eth1/index.js"; -import {IExecutionEngine, IExecutionBuilder} from "../execution/index.js"; +import {IExecutionBuilder, IExecutionEngine} from "../execution/index.js"; import {Metrics} from "../metrics/metrics.js"; -import {IClock} from "../util/clock.js"; import {BufferPool} from "../util/bufferPool.js"; +import {IClock} from "../util/clock.js"; +import {CheckpointBalancesCache} from "./balancesCache.js"; +import {BeaconProposerCache, ProposerPreparationData} from "./beaconProposerCache.js"; +import {BlockInput, ImportBlockOpts} from "./blocks/types.js"; +import {IBlsVerifier} from "./bls/index.js"; import {ChainEventEmitter} from "./emitter.js"; +import {ForkchoiceCaller} from "./forkChoice/index.js"; +import {LightClientServer} from "./lightClient/index.js"; +import {AggregatedAttestationPool} from "./opPools/aggregatedAttestationPool.js"; +import {AttestationPool, OpPool, SyncCommitteeMessagePool, SyncContributionAndProofPool} from "./opPools/index.js"; +import {IChainOptions} from "./options.js"; +import {AssembledBlockType, BlockAttributes, BlockType} from "./produceBlock/produceBlockBody.js"; import {IStateRegenerator, RegenCaller} from "./regen/index.js"; -import {IBlsVerifier} from "./bls/index.js"; +import {ReprocessController} from "./reprocess.js"; +import {AttestationsRewards} from "./rewards/attestationsRewards.js"; +import {BlockRewards} from "./rewards/blockRewards.js"; +import {SyncCommitteeRewards} from "./rewards/syncCommitteeRewards.js"; import { - SeenAttesters, SeenAggregators, + SeenAttesters, SeenBlockProposers, - SeenSyncCommitteeMessages, SeenContributionAndProof, + SeenSyncCommitteeMessages, } from "./seenCache/index.js"; -import {AttestationPool, OpPool, SyncCommitteeMessagePool, SyncContributionAndProofPool} from "./opPools/index.js"; -import {LightClientServer} from "./lightClient/index.js"; -import {AggregatedAttestationPool} from "./opPools/aggregatedAttestationPool.js"; -import {BlockInput, ImportBlockOpts} from "./blocks/types.js"; -import {ReprocessController} from "./reprocess.js"; +import {SeenGossipBlockInput} from "./seenCache/index.js"; import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js"; -import {BeaconProposerCache, ProposerPreparationData} from "./beaconProposerCache.js"; -import {SeenBlockAttesters} from "./seenCache/seenBlockAttesters.js"; -import {CheckpointBalancesCache} from "./balancesCache.js"; -import {IChainOptions} from "./options.js"; -import {AssembledBlockType, BlockAttributes, BlockType} from "./produceBlock/produceBlockBody.js"; import {SeenAttestationDatas} from "./seenCache/seenAttestationData.js"; -import {SeenGossipBlockInput} from "./seenCache/index.js"; +import {SeenBlockAttesters} from "./seenCache/seenBlockAttesters.js"; import {ShufflingCache} from "./shufflingCache.js"; -import {BlockRewards} from "./rewards/blockRewards.js"; -import {AttestationsRewards} from "./rewards/attestationsRewards.js"; -import {SyncCommitteeRewards} from "./rewards/syncCommitteeRewards.js"; -import {ForkchoiceCaller} from "./forkChoice/index.js"; export {BlockType, type AssembledBlockType}; export {type ProposerPreparationData}; diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index 0a41ea059e73..94dadbd2a646 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -1,6 +1,30 @@ import {BitArray, CompositeViewDU} from "@chainsafe/ssz"; +import {routes} from "@lodestar/api"; +import {ChainForkConfig} from "@lodestar/config"; +import { + LightClientUpdateSummary, + isBetterUpdate, + toLightClientUpdateSummary, + upgradeLightClientHeader, +} from "@lodestar/light-client/spec"; +import { + ForkExecution, + ForkLightClient, + ForkName, + ForkSeq, + MIN_SYNC_COMMITTEE_PARTICIPANTS, + SYNC_COMMITTEE_SIZE, + forkLightClient, + highestFork, +} from "@lodestar/params"; +import { + CachedBeaconStateAltair, + computeStartSlotAtEpoch, + computeSyncPeriodAtEpoch, + computeSyncPeriodAtSlot, + executionPayloadToPayloadHeader, +} from "@lodestar/state-transition"; import { - altair, BeaconBlock, BeaconBlockBody, LightClientBootstrap, @@ -8,54 +32,30 @@ import { LightClientHeader, LightClientOptimisticUpdate, LightClientUpdate, - phase0, Root, RootHex, + SSZTypesFor, Slot, + SyncPeriod, + altair, + phase0, ssz, sszTypesFor, - SSZTypesFor, - SyncPeriod, } from "@lodestar/types"; -import {ChainForkConfig} from "@lodestar/config"; -import { - CachedBeaconStateAltair, - computeStartSlotAtEpoch, - computeSyncPeriodAtEpoch, - computeSyncPeriodAtSlot, - executionPayloadToPayloadHeader, -} from "@lodestar/state-transition"; -import { - isBetterUpdate, - toLightClientUpdateSummary, - LightClientUpdateSummary, - upgradeLightClientHeader, -} from "@lodestar/light-client/spec"; import {Logger, MapDef, pruneSetToMax, toRootHex} from "@lodestar/utils"; -import {routes} from "@lodestar/api"; -import { - MIN_SYNC_COMMITTEE_PARTICIPANTS, - SYNC_COMMITTEE_SIZE, - ForkName, - ForkSeq, - ForkExecution, - ForkLightClient, - highestFork, - forkLightClient, -} from "@lodestar/params"; +import {ZERO_HASH} from "../../constants/index.js"; import {IBeaconDb} from "../../db/index.js"; import {Metrics} from "../../metrics/index.js"; -import {ChainEventEmitter} from "../emitter.js"; import {byteArrayEquals} from "../../util/bytes.js"; -import {ZERO_HASH} from "../../constants/index.js"; +import {ChainEventEmitter} from "../emitter.js"; import {LightClientServerError, LightClientServerErrorCode} from "../errors/lightClientError.js"; import { + getBlockBodyExecutionHeaderProof, + getCurrentSyncCommitteeBranch, + getFinalizedRootProof, getNextSyncCommitteeBranch, getSyncCommitteesWitness, - getFinalizedRootProof, - getCurrentSyncCommitteeBranch, - getBlockBodyExecutionHeaderProof, } from "./proofs.js"; export type LightClientServerOpts = { diff --git a/packages/beacon-node/src/chain/lightClient/proofs.ts b/packages/beacon-node/src/chain/lightClient/proofs.ts index 8d273e30ae5c..d4380e66255f 100644 --- a/packages/beacon-node/src/chain/lightClient/proofs.ts +++ b/packages/beacon-node/src/chain/lightClient/proofs.ts @@ -1,11 +1,11 @@ import {Tree} from "@chainsafe/persistent-merkle-tree"; -import {BeaconStateAllForks, CachedBeaconStateAllForks} from "@lodestar/state-transition"; import { - FINALIZED_ROOT_GINDEX, BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX, - ForkExecution, + FINALIZED_ROOT_GINDEX, FINALIZED_ROOT_GINDEX_ELECTRA, + ForkExecution, } from "@lodestar/params"; +import {BeaconStateAllForks, CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {BeaconBlockBody, SSZTypesFor, ssz} from "@lodestar/types"; import {SyncCommitteeWitness} from "./types.js"; diff --git a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts index 92d7383b8cad..c4d76db96997 100644 --- a/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/aggregatedAttestationPool.ts @@ -1,40 +1,40 @@ -import {aggregateSignatures, Signature} from "@chainsafe/blst"; +import {Signature, aggregateSignatures} from "@chainsafe/blst"; import {BitArray} from "@chainsafe/ssz"; +import {ChainForkConfig} from "@lodestar/config"; +import {EpochDifference, IForkChoice} from "@lodestar/fork-choice"; import { ForkName, ForkSeq, - isForkPostElectra, MAX_ATTESTATIONS, MAX_ATTESTATIONS_ELECTRA, MAX_COMMITTEES_PER_SLOT, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH, + isForkPostElectra, } from "@lodestar/params"; -import { - phase0, - Epoch, - Slot, - ssz, - ValidatorIndex, - RootHex, - electra, - isElectraAttestation, - Attestation, -} from "@lodestar/types"; import { CachedBeaconStateAllForks, - CachedBeaconStatePhase0, CachedBeaconStateAltair, + CachedBeaconStatePhase0, computeEpochAtSlot, computeStartSlotAtEpoch, getBlockRootAtSlot, } from "@lodestar/state-transition"; -import {IForkChoice, EpochDifference} from "@lodestar/fork-choice"; -import {MapDef, toRootHex, assert} from "@lodestar/utils"; -import {ChainForkConfig} from "@lodestar/config"; -import {intersectUint8Arrays, IntersectResult} from "../../util/bitArray.js"; -import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; +import { + Attestation, + Epoch, + RootHex, + Slot, + ValidatorIndex, + electra, + isElectraAttestation, + phase0, + ssz, +} from "@lodestar/types"; +import {assert, MapDef, toRootHex} from "@lodestar/utils"; +import {IntersectResult, intersectUint8Arrays} from "../../util/bitArray.js"; import {InsertOutcome} from "./types.js"; +import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; type DataRootHex = string; diff --git a/packages/beacon-node/src/chain/opPools/attestationPool.ts b/packages/beacon-node/src/chain/opPools/attestationPool.ts index 8d8fbb92c0f1..9809c9c6304a 100644 --- a/packages/beacon-node/src/chain/opPools/attestationPool.ts +++ b/packages/beacon-node/src/chain/opPools/attestationPool.ts @@ -1,9 +1,9 @@ -import {BitArray} from "@chainsafe/ssz"; import {Signature, aggregateSignatures} from "@chainsafe/blst"; -import {Slot, RootHex, isElectraAttestation, Attestation} from "@lodestar/types"; -import {MapDef, assert} from "@lodestar/utils"; -import {isForkPostElectra} from "@lodestar/params"; +import {BitArray} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; +import {isForkPostElectra} from "@lodestar/params"; +import {Attestation, RootHex, Slot, isElectraAttestation} from "@lodestar/types"; +import {assert, MapDef} from "@lodestar/utils"; import {IClock} from "../../util/clock.js"; import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js"; import {isElectraAggregate, pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index f71186c06d35..5eec1597a24e 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -1,3 +1,13 @@ +import {Id, Repository} from "@lodestar/db"; +import { + BLS_WITHDRAWAL_PREFIX, + ForkSeq, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTER_SLASHINGS_ELECTRA, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_PROPOSER_SLASHINGS, + MAX_VOLUNTARY_EXITS, +} from "@lodestar/params"; import { CachedBeaconStateAllForks, computeEpochAtSlot, @@ -5,22 +15,12 @@ import { getAttesterSlashableIndices, isValidVoluntaryExit, } from "@lodestar/state-transition"; -import {Repository, Id} from "@lodestar/db"; -import { - MAX_PROPOSER_SLASHINGS, - MAX_VOLUNTARY_EXITS, - MAX_BLS_TO_EXECUTION_CHANGES, - BLS_WITHDRAWAL_PREFIX, - MAX_ATTESTER_SLASHINGS, - ForkSeq, - MAX_ATTESTER_SLASHINGS_ELECTRA, -} from "@lodestar/params"; +import {AttesterSlashing, Epoch, SignedBeaconBlock, ValidatorIndex, capella, phase0, ssz} from "@lodestar/types"; import {fromHex, toHex, toRootHex} from "@lodestar/utils"; -import {Epoch, phase0, capella, ssz, ValidatorIndex, SignedBeaconBlock, AttesterSlashing} from "@lodestar/types"; import {IBeaconDb} from "../../db/index.js"; +import {Metrics} from "../../metrics/metrics.js"; import {SignedBLSToExecutionChangeVersioned} from "../../util/types.js"; import {BlockType} from "../interface.js"; -import {Metrics} from "../../metrics/metrics.js"; import {BlockProductionStep} from "../produceBlock/produceBlockBody.js"; import {isValidBlsToExecutionChangeForBlockInclusion} from "./utils.js"; diff --git a/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts b/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts index 4de11e447231..6551ee625491 100644 --- a/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts +++ b/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts @@ -1,7 +1,7 @@ -import {BitArray} from "@chainsafe/ssz"; import {Signature, aggregateSignatures} from "@chainsafe/blst"; +import {BitArray} from "@chainsafe/ssz"; import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; -import {altair, Root, Slot, SubcommitteeIndex} from "@lodestar/types"; +import {Root, Slot, SubcommitteeIndex, altair} from "@lodestar/types"; import {MapDef, toRootHex} from "@lodestar/utils"; import {IClock} from "../../util/clock.js"; import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js"; diff --git a/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts b/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts index 81363be218d8..0f25032e1d7e 100644 --- a/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts +++ b/packages/beacon-node/src/chain/opPools/syncContributionAndProofPool.ts @@ -1,8 +1,8 @@ -import {BitArray} from "@chainsafe/ssz"; import {Signature, aggregateSignatures} from "@chainsafe/blst"; +import {BitArray} from "@chainsafe/ssz"; import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; -import {altair, Slot, Root, ssz} from "@lodestar/types"; import {G2_POINT_AT_INFINITY} from "@lodestar/state-transition"; +import {Root, Slot, altair, ssz} from "@lodestar/types"; import {MapDef, toRootHex} from "@lodestar/utils"; import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js"; import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js"; diff --git a/packages/beacon-node/src/chain/options.ts b/packages/beacon-node/src/chain/options.ts index cf83c4432984..f87fffd7b363 100644 --- a/packages/beacon-node/src/chain/options.ts +++ b/packages/beacon-node/src/chain/options.ts @@ -1,5 +1,6 @@ import {SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY} from "@lodestar/params"; import {defaultOptions as defaultValidatorOptions} from "@lodestar/validator"; +import {DEFAULT_STATE_ARCHIVE_MODE} from "./archiver/archiver.js"; import {ArchiverOpts} from "./archiver/interface.js"; import {ForkChoiceOpts} from "./forkChoice/index.js"; import {LightClientServerOpts} from "./lightClient/index.js"; @@ -7,7 +8,6 @@ import {ShufflingCacheOpts} from "./shufflingCache.js"; import {DEFAULT_MAX_BLOCK_STATES, FIFOBlockStateCacheOpts} from "./stateCache/fifoBlockStateCache.js"; import {PersistentCheckpointStateCacheOpts} from "./stateCache/persistentCheckpointsCache.js"; import {DEFAULT_MAX_CP_STATE_EPOCHS_IN_MEMORY} from "./stateCache/persistentCheckpointsCache.js"; -import {DEFAULT_STATE_ARCHIVE_MODE} from "./archiver/archiver.js"; export {StateArchiveMode} from "./archiver/interface.js"; export {DEFAULT_STATE_ARCHIVE_MODE} from "./archiver/archiver.js"; diff --git a/packages/beacon-node/src/chain/prepareNextSlot.ts b/packages/beacon-node/src/chain/prepareNextSlot.ts index bda618758842..40cadb3774c7 100644 --- a/packages/beacon-node/src/chain/prepareNextSlot.ts +++ b/packages/beacon-node/src/chain/prepareNextSlot.ts @@ -1,24 +1,24 @@ +import {routes} from "@lodestar/api"; +import {ChainForkConfig} from "@lodestar/config"; +import {ForkExecution, ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params"; import { - computeEpochAtSlot, - isExecutionStateType, - computeTimeAtSlot, + CachedBeaconStateAllForks, CachedBeaconStateExecutions, StateHashTreeRootSource, - CachedBeaconStateAllForks, + computeEpochAtSlot, + computeTimeAtSlot, + isExecutionStateType, } from "@lodestar/state-transition"; -import {ChainForkConfig} from "@lodestar/config"; -import {ForkSeq, SLOTS_PER_EPOCH, ForkExecution} from "@lodestar/params"; import {Slot} from "@lodestar/types"; -import {Logger, sleep, fromHex, isErrorAborted} from "@lodestar/utils"; -import {routes} from "@lodestar/api"; +import {Logger, fromHex, isErrorAborted, sleep} from "@lodestar/utils"; import {GENESIS_SLOT, ZERO_HASH_HEX} from "../constants/constants.js"; import {Metrics} from "../metrics/index.js"; import {ClockEvent} from "../util/clock.js"; import {isQueueErrorAborted} from "../util/queue/index.js"; -import {prepareExecutionPayload, getPayloadAttributesForSSE} from "./produceBlock/produceBlockBody.js"; +import {ForkchoiceCaller} from "./forkChoice/index.js"; import {IBeaconChain} from "./interface.js"; +import {getPayloadAttributesForSSE, prepareExecutionPayload} from "./produceBlock/produceBlockBody.js"; import {RegenCaller} from "./regen/index.js"; -import {ForkchoiceCaller} from "./forkChoice/index.js"; /* With 12s slot times, this scheduler will run 4s before the start of each slot (`12 / 3 = 4`). */ export const SCHEDULER_LOOKAHEAD_FACTOR = 3; diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index a353c4e54ff9..d26703050070 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -1,44 +1,44 @@ +import {ChainForkConfig} from "@lodestar/config"; +import {ForkExecution, ForkSeq, isForkExecution} from "@lodestar/params"; +import { + CachedBeaconStateAllForks, + CachedBeaconStateBellatrix, + CachedBeaconStateCapella, + CachedBeaconStateExecutions, + computeEpochAtSlot, + computeTimeAtSlot, + getCurrentEpoch, + getExpectedWithdrawals, + getRandaoMix, + isMergeTransitionComplete, +} from "@lodestar/state-transition"; import { + BLSPubkey, + BLSSignature, + BeaconBlock, + BeaconBlockBody, + BlindedBeaconBlock, + BlindedBeaconBlockBody, Bytes32, + ExecutionPayloadHeader, Root, RootHex, + SSEPayloadAttributes, Slot, - ssz, ValidatorIndex, - BLSPubkey, - BLSSignature, + Wei, capella, deneb, - Wei, - SSEPayloadAttributes, - BeaconBlock, - BeaconBlockBody, - ExecutionPayloadHeader, - BlindedBeaconBlockBody, - BlindedBeaconBlock, - sszTypesFor, electra, + ssz, + sszTypesFor, } from "@lodestar/types"; -import { - CachedBeaconStateAllForks, - CachedBeaconStateCapella, - CachedBeaconStateBellatrix, - CachedBeaconStateExecutions, - computeEpochAtSlot, - computeTimeAtSlot, - getRandaoMix, - getCurrentEpoch, - isMergeTransitionComplete, - getExpectedWithdrawals, -} from "@lodestar/state-transition"; -import {ChainForkConfig} from "@lodestar/config"; -import {ForkSeq, ForkExecution, isForkExecution} from "@lodestar/params"; -import {toHex, sleep, Logger, toRootHex} from "@lodestar/utils"; -import type {BeaconChain} from "../chain.js"; -import {PayloadId, IExecutionEngine, IExecutionBuilder, PayloadAttributes} from "../../execution/index.js"; +import {Logger, sleep, toHex, toRootHex} from "@lodestar/utils"; import {ZERO_HASH, ZERO_HASH_HEX} from "../../constants/index.js"; import {IEth1ForBlockProduction} from "../../eth1/index.js"; import {numToQuantity} from "../../eth1/provider/utils.js"; +import {IExecutionBuilder, IExecutionEngine, PayloadAttributes, PayloadId} from "../../execution/index.js"; +import type {BeaconChain} from "../chain.js"; import {CommonBlockBody} from "../interface.js"; import {validateBlobsAndKzgCommitments} from "./validateBlobsAndKzgCommitments.js"; diff --git a/packages/beacon-node/src/chain/regen/errors.ts b/packages/beacon-node/src/chain/regen/errors.ts index 7c1573b415f8..eb41e8321da3 100644 --- a/packages/beacon-node/src/chain/regen/errors.ts +++ b/packages/beacon-node/src/chain/regen/errors.ts @@ -1,4 +1,4 @@ -import {Root, Slot, RootHex} from "@lodestar/types"; +import {Root, RootHex, Slot} from "@lodestar/types"; export enum RegenErrorCode { BLOCK_NOT_IN_FORKCHOICE = "REGEN_ERROR_BLOCK_NOT_IN_FORKCHOICE", diff --git a/packages/beacon-node/src/chain/regen/interface.ts b/packages/beacon-node/src/chain/regen/interface.ts index 031d19860789..b70fbc059875 100644 --- a/packages/beacon-node/src/chain/regen/interface.ts +++ b/packages/beacon-node/src/chain/regen/interface.ts @@ -1,7 +1,7 @@ -import {phase0, Slot, RootHex, Epoch, BeaconBlock} from "@lodestar/types"; -import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {routes} from "@lodestar/api"; import {ProtoBlock} from "@lodestar/fork-choice"; +import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types"; import {CheckpointHex} from "../stateCache/index.js"; export enum RegenCaller { diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index 694e8635a3b7..7b812c04dc8d 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -1,15 +1,15 @@ -import {phase0, Slot, RootHex, Epoch, BeaconBlock} from "@lodestar/types"; +import {routes} from "@lodestar/api"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {CachedBeaconStateAllForks, UnfinalizedPubkeyIndexMap, computeEpochAtSlot} from "@lodestar/state-transition"; +import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types"; import {Logger, toRootHex} from "@lodestar/utils"; -import {routes} from "@lodestar/api"; -import {CheckpointHex, toCheckpointHex} from "../stateCache/index.js"; import {Metrics} from "../../metrics/index.js"; import {JobItemQueue} from "../../util/queue/index.js"; +import {CheckpointHex, toCheckpointHex} from "../stateCache/index.js"; import {BlockStateCache, CheckpointStateCache} from "../stateCache/types.js"; -import {IStateRegenerator, IStateRegeneratorInternal, RegenCaller, RegenFnName, StateCloneOpts} from "./interface.js"; -import {StateRegenerator, RegenModules} from "./regen.js"; import {RegenError, RegenErrorCode} from "./errors.js"; +import {IStateRegenerator, IStateRegeneratorInternal, RegenCaller, RegenFnName, StateCloneOpts} from "./interface.js"; +import {RegenModules, StateRegenerator} from "./regen.js"; const REGEN_QUEUE_MAX_LEN = 256; // TODO: Should this constant be lower than above? 256 feels high diff --git a/packages/beacon-node/src/chain/regen/regen.ts b/packages/beacon-node/src/chain/regen/regen.ts index 7c663c6e0d3d..073556d8162f 100644 --- a/packages/beacon-node/src/chain/regen/regen.ts +++ b/packages/beacon-node/src/chain/regen/regen.ts @@ -1,26 +1,26 @@ -import {phase0, Slot, RootHex, BeaconBlock, SignedBeaconBlock} from "@lodestar/types"; +import {ChainForkConfig} from "@lodestar/config"; +import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; import { CachedBeaconStateAllForks, + DataAvailableStatus, + ExecutionPayloadStatus, + StateHashTreeRootSource, computeEpochAtSlot, computeStartSlotAtEpoch, - ExecutionPayloadStatus, - DataAvailableStatus, processSlots, stateTransition, - StateHashTreeRootSource, } from "@lodestar/state-transition"; -import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; +import {BeaconBlock, RootHex, SignedBeaconBlock, Slot, phase0} from "@lodestar/types"; import {Logger, fromHex, toRootHex} from "@lodestar/utils"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {ChainForkConfig} from "@lodestar/config"; -import {Metrics} from "../../metrics/index.js"; import {IBeaconDb} from "../../db/index.js"; +import {Metrics} from "../../metrics/index.js"; +import {nextEventLoop} from "../../util/eventLoop.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 {BlockStateCache, CheckpointStateCache} from "../stateCache/types.js"; import {RegenError, RegenErrorCode} from "./errors.js"; +import {IStateRegeneratorInternal, RegenCaller, StateCloneOpts} from "./interface.js"; export type RegenModules = { db: IBeaconDb; diff --git a/packages/beacon-node/src/chain/reprocess.ts b/packages/beacon-node/src/chain/reprocess.ts index 4c91ef07ff69..a4d8fa43967d 100644 --- a/packages/beacon-node/src/chain/reprocess.ts +++ b/packages/beacon-node/src/chain/reprocess.ts @@ -1,4 +1,4 @@ -import {Slot, RootHex} from "@lodestar/types"; +import {RootHex, Slot} from "@lodestar/types"; import {MapDef} from "@lodestar/utils"; import {Metrics} from "../metrics/index.js"; diff --git a/packages/beacon-node/src/chain/rewards/attestationsRewards.ts b/packages/beacon-node/src/chain/rewards/attestationsRewards.ts index 588b310f87ea..14f2f1ccbc79 100644 --- a/packages/beacon-node/src/chain/rewards/attestationsRewards.ts +++ b/packages/beacon-node/src/chain/rewards/attestationsRewards.ts @@ -1,4 +1,5 @@ -import {Epoch, ValidatorIndex} from "@lodestar/types"; +import {routes} from "@lodestar/api"; +import {BeaconConfig} from "@lodestar/config"; import { EFFECTIVE_BALANCE_INCREMENT, ForkName, @@ -10,7 +11,6 @@ import { TIMELY_TARGET_FLAG_INDEX, WEIGHT_DENOMINATOR, } from "@lodestar/params"; -import {routes} from "@lodestar/api"; import { CachedBeaconStateAllForks, CachedBeaconStateAltair, @@ -23,7 +23,7 @@ import { hasMarkers, isInInactivityLeak, } from "@lodestar/state-transition"; -import {BeaconConfig} from "@lodestar/config"; +import {Epoch, ValidatorIndex} from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; export type AttestationsRewards = routes.beacon.AttestationsRewards; diff --git a/packages/beacon-node/src/chain/rewards/blockRewards.ts b/packages/beacon-node/src/chain/rewards/blockRewards.ts index 19a59aaa028e..4b9c95de4c3b 100644 --- a/packages/beacon-node/src/chain/rewards/blockRewards.ts +++ b/packages/beacon-node/src/chain/rewards/blockRewards.ts @@ -1,3 +1,5 @@ +import {routes} from "@lodestar/api"; +import {ForkName, WHISTLEBLOWER_REWARD_QUOTIENT} from "@lodestar/params"; import { CachedBeaconStateAllForks, CachedBeaconStateAltair, @@ -6,8 +8,6 @@ import { processAttestationsAltair, } from "@lodestar/state-transition"; import {BeaconBlock, altair, phase0} from "@lodestar/types"; -import {ForkName, WHISTLEBLOWER_REWARD_QUOTIENT} from "@lodestar/params"; -import {routes} from "@lodestar/api"; export type BlockRewards = routes.beacon.BlockRewards; type SubRewardValue = number; // All reward values should be integer diff --git a/packages/beacon-node/src/chain/rewards/syncCommitteeRewards.ts b/packages/beacon-node/src/chain/rewards/syncCommitteeRewards.ts index 71d345e32811..55ab69ec0285 100644 --- a/packages/beacon-node/src/chain/rewards/syncCommitteeRewards.ts +++ b/packages/beacon-node/src/chain/rewards/syncCommitteeRewards.ts @@ -1,7 +1,7 @@ +import {routes} from "@lodestar/api"; +import {ForkName, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "@lodestar/state-transition"; import {BeaconBlock, ValidatorIndex, altair} from "@lodestar/types"; -import {ForkName, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; -import {routes} from "@lodestar/api"; export type SyncCommitteeRewards = routes.beacon.SyncCommitteeRewards; type BalanceRecord = {val: number}; // Use val for convenient way to increment/decrement balance diff --git a/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts b/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts index a0aa6db35893..8e0dfcb3bd96 100644 --- a/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts +++ b/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts @@ -1,5 +1,5 @@ import {BitArray} from "@chainsafe/ssz"; -import {CommitteeIndex, phase0, RootHex, Slot} from "@lodestar/types"; +import {CommitteeIndex, RootHex, Slot, phase0} from "@lodestar/types"; import {MapDef} from "@lodestar/utils"; import {Metrics} from "../../metrics/metrics.js"; import {InsertOutcome} from "../opPools/types.js"; diff --git a/packages/beacon-node/src/chain/seenCache/seenCommittee.ts b/packages/beacon-node/src/chain/seenCache/seenCommittee.ts index 38d7f67c74a2..9d7e930c94d7 100644 --- a/packages/beacon-node/src/chain/seenCache/seenCommittee.ts +++ b/packages/beacon-node/src/chain/seenCache/seenCommittee.ts @@ -1,4 +1,4 @@ -import {SubcommitteeIndex, Slot, ValidatorIndex, RootHex} from "@lodestar/types"; +import {RootHex, Slot, SubcommitteeIndex, ValidatorIndex} from "@lodestar/types"; import {MapDef} from "@lodestar/utils"; /** diff --git a/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts b/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts index 1c03979b7d77..fd0d396bb0ba 100644 --- a/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts +++ b/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts @@ -1,20 +1,20 @@ -import {deneb, RootHex, SignedBeaconBlock, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; +import {BLOBSIDECAR_FIXED_SIZE, ForkName, isForkBlobs} from "@lodestar/params"; +import {RootHex, SignedBeaconBlock, deneb, ssz} from "@lodestar/types"; import {pruneSetToMax, toRootHex} from "@lodestar/utils"; -import {BLOBSIDECAR_FIXED_SIZE, isForkBlobs, ForkName} from "@lodestar/params"; +import {Metrics} from "../../metrics/index.js"; import { + BlobsSource, BlockInput, - NullBlockInput, - getBlockInput, - BlockSource, BlockInputDataBlobs, + BlockSource, CachedData, GossipedInputType, + NullBlockInput, + getBlockInput, getBlockInputBlobs, - BlobsSource, } from "../blocks/types.js"; -import {Metrics} from "../../metrics/index.js"; export enum BlockInputAvailabilitySource { GOSSIP = "gossip", diff --git a/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts index 1cb67cd6cf09..886f6e386309 100644 --- a/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts +++ b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts @@ -1,6 +1,6 @@ -import {Epoch, RootHex} from "@lodestar/types"; -import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {routes} from "@lodestar/api"; +import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import {Epoch, RootHex} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; import {StateCloneOpts} from "../regen/interface.js"; diff --git a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts index 7766daf3c5b3..eec1fce5d6c2 100644 --- a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts +++ b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts @@ -1,6 +1,6 @@ -import {RootHex} from "@lodestar/types"; -import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {routes} from "@lodestar/api"; +import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import {RootHex} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; import {LinkedList} from "../../util/array.js"; diff --git a/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts index 38aeabb97955..4caa6779f697 100644 --- a/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts @@ -1,11 +1,11 @@ -import {phase0, Epoch, RootHex} from "@lodestar/types"; +import {routes} from "@lodestar/api"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import {Epoch, RootHex, phase0} from "@lodestar/types"; import {MapDef, toRootHex} from "@lodestar/utils"; -import {routes} from "@lodestar/api"; import {Metrics} from "../../metrics/index.js"; import {StateCloneOpts} from "../regen/interface.js"; import {MapTracker} from "./mapMetrics.js"; -import {CheckpointStateCache, CacheItemType} from "./types.js"; +import {CacheItemType, CheckpointStateCache} from "./types.js"; export type CheckpointHex = {epoch: Epoch; rootHex: RootHex}; const MAX_EPOCHS = 10; diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 0719efcfd309..4c9a8b0f1265 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -1,18 +1,18 @@ -import {phase0, Epoch, RootHex} from "@lodestar/types"; -import {CachedBeaconStateAllForks, computeStartSlotAtEpoch, getBlockRootAtSlot} from "@lodestar/state-transition"; -import {Logger, MapDef, fromHex, sleep, toHex, toRootHex} from "@lodestar/utils"; import {routes} from "@lodestar/api"; -import {loadCachedBeaconState} from "@lodestar/state-transition"; import {INTERVALS_PER_SLOT} from "@lodestar/params"; +import {CachedBeaconStateAllForks, computeStartSlotAtEpoch, getBlockRootAtSlot} from "@lodestar/state-transition"; +import {loadCachedBeaconState} from "@lodestar/state-transition"; +import {Epoch, RootHex, phase0} from "@lodestar/types"; +import {Logger, MapDef, fromHex, sleep, toHex, toRootHex} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; -import {IClock} from "../../util/clock.js"; -import {ShufflingCache} from "../shufflingCache.js"; import {AllocSource, BufferPool, BufferWithKey} from "../../util/bufferPool.js"; +import {IClock} from "../../util/clock.js"; import {StateCloneOpts} from "../regen/interface.js"; import {serializeState} from "../serializeState.js"; -import {MapTracker} from "./mapMetrics.js"; +import {ShufflingCache} from "../shufflingCache.js"; import {CPStateDatastore, DatastoreKey, datastoreKeyToCheckpoint} from "./datastore/index.js"; -import {CheckpointHex, CacheItemType, CheckpointStateCache, BlockStateCache} from "./types.js"; +import {MapTracker} from "./mapMetrics.js"; +import {BlockStateCache, CacheItemType, CheckpointHex, CheckpointStateCache} from "./types.js"; export type PersistentCheckpointStateCacheOpts = { /** Keep max n states in memory, persist the rest to disk */ diff --git a/packages/beacon-node/src/chain/stateCache/types.ts b/packages/beacon-node/src/chain/stateCache/types.ts index 1e8d6bd1bd62..403b469dd352 100644 --- a/packages/beacon-node/src/chain/stateCache/types.ts +++ b/packages/beacon-node/src/chain/stateCache/types.ts @@ -1,6 +1,6 @@ +import {routes} from "@lodestar/api"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {Epoch, RootHex, phase0} from "@lodestar/types"; -import {routes} from "@lodestar/api"; import {StateCloneOpts} from "../regen/interface.js"; export type CheckpointHex = {epoch: Epoch; rootHex: RootHex}; diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 6d6eab6ec15a..781e63cf623a 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -1,15 +1,14 @@ import {ForkName, ForkSeq} from "@lodestar/params"; -import {electra, phase0, RootHex, ssz, IndexedAttestation, SignedAggregateAndProof} from "@lodestar/types"; import { computeEpochAtSlot, - isAggregatorFromCommitteeLength, createAggregateSignatureSetFromComponents, + isAggregatorFromCommitteeLength, } from "@lodestar/state-transition"; +import {IndexedAttestation, RootHex, SignedAggregateAndProof, electra, phase0, ssz} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; -import {IBeaconChain} from "../index.js"; import {AttestationError, AttestationErrorCode, GossipAction} from "../errors/index.js"; +import {IBeaconChain} from "../index.js"; import {RegenCaller} from "../regen/index.js"; -import {getSelectionProofSignatureSet, getAggregateAndProofSignatureSet} from "./signatureSets/index.js"; import { getAttestationDataSigningRoot, getCommitteeIndices, @@ -18,6 +17,7 @@ import { verifyHeadBlockAndTargetRoot, verifyPropagationSlotRange, } from "./attestation.js"; +import {getAggregateAndProofSignatureSet, getSelectionProofSignatureSet} from "./signatureSets/index.js"; export type AggregateAndProofValidationResult = { indexedAttestation: IndexedAttestation; diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index 0b3f490e4129..e49a3f79450c 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -1,54 +1,54 @@ import {BitArray} from "@chainsafe/ssz"; -import { - phase0, - Epoch, - Root, - Slot, - RootHex, - ssz, - electra, - isElectraAttestation, - CommitteeIndex, - Attestation, - IndexedAttestation, -} from "@lodestar/types"; +import {BeaconConfig} from "@lodestar/config"; import {ProtoBlock} from "@lodestar/fork-choice"; import { ATTESTATION_SUBNET_COUNT, - SLOTS_PER_EPOCH, + DOMAIN_BEACON_ATTESTER, ForkName, ForkSeq, - DOMAIN_BEACON_ATTESTER, + SLOTS_PER_EPOCH, isForkPostElectra, } from "@lodestar/params"; import { - computeEpochAtSlot, - createSingleSignatureSetFromComponents, - SingleSignatureSet, EpochCacheError, EpochCacheErrorCode, EpochShuffling, - computeStartSlotAtEpoch, + SingleSignatureSet, + computeEpochAtSlot, computeSigningRoot, + computeStartSlotAtEpoch, + createSingleSignatureSetFromComponents, } from "@lodestar/state-transition"; -import {BeaconConfig} from "@lodestar/config"; +import { + Attestation, + CommitteeIndex, + Epoch, + IndexedAttestation, + Root, + RootHex, + Slot, + electra, + isElectraAttestation, + phase0, + ssz, +} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; -import {AttestationError, AttestationErrorCode, GossipAction} from "../errors/index.js"; import {MAXIMUM_GOSSIP_CLOCK_DISPARITY_SEC} from "../../constants/index.js"; -import {RegenCaller} from "../regen/index.js"; +import {sszDeserializeAttestation} from "../../network/gossip/topic.js"; +import {getShufflingDependentRoot} from "../../util/dependentRoot.js"; import { getAggregationBitsFromAttestationSerialized, getAttDataFromSignedAggregateAndProofElectra, + getAttDataFromSignedAggregateAndProofPhase0, getCommitteeBitsFromAttestationSerialized, getCommitteeBitsFromSignedAggregateAndProofElectra, - getAttDataFromSignedAggregateAndProofPhase0, getSignatureFromAttestationSerialized, } from "../../util/sszBytes.js"; -import {AttestationDataCacheEntry, SeenAttDataKey} from "../seenCache/seenAttestationData.js"; -import {sszDeserializeAttestation} from "../../network/gossip/topic.js"; import {Result, wrapError} from "../../util/wrapError.js"; +import {AttestationError, AttestationErrorCode, GossipAction} from "../errors/index.js"; import {IBeaconChain} from "../interface.js"; -import {getShufflingDependentRoot} from "../../util/dependentRoot.js"; +import {RegenCaller} from "../regen/index.js"; +import {AttestationDataCacheEntry, SeenAttDataKey} from "../seenCache/seenAttestationData.js"; export type BatchResult = { results: Result[]; diff --git a/packages/beacon-node/src/chain/validation/attesterSlashing.ts b/packages/beacon-node/src/chain/validation/attesterSlashing.ts index 5da146a67a86..c097774ecb02 100644 --- a/packages/beacon-node/src/chain/validation/attesterSlashing.ts +++ b/packages/beacon-node/src/chain/validation/attesterSlashing.ts @@ -1,11 +1,11 @@ -import {phase0} from "@lodestar/types"; import { - getAttesterSlashableIndices, assertValidAttesterSlashing, + getAttesterSlashableIndices, getAttesterSlashingSignatureSets, } from "@lodestar/state-transition"; -import {IBeaconChain} from "../index.js"; +import {phase0} from "@lodestar/types"; import {AttesterSlashingError, AttesterSlashingErrorCode, GossipAction} from "../errors/index.js"; +import {IBeaconChain} from "../index.js"; export async function validateApiAttesterSlashing( chain: IBeaconChain, diff --git a/packages/beacon-node/src/chain/validation/blobSidecar.ts b/packages/beacon-node/src/chain/validation/blobSidecar.ts index 4c82d7be153d..3b90972f62b1 100644 --- a/packages/beacon-node/src/chain/validation/blobSidecar.ts +++ b/packages/beacon-node/src/chain/validation/blobSidecar.ts @@ -1,12 +1,12 @@ -import {deneb, Root, Slot, ssz} from "@lodestar/types"; -import {toRootHex, verifyMerkleBranch} from "@lodestar/utils"; -import {computeStartSlotAtEpoch, getBlockHeaderProposerSignatureSet} from "@lodestar/state-transition"; import {KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, KZG_COMMITMENT_SUBTREE_INDEX0} from "@lodestar/params"; +import {computeStartSlotAtEpoch, getBlockHeaderProposerSignatureSet} from "@lodestar/state-transition"; +import {Root, Slot, deneb, ssz} from "@lodestar/types"; +import {toRootHex, verifyMerkleBranch} from "@lodestar/utils"; -import {BlobSidecarGossipError, BlobSidecarErrorCode} from "../errors/blobSidecarError.js"; -import {GossipAction} from "../errors/gossipValidation.js"; -import {ckzg} from "../../util/kzg.js"; import {byteArrayEquals} from "../../util/bytes.js"; +import {ckzg} from "../../util/kzg.js"; +import {BlobSidecarErrorCode, BlobSidecarGossipError} from "../errors/blobSidecarError.js"; +import {GossipAction} from "../errors/gossipValidation.js"; import {IBeaconChain} from "../interface.js"; import {RegenCaller} from "../regen/index.js"; diff --git a/packages/beacon-node/src/chain/validation/block.ts b/packages/beacon-node/src/chain/validation/block.ts index aabc1b14958a..1b5251f77809 100644 --- a/packages/beacon-node/src/chain/validation/block.ts +++ b/packages/beacon-node/src/chain/validation/block.ts @@ -1,18 +1,18 @@ import {ChainForkConfig} from "@lodestar/config"; +import {ForkName} from "@lodestar/params"; import { computeStartSlotAtEpoch, computeTimeAtSlot, + getBlockProposerSignatureSet, isExecutionBlockBodyType, - isExecutionStateType, isExecutionEnabled, - getBlockProposerSignatureSet, + isExecutionStateType, } from "@lodestar/state-transition"; -import {sleep, toRootHex} from "@lodestar/utils"; -import {ForkName} from "@lodestar/params"; import {SignedBeaconBlock} from "@lodestar/types"; +import {sleep, toRootHex} from "@lodestar/utils"; import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../../constants/index.js"; +import {BlockErrorCode, BlockGossipError, GossipAction} from "../errors/index.js"; import {IBeaconChain} from "../interface.js"; -import {BlockGossipError, BlockErrorCode, GossipAction} from "../errors/index.js"; import {RegenCaller} from "../regen/index.js"; export async function validateGossipBlock( diff --git a/packages/beacon-node/src/chain/validation/blsToExecutionChange.ts b/packages/beacon-node/src/chain/validation/blsToExecutionChange.ts index fff399aada50..53e8b6f5d2b6 100644 --- a/packages/beacon-node/src/chain/validation/blsToExecutionChange.ts +++ b/packages/beacon-node/src/chain/validation/blsToExecutionChange.ts @@ -1,11 +1,11 @@ -import {capella} from "@lodestar/types"; import { - isValidBlsToExecutionChange, - getBlsToExecutionChangeSignatureSet, CachedBeaconStateCapella, + getBlsToExecutionChangeSignatureSet, + isValidBlsToExecutionChange, } from "@lodestar/state-transition"; -import {IBeaconChain} from "../index.js"; +import {capella} from "@lodestar/types"; import {BlsToExecutionChangeError, BlsToExecutionChangeErrorCode, GossipAction} from "../errors/index.js"; +import {IBeaconChain} from "../index.js"; export async function validateApiBlsToExecutionChange( chain: IBeaconChain, diff --git a/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts b/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts index 0b19495abde6..e19b3c28da87 100644 --- a/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts +++ b/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts @@ -1,9 +1,9 @@ import {ChainForkConfig} from "@lodestar/config"; import {LightClientFinalityUpdate} from "@lodestar/types"; -import {IBeaconChain} from "../interface.js"; -import {LightClientError, LightClientErrorCode} from "../errors/lightClientError.js"; -import {GossipAction} from "../errors/index.js"; import {assertLightClientServer} from "../../node/utils/lightclient.js"; +import {GossipAction} from "../errors/index.js"; +import {LightClientError, LightClientErrorCode} from "../errors/lightClientError.js"; +import {IBeaconChain} from "../interface.js"; import {updateReceivedTooEarly} from "./lightClientOptimisticUpdate.js"; // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/p2p-interface.md#light_client_finality_update diff --git a/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts b/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts index 7a7dd7f34a91..49bffb3a5305 100644 --- a/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts +++ b/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts @@ -1,11 +1,11 @@ import {ChainForkConfig} from "@lodestar/config"; import {computeTimeAtSlot} from "@lodestar/state-transition"; import {LightClientOptimisticUpdate} from "@lodestar/types"; -import {IBeaconChain} from "../interface.js"; -import {LightClientError, LightClientErrorCode} from "../errors/lightClientError.js"; -import {GossipAction} from "../errors/index.js"; import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../../constants/index.js"; import {assertLightClientServer} from "../../node/utils/lightclient.js"; +import {GossipAction} from "../errors/index.js"; +import {LightClientError, LightClientErrorCode} from "../errors/lightClientError.js"; +import {IBeaconChain} from "../interface.js"; // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/p2p-interface.md#light_client_optimistic_update export function validateLightClientOptimisticUpdate( diff --git a/packages/beacon-node/src/chain/validation/proposerSlashing.ts b/packages/beacon-node/src/chain/validation/proposerSlashing.ts index 48fe6db326c9..8d76470bb03b 100644 --- a/packages/beacon-node/src/chain/validation/proposerSlashing.ts +++ b/packages/beacon-node/src/chain/validation/proposerSlashing.ts @@ -1,7 +1,7 @@ -import {phase0} from "@lodestar/types"; import {assertValidProposerSlashing, getProposerSlashingSignatureSets} from "@lodestar/state-transition"; +import {phase0} from "@lodestar/types"; +import {GossipAction, ProposerSlashingError, ProposerSlashingErrorCode} from "../errors/index.js"; import {IBeaconChain} from "../index.js"; -import {ProposerSlashingError, ProposerSlashingErrorCode, GossipAction} from "../errors/index.js"; export async function validateApiProposerSlashing( chain: IBeaconChain, diff --git a/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts index 31d931818595..6d171aa0c1f4 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/aggregateAndProof.ts @@ -1,14 +1,14 @@ import {PublicKey} from "@chainsafe/blst"; +import {BeaconConfig} from "@lodestar/config"; import {DOMAIN_AGGREGATE_AND_PROOF, ForkSeq} from "@lodestar/params"; -import {ssz, SignedAggregateAndProof} from "@lodestar/types"; -import {Epoch} from "@lodestar/types"; import { + ISignatureSet, computeSigningRoot, computeStartSlotAtEpoch, createSingleSignatureSetFromComponents, - ISignatureSet, } from "@lodestar/state-transition"; -import {BeaconConfig} from "@lodestar/config"; +import {SignedAggregateAndProof, ssz} from "@lodestar/types"; +import {Epoch} from "@lodestar/types"; export function getAggregateAndProofSigningRoot( config: BeaconConfig, diff --git a/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts b/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts index 21e447b83677..4fe5122c0d3f 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts @@ -1,11 +1,11 @@ import {DOMAIN_CONTRIBUTION_AND_PROOF} from "@lodestar/params"; -import {altair, ssz} from "@lodestar/types"; import { CachedBeaconStateAllForks, - computeSigningRoot, ISignatureSet, SignatureSetType, + computeSigningRoot, } from "@lodestar/state-transition"; +import {altair, ssz} from "@lodestar/types"; export function getContributionAndProofSignatureSet( state: CachedBeaconStateAllForks, diff --git a/packages/beacon-node/src/chain/validation/signatureSets/selectionProof.ts b/packages/beacon-node/src/chain/validation/signatureSets/selectionProof.ts index 5e129a88aa20..6aa0cffc9b94 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/selectionProof.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/selectionProof.ts @@ -1,8 +1,8 @@ import {PublicKey} from "@chainsafe/blst"; -import {DOMAIN_SELECTION_PROOF} from "@lodestar/params"; -import {phase0, Slot, ssz} from "@lodestar/types"; -import {computeSigningRoot, createSingleSignatureSetFromComponents, ISignatureSet} from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; +import {DOMAIN_SELECTION_PROOF} from "@lodestar/params"; +import {ISignatureSet, computeSigningRoot, createSingleSignatureSetFromComponents} from "@lodestar/state-transition"; +import {Slot, phase0, ssz} from "@lodestar/types"; export function getSelectionProofSigningRoot(config: BeaconConfig, slot: Slot): Uint8Array { // previously, we call `const selectionProofDomain = config.getDomain(state.slot, DOMAIN_SELECTION_PROOF, slot)` diff --git a/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts b/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts index ce2b2e2484ab..7765e4d89ea0 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts @@ -1,11 +1,11 @@ import {DOMAIN_SYNC_COMMITTEE} from "@lodestar/params"; -import {altair, ssz} from "@lodestar/types"; import { CachedBeaconStateAllForks, - computeSigningRoot, ISignatureSet, SignatureSetType, + computeSigningRoot, } from "@lodestar/state-transition"; +import {altair, ssz} from "@lodestar/types"; export function getSyncCommitteeSignatureSet( state: CachedBeaconStateAllForks, diff --git a/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeContribution.ts b/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeContribution.ts index 0e1eaefef7c6..f444c48a2103 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeContribution.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeContribution.ts @@ -1,7 +1,7 @@ import {PublicKey} from "@chainsafe/blst"; -import {altair, ssz} from "@lodestar/types"; import {DOMAIN_SYNC_COMMITTEE} from "@lodestar/params"; -import {CachedBeaconStateAltair, computeSigningRoot, ISignatureSet, SignatureSetType} from "@lodestar/state-transition"; +import {CachedBeaconStateAltair, ISignatureSet, SignatureSetType, computeSigningRoot} from "@lodestar/state-transition"; +import {altair, ssz} from "@lodestar/types"; export function getSyncCommitteeContributionSignatureSet( state: CachedBeaconStateAltair, diff --git a/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts b/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts index 14fcfad2b92e..b94ae87b240f 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts @@ -1,11 +1,11 @@ import {DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF} from "@lodestar/params"; -import {altair, ssz} from "@lodestar/types"; import { CachedBeaconStateAllForks, - computeSigningRoot, ISignatureSet, SignatureSetType, + computeSigningRoot, } from "@lodestar/state-transition"; +import {altair, ssz} from "@lodestar/types"; export function getSyncCommitteeSelectionProofSignatureSet( state: CachedBeaconStateAllForks, diff --git a/packages/beacon-node/src/chain/validation/syncCommittee.ts b/packages/beacon-node/src/chain/validation/syncCommittee.ts index f47aa53a314e..c563bf7cf6be 100644 --- a/packages/beacon-node/src/chain/validation/syncCommittee.ts +++ b/packages/beacon-node/src/chain/validation/syncCommittee.ts @@ -1,5 +1,5 @@ +import {SYNC_COMMITTEE_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; -import {SYNC_COMMITTEE_SUBNET_SIZE, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {altair} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {GossipAction, SyncCommitteeError, SyncCommitteeErrorCode} from "../errors/index.js"; diff --git a/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts b/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts index 3f9351f2d0d3..611d738b15b6 100644 --- a/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts +++ b/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts @@ -1,14 +1,14 @@ -import {CachedBeaconStateAltair, isSyncCommitteeAggregator} from "@lodestar/state-transition"; -import {altair, ValidatorIndex} from "@lodestar/types"; import {SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; +import {CachedBeaconStateAltair, isSyncCommitteeAggregator} from "@lodestar/state-transition"; +import {ValidatorIndex, altair} from "@lodestar/types"; import {GossipAction, SyncCommitteeError, SyncCommitteeErrorCode} from "../errors/index.js"; import {IBeaconChain} from "../interface.js"; -import {validateGossipSyncCommitteeExceptSig} from "./syncCommittee.js"; import { - getSyncCommitteeSelectionProofSignatureSet, getContributionAndProofSignatureSet, getSyncCommitteeContributionSignatureSet, + getSyncCommitteeSelectionProofSignatureSet, } from "./signatureSets/index.js"; +import {validateGossipSyncCommitteeExceptSig} from "./syncCommittee.js"; /** * Spec v1.1.0-beta.2 diff --git a/packages/beacon-node/src/chain/validation/voluntaryExit.ts b/packages/beacon-node/src/chain/validation/voluntaryExit.ts index 2b38b161423e..79da31084a36 100644 --- a/packages/beacon-node/src/chain/validation/voluntaryExit.ts +++ b/packages/beacon-node/src/chain/validation/voluntaryExit.ts @@ -1,7 +1,7 @@ +import {getVoluntaryExitSignatureSet, isValidVoluntaryExit} from "@lodestar/state-transition"; import {phase0} from "@lodestar/types"; -import {isValidVoluntaryExit, getVoluntaryExitSignatureSet} from "@lodestar/state-transition"; +import {GossipAction, VoluntaryExitError, VoluntaryExitErrorCode} from "../errors/index.js"; import {IBeaconChain} from "../index.js"; -import {VoluntaryExitError, VoluntaryExitErrorCode, GossipAction} from "../errors/index.js"; import {RegenCaller} from "../regen/index.js"; export async function validateApiVoluntaryExit( diff --git a/packages/beacon-node/src/db/beacon.ts b/packages/beacon-node/src/db/beacon.ts index 07cc47fa54d8..1e15aa369141 100644 --- a/packages/beacon-node/src/db/beacon.ts +++ b/packages/beacon-node/src/db/beacon.ts @@ -1,27 +1,27 @@ -import {Db, LevelDbControllerMetrics} from "@lodestar/db"; import {ChainForkConfig} from "@lodestar/config"; +import {Db, LevelDbControllerMetrics} from "@lodestar/db"; import {IBeaconDb} from "./interface.js"; +import {CheckpointStateRepository} from "./repositories/checkpointState.js"; import { AttesterSlashingRepository, + BLSToExecutionChangeRepository, + BackfilledRanges, + BestLightClientUpdateRepository, + BlobSidecarsArchiveRepository, + BlobSidecarsRepository, BlockArchiveRepository, BlockRepository, - DepositEventRepository, + CheckpointHeaderRepository, DepositDataRootRepository, + DepositEventRepository, Eth1DataRepository, ProposerSlashingRepository, StateArchiveRepository, - VoluntaryExitRepository, - BestLightClientUpdateRepository, - CheckpointHeaderRepository, SyncCommitteeRepository, SyncCommitteeWitnessRepository, - BackfilledRanges, - BlobSidecarsRepository, - BlobSidecarsArchiveRepository, - BLSToExecutionChangeRepository, + VoluntaryExitRepository, } from "./repositories/index.js"; import {PreGenesisState, PreGenesisStateLastProcessedBlock} from "./single/index.js"; -import {CheckpointStateRepository} from "./repositories/checkpointState.js"; export type BeaconDbModules = { config: ChainForkConfig; diff --git a/packages/beacon-node/src/db/interface.ts b/packages/beacon-node/src/db/interface.ts index 6ffb8992f635..95336407ef20 100644 --- a/packages/beacon-node/src/db/interface.ts +++ b/packages/beacon-node/src/db/interface.ts @@ -1,25 +1,25 @@ import {LevelDbControllerMetrics} from "@lodestar/db"; +import {CheckpointStateRepository} from "./repositories/checkpointState.js"; import { AttesterSlashingRepository, + BLSToExecutionChangeRepository, + BackfilledRanges, + BestLightClientUpdateRepository, + BlobSidecarsArchiveRepository, + BlobSidecarsRepository, BlockArchiveRepository, BlockRepository, - DepositEventRepository, + CheckpointHeaderRepository, DepositDataRootRepository, + DepositEventRepository, Eth1DataRepository, ProposerSlashingRepository, StateArchiveRepository, - VoluntaryExitRepository, - BestLightClientUpdateRepository, - CheckpointHeaderRepository, SyncCommitteeRepository, SyncCommitteeWitnessRepository, - BackfilledRanges, - BlobSidecarsRepository, - BlobSidecarsArchiveRepository, - BLSToExecutionChangeRepository, + VoluntaryExitRepository, } from "./repositories/index.js"; import {PreGenesisState, PreGenesisStateLastProcessedBlock} from "./single/index.js"; -import {CheckpointStateRepository} from "./repositories/checkpointState.js"; /** * The DB service manages the data layer of the beacon chain diff --git a/packages/beacon-node/src/db/repositories/attesterSlashing.ts b/packages/beacon-node/src/db/repositories/attesterSlashing.ts index a484f605ac15..dd83c25998b6 100644 --- a/packages/beacon-node/src/db/repositories/attesterSlashing.ts +++ b/packages/beacon-node/src/db/repositories/attesterSlashing.ts @@ -1,6 +1,6 @@ -import {phase0, ssz, ValidatorIndex} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {Db, Repository} from "@lodestar/db"; +import {ValidatorIndex, phase0, ssz} from "@lodestar/types"; import {Bucket, getBucketNameByValue} from "../buckets.js"; /** diff --git a/packages/beacon-node/src/db/repositories/backfilledRanges.ts b/packages/beacon-node/src/db/repositories/backfilledRanges.ts index f86c20288099..c2958a0e972e 100644 --- a/packages/beacon-node/src/db/repositories/backfilledRanges.ts +++ b/packages/beacon-node/src/db/repositories/backfilledRanges.ts @@ -1,6 +1,6 @@ import {ChainForkConfig} from "@lodestar/config"; -import {Slot, ssz} from "@lodestar/types"; import {DatabaseController, Repository} from "@lodestar/db"; +import {Slot, ssz} from "@lodestar/types"; import {bytesToInt} from "@lodestar/utils"; import {Bucket, getBucketNameByValue} from "../buckets.js"; diff --git a/packages/beacon-node/src/db/repositories/blobSidecars.ts b/packages/beacon-node/src/db/repositories/blobSidecars.ts index e5750ed31b58..aaa16f760dd6 100644 --- a/packages/beacon-node/src/db/repositories/blobSidecars.ts +++ b/packages/beacon-node/src/db/repositories/blobSidecars.ts @@ -1,4 +1,4 @@ -import {ValueOf, ContainerType} from "@chainsafe/ssz"; +import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {Db, Repository} from "@lodestar/db"; import {ssz} from "@lodestar/types"; diff --git a/packages/beacon-node/src/db/repositories/blobSidecarsArchive.ts b/packages/beacon-node/src/db/repositories/blobSidecarsArchive.ts index 18293fc2924c..4b6c8fbcf046 100644 --- a/packages/beacon-node/src/db/repositories/blobSidecarsArchive.ts +++ b/packages/beacon-node/src/db/repositories/blobSidecarsArchive.ts @@ -3,7 +3,7 @@ import {Db, Repository} from "@lodestar/db"; import {Slot} from "@lodestar/types"; import {bytesToInt} from "@lodestar/utils"; import {Bucket, getBucketNameByValue} from "../buckets.js"; -import {blobSidecarsWrapperSsz, BlobSidecarsWrapper} from "./blobSidecars.js"; +import {BlobSidecarsWrapper, blobSidecarsWrapperSsz} from "./blobSidecars.js"; /** * blobSidecarsWrapper by slot diff --git a/packages/beacon-node/src/db/repositories/blockArchive.ts b/packages/beacon-node/src/db/repositories/blockArchive.ts index 427650a37bc3..12994ceba5db 100644 --- a/packages/beacon-node/src/db/repositories/blockArchive.ts +++ b/packages/beacon-node/src/db/repositories/blockArchive.ts @@ -1,11 +1,11 @@ -import all from "it-all"; import {ChainForkConfig} from "@lodestar/config"; -import {Db, Repository, KeyValue, FilterOptions} from "@lodestar/db"; -import {Slot, Root, ssz, SignedBeaconBlock} from "@lodestar/types"; +import {Db, FilterOptions, KeyValue, Repository} from "@lodestar/db"; +import {Root, SignedBeaconBlock, Slot, ssz} from "@lodestar/types"; import {bytesToInt} from "@lodestar/utils"; +import all from "it-all"; import {getSignedBlockTypeFromBytes} from "../../util/multifork.js"; import {Bucket, getBucketNameByValue} from "../buckets.js"; -import {getRootIndexKey, getParentRootIndexKey} from "./blockArchiveIndex.js"; +import {getParentRootIndexKey, getRootIndexKey} from "./blockArchiveIndex.js"; import {deleteParentRootIndex, deleteRootIndex, storeParentRootIndex, storeRootIndex} from "./blockArchiveIndex.js"; export interface BlockFilterOptions extends FilterOptions { diff --git a/packages/beacon-node/src/db/repositories/blockArchiveIndex.ts b/packages/beacon-node/src/db/repositories/blockArchiveIndex.ts index 8c2785dbe67c..12e133ec9acd 100644 --- a/packages/beacon-node/src/db/repositories/blockArchiveIndex.ts +++ b/packages/beacon-node/src/db/repositories/blockArchiveIndex.ts @@ -1,7 +1,7 @@ import {Db, encodeKey} from "@lodestar/db"; -import {Slot, Root, ssz, SignedBeaconBlock, SSZTypesFor} from "@lodestar/types"; -import {intToBytes} from "@lodestar/utils"; import {ForkAll} from "@lodestar/params"; +import {Root, SSZTypesFor, SignedBeaconBlock, Slot, ssz} from "@lodestar/types"; +import {intToBytes} from "@lodestar/utils"; import {Bucket} from "../buckets.js"; export async function storeRootIndex(db: Db, slot: Slot, blockRoot: Root): Promise { diff --git a/packages/beacon-node/src/db/repositories/blsToExecutionChange.ts b/packages/beacon-node/src/db/repositories/blsToExecutionChange.ts index a1b32403dd14..c9495f8fc9a6 100644 --- a/packages/beacon-node/src/db/repositories/blsToExecutionChange.ts +++ b/packages/beacon-node/src/db/repositories/blsToExecutionChange.ts @@ -1,6 +1,6 @@ -import {ValidatorIndex} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {Db, Repository} from "@lodestar/db"; +import {ValidatorIndex} from "@lodestar/types"; import {SignedBLSToExecutionChangeVersioned, signedBLSToExecutionChangeVersionedType} from "../../util/types.js"; import {Bucket, getBucketNameByValue} from "../buckets.js"; diff --git a/packages/beacon-node/src/db/repositories/depositDataRoot.ts b/packages/beacon-node/src/db/repositories/depositDataRoot.ts index 97200ccd0f92..50648655e440 100644 --- a/packages/beacon-node/src/db/repositories/depositDataRoot.ts +++ b/packages/beacon-node/src/db/repositories/depositDataRoot.ts @@ -1,8 +1,8 @@ import {ByteVectorType, CompositeViewDU, ListCompositeType} from "@chainsafe/ssz"; -import {Root, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; +import {Db, KeyValue, Repository} from "@lodestar/db"; +import {Root, ssz} from "@lodestar/types"; import {bytesToInt} from "@lodestar/utils"; -import {Db, Repository, KeyValue} from "@lodestar/db"; import {Bucket, getBucketNameByValue} from "../buckets.js"; // TODO: Review where is best to put this type diff --git a/packages/beacon-node/src/db/repositories/depositEvent.ts b/packages/beacon-node/src/db/repositories/depositEvent.ts index c1d2dd99047f..f2e180a02c43 100644 --- a/packages/beacon-node/src/db/repositories/depositEvent.ts +++ b/packages/beacon-node/src/db/repositories/depositEvent.ts @@ -1,6 +1,6 @@ import {ChainForkConfig} from "@lodestar/config"; -import {phase0, ssz} from "@lodestar/types"; import {Db, Repository} from "@lodestar/db"; +import {phase0, ssz} from "@lodestar/types"; import {Bucket, getBucketNameByValue} from "../buckets.js"; /** diff --git a/packages/beacon-node/src/db/repositories/eth1Data.ts b/packages/beacon-node/src/db/repositories/eth1Data.ts index f87199a0b80e..5a21e8f7d226 100644 --- a/packages/beacon-node/src/db/repositories/eth1Data.ts +++ b/packages/beacon-node/src/db/repositories/eth1Data.ts @@ -1,7 +1,7 @@ -import {phase0, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; -import {bytesToInt} from "@lodestar/utils"; import {Db, Repository} from "@lodestar/db"; +import {phase0, ssz} from "@lodestar/types"; +import {bytesToInt} from "@lodestar/utils"; import {Bucket, getBucketNameByValue} from "../buckets.js"; export class Eth1DataRepository extends Repository { diff --git a/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts b/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts index 26493e35e408..ad37b1425c58 100644 --- a/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts +++ b/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts @@ -1,6 +1,6 @@ import {ChainForkConfig} from "@lodestar/config"; import {DatabaseController, Repository} from "@lodestar/db"; -import {LightClientUpdate, ssz, SyncPeriod} from "@lodestar/types"; +import {LightClientUpdate, SyncPeriod, ssz} from "@lodestar/types"; import {Bucket, getBucketNameByValue} from "../buckets.js"; const SLOT_BYTE_COUNT = 8; diff --git a/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts b/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts index 22d6559792eb..36b7b9c187e7 100644 --- a/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts +++ b/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts @@ -1,8 +1,8 @@ import {ChainForkConfig} from "@lodestar/config"; import {DatabaseController, Repository} from "@lodestar/db"; import {LightClientHeader, ssz} from "@lodestar/types"; -import {Bucket, getBucketNameByValue} from "../buckets.js"; import {getLightClientHeaderTypeFromBytes} from "../../util/multifork.js"; +import {Bucket, getBucketNameByValue} from "../buckets.js"; /** * Block headers by block root. Until finality includes all headers seen by this node. After finality, diff --git a/packages/beacon-node/src/db/repositories/proposerSlashing.ts b/packages/beacon-node/src/db/repositories/proposerSlashing.ts index e599c22a9c32..210d33234d9b 100644 --- a/packages/beacon-node/src/db/repositories/proposerSlashing.ts +++ b/packages/beacon-node/src/db/repositories/proposerSlashing.ts @@ -1,6 +1,6 @@ -import {phase0, ssz, ValidatorIndex} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {Db, Repository} from "@lodestar/db"; +import {ValidatorIndex, phase0, ssz} from "@lodestar/types"; import {Bucket, getBucketNameByValue} from "../buckets.js"; export class ProposerSlashingRepository extends Repository { diff --git a/packages/beacon-node/src/db/repositories/stateArchive.ts b/packages/beacon-node/src/db/repositories/stateArchive.ts index b3b3d67fd7a0..638499c5fe01 100644 --- a/packages/beacon-node/src/db/repositories/stateArchive.ts +++ b/packages/beacon-node/src/db/repositories/stateArchive.ts @@ -1,8 +1,8 @@ +import {ChainForkConfig} from "@lodestar/config"; +import {Db, Repository} from "@lodestar/db"; import {BeaconStateAllForks} from "@lodestar/state-transition"; import {Epoch, Root, RootHex, Slot, ssz} from "@lodestar/types"; -import {ChainForkConfig} from "@lodestar/config"; import {bytesToInt, toHex} from "@lodestar/utils"; -import {Db, Repository} from "@lodestar/db"; import {getStateTypeFromBytes} from "../../util/multifork.js"; import {Bucket, getBucketNameByValue} from "../buckets.js"; import {getRootIndexKey, storeRootIndex} from "./stateArchiveIndex.js"; diff --git a/packages/beacon-node/src/db/repositories/stateArchiveIndex.ts b/packages/beacon-node/src/db/repositories/stateArchiveIndex.ts index a088aa2413e9..f119cd245080 100644 --- a/packages/beacon-node/src/db/repositories/stateArchiveIndex.ts +++ b/packages/beacon-node/src/db/repositories/stateArchiveIndex.ts @@ -1,4 +1,4 @@ -import {encodeKey, Db} from "@lodestar/db"; +import {Db, encodeKey} from "@lodestar/db"; import {Root, Slot} from "@lodestar/types"; import {intToBytes} from "@lodestar/utils"; import {Bucket} from "../buckets.js"; diff --git a/packages/beacon-node/src/db/repositories/voluntaryExit.ts b/packages/beacon-node/src/db/repositories/voluntaryExit.ts index ea2dc73a2903..8609725b6337 100644 --- a/packages/beacon-node/src/db/repositories/voluntaryExit.ts +++ b/packages/beacon-node/src/db/repositories/voluntaryExit.ts @@ -1,6 +1,6 @@ -import {phase0, ssz, ValidatorIndex} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {Db, Repository} from "@lodestar/db"; +import {ValidatorIndex, phase0, ssz} from "@lodestar/types"; import {Bucket, getBucketNameByValue} from "../buckets.js"; export class VoluntaryExitRepository extends Repository { diff --git a/packages/beacon-node/src/db/single/preGenesisState.ts b/packages/beacon-node/src/db/single/preGenesisState.ts index 3789e19d1a7d..a43a54c0923c 100644 --- a/packages/beacon-node/src/db/single/preGenesisState.ts +++ b/packages/beacon-node/src/db/single/preGenesisState.ts @@ -1,6 +1,6 @@ -import {ForkAll, GENESIS_SLOT} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; import {Db} from "@lodestar/db"; +import {ForkAll, GENESIS_SLOT} from "@lodestar/params"; import {BeaconStateAllForks} from "@lodestar/state-transition"; import {SSZTypesFor} from "@lodestar/types"; import {Bucket} from "../buckets.js"; diff --git a/packages/beacon-node/src/db/single/preGenesisStateLastProcessedBlock.ts b/packages/beacon-node/src/db/single/preGenesisStateLastProcessedBlock.ts index 37dcb069acc9..c31382ec9ee6 100644 --- a/packages/beacon-node/src/db/single/preGenesisStateLastProcessedBlock.ts +++ b/packages/beacon-node/src/db/single/preGenesisStateLastProcessedBlock.ts @@ -1,7 +1,7 @@ import {UintNumberType} from "@chainsafe/ssz"; -import {ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {Db} from "@lodestar/db"; +import {ssz} from "@lodestar/types"; import {Bucket} from "../buckets.js"; export class PreGenesisStateLastProcessedBlock { diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index 674b6b600f31..815f5aeb8938 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -1,4 +1,3 @@ -import {phase0, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import { BeaconStateAllForks, @@ -6,19 +5,20 @@ import { CachedBeaconStateElectra, becomesNewEth1Data, } from "@lodestar/state-transition"; -import {ErrorAborted, TimeoutError, fromHex, Logger, isErrorAborted, sleep} from "@lodestar/utils"; +import {phase0, ssz} from "@lodestar/types"; +import {ErrorAborted, Logger, TimeoutError, fromHex, isErrorAborted, sleep} from "@lodestar/utils"; import {IBeaconDb} from "../db/index.js"; import {Metrics} from "../metrics/index.js"; -import {Eth1DepositsCache} from "./eth1DepositsCache.js"; import {Eth1DataCache} from "./eth1DataCache.js"; -import {getEth1VotesToConsider, pickEth1Vote} from "./utils/eth1Vote.js"; -import {getDeposits} from "./utils/deposits.js"; +import {Eth1DepositsCache} from "./eth1DepositsCache.js"; import {Eth1DataAndDeposits, EthJsonRpcBlockRaw, IEth1Provider} from "./interface.js"; import {Eth1Options} from "./options.js"; -import {HttpRpcError} from "./provider/jsonRpcHttpClient.js"; import {parseEth1Block} from "./provider/eth1Provider.js"; +import {HttpRpcError} from "./provider/jsonRpcHttpClient.js"; import {isJsonRpcTruncatedError} from "./provider/utils.js"; +import {getDeposits} from "./utils/deposits.js"; +import {getEth1VotesToConsider, pickEth1Vote} from "./utils/eth1Vote.js"; const MAX_BLOCKS_PER_BLOCK_QUERY = 1000; const MIN_BLOCKS_PER_BLOCK_QUERY = 10; diff --git a/packages/beacon-node/src/eth1/eth1DepositsCache.ts b/packages/beacon-node/src/eth1/eth1DepositsCache.ts index 13dd29013124..16ed7c95a465 100644 --- a/packages/beacon-node/src/eth1/eth1DepositsCache.ts +++ b/packages/beacon-node/src/eth1/eth1DepositsCache.ts @@ -1,14 +1,14 @@ import {byteArrayEquals} from "@chainsafe/ssz"; -import {phase0, ssz} from "@lodestar/types"; -import {FilterOptions} from "@lodestar/db"; import {ChainForkConfig} from "@lodestar/config"; +import {FilterOptions} from "@lodestar/db"; +import {phase0, ssz} from "@lodestar/types"; import {IBeaconDb} from "../db/index.js"; -import {getEth1DataForBlocks} from "./utils/eth1Data.js"; -import {assertConsecutiveDeposits} from "./utils/eth1DepositEvent.js"; -import {getDepositsWithProofs} from "./utils/deposits.js"; import {Eth1Error, Eth1ErrorCode} from "./errors.js"; import {Eth1Block} from "./interface.js"; +import {getDepositsWithProofs} from "./utils/deposits.js"; +import {getEth1DataForBlocks} from "./utils/eth1Data.js"; +import {assertConsecutiveDeposits} from "./utils/eth1DepositEvent.js"; export class Eth1DepositsCache { unsafeAllowDepositDataOverwrite: boolean; diff --git a/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts b/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts index 5bf76625dfe8..ea2d134fe4dd 100644 --- a/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts +++ b/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts @@ -1,11 +1,11 @@ import {ChainConfig} from "@lodestar/config"; import {RootHex} from "@lodestar/types"; import {Logger, pruneSetToMax, toRootHex} from "@lodestar/utils"; -import {Metrics} from "../metrics/index.js"; import {ZERO_HASH_HEX} from "../constants/index.js"; +import {Metrics} from "../metrics/index.js"; import {enumToIndexMap} from "../util/enum.js"; -import {IEth1Provider, EthJsonRpcBlockRaw, PowMergeBlock, PowMergeBlockTimestamp, TDProgress} from "./interface.js"; -import {quantityToNum, quantityToBigint, dataToRootHex} from "./provider/utils.js"; +import {EthJsonRpcBlockRaw, IEth1Provider, PowMergeBlock, PowMergeBlockTimestamp, TDProgress} from "./interface.js"; +import {dataToRootHex, quantityToBigint, quantityToNum} from "./provider/utils.js"; export enum StatusCode { STOPPED = "STOPPED", diff --git a/packages/beacon-node/src/eth1/index.ts b/packages/beacon-node/src/eth1/index.ts index 42b82d03a848..f8c28afc5aed 100644 --- a/packages/beacon-node/src/eth1/index.ts +++ b/packages/beacon-node/src/eth1/index.ts @@ -1,9 +1,9 @@ import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {Root} from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; -import {IEth1ForBlockProduction, Eth1DataAndDeposits, IEth1Provider, PowMergeBlock, TDProgress} from "./interface.js"; import {Eth1DepositDataTracker, Eth1DepositDataTrackerModules} from "./eth1DepositDataTracker.js"; import {Eth1MergeBlockTracker, Eth1MergeBlockTrackerModules} from "./eth1MergeBlockTracker.js"; +import {Eth1DataAndDeposits, IEth1ForBlockProduction, IEth1Provider, PowMergeBlock, TDProgress} from "./interface.js"; import {Eth1Options} from "./options.js"; import {Eth1Provider} from "./provider/eth1Provider.js"; export {Eth1Provider}; diff --git a/packages/beacon-node/src/eth1/interface.ts b/packages/beacon-node/src/eth1/interface.ts index 54fcdd12492f..ccfd3568e479 100644 --- a/packages/beacon-node/src/eth1/interface.ts +++ b/packages/beacon-node/src/eth1/interface.ts @@ -1,6 +1,6 @@ import {BeaconConfig} from "@lodestar/config"; -import {phase0, Root, RootHex} from "@lodestar/types"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import {Root, RootHex, phase0} from "@lodestar/types"; export type EthJsonRpcBlockRaw = { /** the block number. null when its pending block. `"0x1b4"` */ diff --git a/packages/beacon-node/src/eth1/provider/eth1Provider.ts b/packages/beacon-node/src/eth1/provider/eth1Provider.ts index d284700ddb1d..8320f1dedac1 100644 --- a/packages/beacon-node/src/eth1/provider/eth1Provider.ts +++ b/packages/beacon-node/src/eth1/provider/eth1Provider.ts @@ -1,16 +1,16 @@ -import {phase0} from "@lodestar/types"; import {ChainConfig} from "@lodestar/config"; -import {fromHex, isErrorAborted, createElapsedTimeTracker, toPrintableUrl, toHex} from "@lodestar/utils"; import {Logger} from "@lodestar/logger"; +import {phase0} from "@lodestar/types"; +import {createElapsedTimeTracker, fromHex, isErrorAborted, toHex, toPrintableUrl} from "@lodestar/utils"; import {FetchError, isFetchError} from "@lodestar/api"; +import {HTTP_CONNECTION_ERROR_CODES, HTTP_FATAL_ERROR_CODES} from "../../execution/engine/utils.js"; +import {isValidAddress} from "../../util/address.js"; import {linspace} from "../../util/numpy.js"; -import {depositEventTopics, parseDepositLog} from "../utils/depositContract.js"; import {Eth1Block, Eth1ProviderState, IEth1Provider} from "../interface.js"; -import {DEFAULT_PROVIDER_URLS, Eth1Options} from "../options.js"; -import {isValidAddress} from "../../util/address.js"; import {EthJsonRpcBlockRaw} from "../interface.js"; -import {HTTP_CONNECTION_ERROR_CODES, HTTP_FATAL_ERROR_CODES} from "../../execution/engine/utils.js"; +import {DEFAULT_PROVIDER_URLS, Eth1Options} from "../options.js"; +import {depositEventTopics, parseDepositLog} from "../utils/depositContract.js"; import { ErrorJsonRpcResponse, HttpRpcError, @@ -19,7 +19,7 @@ import { JsonRpcHttpClientMetrics, ReqOpts, } from "./jsonRpcHttpClient.js"; -import {isJsonRpcTruncatedError, quantityToNum, numToQuantity, dataToBytes} from "./utils.js"; +import {dataToBytes, isJsonRpcTruncatedError, numToQuantity, quantityToNum} from "./utils.js"; /** * Binds return types to Ethereum JSON RPC methods diff --git a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts index f2ceae0d8c19..da72d5183d30 100644 --- a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts +++ b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts @@ -1,7 +1,7 @@ import {EventEmitter} from "node:events"; -import {StrictEventEmitter} from "strict-event-emitter-types"; import {fetch} from "@lodestar/api"; import {ErrorAborted, Gauge, Histogram, TimeoutError, isValidHttpUrl, retry} from "@lodestar/utils"; +import {StrictEventEmitter} from "strict-event-emitter-types"; import {IJson, RpcPayload} from "../interface.js"; import {JwtClaim, encodeJwtToken} from "./jwt.js"; diff --git a/packages/beacon-node/src/eth1/provider/utils.ts b/packages/beacon-node/src/eth1/provider/utils.ts index 7010e1377ca6..39cb9d4b1849 100644 --- a/packages/beacon-node/src/eth1/provider/utils.ts +++ b/packages/beacon-node/src/eth1/provider/utils.ts @@ -1,5 +1,5 @@ import {RootHex} from "@lodestar/types"; -import {bytesToBigInt, bigIntToBytes, toHex, fromHex} from "@lodestar/utils"; +import {bigIntToBytes, bytesToBigInt, fromHex, toHex} from "@lodestar/utils"; import {ErrorParseJson} from "./jsonRpcHttpClient.js"; /** QUANTITY as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API */ diff --git a/packages/beacon-node/src/eth1/stream.ts b/packages/beacon-node/src/eth1/stream.ts index 1e8583bb59a9..f4adaf2829f2 100644 --- a/packages/beacon-node/src/eth1/stream.ts +++ b/packages/beacon-node/src/eth1/stream.ts @@ -1,9 +1,9 @@ -import {sleep} from "@lodestar/utils"; import {phase0} from "@lodestar/types"; -import {Eth1Block, BatchDepositEvents, IEth1Provider, IEth1StreamParams} from "./interface.js"; +import {sleep} from "@lodestar/utils"; +import {BatchDepositEvents, Eth1Block, IEth1Provider, IEth1StreamParams} from "./interface.js"; +import {parseEth1Block} from "./provider/eth1Provider.js"; import {groupDepositEventsByBlock} from "./utils/groupDepositEventsByBlock.js"; import {optimizeNextBlockDiffForGenesis} from "./utils/optimizeNextBlockDiffForGenesis.js"; -import {parseEth1Block} from "./provider/eth1Provider.js"; /** * Phase 1 of genesis building. diff --git a/packages/beacon-node/src/eth1/utils/deposits.ts b/packages/beacon-node/src/eth1/utils/deposits.ts index 36f8c331ebc9..803b4f9deadf 100644 --- a/packages/beacon-node/src/eth1/utils/deposits.ts +++ b/packages/beacon-node/src/eth1/utils/deposits.ts @@ -1,11 +1,11 @@ -import {toGindex, Tree} from "@chainsafe/persistent-merkle-tree"; -import {toRootHex} from "@lodestar/utils"; -import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; -import {phase0, ssz} from "@lodestar/types"; +import {Tree, toGindex} from "@chainsafe/persistent-merkle-tree"; import {FilterOptions} from "@lodestar/db"; +import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {getEth1DepositCount} from "@lodestar/state-transition"; -import {Eth1Error, Eth1ErrorCode} from "../errors.js"; +import {phase0, ssz} from "@lodestar/types"; +import {toRootHex} from "@lodestar/utils"; import {DepositTree} from "../../db/repositories/depositDataRoot.js"; +import {Eth1Error, Eth1ErrorCode} from "../errors.js"; export type DepositGetter = (indexRange: FilterOptions, eth1Data: phase0.Eth1Data) => Promise; diff --git a/packages/beacon-node/src/eth1/utils/eth1Data.ts b/packages/beacon-node/src/eth1/utils/eth1Data.ts index 2b8e976cac2e..96a7031788ff 100644 --- a/packages/beacon-node/src/eth1/utils/eth1Data.ts +++ b/packages/beacon-node/src/eth1/utils/eth1Data.ts @@ -1,7 +1,7 @@ import {Root, phase0} from "@lodestar/types"; +import {DepositTree} from "../../db/repositories/depositDataRoot.js"; import {binarySearchLte} from "../../util/binarySearch.js"; import {Eth1Error, Eth1ErrorCode} from "../errors.js"; -import {DepositTree} from "../../db/repositories/depositDataRoot.js"; import {Eth1Block} from "../interface.js"; type BlockNumber = number; diff --git a/packages/beacon-node/src/eth1/utils/eth1Vote.ts b/packages/beacon-node/src/eth1/utils/eth1Vote.ts index 84d35ae7d434..e1cd47301c22 100644 --- a/packages/beacon-node/src/eth1/utils/eth1Vote.ts +++ b/packages/beacon-node/src/eth1/utils/eth1Vote.ts @@ -1,7 +1,7 @@ -import {EPOCHS_PER_ETH1_VOTING_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; -import {phase0, RootHex} from "@lodestar/types"; +import {EPOCHS_PER_ETH1_VOTING_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params"; import {BeaconStateAllForks, computeTimeAtSlot} from "@lodestar/state-transition"; +import {RootHex, phase0} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; export type Eth1DataGetter = ({ diff --git a/packages/beacon-node/src/execution/builder/http.ts b/packages/beacon-node/src/execution/builder/http.ts index b95cfd6a80b9..12e45412bafc 100644 --- a/packages/beacon-node/src/execution/builder/http.ts +++ b/packages/beacon-node/src/execution/builder/http.ts @@ -1,25 +1,25 @@ +import {WireFormat} from "@lodestar/api"; +import {ApiClient as BuilderApi, getClient} from "@lodestar/api/builder"; +import {ChainForkConfig} from "@lodestar/config"; +import {Logger} from "@lodestar/logger"; +import {ForkExecution, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {parseExecutionPayloadAndBlobsBundle, reconstructFullBlockOrContents} from "@lodestar/state-transition"; import { - bellatrix, - Slot, - Root, BLSPubkey, - deneb, - Wei, + ExecutionPayloadHeader, + Root, SignedBeaconBlockOrContents, SignedBlindedBeaconBlock, - ExecutionPayloadHeader, - electra, + Slot, + Wei, WithOptionalBytes, + bellatrix, + deneb, + electra, } from "@lodestar/types"; -import {parseExecutionPayloadAndBlobsBundle, reconstructFullBlockOrContents} from "@lodestar/state-transition"; -import {ChainForkConfig} from "@lodestar/config"; -import {Logger} from "@lodestar/logger"; -import {getClient, ApiClient as BuilderApi} from "@lodestar/api/builder"; -import {SLOTS_PER_EPOCH, ForkExecution} from "@lodestar/params"; import {toPrintableUrl} from "@lodestar/utils"; import {Metrics} from "../../metrics/metrics.js"; import {IExecutionBuilder} from "./interface.js"; -import {WireFormat} from "@lodestar/api"; export type ExecutionBuilderHttpOpts = { enabled: boolean; diff --git a/packages/beacon-node/src/execution/builder/interface.ts b/packages/beacon-node/src/execution/builder/interface.ts index 19a935a9bf7e..06cdc1da4ed0 100644 --- a/packages/beacon-node/src/execution/builder/interface.ts +++ b/packages/beacon-node/src/execution/builder/interface.ts @@ -1,17 +1,17 @@ +import {ForkExecution} from "@lodestar/params"; import { - bellatrix, - Root, - Slot, BLSPubkey, - deneb, - Wei, - SignedBeaconBlockOrContents, ExecutionPayloadHeader, + Root, + SignedBeaconBlockOrContents, SignedBlindedBeaconBlock, - electra, + Slot, + Wei, WithOptionalBytes, + bellatrix, + deneb, + electra, } from "@lodestar/types"; -import {ForkExecution} from "@lodestar/params"; export interface IExecutionBuilder { /** diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index e5e65746d90f..c5cf61481b67 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -1,6 +1,6 @@ -import {ExecutionPayload, ExecutionRequests, Root, RootHex, Wei} from "@lodestar/types"; -import {SLOTS_PER_EPOCH, ForkName, ForkSeq} from "@lodestar/params"; import {Logger} from "@lodestar/logger"; +import {ForkName, ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ExecutionPayload, ExecutionRequests, Root, RootHex, Wei} from "@lodestar/types"; import { ErrorJsonRpcResponse, HttpRpcError, @@ -8,36 +8,36 @@ import { JsonRpcHttpClientEvent, ReqOpts, } from "../../eth1/provider/jsonRpcHttpClient.js"; +import {numToQuantity} from "../../eth1/provider/utils.js"; import {Metrics} from "../../metrics/index.js"; -import {JobItemQueue} from "../../util/queue/index.js"; import {EPOCHS_PER_BATCH} from "../../sync/constants.js"; -import {numToQuantity} from "../../eth1/provider/utils.js"; import {getLodestarClientVersion} from "../../util/metadata.js"; +import {JobItemQueue} from "../../util/queue/index.js"; import { - ExecutionPayloadStatus, + BlobsBundle, + ClientCode, + ClientVersion, ExecutePayloadResponse, + ExecutionEngineState, + ExecutionPayloadStatus, IExecutionEngine, - PayloadId, PayloadAttributes, - BlobsBundle, + PayloadId, VersionedHashes, - ExecutionEngineState, - ClientVersion, - ClientCode, } from "./interface.js"; import {PayloadIdCache} from "./payloadIdCache.js"; import { EngineApiRpcParamTypes, EngineApiRpcReturnTypes, - parseExecutionPayload, - serializeExecutionPayload, - serializeVersionedHashes, - serializePayloadAttributes, - serializeBeaconBlockRoot, ExecutionPayloadBody, assertReqSizeLimit, deserializeExecutionPayloadBody, + parseExecutionPayload, + serializeBeaconBlockRoot, + serializeExecutionPayload, serializeExecutionRequests, + serializePayloadAttributes, + serializeVersionedHashes, } from "./types.js"; import {getExecutionEngineState} from "./utils.js"; diff --git a/packages/beacon-node/src/execution/engine/index.ts b/packages/beacon-node/src/execution/engine/index.ts index dd2de2017c22..d339276e2cc2 100644 --- a/packages/beacon-node/src/execution/engine/index.ts +++ b/packages/beacon-node/src/execution/engine/index.ts @@ -1,14 +1,14 @@ import {fromHex, toPrintableUrl} from "@lodestar/utils"; import {JsonRpcHttpClient} from "../../eth1/provider/jsonRpcHttpClient.js"; -import {IExecutionEngine} from "./interface.js"; import {ExecutionEngineDisabled} from "./disabled.js"; import { ExecutionEngineHttp, - ExecutionEngineModules, ExecutionEngineHttpOpts, + ExecutionEngineModules, defaultExecutionEngineHttpOpts, } from "./http.js"; -import {ExecutionEngineMockOpts, ExecutionEngineMockBackend} from "./mock.js"; +import {IExecutionEngine} from "./interface.js"; +import {ExecutionEngineMockBackend, ExecutionEngineMockOpts} from "./mock.js"; import {ExecutionEngineMockJsonRpcClient, JsonRpcBackend} from "./utils.js"; export {ExecutionEngineHttp, ExecutionEngineDisabled, defaultExecutionEngineHttpOpts}; diff --git a/packages/beacon-node/src/execution/engine/interface.ts b/packages/beacon-node/src/execution/engine/interface.ts index e6f9cfee526b..7bbf1bb27c1d 100644 --- a/packages/beacon-node/src/execution/engine/interface.ts +++ b/packages/beacon-node/src/execution/engine/interface.ts @@ -1,9 +1,9 @@ import {ForkName} from "@lodestar/params"; -import {KZGCommitment, Blob, KZGProof} from "@lodestar/types/deneb"; -import {Root, RootHex, capella, Wei, ExecutionPayload, ExecutionRequests} from "@lodestar/types"; +import {ExecutionPayload, ExecutionRequests, Root, RootHex, Wei, capella} from "@lodestar/types"; +import {Blob, KZGCommitment, KZGProof} from "@lodestar/types/deneb"; import {DATA} from "../../eth1/provider/utils.js"; -import {PayloadIdCache, PayloadId, WithdrawalV1} from "./payloadIdCache.js"; +import {PayloadId, PayloadIdCache, WithdrawalV1} from "./payloadIdCache.js"; import {ExecutionPayloadBody} from "./types.js"; export {PayloadIdCache, type PayloadId, type WithdrawalV1}; diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index 8062b68bf572..2331500624eb 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -1,30 +1,30 @@ import crypto from "node:crypto"; -import {bellatrix, deneb, RootHex, ssz} from "@lodestar/types"; -import {fromHex, toHex} from "@lodestar/utils"; import { + BLOB_TX_TYPE, BYTES_PER_FIELD_ELEMENT, FIELD_ELEMENTS_PER_BLOB, - ForkSeq, ForkExecution, ForkName, - BLOB_TX_TYPE, + ForkSeq, } from "@lodestar/params"; +import {RootHex, bellatrix, deneb, ssz} from "@lodestar/types"; +import {fromHex, toHex} from "@lodestar/utils"; import {ZERO_HASH_HEX} from "../../constants/index.js"; -import {ckzg} from "../../util/kzg.js"; -import {kzgCommitmentToVersionedHash} from "../../util/blobs.js"; import {quantityToNum} from "../../eth1/provider/utils.js"; +import {kzgCommitmentToVersionedHash} from "../../util/blobs.js"; +import {ckzg} from "../../util/kzg.js"; +import {ClientCode, ExecutionPayloadStatus, PayloadIdCache} from "./interface.js"; import { + BlobsBundleRpc, EngineApiRpcParamTypes, EngineApiRpcReturnTypes, - deserializePayloadAttributes, + ExecutionPayloadBodyRpc, + ExecutionPayloadRpc, PayloadStatus, + deserializePayloadAttributes, serializeBlobsBundle, serializeExecutionPayload, - ExecutionPayloadRpc, - BlobsBundleRpc, - ExecutionPayloadBodyRpc, } from "./types.js"; -import {ClientCode, ExecutionPayloadStatus, PayloadIdCache} from "./interface.js"; import {JsonRpcBackend} from "./utils.js"; const INTEROP_GAS_LIMIT = 30e6; diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index ea37e0922e9c..f6c18ddac6fa 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -1,7 +1,7 @@ import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {pruneSetToMax} from "@lodestar/utils"; -import {Metrics} from "../../metrics/index.js"; import {DATA, QUANTITY} from "../../eth1/provider/utils.js"; +import {Metrics} from "../../metrics/index.js"; import {PayloadAttributesRpc} from "./types.js"; // Idealy this only need to be set to the max head reorgs number diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 52ddb8548629..9af2d8d1ce10 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -1,22 +1,22 @@ -import {capella, deneb, electra, Wei, bellatrix, Root, ExecutionPayload, ExecutionRequests, ssz} from "@lodestar/types"; import { + BYTES_PER_FIELD_ELEMENT, BYTES_PER_LOGS_BLOOM, FIELD_ELEMENTS_PER_BLOB, - BYTES_PER_FIELD_ELEMENT, ForkName, ForkSeq, } from "@lodestar/params"; +import {ExecutionPayload, ExecutionRequests, Root, Wei, bellatrix, capella, deneb, electra, ssz} from "@lodestar/types"; import { - bytesToData, - numToQuantity, - dataToBytes, - quantityToNum, DATA, QUANTITY, + bytesToData, + dataToBytes, + numToQuantity, quantityToBigint, + quantityToNum, } from "../../eth1/provider/utils.js"; -import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js"; +import {BlobsBundle, ExecutionPayloadStatus, PayloadAttributes, VersionedHashes} from "./interface.js"; import {WithdrawalV1} from "./payloadIdCache.js"; export type EngineApiRpcParamTypes = { diff --git a/packages/beacon-node/src/execution/engine/utils.ts b/packages/beacon-node/src/execution/engine/utils.ts index 4d84eda52c44..1a88edb22cce 100644 --- a/packages/beacon-node/src/execution/engine/utils.ts +++ b/packages/beacon-node/src/execution/engine/utils.ts @@ -2,14 +2,14 @@ import {isFetchError} from "@lodestar/api"; import {isErrorAborted} from "@lodestar/utils"; import {IJson, RpcPayload} from "../../eth1/interface.js"; import { - IJsonRpcHttpClient, ErrorJsonRpcResponse, HttpRpcError, - JsonRpcHttpClientEventEmitter, + IJsonRpcHttpClient, JsonRpcHttpClientEvent, + JsonRpcHttpClientEventEmitter, } from "../../eth1/provider/jsonRpcHttpClient.js"; import {isQueueErrorAborted} from "../../util/queue/errors.js"; -import {ExecutionPayloadStatus, ExecutionEngineState} from "./interface.js"; +import {ExecutionEngineState, ExecutionPayloadStatus} from "./interface.js"; export type JsonRpcBackend = { // biome-ignore lint/suspicious/noExplicitAny: diff --git a/packages/beacon-node/src/metrics/metrics.ts b/packages/beacon-node/src/metrics/metrics.ts index 58a48e34bbd5..ed607c7521ed 100644 --- a/packages/beacon-node/src/metrics/metrics.ts +++ b/packages/beacon-node/src/metrics/metrics.ts @@ -1,13 +1,13 @@ -import {Metric, Registry} from "prom-client"; -import {Logger} from "@lodestar/utils"; -import {BeaconStateAllForks, getCurrentSlot} from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; -import {createBeaconMetrics, BeaconMetrics} from "./metrics/beacon.js"; -import {createLodestarMetrics, LodestarMetrics} from "./metrics/lodestar.js"; +import {BeaconStateAllForks, getCurrentSlot} from "@lodestar/state-transition"; +import {Logger} from "@lodestar/utils"; +import {Metric, Registry} from "prom-client"; +import {BeaconMetrics, createBeaconMetrics} from "./metrics/beacon.js"; +import {LodestarMetrics, createLodestarMetrics} from "./metrics/lodestar.js"; +import {collectNodeJSMetrics} from "./nodeJsMetrics.js"; import {MetricsOptions} from "./options.js"; import {RegistryMetricCreator} from "./utils/registryMetricCreator.js"; -import {createValidatorMonitor, ValidatorMonitor} from "./validatorMonitor.js"; -import {collectNodeJSMetrics} from "./nodeJsMetrics.js"; +import {ValidatorMonitor, createValidatorMonitor} from "./validatorMonitor.js"; export type Metrics = BeaconMetrics & LodestarMetrics & diff --git a/packages/beacon-node/src/metrics/metrics/beacon.ts b/packages/beacon-node/src/metrics/metrics/beacon.ts index b9a02a3b2059..0347aef8957b 100644 --- a/packages/beacon-node/src/metrics/metrics/beacon.ts +++ b/packages/beacon-node/src/metrics/metrics/beacon.ts @@ -1,13 +1,13 @@ -import {ProducedBlockSource} from "@lodestar/types"; -import {NotReorgedReason} from "@lodestar/fork-choice/lib/forkChoice/interface.js"; import {UpdateHeadOpt} from "@lodestar/fork-choice"; -import {RegistryMetricCreator} from "../utils/registryMetricCreator.js"; -import {BlockProductionStep, PayloadPreparationType} from "../../chain/produceBlock/index.js"; +import {NotReorgedReason} from "@lodestar/fork-choice/lib/forkChoice/interface.js"; +import {ProducedBlockSource} from "@lodestar/types"; import { BlockSelectionResult, BuilderBlockSelectionReason, EngineBlockSelectionReason, } from "../../api/impl/validator/index.js"; +import {BlockProductionStep, PayloadPreparationType} from "../../chain/produceBlock/index.js"; +import {RegistryMetricCreator} from "../utils/registryMetricCreator.js"; export type BeaconMetrics = ReturnType; diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index ac2cca319775..c138a8dfe26a 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 {BeaconState} from "@lodestar/types"; -import {BlockSource, BlobsSource} from "../../chain/blocks/types.js"; +import {BlobsSource, BlockSource} 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"; @@ -8,17 +8,17 @@ import {RegenCaller, RegenFnName} from "../../chain/regen/interface.js"; import {ReprocessStatus} from "../../chain/reprocess.js"; import {RejectReason} from "../../chain/seenCache/seenAttestationData.js"; import {BlockInputAvailabilitySource} from "../../chain/seenCache/seenGossipBlockInput.js"; +import {CacheItemType} from "../../chain/stateCache/types.js"; import {ExecutionPayloadStatus} from "../../execution/index.js"; import {GossipType} from "../../network/index.js"; import {CannotAcceptWorkReason, ReprocessRejectReason} from "../../network/processor/index.js"; import {BackfillSyncMethod} from "../../sync/backfill/backfill.js"; import {PendingBlockType} from "../../sync/index.js"; import {PeerSyncType, RangeSyncType} from "../../sync/utils/remoteSyncType.js"; +import {AllocSource} from "../../util/bufferPool.js"; import {LodestarMetadata} from "../options.js"; import {RegistryMetricCreator} from "../utils/registryMetricCreator.js"; import {OpSource} from "../validatorMonitor.js"; -import {CacheItemType} from "../../chain/stateCache/types.js"; -import {AllocSource} from "../../util/bufferPool.js"; export type LodestarMetrics = ReturnType; diff --git a/packages/beacon-node/src/metrics/nodeJsMetrics.ts b/packages/beacon-node/src/metrics/nodeJsMetrics.ts index c565cfc07ba5..c448276e278a 100644 --- a/packages/beacon-node/src/metrics/nodeJsMetrics.ts +++ b/packages/beacon-node/src/metrics/nodeJsMetrics.ts @@ -1,5 +1,5 @@ -import {collectDefaultMetrics, Registry} from "prom-client"; import {gcStats} from "@chainsafe/prometheus-gc-stats"; +import {Registry, collectDefaultMetrics} from "prom-client"; export function collectNodeJSMetrics(register: Registry, prefix?: string): () => void { collectDefaultMetrics({ diff --git a/packages/beacon-node/src/metrics/server/http.ts b/packages/beacon-node/src/metrics/server/http.ts index e197dcfa2a25..5d4fa36998fb 100644 --- a/packages/beacon-node/src/metrics/server/http.ts +++ b/packages/beacon-node/src/metrics/server/http.ts @@ -1,9 +1,9 @@ import http from "node:http"; import {AddressInfo} from "node:net"; -import {Registry} from "prom-client"; import {Logger} from "@lodestar/utils"; -import {wrapError} from "../../util/wrapError.js"; +import {Registry} from "prom-client"; import {HttpActiveSocketsTracker} from "../../api/rest/activeSockets.js"; +import {wrapError} from "../../util/wrapError.js"; import {RegistryMetricCreator} from "../utils/registryMetricCreator.js"; export type HttpMetricsServerOpts = { diff --git a/packages/beacon-node/src/metrics/utils/avgMinMax.ts b/packages/beacon-node/src/metrics/utils/avgMinMax.ts index 709c83ee38d6..8bb5b196141e 100644 --- a/packages/beacon-node/src/metrics/utils/avgMinMax.ts +++ b/packages/beacon-node/src/metrics/utils/avgMinMax.ts @@ -1,5 +1,5 @@ -import {GaugeConfiguration} from "prom-client"; import {AvgMinMax as IAvgMinMax, LabelKeys, LabelsGeneric} from "@lodestar/utils"; +import {GaugeConfiguration} from "prom-client"; import {GaugeExtra} from "./gauge.js"; type GetValuesFn = () => number[]; diff --git a/packages/beacon-node/src/metrics/utils/gauge.ts b/packages/beacon-node/src/metrics/utils/gauge.ts index 1f527adfcb64..a4c5e9966759 100644 --- a/packages/beacon-node/src/metrics/utils/gauge.ts +++ b/packages/beacon-node/src/metrics/utils/gauge.ts @@ -1,5 +1,5 @@ -import {Gauge} from "prom-client"; import {CollectFn, Gauge as IGauge, LabelKeys, LabelsGeneric} from "@lodestar/utils"; +import {Gauge} from "prom-client"; /** * Extends the prom-client Gauge to be able to add multiple collect functions after instantiation diff --git a/packages/beacon-node/src/metrics/utils/registryMetricCreator.ts b/packages/beacon-node/src/metrics/utils/registryMetricCreator.ts index adec6f984702..30de36969456 100644 --- a/packages/beacon-node/src/metrics/utils/registryMetricCreator.ts +++ b/packages/beacon-node/src/metrics/utils/registryMetricCreator.ts @@ -1,4 +1,3 @@ -import {Gauge, Registry, Counter, Histogram} from "prom-client"; import { AvgMinMaxConfig, CounterConfig, @@ -14,6 +13,7 @@ import { NoLabels, StaticConfig, } from "@lodestar/utils"; +import {Counter, Gauge, Histogram, Registry} from "prom-client"; import {AvgMinMax} from "./avgMinMax.js"; import {GaugeExtra} from "./gauge.js"; diff --git a/packages/beacon-node/src/metrics/validatorMonitor.ts b/packages/beacon-node/src/metrics/validatorMonitor.ts index 14a210f62997..401d58af57ff 100644 --- a/packages/beacon-node/src/metrics/validatorMonitor.ts +++ b/packages/beacon-node/src/metrics/validatorMonitor.ts @@ -1,19 +1,19 @@ +import {ChainConfig, ChainForkConfig} from "@lodestar/config"; +import {ForkSeq, INTERVALS_PER_SLOT, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params"; import { - computeEpochAtSlot, - parseAttesterFlags, CachedBeaconStateAllForks, CachedBeaconStateAltair, - parseParticipationFlags, + ParticipationFlags, + computeEpochAtSlot, computeStartSlotAtEpoch, getBlockRootAtSlot, - ParticipationFlags, + parseAttesterFlags, + parseParticipationFlags, } from "@lodestar/state-transition"; -import {LogData, LogHandler, LogLevel, Logger, MapDef, MapDefMax, toRootHex} from "@lodestar/utils"; import {BeaconBlock, RootHex, altair, deneb} from "@lodestar/types"; -import {ChainConfig, ChainForkConfig} from "@lodestar/config"; -import {ForkSeq, INTERVALS_PER_SLOT, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params"; import {Epoch, Slot, ValidatorIndex} from "@lodestar/types"; import {IndexedAttestation, SignedAggregateAndProof} from "@lodestar/types"; +import {LogData, LogHandler, LogLevel, Logger, MapDef, MapDefMax, toRootHex} from "@lodestar/utils"; import {GENESIS_SLOT} from "../constants/constants.js"; import {LodestarMetrics} from "./metrics/lodestar.js"; diff --git a/packages/beacon-node/src/monitoring/service.ts b/packages/beacon-node/src/monitoring/service.ts index f6a6a2352e02..930fe4a65224 100644 --- a/packages/beacon-node/src/monitoring/service.ts +++ b/packages/beacon-node/src/monitoring/service.ts @@ -1,11 +1,11 @@ -import {Registry} from "prom-client"; import {fetch} from "@lodestar/api"; import {ErrorAborted, Histogram, Logger, TimeoutError} from "@lodestar/utils"; +import {Registry} from "prom-client"; import {RegistryMetricCreator} from "../metrics/index.js"; -import {defaultMonitoringOptions, MonitoringOptions} from "./options.js"; import {createClientStats} from "./clientStats.js"; -import {ClientStats} from "./types.js"; +import {MonitoringOptions, defaultMonitoringOptions} from "./options.js"; import system from "./system.js"; +import {ClientStats} from "./types.js"; type MonitoringData = Record; diff --git a/packages/beacon-node/src/monitoring/system.ts b/packages/beacon-node/src/monitoring/system.ts index 83507443be01..4afcc6064b16 100644 --- a/packages/beacon-node/src/monitoring/system.ts +++ b/packages/beacon-node/src/monitoring/system.ts @@ -2,9 +2,9 @@ /* eslint-disable import/no-named-as-default-member */ import os from "node:os"; import path from "node:path"; +import {Logger} from "@lodestar/utils"; // We want to keep `system` export as it's more readable and easier to understand import system from "systeminformation"; -import {Logger} from "@lodestar/utils"; type MiscOs = "lin" | "win" | "mac" | "unk"; diff --git a/packages/beacon-node/src/network/core/networkCore.ts b/packages/beacon-node/src/network/core/networkCore.ts index d47fcabd4146..718b7c92df7f 100644 --- a/packages/beacon-node/src/network/core/networkCore.ts +++ b/packages/beacon-node/src/network/core/networkCore.ts @@ -1,37 +1,37 @@ -import {Connection, PeerId} from "@libp2p/interface"; -import {multiaddr} from "@multiformats/multiaddr"; -import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; -import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/dist/src/score/peer-score.js"; import {ENR} from "@chainsafe/enr"; +import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/dist/src/score/peer-score.js"; +import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; +import {Connection, PeerId} from "@libp2p/interface"; import {routes} from "@lodestar/api"; import {BeaconConfig} from "@lodestar/config"; import type {LoggerNode} from "@lodestar/logger/node"; -import {Epoch, phase0} from "@lodestar/types"; -import {fromHex, withTimeout} from "@lodestar/utils"; import {ForkName} from "@lodestar/params"; import {ResponseIncoming} from "@lodestar/reqresp"; -import {Libp2p} from "../interface.js"; -import {PeerManager} from "../peers/peerManager.js"; -import {ReqRespBeaconNode} from "../reqresp/ReqRespBeaconNode.js"; -import {OutgoingRequestArgs, GetReqRespHandlerFn} from "../reqresp/types.js"; -import {Eth2Gossipsub, getCoreTopicsAtFork} from "../gossip/index.js"; -import {SyncnetsService} from "../subnets/syncnetsService.js"; +import {Epoch, phase0} from "@lodestar/types"; +import {fromHex, withTimeout} from "@lodestar/utils"; +import {multiaddr} from "@multiformats/multiaddr"; +import {formatNodePeer} from "../../api/impl/node/utils.js"; +import {RegistryMetricCreator} from "../../metrics/index.js"; +import {ClockEvent, IClock} from "../../util/clock.js"; +import {peerIdFromString, peerIdToString} from "../../util/peerId.js"; +import {Discv5Worker} from "../discv5/index.js"; +import {NetworkEventBus} from "../events.js"; import {FORK_EPOCH_LOOKAHEAD, getActiveForks} from "../forks.js"; -import {NetworkOptions} from "../options.js"; -import {CommitteeSubscription, IAttnetsService} from "../subnets/interface.js"; -import {MetadataController} from "../metadata.js"; +import {Eth2Gossipsub, getCoreTopicsAtFork} from "../gossip/index.js"; +import {Libp2p} from "../interface.js"; import {createNodeJsLibp2p} from "../libp2p/index.js"; -import {PeersData} from "../peers/peersData.js"; +import {MetadataController} from "../metadata.js"; +import {NetworkOptions} from "../options.js"; import {PeerAction, PeerRpcScoreStore, PeerScoreStats} from "../peers/index.js"; -import {getConnectionsMap} from "../util.js"; -import {IClock, ClockEvent} from "../../util/clock.js"; -import {formatNodePeer} from "../../api/impl/node/utils.js"; -import {NetworkEventBus} from "../events.js"; -import {Discv5Worker} from "../discv5/index.js"; +import {PeerManager} from "../peers/peerManager.js"; +import {PeersData} from "../peers/peersData.js"; +import {ReqRespBeaconNode} from "../reqresp/ReqRespBeaconNode.js"; +import {GetReqRespHandlerFn, OutgoingRequestArgs} from "../reqresp/types.js"; import {LocalStatusCache} from "../statusCache.js"; -import {RegistryMetricCreator} from "../../metrics/index.js"; -import {peerIdFromString, peerIdToString} from "../../util/peerId.js"; import {AttnetsService} from "../subnets/attnetsService.js"; +import {CommitteeSubscription, IAttnetsService} from "../subnets/interface.js"; +import {SyncnetsService} from "../subnets/syncnetsService.js"; +import {getConnectionsMap} from "../util.js"; import {NetworkCoreMetrics, createNetworkCoreMetrics} from "./metrics.js"; import {INetworkCore, MultiaddrStr, PeerIdStr} from "./types.js"; diff --git a/packages/beacon-node/src/network/core/networkCoreWorker.ts b/packages/beacon-node/src/network/core/networkCoreWorker.ts index 5e4b057402d8..a5622bc6a5c1 100644 --- a/packages/beacon-node/src/network/core/networkCoreWorker.ts +++ b/packages/beacon-node/src/network/core/networkCoreWorker.ts @@ -11,11 +11,8 @@ import {AsyncIterableBridgeCaller, AsyncIterableBridgeHandler} from "../../util/ import {Clock} from "../../util/clock.js"; import {peerIdToString} from "../../util/peerId.js"; import {profileNodeJS, writeHeapSnapshot} from "../../util/profile.js"; -import {NetworkEventBus, NetworkEventData, networkEventDirection} from "../events.js"; import {wireEventsOnWorkerThread} from "../../util/workerEvents.js"; -import {getNetworkCoreWorkerMetrics} from "./metrics.js"; -import {NetworkWorkerApi, NetworkWorkerData} from "./types.js"; -import {NetworkCore} from "./networkCore.js"; +import {NetworkEventBus, NetworkEventData, networkEventDirection} from "../events.js"; import { NetworkWorkerThreadEventType, ReqRespBridgeEventBus, @@ -24,6 +21,9 @@ import { getReqRespBridgeRespEvents, reqRespBridgeEventDirection, } from "./events.js"; +import {getNetworkCoreWorkerMetrics} from "./metrics.js"; +import {NetworkCore} from "./networkCore.js"; +import {NetworkWorkerApi, NetworkWorkerData} from "./types.js"; // Cloned data from instantiation const workerData = worker.workerData as NetworkWorkerData; diff --git a/packages/beacon-node/src/network/core/types.ts b/packages/beacon-node/src/network/core/types.ts index 4eeaf96e1903..87feb9da9d21 100644 --- a/packages/beacon-node/src/network/core/types.ts +++ b/packages/beacon-node/src/network/core/types.ts @@ -1,13 +1,13 @@ import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/score"; import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; import {routes} from "@lodestar/api"; +import {LoggerNodeOpts} from "@lodestar/logger/node"; import {ResponseIncoming} from "@lodestar/reqresp"; import {phase0} from "@lodestar/types"; -import {LoggerNodeOpts} from "@lodestar/logger/node"; import {NetworkOptions} from "../options.js"; -import {CommitteeSubscription} from "../subnets/interface.js"; import {PeerAction, PeerScoreStats} from "../peers/index.js"; import {OutgoingRequestArgs} from "../reqresp/types.js"; +import {CommitteeSubscription} from "../subnets/interface.js"; export type MultiaddrStr = string; export type PeerIdStr = string; diff --git a/packages/beacon-node/src/network/discv5/index.ts b/packages/beacon-node/src/network/discv5/index.ts index 745b3171c38d..b010ee1ac670 100644 --- a/packages/beacon-node/src/network/discv5/index.ts +++ b/packages/beacon-node/src/network/discv5/index.ts @@ -1,11 +1,11 @@ import EventEmitter from "node:events"; +import {ENR, ENRData, SignableENR, createPrivateKeyFromPeerId} from "@chainsafe/enr"; +import {Thread, Worker, spawn} from "@chainsafe/threads"; 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"; -import {spawn, Thread, Worker} from "@chainsafe/threads"; -import {chainConfigFromJson, chainConfigToJson, BeaconConfig} from "@lodestar/config"; +import {BeaconConfig, chainConfigFromJson, chainConfigToJson} from "@lodestar/config"; import {LoggerNode} from "@lodestar/logger/node"; +import {StrictEventEmitter} from "strict-event-emitter-types"; import {NetworkCoreMetrics} from "../core/metrics.js"; import {Discv5WorkerApi, Discv5WorkerData, LodestarDiscv5Opts} from "./types.js"; diff --git a/packages/beacon-node/src/network/discv5/worker.ts b/packages/beacon-node/src/network/discv5/worker.ts index 8e96751d5fe7..49dfc9c2f35d 100644 --- a/packages/beacon-node/src/network/discv5/worker.ts +++ b/packages/beacon-node/src/network/discv5/worker.ts @@ -1,20 +1,20 @@ -import worker from "node:worker_threads"; -import path from "node:path"; import fs from "node:fs"; -import {createFromProtobuf} from "@libp2p/peer-id-factory"; -import {Multiaddr, multiaddr} from "@multiformats/multiaddr"; -import {expose} from "@chainsafe/threads/worker"; -import {Observable, Subject} from "@chainsafe/threads/observable"; +import path from "node:path"; +import worker from "node:worker_threads"; import {Discv5} from "@chainsafe/discv5"; -import {createPrivateKeyFromPeerId, ENR, ENRData, SignableENR, SignableENRData} from "@chainsafe/enr"; +import {ENR, ENRData, SignableENR, SignableENRData, createPrivateKeyFromPeerId} from "@chainsafe/enr"; +import {Observable, Subject} from "@chainsafe/threads/observable"; +import {expose} from "@chainsafe/threads/worker"; +import {createFromProtobuf} from "@libp2p/peer-id-factory"; import {createBeaconConfig} from "@lodestar/config"; import {getNodeLogger} from "@lodestar/logger/node"; import {Gauge} from "@lodestar/utils"; +import {Multiaddr, multiaddr} from "@multiformats/multiaddr"; import {RegistryMetricCreator} from "../../metrics/index.js"; import {collectNodeJSMetrics} from "../../metrics/nodeJsMetrics.js"; import {profileNodeJS, writeHeapSnapshot} from "../../util/profile.js"; import {Discv5WorkerApi, Discv5WorkerData} from "./types.js"; -import {enrRelevance, ENRRelevance} from "./utils.js"; +import {ENRRelevance, enrRelevance} from "./utils.js"; // This discv5 worker will start discv5 on initialization (there is no `start` function to call) // A consumer _should_ call `close` before terminating the worker to cleanly exit discv5 before destroying the thread diff --git a/packages/beacon-node/src/network/events.ts b/packages/beacon-node/src/network/events.ts index a95b52394163..ed3e7ec876ed 100644 --- a/packages/beacon-node/src/network/events.ts +++ b/packages/beacon-node/src/network/events.ts @@ -1,12 +1,12 @@ import {EventEmitter} from "node:events"; import {PeerId, TopicValidatorResult} from "@libp2p/interface"; -import {phase0, RootHex} from "@lodestar/types"; +import {RootHex, phase0} from "@lodestar/types"; import {BlockInput, NullBlockInput} from "../chain/blocks/types.js"; -import {StrictEventEmitterSingleArg} from "../util/strictEvents.js"; import {PeerIdStr} from "../util/peerId.js"; +import {StrictEventEmitterSingleArg} from "../util/strictEvents.js"; import {EventDirection} from "../util/workerEvents.js"; -import {RequestTypedContainer} from "./reqresp/ReqRespBeaconNode.js"; import {PendingGossipsubMessage} from "./processor/types.js"; +import {RequestTypedContainer} from "./reqresp/ReqRespBeaconNode.js"; export enum NetworkEvent { /** A relevant peer has connected or has been re-STATUS'd */ diff --git a/packages/beacon-node/src/network/forks.ts b/packages/beacon-node/src/network/forks.ts index 1c613f4cee94..cad4616c008b 100644 --- a/packages/beacon-node/src/network/forks.ts +++ b/packages/beacon-node/src/network/forks.ts @@ -1,5 +1,5 @@ -import {ForkName} from "@lodestar/params"; import {ChainForkConfig, ForkInfo} from "@lodestar/config"; +import {ForkName} from "@lodestar/params"; import {Epoch} from "@lodestar/types"; /** diff --git a/packages/beacon-node/src/network/gossip/encoding.ts b/packages/beacon-node/src/network/gossip/encoding.ts index f7f733fcd915..f6121bf8af91 100644 --- a/packages/beacon-node/src/network/gossip/encoding.ts +++ b/packages/beacon-node/src/network/gossip/encoding.ts @@ -1,13 +1,13 @@ -import {compress, uncompress} from "snappyjs"; -import xxhashFactory from "xxhash-wasm"; -import {Message} from "@libp2p/interface"; import {digest} from "@chainsafe/as-sha256"; import {RPC} from "@chainsafe/libp2p-gossipsub/message"; import {DataTransform} from "@chainsafe/libp2p-gossipsub/types"; -import {intToBytes} from "@lodestar/utils"; +import {Message} from "@libp2p/interface"; import {ForkName} from "@lodestar/params"; +import {intToBytes} from "@lodestar/utils"; +import {compress, uncompress} from "snappyjs"; +import xxhashFactory from "xxhash-wasm"; import {MESSAGE_DOMAIN_VALID_SNAPPY} from "./constants.js"; -import {getGossipSSZType, GossipTopicCache} from "./topic.js"; +import {GossipTopicCache, getGossipSSZType} from "./topic.js"; // Load WASM const xxhash = await xxhashFactory(); diff --git a/packages/beacon-node/src/network/gossip/gossipsub.ts b/packages/beacon-node/src/network/gossip/gossipsub.ts index 76e1330cd4a1..42f8ba8b114c 100644 --- a/packages/beacon-node/src/network/gossip/gossipsub.ts +++ b/packages/beacon-node/src/network/gossip/gossipsub.ts @@ -1,29 +1,29 @@ import {GossipSub, GossipsubEvents} from "@chainsafe/libp2p-gossipsub"; -import {SignaturePolicy, TopicStr} from "@chainsafe/libp2p-gossipsub/types"; -import {PeerScoreParams} from "@chainsafe/libp2p-gossipsub/score"; import {MetricsRegister, TopicLabel, TopicStrToLabel} from "@chainsafe/libp2p-gossipsub/metrics"; +import {PeerScoreParams} from "@chainsafe/libp2p-gossipsub/score"; +import {SignaturePolicy, TopicStr} from "@chainsafe/libp2p-gossipsub/types"; import {BeaconConfig} from "@lodestar/config"; import {ATTESTATION_SUBNET_COUNT, ForkName, SLOTS_PER_EPOCH, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {Logger, Map2d, Map2dArr} from "@lodestar/utils"; -import {RegistryMetricCreator} from "../../metrics/index.js"; -import {PeersData} from "../peers/peersData.js"; -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 {RegistryMetricCreator} from "../../metrics/index.js"; import {callInNextEventLoop} from "../../util/eventLoop.js"; -import {GossipTopic, GossipType} from "./interface.js"; -import {GossipTopicCache, stringifyGossipTopic, getCoreTopicsAtFork} from "./topic.js"; +import {NetworkEvent, NetworkEventBus, NetworkEventData} from "../events.js"; +import {Libp2p} from "../interface.js"; +import {ClientKind} from "../peers/client.js"; +import {PeersData} from "../peers/peersData.js"; import {DataTransformSnappy, fastMsgIdFn, msgIdFn, msgIdToStrFn} from "./encoding.js"; -import {createEth2GossipsubMetrics, Eth2GossipsubMetrics} from "./metrics.js"; +import {GossipTopic, GossipType} from "./interface.js"; +import {Eth2GossipsubMetrics, createEth2GossipsubMetrics} from "./metrics.js"; +import {GossipTopicCache, getCoreTopicsAtFork, stringifyGossipTopic} from "./topic.js"; import { - computeGossipPeerScoreParams, - gossipScoreThresholds, GOSSIP_D, GOSSIP_D_HIGH, GOSSIP_D_LOW, + computeGossipPeerScoreParams, + gossipScoreThresholds, } from "./scoringParameters.js"; /** As specified in https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md */ diff --git a/packages/beacon-node/src/network/gossip/interface.ts b/packages/beacon-node/src/network/gossip/interface.ts index ff1bfa088c17..9939ed5af657 100644 --- a/packages/beacon-node/src/network/gossip/interface.ts +++ b/packages/beacon-node/src/network/gossip/interface.ts @@ -1,25 +1,25 @@ -import {Libp2p} from "libp2p"; -import {Message, TopicValidatorResult} from "@libp2p/interface"; import {PeerIdStr} from "@chainsafe/libp2p-gossipsub/types"; +import {Message, TopicValidatorResult} from "@libp2p/interface"; +import {BeaconConfig} from "@lodestar/config"; import {ForkName} from "@lodestar/params"; import { - altair, - capella, - deneb, + Attestation, LightClientFinalityUpdate, LightClientOptimisticUpdate, - phase0, + SignedAggregateAndProof, SignedBeaconBlock, Slot, - Attestation, - SignedAggregateAndProof, + altair, + capella, + deneb, + phase0, } from "@lodestar/types"; -import {BeaconConfig} from "@lodestar/config"; import {Logger} from "@lodestar/utils"; -import {IBeaconChain} from "../../chain/index.js"; -import {JobItemQueue} from "../../util/queue/index.js"; +import {Libp2p} from "libp2p"; import {AttestationError, AttestationErrorType} from "../../chain/errors/attestationError.js"; import {GossipActionError} from "../../chain/errors/gossipValidation.js"; +import {IBeaconChain} from "../../chain/index.js"; +import {JobItemQueue} from "../../util/queue/index.js"; export enum GossipType { beacon_block = "beacon_block", diff --git a/packages/beacon-node/src/network/gossip/scoringParameters.ts b/packages/beacon-node/src/network/gossip/scoringParameters.ts index 3ba32614afeb..890fd5acd251 100644 --- a/packages/beacon-node/src/network/gossip/scoringParameters.ts +++ b/packages/beacon-node/src/network/gossip/scoringParameters.ts @@ -1,12 +1,12 @@ import { - defaultTopicScoreParams, PeerScoreParams, - TopicScoreParams, PeerScoreThresholds, + TopicScoreParams, + defaultTopicScoreParams, } from "@chainsafe/libp2p-gossipsub/score"; -import {computeCommitteeCount} from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; import {ATTESTATION_SUBNET_COUNT, SLOTS_PER_EPOCH, TARGET_AGGREGATORS_PER_COMMITTEE} from "@lodestar/params"; +import {computeCommitteeCount} from "@lodestar/state-transition"; import {getActiveForks} from "../forks.js"; import {Eth2Context, Eth2GossipsubModules} from "./gossipsub.js"; import {GossipType} from "./interface.js"; diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index ed44c8314425..de52860605a9 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -1,17 +1,17 @@ -import {ssz, Attestation, sszTypesFor} from "@lodestar/types"; import {ForkDigestContext} from "@lodestar/config"; import { ATTESTATION_SUBNET_COUNT, ForkName, ForkSeq, + MAX_BLOBS_PER_BLOCK, SYNC_COMMITTEE_SUBNET_COUNT, isForkLightClient, - MAX_BLOBS_PER_BLOCK, } from "@lodestar/params"; +import {Attestation, ssz, sszTypesFor} from "@lodestar/types"; import {GossipAction, GossipActionError, GossipErrorCode} from "../../chain/errors/gossipValidation.js"; -import {GossipEncoding, GossipTopic, GossipType, GossipTopicTypeMap, SSZTypeOfGossipTopic} from "./interface.js"; import {DEFAULT_ENCODING} from "./constants.js"; +import {GossipEncoding, GossipTopic, GossipTopicTypeMap, GossipType, SSZTypeOfGossipTopic} from "./interface.js"; export interface IGossipTopicCache { getTopic(topicStr: string): GossipTopic; diff --git a/packages/beacon-node/src/network/interface.ts b/packages/beacon-node/src/network/interface.ts index 0d48df42b31e..bf117cc8a743 100644 --- a/packages/beacon-node/src/network/interface.ts +++ b/packages/beacon-node/src/network/interface.ts @@ -1,40 +1,40 @@ -import {Libp2p as ILibp2p} from "libp2p"; +import {Identify} from "@chainsafe/libp2p-identify"; import { - Libp2pEvents, ComponentLogger, - NodeInfo, - ConnectionProtector, ConnectionGater, + ConnectionProtector, ContentRouting, - TypedEventTarget, + Libp2pEvents, Metrics, + NodeInfo, PeerId, PeerRouting, PeerStore, + TypedEventTarget, Upgrader, } from "@libp2p/interface"; import type {AddressManager, ConnectionManager, Registrar, TransportManager} from "@libp2p/interface-internal"; -import type {Datastore} from "interface-datastore"; -import {Identify} from "@chainsafe/libp2p-identify"; import { LightClientFinalityUpdate, LightClientOptimisticUpdate, + SignedAggregateAndProof, SignedBeaconBlock, Slot, SlotRootHex, + WithBytes, altair, capella, deneb, phase0, - SignedAggregateAndProof, - WithBytes, } from "@lodestar/types"; +import type {Datastore} from "interface-datastore"; +import {Libp2p as ILibp2p} from "libp2p"; import {PeerIdStr} from "../util/peerId.js"; -import {INetworkEventBus} from "./events.js"; import {INetworkCorePublic} from "./core/types.js"; +import {INetworkEventBus} from "./events.js"; import {GossipType} from "./gossip/interface.js"; -import {PendingGossipsubMessage} from "./processor/types.js"; import {PeerAction} from "./peers/index.js"; +import {PendingGossipsubMessage} from "./processor/types.js"; /** * The architecture of the network looks like so: diff --git a/packages/beacon-node/src/network/libp2p/index.ts b/packages/beacon-node/src/network/libp2p/index.ts index a0d58033cf2f..3191a63ac85c 100644 --- a/packages/beacon-node/src/network/libp2p/index.ts +++ b/packages/beacon-node/src/network/libp2p/index.ts @@ -1,18 +1,18 @@ -import {PeerId} from "@libp2p/interface"; -import {Registry} from "prom-client"; import {ENR} from "@chainsafe/enr"; // TODO: We should use this fork until https://github.com/libp2p/js-libp2p/pull/2387 import {identify} from "@chainsafe/libp2p-identify"; +import {noise} from "@chainsafe/libp2p-noise"; import {bootstrap} from "@libp2p/bootstrap"; +import {PeerId} from "@libp2p/interface"; import {mdns} from "@libp2p/mdns"; -import {createLibp2p} from "libp2p"; import {mplex} from "@libp2p/mplex"; import {prometheusMetrics} from "@libp2p/prometheus-metrics"; import {tcp} from "@libp2p/tcp"; -import {noise} from "@chainsafe/libp2p-noise"; -import {defaultNetworkOptions, NetworkOptions} from "../options.js"; -import {Eth2PeerDataStore} from "../peers/datastore.js"; +import {createLibp2p} from "libp2p"; +import {Registry} from "prom-client"; import {Libp2p, LodestarComponents} from "../interface.js"; +import {NetworkOptions, defaultNetworkOptions} from "../options.js"; +import {Eth2PeerDataStore} from "../peers/datastore.js"; export type NodeJsLibp2pOpts = { peerStoreDir?: string; diff --git a/packages/beacon-node/src/network/metadata.ts b/packages/beacon-node/src/network/metadata.ts index fab220c1ebf8..7b70775d63c6 100644 --- a/packages/beacon-node/src/network/metadata.ts +++ b/packages/beacon-node/src/network/metadata.ts @@ -1,8 +1,8 @@ import {BitArray} from "@chainsafe/ssz"; +import {BeaconConfig} from "@lodestar/config"; import {ForkSeq} from "@lodestar/params"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {altair, Epoch, phase0, ssz} from "@lodestar/types"; -import {BeaconConfig} from "@lodestar/config"; +import {Epoch, altair, phase0, ssz} from "@lodestar/types"; import {FAR_FUTURE_EPOCH} from "../constants/index.js"; import {getCurrentAndNextFork} from "./forks.js"; diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 15414fcf9138..2181e21744da 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -1,53 +1,53 @@ -import {PeerId} from "@libp2p/interface"; -import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/score"; +import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; +import {PeerId} from "@libp2p/interface"; +import {routes} from "@lodestar/api"; import {BeaconConfig} from "@lodestar/config"; -import {sleep} from "@lodestar/utils"; import {LoggerNode} from "@lodestar/logger/node"; +import {ForkSeq, MAX_BLOBS_PER_BLOCK} from "@lodestar/params"; +import {ResponseIncoming} from "@lodestar/reqresp"; import {computeStartSlotAtEpoch, computeTimeAtSlot} from "@lodestar/state-transition"; import { - phase0, - deneb, - altair, - Root, - capella, - SlotRootHex, - SignedBeaconBlock, LightClientBootstrap, LightClientFinalityUpdate, LightClientOptimisticUpdate, LightClientUpdate, + Root, SignedAggregateAndProof, + SignedBeaconBlock, + SlotRootHex, WithBytes, + altair, + capella, + deneb, + phase0, } from "@lodestar/types"; -import {routes} from "@lodestar/api"; -import {ResponseIncoming} from "@lodestar/reqresp"; -import {ForkSeq, MAX_BLOBS_PER_BLOCK} from "@lodestar/params"; -import {Metrics, RegistryMetricCreator} from "../metrics/index.js"; +import {sleep} from "@lodestar/utils"; import {IBeaconChain} from "../chain/index.js"; import {IBeaconDb} from "../db/interface.js"; -import {PeerIdStr, peerIdToString} from "../util/peerId.js"; +import {Metrics, RegistryMetricCreator} from "../metrics/index.js"; import {IClock} from "../util/clock.js"; -import {NetworkOptions} from "./options.js"; -import {INetwork} from "./interface.js"; -import {ReqRespMethod} from "./reqresp/index.js"; +import {PeerIdStr, peerIdToString} from "../util/peerId.js"; +import {INetworkCore, NetworkCore, WorkerNetworkCore} from "./core/index.js"; +import {INetworkEventBus, NetworkEvent, NetworkEventBus, NetworkEventData} from "./events.js"; +import {getActiveForks} from "./forks.js"; import {GossipHandlers, GossipTopicMap, GossipType, GossipTypeMap} from "./gossip/index.js"; +import {getGossipSSZType, gossipTopicIgnoreDuplicatePublishError, stringifyGossipTopic} from "./gossip/topic.js"; +import {INetwork} from "./interface.js"; +import {NetworkOptions} from "./options.js"; import {PeerAction, PeerScoreStats} from "./peers/index.js"; -import {INetworkEventBus, NetworkEvent, NetworkEventBus, NetworkEventData} from "./events.js"; -import {CommitteeSubscription} from "./subnets/index.js"; -import {isPublishToZeroPeersError} from "./util.js"; +import {AggregatorTracker} from "./processor/aggregatorTracker.js"; import {NetworkProcessor, PendingGossipsubMessage} from "./processor/index.js"; -import {INetworkCore, NetworkCore, WorkerNetworkCore} from "./core/index.js"; +import {ReqRespMethod} from "./reqresp/index.js"; +import {GetReqRespHandlerFn, Version, requestSszTypeByMethod, responseSszTypeByMethod} from "./reqresp/types.js"; import { collectExactOneTyped, collectMaxResponseTyped, collectMaxResponseTypedWithBytes, } from "./reqresp/utils/collect.js"; -import {GetReqRespHandlerFn, Version, requestSszTypeByMethod, responseSszTypeByMethod} from "./reqresp/types.js"; import {collectSequentialBlocksInRange} from "./reqresp/utils/collectSequentialBlocksInRange.js"; -import {getGossipSSZType, gossipTopicIgnoreDuplicatePublishError, stringifyGossipTopic} from "./gossip/topic.js"; -import {AggregatorTracker} from "./processor/aggregatorTracker.js"; -import {getActiveForks} from "./forks.js"; +import {CommitteeSubscription} from "./subnets/index.js"; +import {isPublishToZeroPeersError} from "./util.js"; type NetworkModules = { opts: NetworkOptions; diff --git a/packages/beacon-node/src/network/options.ts b/packages/beacon-node/src/network/options.ts index ebb321584d12..1420be1d58fb 100644 --- a/packages/beacon-node/src/network/options.ts +++ b/packages/beacon-node/src/network/options.ts @@ -1,7 +1,7 @@ import {Eth2GossipsubOpts} from "./gossip/gossipsub.js"; import {PeerManagerOpts, PeerRpcScoreOpts} from "./peers/index.js"; -import {ReqRespBeaconNodeOpts} from "./reqresp/ReqRespBeaconNode.js"; import {NetworkProcessorOpts} from "./processor/index.js"; +import {ReqRespBeaconNodeOpts} from "./reqresp/ReqRespBeaconNode.js"; import {SubnetsServiceOpts} from "./subnets/interface.js"; // Since Network is eventually intended to be run in a separate thread, ensure that all options are cloneable using structuredClone diff --git a/packages/beacon-node/src/network/peers/datastore.ts b/packages/beacon-node/src/network/peers/datastore.ts index 88a7a6f5f2d6..ba5cae92c9a9 100644 --- a/packages/beacon-node/src/network/peers/datastore.ts +++ b/packages/beacon-node/src/network/peers/datastore.ts @@ -1,6 +1,6 @@ import {BaseDatastore} from "datastore-core"; import {LevelDatastore} from "datastore-level"; -import {Key, KeyQuery, Query, Pair} from "interface-datastore"; +import {Key, KeyQuery, Pair, Query} from "interface-datastore"; type MemoryItem = { lastAccessedMs: number; diff --git a/packages/beacon-node/src/network/peers/discover.ts b/packages/beacon-node/src/network/peers/discover.ts index 2b03656064e4..e658fd6378bf 100644 --- a/packages/beacon-node/src/network/peers/discover.ts +++ b/packages/beacon-node/src/network/peers/discover.ts @@ -1,18 +1,18 @@ -import {Multiaddr} from "@multiformats/multiaddr"; -import type {PeerId, PeerInfo} from "@libp2p/interface"; import {ENR} from "@chainsafe/enr"; +import type {PeerId, PeerInfo} from "@libp2p/interface"; import {BeaconConfig} from "@lodestar/config"; -import {pruneSetToMax, sleep} from "@lodestar/utils"; -import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {LoggerNode} from "@lodestar/logger/node"; +import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; +import {pruneSetToMax, sleep} from "@lodestar/utils"; +import {Multiaddr} from "@multiformats/multiaddr"; import {NetworkCoreMetrics} from "../core/metrics.js"; +import {Discv5Worker} from "../discv5/index.js"; +import {LodestarDiscv5Opts} from "../discv5/types.js"; import {Libp2p} from "../interface.js"; import {ENRKey, SubnetType} from "../metadata.js"; import {getConnectionsMap, prettyPrintPeerId} from "../util.js"; -import {Discv5Worker} from "../discv5/index.js"; -import {LodestarDiscv5Opts} from "../discv5/types.js"; -import {deserializeEnrSubnets, zeroAttnets, zeroSyncnets} from "./utils/enrSubnetsDeserialize.js"; import {IPeerRpcScoreStore, ScoreState} from "./score/index.js"; +import {deserializeEnrSubnets, zeroAttnets, zeroSyncnets} from "./utils/enrSubnetsDeserialize.js"; /** Max number of cached ENRs after discovering a good peer */ const MAX_CACHED_ENRS = 100; diff --git a/packages/beacon-node/src/network/peers/peerManager.ts b/packages/beacon-node/src/network/peers/peerManager.ts index b8742789d4fb..b8787bcc73a7 100644 --- a/packages/beacon-node/src/network/peers/peerManager.ts +++ b/packages/beacon-node/src/network/peers/peerManager.ts @@ -1,33 +1,33 @@ -import {Connection, PeerId} from "@libp2p/interface"; import {BitArray} from "@chainsafe/ssz"; -import {SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; +import {Connection, PeerId} from "@libp2p/interface"; import {BeaconConfig} from "@lodestar/config"; +import {LoggerNode} from "@lodestar/logger/node"; +import {SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {Metadata, altair, phase0} from "@lodestar/types"; import {withTimeout} from "@lodestar/utils"; -import {LoggerNode} from "@lodestar/logger/node"; -import {GoodByeReasonCode, GOODBYE_KNOWN_CODES, Libp2pEvent} from "../../constants/index.js"; +import {GOODBYE_KNOWN_CODES, GoodByeReasonCode, Libp2pEvent} from "../../constants/index.js"; import {IClock} from "../../util/clock.js"; -import {NetworkEvent, INetworkEventBus, NetworkEventData} from "../events.js"; +import {NetworkCoreMetrics} from "../core/metrics.js"; +import {LodestarDiscv5Opts} from "../discv5/types.js"; +import {INetworkEventBus, NetworkEvent, NetworkEventData} from "../events.js"; +import {Eth2Gossipsub} from "../gossip/gossipsub.js"; import {Libp2p} from "../interface.js"; -import {ReqRespMethod} from "../reqresp/ReqRespBeaconNode.js"; -import {getConnection, getConnectionsMap, prettyPrintPeerId} from "../util.js"; -import {SubnetsService} from "../subnets/index.js"; import {SubnetType} from "../metadata.js"; -import {Eth2Gossipsub} from "../gossip/gossipsub.js"; +import {ReqRespMethod} from "../reqresp/ReqRespBeaconNode.js"; import {StatusCache} from "../statusCache.js"; -import {NetworkCoreMetrics} from "../core/metrics.js"; -import {LodestarDiscv5Opts} from "../discv5/types.js"; +import {SubnetsService} from "../subnets/index.js"; +import {getConnection, getConnectionsMap, prettyPrintPeerId} from "../util.js"; +import {ClientKind, getKnownClientFromAgentVersion} from "./client.js"; import {PeerDiscovery, SubnetDiscvQueryMs} from "./discover.js"; -import {PeersData, PeerData} from "./peersData.js"; -import {getKnownClientFromAgentVersion, ClientKind} from "./client.js"; +import {PeerData, PeersData} from "./peersData.js"; +import {IPeerRpcScoreStore, PeerAction, PeerScoreStats, ScoreState, updateGossipsubScores} from "./score/index.js"; import { + assertPeerRelevance, getConnectedPeerIds, hasSomeConnectedPeer, - assertPeerRelevance, prioritizePeers, renderIrrelevantPeerType, } from "./utils/index.js"; -import {IPeerRpcScoreStore, PeerAction, PeerScoreStats, ScoreState, updateGossipsubScores} from "./score/index.js"; /** heartbeat performs regular updates such as updating reputations and performing discovery requests */ const HEARTBEAT_INTERVAL_MS = 30 * 1000; diff --git a/packages/beacon-node/src/network/peers/peersData.ts b/packages/beacon-node/src/network/peers/peersData.ts index 4f96548c73e4..1a2619f202cd 100644 --- a/packages/beacon-node/src/network/peers/peersData.ts +++ b/packages/beacon-node/src/network/peers/peersData.ts @@ -1,6 +1,6 @@ import {PeerId} from "@libp2p/interface"; -import {altair} from "@lodestar/types"; import {Encoding} from "@lodestar/reqresp"; +import {altair} from "@lodestar/types"; import {ClientKind} from "./client.js"; type PeerIdStr = string; diff --git a/packages/beacon-node/src/network/peers/utils/enrSubnetsDeserialize.ts b/packages/beacon-node/src/network/peers/utils/enrSubnetsDeserialize.ts index 0a26cce9b215..a330a8dca3c8 100644 --- a/packages/beacon-node/src/network/peers/utils/enrSubnetsDeserialize.ts +++ b/packages/beacon-node/src/network/peers/utils/enrSubnetsDeserialize.ts @@ -1,6 +1,6 @@ import {getUint8ByteToBitBooleanArray} from "@chainsafe/ssz"; -import {newFilledArray} from "@lodestar/state-transition"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; +import {newFilledArray} from "@lodestar/state-transition"; export const zeroAttnets = newFilledArray(ATTESTATION_SUBNET_COUNT, false); export const zeroSyncnets = newFilledArray(SYNC_COMMITTEE_SUBNET_COUNT, false); diff --git a/packages/beacon-node/src/network/peers/utils/prioritizePeers.ts b/packages/beacon-node/src/network/peers/utils/prioritizePeers.ts index b6fe4cb6bc77..545d8a6ca8b0 100644 --- a/packages/beacon-node/src/network/peers/utils/prioritizePeers.ts +++ b/packages/beacon-node/src/network/peers/utils/prioritizePeers.ts @@ -1,7 +1,7 @@ -import {Direction, PeerId} from "@libp2p/interface"; import {BitArray} from "@chainsafe/ssz"; -import {altair, phase0} from "@lodestar/types"; +import {Direction, PeerId} from "@libp2p/interface"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; +import {altair, phase0} from "@lodestar/types"; import {MapDef} from "@lodestar/utils"; import {shuffle} from "../../../util/shuffle.js"; import {sortBy} from "../../../util/sortBy.js"; diff --git a/packages/beacon-node/src/network/processor/extractSlotRootFns.ts b/packages/beacon-node/src/network/processor/extractSlotRootFns.ts index d31cb3e2d7f9..57a4861b4cb8 100644 --- a/packages/beacon-node/src/network/processor/extractSlotRootFns.ts +++ b/packages/beacon-node/src/network/processor/extractSlotRootFns.ts @@ -3,8 +3,8 @@ import { getBlockRootFromAttestationSerialized, getBlockRootFromSignedAggregateAndProofSerialized, getSlotFromAttestationSerialized, - getSlotFromSignedAggregateAndProofSerialized, getSlotFromBlobSidecarSerialized, + getSlotFromSignedAggregateAndProofSerialized, getSlotFromSignedBeaconBlockSerialized, } from "../../util/sszBytes.js"; import {GossipType} from "../gossip/index.js"; diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index dab3af0df8ba..5bec263a45c8 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -1,59 +1,59 @@ +import {routes} from "@lodestar/api"; import {BeaconConfig, ChainForkConfig} from "@lodestar/config"; -import {LogLevel, Logger, prettyBytes, toRootHex} from "@lodestar/utils"; -import {Root, Slot, ssz, deneb, UintNum64, SignedBeaconBlock, sszTypesFor} from "@lodestar/types"; import {ForkName, ForkSeq} from "@lodestar/params"; -import {routes} from "@lodestar/api"; import {computeTimeAtSlot} from "@lodestar/state-transition"; -import {Metrics} from "../../metrics/index.js"; -import {OpSource} from "../../metrics/validatorMonitor.js"; +import {Root, SignedBeaconBlock, Slot, UintNum64, deneb, ssz, sszTypesFor} from "@lodestar/types"; +import {LogLevel, Logger, prettyBytes, toRootHex} from "@lodestar/utils"; +import { + BlobSidecarValidation, + BlockInput, + BlockInputType, + GossipedInputType, + NullBlockInput, +} from "../../chain/blocks/types.js"; import { AttestationError, AttestationErrorCode, + BlobSidecarErrorCode, + BlobSidecarGossipError, BlockError, BlockErrorCode, BlockGossipError, - BlobSidecarErrorCode, - BlobSidecarGossipError, GossipAction, GossipActionError, SyncCommitteeError, } from "../../chain/errors/index.js"; +import {IBeaconChain} from "../../chain/interface.js"; +import {validateGossipBlobSidecar} from "../../chain/validation/blobSidecar.js"; import { - BatchGossipHandlers, - SequentialGossipHandlers, - GossipHandlerParamGeneric, - GossipHandlers, - GossipType, -} from "../gossip/interface.js"; -import { + AggregateAndProofValidationResult, + GossipAttestation, validateGossipAggregateAndProof, + validateGossipAttestationsSameAttData, validateGossipAttesterSlashing, validateGossipBlock, + validateGossipBlsToExecutionChange, validateGossipProposerSlashing, validateGossipSyncCommittee, - validateSyncCommitteeGossipContributionAndProof, validateGossipVoluntaryExit, - validateGossipBlsToExecutionChange, - AggregateAndProofValidationResult, - validateGossipAttestationsSameAttData, - GossipAttestation, + validateSyncCommitteeGossipContributionAndProof, } from "../../chain/validation/index.js"; -import {NetworkEvent, NetworkEventBus} from "../events.js"; -import {PeerAction} from "../peers/index.js"; import {validateLightClientFinalityUpdate} from "../../chain/validation/lightClientFinalityUpdate.js"; import {validateLightClientOptimisticUpdate} from "../../chain/validation/lightClientOptimisticUpdate.js"; -import {validateGossipBlobSidecar} from "../../chain/validation/blobSidecar.js"; +import {Metrics} from "../../metrics/index.js"; +import {OpSource} from "../../metrics/validatorMonitor.js"; +import {INetworkCore} from "../core/index.js"; +import {NetworkEvent, NetworkEventBus} from "../events.js"; import { - BlockInput, - GossipedInputType, - BlobSidecarValidation, - BlockInputType, - NullBlockInput, -} from "../../chain/blocks/types.js"; + BatchGossipHandlers, + GossipHandlerParamGeneric, + GossipHandlers, + GossipType, + SequentialGossipHandlers, +} from "../gossip/interface.js"; import {sszDeserialize} from "../gossip/topic.js"; -import {INetworkCore} from "../core/index.js"; import {INetwork} from "../interface.js"; -import {IBeaconChain} from "../../chain/interface.js"; +import {PeerAction} from "../peers/index.js"; import {AggregatorTracker} from "./aggregatorTracker.js"; /** diff --git a/packages/beacon-node/src/network/processor/gossipQueues/index.ts b/packages/beacon-node/src/network/processor/gossipQueues/index.ts index dfa5b0dd1973..b76ebe2d875d 100644 --- a/packages/beacon-node/src/network/processor/gossipQueues/index.ts +++ b/packages/beacon-node/src/network/processor/gossipQueues/index.ts @@ -1,10 +1,10 @@ import {mapValues} from "@lodestar/utils"; +import {getGossipAttestationIndex} from "../../../util/sszBytes.js"; import {BatchGossipType, GossipType, SequentialGossipType} from "../../gossip/interface.js"; import {PendingGossipsubMessage} from "../types.js"; -import {getGossipAttestationIndex} from "../../../util/sszBytes.js"; +import {IndexedGossipQueueMinSize} from "./indexed.js"; import {LinearGossipQueue} from "./linear.js"; import {DropType, GossipQueue, GossipQueueOpts, QueueType, isIndexedGossipQueueMinSizeOpts} from "./types.js"; -import {IndexedGossipQueueMinSize} from "./indexed.js"; /** * In normal condition, the higher this value the more efficient the signature verification. diff --git a/packages/beacon-node/src/network/processor/gossipQueues/linear.ts b/packages/beacon-node/src/network/processor/gossipQueues/linear.ts index 57a29054d417..f8a06c0d4622 100644 --- a/packages/beacon-node/src/network/processor/gossipQueues/linear.ts +++ b/packages/beacon-node/src/network/processor/gossipQueues/linear.ts @@ -1,5 +1,5 @@ import {LinkedList} from "../../../util/array.js"; -import {LinearGossipQueueOpts, DropType, GossipQueue, QueueType} from "./types.js"; +import {DropType, GossipQueue, LinearGossipQueueOpts, QueueType} from "./types.js"; // Having a drop ratio of 1 will empty the queue which is too severe // Worse case drop 95% of the queue diff --git a/packages/beacon-node/src/network/processor/gossipValidatorFn.ts b/packages/beacon-node/src/network/processor/gossipValidatorFn.ts index e5b276e7c707..6fda29bf4ac4 100644 --- a/packages/beacon-node/src/network/processor/gossipValidatorFn.ts +++ b/packages/beacon-node/src/network/processor/gossipValidatorFn.ts @@ -1,16 +1,16 @@ import {TopicValidatorResult} from "@libp2p/interface"; import {ChainForkConfig} from "@lodestar/config"; import {Logger} from "@lodestar/utils"; +import {AttestationError, GossipAction, GossipActionError} from "../../chain/errors/index.js"; import {Metrics} from "../../metrics/index.js"; import { - GossipValidatorFn, - GossipHandlers, - GossipHandlerFn, - GossipValidatorBatchFn, BatchGossipHandlerFn, + GossipHandlerFn, + GossipHandlers, GossipMessageInfo, + GossipValidatorBatchFn, + GossipValidatorFn, } from "../gossip/interface.js"; -import {GossipActionError, GossipAction, AttestationError} from "../../chain/errors/index.js"; export type ValidatorFnModules = { config: ChainForkConfig; diff --git a/packages/beacon-node/src/network/processor/index.ts b/packages/beacon-node/src/network/processor/index.ts index ec0edf54644f..4bfc4263adc8 100644 --- a/packages/beacon-node/src/network/processor/index.ts +++ b/packages/beacon-node/src/network/processor/index.ts @@ -1,14 +1,15 @@ -import {Logger, MapDef, mapValues, sleep} from "@lodestar/utils"; -import {RootHex, Slot, SlotRootHex} from "@lodestar/types"; import {routes} from "@lodestar/api"; -import {pruneSetToMax} from "@lodestar/utils"; import {ForkSeq} from "@lodestar/params"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {IBeaconChain} from "../../chain/interface.js"; +import {RootHex, Slot, SlotRootHex} from "@lodestar/types"; +import {Logger, MapDef, mapValues, sleep} from "@lodestar/utils"; +import {pruneSetToMax} from "@lodestar/utils"; import {GossipErrorCode} from "../../chain/errors/gossipValidation.js"; -import {Metrics} from "../../metrics/metrics.js"; +import {IBeaconChain} from "../../chain/interface.js"; import {IBeaconDb} from "../../db/interface.js"; +import {Metrics} from "../../metrics/metrics.js"; import {ClockEvent} from "../../util/clock.js"; +import {callInNextEventLoop} from "../../util/eventLoop.js"; import {NetworkEvent, NetworkEventBus} from "../events.js"; import { GossipHandlers, @@ -18,12 +19,11 @@ 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"; import {createExtractBlockSlotRootFns} from "./extractSlotRootFns.js"; +import {GossipHandlerOpts, ValidatorFnsModules, getGossipHandlers} from "./gossipHandlers.js"; +import {createGossipQueues} from "./gossipQueues/index.js"; import {ValidatorFnModules, getGossipValidatorBatchFn, getGossipValidatorFn} from "./gossipValidatorFn.js"; +import {PendingGossipsubMessage} from "./types.js"; export * from "./types.js"; diff --git a/packages/beacon-node/src/network/processor/types.ts b/packages/beacon-node/src/network/processor/types.ts index 386b9e8afc37..ec78116bc766 100644 --- a/packages/beacon-node/src/network/processor/types.ts +++ b/packages/beacon-node/src/network/processor/types.ts @@ -1,7 +1,7 @@ import {Message} from "@libp2p/interface"; import {Slot, SlotOptionalRoot} from "@lodestar/types"; -import {GossipTopic, GossipType} from "../gossip/index.js"; import {PeerIdStr} from "../../util/peerId.js"; +import {GossipTopic, GossipType} from "../gossip/index.js"; export type GossipAttestationsWork = { messages: PendingGossipsubMessage[]; diff --git a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts index d34b379f4ccd..a2a2ebd657ab 100644 --- a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts +++ b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts @@ -1,5 +1,4 @@ import {PeerId} from "@libp2p/interface"; -import {Libp2p} from "libp2p"; import {BeaconConfig} from "@lodestar/config"; import {ForkName, ForkSeq} from "@lodestar/params"; import { @@ -15,13 +14,15 @@ import { } from "@lodestar/reqresp"; import {Metadata, phase0, ssz} from "@lodestar/types"; import {Logger} from "@lodestar/utils"; +import {Libp2p} from "libp2p"; +import {callInNextEventLoop} from "../../util/eventLoop.js"; +import {NetworkCoreMetrics} from "../core/metrics.js"; import {INetworkEventBus, NetworkEvent} from "../events.js"; import {MetadataController} from "../metadata.js"; 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 * as protocols from "./protocols.js"; import {onOutgoingReqRespError} from "./score.js"; import { GetReqRespHandlerFn, @@ -32,7 +33,6 @@ import { requestSszTypeByMethod, responseSszTypeByMethod, } from "./types.js"; -import * as protocols from "./protocols.js"; import {collectExactOneTyped} from "./utils/collect.js"; export {getReqRespHandlers} from "./handlers/index.js"; diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts index 3d71087c8fd8..21d781f11437 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts @@ -1,9 +1,9 @@ import {ChainForkConfig} from "@lodestar/config"; -import {deneb, Epoch, phase0, SignedBeaconBlock, Slot, WithBytes} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import {computeEpochAtSlot} from "@lodestar/state-transition"; +import {Epoch, SignedBeaconBlock, Slot, WithBytes, deneb, phase0} from "@lodestar/types"; -import {BlobsSource, BlockInput, BlockSource, getBlockInput, BlockInputDataBlobs} from "../../chain/blocks/types.js"; +import {BlobsSource, BlockInput, BlockInputDataBlobs, BlockSource, getBlockInput} from "../../chain/blocks/types.js"; import {PeerIdStr} from "../../util/peerId.js"; import {INetwork} from "../interface.js"; diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts index 3d121156d8e6..a6919318999d 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts @@ -1,21 +1,21 @@ import {ChainForkConfig} from "@lodestar/config"; -import {phase0, deneb, SignedBeaconBlock} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; +import {SignedBeaconBlock, deneb, phase0} from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; import { + BlobsSource, BlockInput, + BlockInputDataBlobs, BlockInputType, BlockSource, - getBlockInputBlobs, - getBlockInput, NullBlockInput, - BlobsSource, - BlockInputDataBlobs, + getBlockInput, + getBlockInputBlobs, } from "../../chain/blocks/types.js"; -import {PeerIdStr} from "../../util/peerId.js"; -import {INetwork} from "../interface.js"; import {BlockInputAvailabilitySource} from "../../chain/seenCache/seenGossipBlockInput.js"; import {Metrics} from "../../metrics/index.js"; +import {PeerIdStr} from "../../util/peerId.js"; +import {INetwork} from "../interface.js"; import {matchBlockWithBlobs} from "./beaconBlocksMaybeBlobsByRange.js"; export async function beaconBlocksMaybeBlobsByRoot( diff --git a/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRange.ts b/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRange.ts index d1046db9651d..e8c19fb49628 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRange.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRange.ts @@ -1,5 +1,5 @@ import {GENESIS_SLOT, MAX_REQUEST_BLOCKS} from "@lodestar/params"; -import {ResponseError, ResponseOutgoing, RespStatus} from "@lodestar/reqresp"; +import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp"; import {deneb, phase0} from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; import {IBeaconChain} from "../../../chain/index.js"; diff --git a/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRange.ts b/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRange.ts index e3655cd90c6f..9cac846fdb61 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRange.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRange.ts @@ -1,6 +1,6 @@ -import {GENESIS_SLOT, MAX_REQUEST_BLOCKS_DENEB, BLOBSIDECAR_FIXED_SIZE} from "@lodestar/params"; -import {ResponseError, ResponseOutgoing, RespStatus} from "@lodestar/reqresp"; -import {deneb, Slot} from "@lodestar/types"; +import {BLOBSIDECAR_FIXED_SIZE, GENESIS_SLOT, MAX_REQUEST_BLOCKS_DENEB} from "@lodestar/params"; +import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp"; +import {Slot, deneb} from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; import {IBeaconChain} from "../../../chain/index.js"; import {IBeaconDb} from "../../../db/index.js"; diff --git a/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts b/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts index 144d470d7199..f44f9482eeb6 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts @@ -1,6 +1,6 @@ -import {ResponseError, ResponseOutgoing, RespStatus} from "@lodestar/reqresp"; import {BLOBSIDECAR_FIXED_SIZE} from "@lodestar/params"; -import {deneb, RootHex} from "@lodestar/types"; +import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp"; +import {RootHex, deneb} from "@lodestar/types"; import {fromHex, toRootHex} from "@lodestar/utils"; import {IBeaconChain} from "../../../chain/index.js"; import {IBeaconDb} from "../../../db/index.js"; diff --git a/packages/beacon-node/src/network/reqresp/handlers/index.ts b/packages/beacon-node/src/network/reqresp/handlers/index.ts index 50b8cc870844..a836cbc47769 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/index.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/index.ts @@ -1,12 +1,12 @@ -import {ssz} from "@lodestar/types"; import {ProtocolHandler} from "@lodestar/reqresp"; +import {ssz} from "@lodestar/types"; import {IBeaconChain} from "../../../chain/index.js"; import {IBeaconDb} from "../../../db/index.js"; import {GetReqRespHandlerFn, ReqRespMethod} from "../types.js"; import {onBeaconBlocksByRange} from "./beaconBlocksByRange.js"; import {onBeaconBlocksByRoot} from "./beaconBlocksByRoot.js"; -import {onBlobSidecarsByRoot} from "./blobSidecarsByRoot.js"; import {onBlobSidecarsByRange} from "./blobSidecarsByRange.js"; +import {onBlobSidecarsByRoot} from "./blobSidecarsByRoot.js"; import {onLightClientBootstrap} from "./lightClientBootstrap.js"; import {onLightClientFinalityUpdate} from "./lightClientFinalityUpdate.js"; import {onLightClientOptimisticUpdate} from "./lightClientOptimisticUpdate.js"; diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts index 3b50304eb50c..ae5b5abf1f80 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts @@ -1,14 +1,14 @@ import { - RespStatus, - ResponseError, LightClientServerError, LightClientServerErrorCode, + RespStatus, + ResponseError, ResponseOutgoing, } from "@lodestar/reqresp"; import {Root} from "@lodestar/types"; import {IBeaconChain} from "../../../chain/index.js"; -import {ReqRespMethod, responseSszTypeByMethod} from "../types.js"; import {assertLightClientServer} from "../../../node/utils/lightclient.js"; +import {ReqRespMethod, responseSszTypeByMethod} from "../types.js"; export async function* onLightClientBootstrap(requestBody: Root, chain: IBeaconChain): AsyncIterable { assertLightClientServer(chain.lightClientServer); diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts index 4764c6f198f7..26eec4585d79 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts @@ -1,7 +1,7 @@ -import {ResponseOutgoing, RespStatus, ResponseError} from "@lodestar/reqresp"; +import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp"; import {IBeaconChain} from "../../../chain/index.js"; -import {ReqRespMethod, responseSszTypeByMethod} from "../types.js"; import {assertLightClientServer} from "../../../node/utils/lightclient.js"; +import {ReqRespMethod, responseSszTypeByMethod} from "../types.js"; export async function* onLightClientFinalityUpdate(chain: IBeaconChain): AsyncIterable { assertLightClientServer(chain.lightClientServer); diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts index 4c030a8e4174..e8cdb73ee05a 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts @@ -1,7 +1,7 @@ -import {ResponseOutgoing, ResponseError, RespStatus} from "@lodestar/reqresp"; +import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp"; import {IBeaconChain} from "../../../chain/index.js"; -import {ReqRespMethod, responseSszTypeByMethod} from "../types.js"; import {assertLightClientServer} from "../../../node/utils/lightclient.js"; +import {ReqRespMethod, responseSszTypeByMethod} from "../types.js"; export async function* onLightClientOptimisticUpdate(chain: IBeaconChain): AsyncIterable { assertLightClientServer(chain.lightClientServer); diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts index 89466eca6c21..53b701d448cd 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts @@ -1,15 +1,15 @@ -import {altair} from "@lodestar/types"; import {MAX_REQUEST_LIGHT_CLIENT_UPDATES} from "@lodestar/params"; import { - ResponseOutgoing, LightClientServerError, LightClientServerErrorCode, - ResponseError, RespStatus, + ResponseError, + ResponseOutgoing, } from "@lodestar/reqresp"; +import {altair} from "@lodestar/types"; import {IBeaconChain} from "../../../chain/index.js"; -import {ReqRespMethod, responseSszTypeByMethod} from "../types.js"; import {assertLightClientServer} from "../../../node/utils/lightclient.js"; +import {ReqRespMethod, responseSszTypeByMethod} from "../types.js"; export async function* onLightClientUpdatesByRange( requestBody: altair.LightClientUpdatesByRange, diff --git a/packages/beacon-node/src/network/reqresp/handlers/status.ts b/packages/beacon-node/src/network/reqresp/handlers/status.ts index e46c1a268b06..22c342177334 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/status.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/status.ts @@ -1,6 +1,6 @@ +import {ForkName} from "@lodestar/params"; import {ResponseOutgoing} from "@lodestar/reqresp"; import {ssz} from "@lodestar/types"; -import {ForkName} from "@lodestar/params"; import {IBeaconChain} from "../../../chain/index.js"; export async function* onStatus(chain: IBeaconChain): AsyncIterable { diff --git a/packages/beacon-node/src/network/reqresp/protocols.ts b/packages/beacon-node/src/network/reqresp/protocols.ts index e63df4b1341b..b6b9c6c48967 100644 --- a/packages/beacon-node/src/network/reqresp/protocols.ts +++ b/packages/beacon-node/src/network/reqresp/protocols.ts @@ -1,7 +1,7 @@ -import {ContextBytesFactory, ContextBytesType, Encoding} from "@lodestar/reqresp"; import {ForkDigestContext} from "@lodestar/config"; -import {ProtocolNoHandler, ReqRespMethod, Version, requestSszTypeByMethod, responseSszTypeByMethod} from "./types.js"; +import {ContextBytesFactory, ContextBytesType, Encoding} from "@lodestar/reqresp"; import {rateLimitQuotas} from "./rateLimit.js"; +import {ProtocolNoHandler, ReqRespMethod, Version, requestSszTypeByMethod, responseSszTypeByMethod} from "./types.js"; export const Goodbye = toProtocol({ method: ReqRespMethod.Goodbye, diff --git a/packages/beacon-node/src/network/reqresp/rateLimit.ts b/packages/beacon-node/src/network/reqresp/rateLimit.ts index b6dacd6ba8e5..5830b48d2eab 100644 --- a/packages/beacon-node/src/network/reqresp/rateLimit.ts +++ b/packages/beacon-node/src/network/reqresp/rateLimit.ts @@ -1,8 +1,8 @@ import { - MAX_REQUEST_BLOCKS, - MAX_REQUEST_LIGHT_CLIENT_UPDATES, MAX_BLOBS_PER_BLOCK, MAX_REQUEST_BLOB_SIDECARS, + MAX_REQUEST_BLOCKS, + MAX_REQUEST_LIGHT_CLIENT_UPDATES, } from "@lodestar/params"; import {InboundRateLimitQuota} from "@lodestar/reqresp"; import {ReqRespMethod, RequestBodyByMethod} from "./types.js"; diff --git a/packages/beacon-node/src/network/reqresp/utils/collect.ts b/packages/beacon-node/src/network/reqresp/utils/collect.ts index 9818b1921f8e..f79ea2abba07 100644 --- a/packages/beacon-node/src/network/reqresp/utils/collect.ts +++ b/packages/beacon-node/src/network/reqresp/utils/collect.ts @@ -1,5 +1,5 @@ import {Type} from "@chainsafe/ssz"; -import {ResponseIncoming, RequestErrorCode, RequestError} from "@lodestar/reqresp"; +import {RequestError, RequestErrorCode, ResponseIncoming} from "@lodestar/reqresp"; import {WithBytes} from "@lodestar/types"; import {ResponseTypeGetter} from "../types.js"; diff --git a/packages/beacon-node/src/network/reqresp/utils/collectSequentialBlocksInRange.ts b/packages/beacon-node/src/network/reqresp/utils/collectSequentialBlocksInRange.ts index 2709cb3f64a9..2e2bcf772d76 100644 --- a/packages/beacon-node/src/network/reqresp/utils/collectSequentialBlocksInRange.ts +++ b/packages/beacon-node/src/network/reqresp/utils/collectSequentialBlocksInRange.ts @@ -1,6 +1,6 @@ import {ResponseIncoming} from "@lodestar/reqresp"; +import {SignedBeaconBlock, WithBytes, phase0} from "@lodestar/types"; import {LodestarError} from "@lodestar/utils"; -import {phase0, SignedBeaconBlock, WithBytes} from "@lodestar/types"; import {ReqRespMethod, responseSszTypeByMethod} from "../types.js"; import {sszDeserializeResponse} from "./collect.js"; diff --git a/packages/beacon-node/src/network/subnets/attnetsService.ts b/packages/beacon-node/src/network/subnets/attnetsService.ts index 5044bac059cd..ed2f94bd56d8 100644 --- a/packages/beacon-node/src/network/subnets/attnetsService.ts +++ b/packages/beacon-node/src/network/subnets/attnetsService.ts @@ -1,3 +1,4 @@ +import {BeaconConfig} from "@lodestar/config"; import { ATTESTATION_SUBNET_COUNT, EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION, @@ -6,16 +7,15 @@ import { } from "@lodestar/params"; import {Epoch, Slot, ssz} from "@lodestar/types"; import {Logger, MapDef} from "@lodestar/utils"; -import {BeaconConfig} from "@lodestar/config"; import {ClockEvent, IClock} from "../../util/clock.js"; -import {GossipType} from "../gossip/index.js"; -import {MetadataController} from "../metadata.js"; -import {SubnetMap, RequestedSubnet} from "../peers/utils/index.js"; -import {getActiveForks} from "../forks.js"; import {NetworkCoreMetrics} from "../core/metrics.js"; -import {stringifyGossipTopic} from "../gossip/topic.js"; +import {getActiveForks} from "../forks.js"; +import {GossipType} from "../gossip/index.js"; import {GOSSIP_D_LOW} from "../gossip/scoringParameters.js"; -import {IAttnetsService, CommitteeSubscription, SubnetsServiceOpts, GossipSubscriber, NodeId} from "./interface.js"; +import {stringifyGossipTopic} from "../gossip/topic.js"; +import {MetadataController} from "../metadata.js"; +import {RequestedSubnet, SubnetMap} from "../peers/utils/index.js"; +import {CommitteeSubscription, GossipSubscriber, IAttnetsService, NodeId, SubnetsServiceOpts} from "./interface.js"; import {computeSubscribedSubnet} from "./util.js"; const gossipType = GossipType.beacon_attestation; diff --git a/packages/beacon-node/src/network/subnets/interface.ts b/packages/beacon-node/src/network/subnets/interface.ts index 1d036bf9831d..e3b1e2513818 100644 --- a/packages/beacon-node/src/network/subnets/interface.ts +++ b/packages/beacon-node/src/network/subnets/interface.ts @@ -1,7 +1,7 @@ import {ForkName} from "@lodestar/params"; import {Bytes32, Slot, ValidatorIndex} from "@lodestar/types"; -import {RequestedSubnet} from "../peers/utils/index.js"; import {GossipTopic} from "../gossip/interface.js"; +import {RequestedSubnet} from "../peers/utils/index.js"; /** Generic CommitteeSubscription for both beacon attnets subs and syncnets subs */ export type CommitteeSubscription = { diff --git a/packages/beacon-node/src/network/subnets/syncnetsService.ts b/packages/beacon-node/src/network/subnets/syncnetsService.ts index c61b1060899a..8dee6243b39f 100644 --- a/packages/beacon-node/src/network/subnets/syncnetsService.ts +++ b/packages/beacon-node/src/network/subnets/syncnetsService.ts @@ -1,14 +1,14 @@ -import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; import {ForkName, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; +import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {Epoch, ssz} from "@lodestar/types"; import {Logger} from "@lodestar/utils"; import {ClockEvent, IClock} from "../../util/clock.js"; +import {NetworkCoreMetrics} from "../core/metrics.js"; import {getActiveForks} from "../forks.js"; import {GossipType} from "../gossip/index.js"; import {MetadataController} from "../metadata.js"; import {RequestedSubnet, SubnetMap} from "../peers/utils/index.js"; -import {NetworkCoreMetrics} from "../core/metrics.js"; import {CommitteeSubscription, GossipSubscriber, SubnetsService, SubnetsServiceOpts} from "./interface.js"; const gossipType = GossipType.sync_committee; diff --git a/packages/beacon-node/src/node/nodejs.ts b/packages/beacon-node/src/node/nodejs.ts index 701ab0fde070..ec3a0ef66a5a 100644 --- a/packages/beacon-node/src/node/nodejs.ts +++ b/packages/beacon-node/src/node/nodejs.ts @@ -2,28 +2,28 @@ import {setMaxListeners} from "node:events"; import {Registry} from "prom-client"; import {PeerId} from "@libp2p/interface"; +import {BeaconApiMethods} from "@lodestar/api/beacon/server"; import {BeaconConfig} from "@lodestar/config"; -import {phase0} from "@lodestar/types"; -import {sleep} from "@lodestar/utils"; import type {LoggerNode} from "@lodestar/logger/node"; -import {BeaconApiMethods} from "@lodestar/api/beacon/server"; import {BeaconStateAllForks} from "@lodestar/state-transition"; +import {phase0} from "@lodestar/types"; +import {sleep} from "@lodestar/utils"; import {ProcessShutdownCallback} from "@lodestar/validator"; +import {BeaconRestApiServer, getApi} from "../api/index.js"; +import {HistoricalStateRegen} from "../chain/historicalState/index.js"; +import {BeaconChain, IBeaconChain, initBeaconMetrics} from "../chain/index.js"; import {IBeaconDb} from "../db/index.js"; +import {initializeEth1ForBlockProduction} from "../eth1/index.js"; +import {initializeExecutionBuilder, initializeExecutionEngine} from "../execution/index.js"; +import {HttpMetricsServer, Metrics, createMetrics, getHttpMetricsServer} from "../metrics/index.js"; +import {MonitoringService} from "../monitoring/index.js"; import {Network, getReqRespHandlers} from "../network/index.js"; -import {BeaconSync, IBeaconSync} from "../sync/index.js"; import {BackfillSync} from "../sync/backfill/index.js"; -import {BeaconChain, IBeaconChain, initBeaconMetrics} from "../chain/index.js"; -import {createMetrics, Metrics, HttpMetricsServer, getHttpMetricsServer} from "../metrics/index.js"; -import {MonitoringService} from "../monitoring/index.js"; -import {getApi, BeaconRestApiServer} from "../api/index.js"; -import {initializeExecutionEngine, initializeExecutionBuilder} from "../execution/index.js"; -import {initializeEth1ForBlockProduction} from "../eth1/index.js"; -import {initCKZG, loadEthereumTrustedSetup, TrustedFileMode} from "../util/kzg.js"; -import {HistoricalStateRegen} from "../chain/historicalState/index.js"; -import {IBeaconNodeOptions} from "./options.js"; +import {BeaconSync, IBeaconSync} from "../sync/index.js"; +import {TrustedFileMode, initCKZG, loadEthereumTrustedSetup} from "../util/kzg.js"; import {runNodeNotifier} from "./notifier.js"; +import {IBeaconNodeOptions} from "./options.js"; export * from "./options.js"; diff --git a/packages/beacon-node/src/node/notifier.ts b/packages/beacon-node/src/node/notifier.ts index 20a359a45c49..c0d9354197ae 100644 --- a/packages/beacon-node/src/node/notifier.ts +++ b/packages/beacon-node/src/node/notifier.ts @@ -1,12 +1,12 @@ import {BeaconConfig} from "@lodestar/config"; -import {Epoch} from "@lodestar/types"; -import {CachedBeaconStateAllForks, computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {ProtoBlock, ExecutionStatus} from "@lodestar/fork-choice"; -import {ErrorAborted, Logger, sleep, prettyBytes, prettyBytesShort} from "@lodestar/utils"; +import {ExecutionStatus, ProtoBlock} from "@lodestar/fork-choice"; import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {CachedBeaconStateAllForks, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {computeEpochAtSlot, isExecutionCachedStateType, isMergeTransitionComplete} from "@lodestar/state-transition"; -import {ExecutionEngineState} from "../execution/index.js"; +import {Epoch} from "@lodestar/types"; +import {ErrorAborted, Logger, prettyBytes, prettyBytesShort, sleep} from "@lodestar/utils"; import {IBeaconChain} from "../chain/index.js"; +import {ExecutionEngineState} from "../execution/index.js"; import {INetwork} from "../network/index.js"; import {IBeaconSync, SyncState} from "../sync/index.js"; import {prettyTimeDiffSec} from "../util/time.js"; diff --git a/packages/beacon-node/src/node/options.ts b/packages/beacon-node/src/node/options.ts index e587e58ec127..1a440bfd4981 100644 --- a/packages/beacon-node/src/node/options.ts +++ b/packages/beacon-node/src/node/options.ts @@ -1,19 +1,19 @@ -import {defaultApiOptions, ApiOptions} from "../api/options.js"; -import {defaultChainOptions, IChainOptions, StateArchiveMode, DEFAULT_STATE_ARCHIVE_MODE} from "../chain/options.js"; -import {defaultDbOptions, DatabaseOptions} from "../db/options.js"; -import {defaultEth1Options, Eth1Options} from "../eth1/options.js"; -import {defaultMetricsOptions, MetricsOptions} from "../metrics/options.js"; -import {defaultMonitoringOptions, MonitoringOptions} from "../monitoring/options.js"; -import {defaultNetworkOptions, NetworkOptions} from "../network/options.js"; -import {defaultSyncOptions, SyncOptions} from "../sync/options.js"; +import {ApiOptions, defaultApiOptions} from "../api/options.js"; +import {DEFAULT_STATE_ARCHIVE_MODE, IChainOptions, StateArchiveMode, defaultChainOptions} from "../chain/options.js"; +import {DatabaseOptions, defaultDbOptions} from "../db/options.js"; +import {Eth1Options, defaultEth1Options} from "../eth1/options.js"; import { - defaultExecutionEngineOpts, - defaultExecutionEngineHttpOpts, - ExecutionEngineOpts, ExecutionBuilderOpts, - defaultExecutionBuilderOpts, + ExecutionEngineOpts, defaultExecutionBuilderHttpOpts, + defaultExecutionBuilderOpts, + defaultExecutionEngineHttpOpts, + defaultExecutionEngineOpts, } from "../execution/index.js"; +import {MetricsOptions, defaultMetricsOptions} from "../metrics/options.js"; +import {MonitoringOptions, defaultMonitoringOptions} from "../monitoring/options.js"; +import {NetworkOptions, defaultNetworkOptions} from "../network/options.js"; +import {SyncOptions, defaultSyncOptions} from "../sync/options.js"; // Re-export so the CLI doesn't need to depend on lodestar-api export {allNamespaces} from "../api/rest/index.js"; diff --git a/packages/beacon-node/src/node/utils/interop/deposits.ts b/packages/beacon-node/src/node/utils/interop/deposits.ts index 6cce7e883b84..21f78a6ec2be 100644 --- a/packages/beacon-node/src/node/utils/interop/deposits.ts +++ b/packages/beacon-node/src/node/utils/interop/deposits.ts @@ -1,14 +1,14 @@ import {digest} from "@chainsafe/as-sha256"; -import {toGindex, Tree} from "@chainsafe/persistent-merkle-tree"; -import {phase0, ssz} from "@lodestar/types"; +import {Tree, toGindex} from "@chainsafe/persistent-merkle-tree"; import {ChainConfig} from "@lodestar/config"; -import {computeDomain, computeSigningRoot, interopSecretKeys, ZERO_HASH} from "@lodestar/state-transition"; import { BLS_WITHDRAWAL_PREFIX, - ETH1_ADDRESS_WITHDRAWAL_PREFIX, DOMAIN_DEPOSIT, + ETH1_ADDRESS_WITHDRAWAL_PREFIX, MAX_EFFECTIVE_BALANCE, } from "@lodestar/params"; +import {ZERO_HASH, computeDomain, computeSigningRoot, interopSecretKeys} from "@lodestar/state-transition"; +import {phase0, ssz} from "@lodestar/types"; import {DepositTree} from "../../../db/repositories/depositDataRoot.js"; /** diff --git a/packages/beacon-node/src/node/utils/interop/state.ts b/packages/beacon-node/src/node/utils/interop/state.ts index fe26afef2013..ef88fb956e05 100644 --- a/packages/beacon-node/src/node/utils/interop/state.ts +++ b/packages/beacon-node/src/node/utils/interop/state.ts @@ -1,8 +1,8 @@ -import {Bytes32, phase0, ssz, sszTypesFor, TimeSeconds} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; +import {ForkName, GENESIS_SLOT} from "@lodestar/params"; import {BeaconStateAllForks, initializeBeaconStateFromEth1} from "@lodestar/state-transition"; import {createEmptyEpochCacheImmutableData} from "@lodestar/state-transition"; -import {ForkName, GENESIS_SLOT} from "@lodestar/params"; +import {Bytes32, TimeSeconds, phase0, ssz, sszTypesFor} from "@lodestar/types"; import {DepositTree} from "../../../db/repositories/depositDataRoot.js"; diff --git a/packages/beacon-node/src/node/utils/state.ts b/packages/beacon-node/src/node/utils/state.ts index 05da7042eef4..ac0ff8101fb6 100644 --- a/packages/beacon-node/src/node/utils/state.ts +++ b/packages/beacon-node/src/node/utils/state.ts @@ -3,7 +3,7 @@ import {BeaconStateAllForks} from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; import {IBeaconDb} from "../../db/index.js"; import {interopDeposits} from "./interop/deposits.js"; -import {getInteropState, InteropStateOpts} from "./interop/state.js"; +import {InteropStateOpts, getInteropState} from "./interop/state.js"; /** * Builds state for `dev` command, for sim testing and some other tests diff --git a/packages/beacon-node/src/sync/backfill/backfill.ts b/packages/beacon-node/src/sync/backfill/backfill.ts index 9612cf23b615..4fedb9d1fd5b 100644 --- a/packages/beacon-node/src/sync/backfill/backfill.ts +++ b/packages/beacon-node/src/sync/backfill/backfill.ts @@ -1,22 +1,22 @@ import {EventEmitter} from "node:events"; -import {StrictEventEmitter} from "strict-event-emitter-types"; -import {BeaconStateAllForks, blockToHeader, computeAnchorCheckpoint} from "@lodestar/state-transition"; import {BeaconConfig, ChainForkConfig} from "@lodestar/config"; -import {phase0, Root, SignedBeaconBlock, Slot, ssz} from "@lodestar/types"; +import {BeaconStateAllForks, blockToHeader, computeAnchorCheckpoint} from "@lodestar/state-transition"; +import {Root, SignedBeaconBlock, Slot, phase0, ssz} from "@lodestar/types"; import {ErrorAborted, Logger, sleep, toRootHex} from "@lodestar/utils"; +import {StrictEventEmitter} from "strict-event-emitter-types"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {IBeaconChain} from "../../chain/index.js"; import {GENESIS_SLOT, ZERO_HASH} from "../../constants/index.js"; import {IBeaconDb} from "../../db/index.js"; +import {Metrics} from "../../metrics/metrics.js"; import {INetwork, NetworkEvent, NetworkEventData, PeerAction} from "../../network/index.js"; +import {byteArrayEquals} from "../../util/bytes.js"; import {ItTrigger} from "../../util/itTrigger.js"; import {PeerIdStr} from "../../util/peerId.js"; import {shuffleOne} from "../../util/shuffle.js"; -import {Metrics} from "../../metrics/metrics.js"; -import {byteArrayEquals} from "../../util/bytes.js"; -import {verifyBlockProposerSignature, verifyBlockSequence, BackfillBlockHeader, BackfillBlock} from "./verify.js"; import {BackfillSyncError, BackfillSyncErrorCode} from "./errors.js"; +import {BackfillBlock, BackfillBlockHeader, verifyBlockProposerSignature, verifyBlockSequence} from "./verify.js"; /** * Timeout in ms to take a break from reading a backfillBatchSize from db, as just yielding * to sync loop gives hardly any. diff --git a/packages/beacon-node/src/sync/backfill/errors.ts b/packages/beacon-node/src/sync/backfill/errors.ts index e62c90407ed5..530507f99f36 100644 --- a/packages/beacon-node/src/sync/backfill/errors.ts +++ b/packages/beacon-node/src/sync/backfill/errors.ts @@ -1,6 +1,6 @@ import {PeerId} from "@libp2p/interface"; -import {LodestarError} from "@lodestar/utils"; import {Root} from "@lodestar/types"; +import {LodestarError} from "@lodestar/utils"; export enum BackfillSyncErrorCode { /** fetched block doesn't connect to anchor block */ diff --git a/packages/beacon-node/src/sync/backfill/verify.ts b/packages/beacon-node/src/sync/backfill/verify.ts index 715cc6621253..9150e17b3e8c 100644 --- a/packages/beacon-node/src/sync/backfill/verify.ts +++ b/packages/beacon-node/src/sync/backfill/verify.ts @@ -1,7 +1,7 @@ -import {CachedBeaconStateAllForks, ISignatureSet, getBlockProposerSignatureSet} from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; -import {Root, ssz, Slot, SignedBeaconBlock, WithBytes} from "@lodestar/types"; import {GENESIS_SLOT} from "@lodestar/params"; +import {CachedBeaconStateAllForks, ISignatureSet, getBlockProposerSignatureSet} from "@lodestar/state-transition"; +import {Root, SignedBeaconBlock, Slot, WithBytes, ssz} from "@lodestar/types"; import {IBlsVerifier} from "../../chain/bls/index.js"; import {BackfillSyncError, BackfillSyncErrorCode} from "./errors.js"; diff --git a/packages/beacon-node/src/sync/interface.ts b/packages/beacon-node/src/sync/interface.ts index c1e83cb476fb..88d7138656f3 100644 --- a/packages/beacon-node/src/sync/interface.ts +++ b/packages/beacon-node/src/sync/interface.ts @@ -1,12 +1,12 @@ -import {Logger} from "@lodestar/utils"; -import {RootHex, Slot, phase0} from "@lodestar/types"; -import {BeaconConfig} from "@lodestar/config"; import {routes} from "@lodestar/api"; +import {BeaconConfig} from "@lodestar/config"; +import {RootHex, Slot, phase0} from "@lodestar/types"; +import {Logger} from "@lodestar/utils"; import {BlockInput, BlockInputType, NullBlockInput} from "../chain/blocks/types.js"; -import {INetwork} from "../network/index.js"; import {IBeaconChain} from "../chain/index.js"; -import {Metrics} from "../metrics/index.js"; import {IBeaconDb} from "../db/index.js"; +import {Metrics} from "../metrics/index.js"; +import {INetwork} from "../network/index.js"; import {SyncChainDebugState} from "./range/chain.js"; export type {SyncChainDebugState}; diff --git a/packages/beacon-node/src/sync/range/batch.ts b/packages/beacon-node/src/sync/range/batch.ts index e3e81bc57143..a78febbc5c7f 100644 --- a/packages/beacon-node/src/sync/range/batch.ts +++ b/packages/beacon-node/src/sync/range/batch.ts @@ -1,10 +1,10 @@ -import {Epoch, phase0, RootHex} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; +import {Epoch, RootHex, phase0} from "@lodestar/types"; import {LodestarError} from "@lodestar/utils"; -import {MAX_BATCH_DOWNLOAD_ATTEMPTS, MAX_BATCH_PROCESSING_ATTEMPTS} from "../constants.js"; -import {PeerIdStr} from "../../util/peerId.js"; import {BlockInput} from "../../chain/blocks/types.js"; import {BlockError, BlockErrorCode} from "../../chain/errors/index.js"; +import {PeerIdStr} from "../../util/peerId.js"; +import {MAX_BATCH_DOWNLOAD_ATTEMPTS, MAX_BATCH_PROCESSING_ATTEMPTS} from "../constants.js"; import {getBatchSlotRange, hashBlocks} from "./utils/index.js"; /** diff --git a/packages/beacon-node/src/sync/range/chain.ts b/packages/beacon-node/src/sync/range/chain.ts index 0a2fc1a3f7c3..2a8d76d99785 100644 --- a/packages/beacon-node/src/sync/range/chain.ts +++ b/packages/beacon-node/src/sync/range/chain.ts @@ -1,24 +1,24 @@ +import {ChainForkConfig} from "@lodestar/config"; import {Epoch, Root, Slot, phase0} from "@lodestar/types"; import {ErrorAborted, Logger, toRootHex} from "@lodestar/utils"; -import {ChainForkConfig} from "@lodestar/config"; import {BlockInput, BlockInputType} from "../../chain/blocks/types.js"; import {PeerAction} from "../../network/index.js"; import {ItTrigger} from "../../util/itTrigger.js"; import {PeerIdStr} from "../../util/peerId.js"; import {wrapError} from "../../util/wrapError.js"; -import {RangeSyncType} from "../utils/remoteSyncType.js"; import {BATCH_BUFFER_SIZE, EPOCHS_PER_BATCH} from "../constants.js"; +import {RangeSyncType} from "../utils/remoteSyncType.js"; import {Batch, BatchError, BatchErrorCode, BatchMetadata, BatchStatus} from "./batch.js"; import { - validateBatchesStatus, - getNextBatchToProcess, - toBeDownloadedStartEpoch, - toArr, ChainPeersBalancer, - computeMostCommonTarget, batchStartEpochIsAfterSlot, - isSyncChainDone, + computeMostCommonTarget, getBatchSlotRange, + getNextBatchToProcess, + isSyncChainDone, + toArr, + toBeDownloadedStartEpoch, + validateBatchesStatus, } from "./utils/index.js"; export type SyncChainModules = { diff --git a/packages/beacon-node/src/sync/range/range.ts b/packages/beacon-node/src/sync/range/range.ts index 51e3a5d0f182..8284abd09955 100644 --- a/packages/beacon-node/src/sync/range/range.ts +++ b/packages/beacon-node/src/sync/range/range.ts @@ -1,18 +1,18 @@ import {EventEmitter} from "node:events"; -import {StrictEventEmitter} from "strict-event-emitter-types"; -import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; +import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {Epoch, phase0} from "@lodestar/types"; import {Logger, toRootHex} from "@lodestar/utils"; +import {StrictEventEmitter} from "strict-event-emitter-types"; +import {AttestationImportOpt, ImportBlockOpts} from "../../chain/blocks/index.js"; import {IBeaconChain} from "../../chain/index.js"; -import {INetwork} from "../../network/index.js"; import {Metrics} from "../../metrics/index.js"; -import {RangeSyncType, rangeSyncTypes, getRangeSyncTarget} from "../utils/remoteSyncType.js"; -import {PeerIdStr} from "../../util/peerId.js"; -import {ImportBlockOpts, AttestationImportOpt} from "../../chain/blocks/index.js"; +import {INetwork} from "../../network/index.js"; import {beaconBlocksMaybeBlobsByRange} from "../../network/reqresp/beaconBlocksMaybeBlobsByRange.js"; +import {PeerIdStr} from "../../util/peerId.js"; +import {RangeSyncType, getRangeSyncTarget, rangeSyncTypes} from "../utils/remoteSyncType.js"; +import {ChainTarget, SyncChain, SyncChainDebugState, SyncChainFns} from "./chain.js"; import {updateChains} from "./utils/index.js"; -import {ChainTarget, SyncChainFns, SyncChain, SyncChainDebugState} from "./chain.js"; export enum RangeSyncEvent { completedChain = "RangeSync-completedChain", diff --git a/packages/beacon-node/src/sync/range/utils/hashBlocks.ts b/packages/beacon-node/src/sync/range/utils/hashBlocks.ts index 986d023d9ca1..9d983fc7278e 100644 --- a/packages/beacon-node/src/sync/range/utils/hashBlocks.ts +++ b/packages/beacon-node/src/sync/range/utils/hashBlocks.ts @@ -1,5 +1,5 @@ -import {RootHex} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; +import {RootHex} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {BlockInput} from "../../../chain/blocks/types.js"; diff --git a/packages/beacon-node/src/sync/sync.ts b/packages/beacon-node/src/sync/sync.ts index 94eea73e1ef8..1a4121f4b9f1 100644 --- a/packages/beacon-node/src/sync/sync.ts +++ b/packages/beacon-node/src/sync/sync.ts @@ -1,20 +1,20 @@ -import {Logger} from "@lodestar/utils"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {Slot} from "@lodestar/types"; -import {INetwork, NetworkEvent, NetworkEventData} from "../network/index.js"; -import {isOptimisticBlock} from "../util/forkChoice.js"; -import {Metrics} from "../metrics/index.js"; +import {Logger} from "@lodestar/utils"; import {IBeaconChain} from "../chain/index.js"; -import {ClockEvent} from "../util/clock.js"; import {GENESIS_SLOT} from "../constants/constants.js"; import {ExecutionEngineState} from "../execution/index.js"; -import {IBeaconSync, SyncModules, SyncingStatus} from "./interface.js"; -import {RangeSync, RangeSyncStatus, RangeSyncEvent} from "./range/range.js"; -import {getPeerSyncType, PeerSyncType, peerSyncTypes} from "./utils/remoteSyncType.js"; +import {Metrics} from "../metrics/index.js"; +import {INetwork, NetworkEvent, NetworkEventData} from "../network/index.js"; +import {ClockEvent} from "../util/clock.js"; +import {isOptimisticBlock} from "../util/forkChoice.js"; import {MIN_EPOCH_TO_START_GOSSIP} from "./constants.js"; -import {SyncState, SyncChainDebugState, syncStateMetric} from "./interface.js"; +import {IBeaconSync, SyncModules, SyncingStatus} from "./interface.js"; +import {SyncChainDebugState, SyncState, syncStateMetric} from "./interface.js"; import {SyncOptions} from "./options.js"; +import {RangeSync, RangeSyncEvent, RangeSyncStatus} from "./range/range.js"; import {UnknownBlockSync} from "./unknownBlock.js"; +import {PeerSyncType, getPeerSyncType, peerSyncTypes} from "./utils/remoteSyncType.js"; export class BeaconSync implements IBeaconSync { private readonly logger: Logger; diff --git a/packages/beacon-node/src/sync/unknownBlock.ts b/packages/beacon-node/src/sync/unknownBlock.ts index 003b035a898d..c9652dc6ecd2 100644 --- a/packages/beacon-node/src/sync/unknownBlock.ts +++ b/packages/beacon-node/src/sync/unknownBlock.ts @@ -1,24 +1,24 @@ import {ChainForkConfig} from "@lodestar/config"; -import {Logger, fromHex, pruneSetToMax, toRootHex} from "@lodestar/utils"; -import {Root, RootHex, deneb} from "@lodestar/types"; import {INTERVALS_PER_SLOT} from "@lodestar/params"; +import {Root, RootHex, deneb} from "@lodestar/types"; +import {Logger, fromHex, pruneSetToMax, toRootHex} from "@lodestar/utils"; import {sleep} from "@lodestar/utils"; -import {INetwork, NetworkEvent, NetworkEventData, PeerAction} from "../network/index.js"; -import {PeerIdStr} from "../util/peerId.js"; -import {IBeaconChain} from "../chain/index.js"; import {BlockInput, BlockInputType, NullBlockInput} from "../chain/blocks/types.js"; -import {Metrics} from "../metrics/index.js"; -import {shuffle} from "../util/shuffle.js"; -import {byteArrayEquals} from "../util/bytes.js"; import {BlockError, BlockErrorCode} from "../chain/errors/index.js"; +import {IBeaconChain} from "../chain/index.js"; +import {Metrics} from "../metrics/index.js"; +import {INetwork, NetworkEvent, NetworkEventData, PeerAction} from "../network/index.js"; import { beaconBlocksMaybeBlobsByRoot, unavailableBeaconBlobsByRoot, } from "../network/reqresp/beaconBlocksMaybeBlobsByRoot.js"; +import {byteArrayEquals} from "../util/bytes.js"; +import {PeerIdStr} from "../util/peerId.js"; +import {shuffle} from "../util/shuffle.js"; import {Result, wrapError} from "../util/wrapError.js"; import {PendingBlock, PendingBlockStatus, PendingBlockType} from "./interface.js"; -import {getDescendantBlocks, getAllDescendantBlocks, getUnknownAndAncestorBlocks} from "./utils/pendingBlocksTree.js"; import {SyncOptions} from "./options.js"; +import {getAllDescendantBlocks, getDescendantBlocks, getUnknownAndAncestorBlocks} from "./utils/pendingBlocksTree.js"; const MAX_ATTEMPTS_PER_BLOCK = 5; const MAX_KNOWN_BAD_BLOCKS = 500; diff --git a/packages/beacon-node/src/sync/utils/pendingBlocksTree.ts b/packages/beacon-node/src/sync/utils/pendingBlocksTree.ts index 0feb15862408..deefba91f366 100644 --- a/packages/beacon-node/src/sync/utils/pendingBlocksTree.ts +++ b/packages/beacon-node/src/sync/utils/pendingBlocksTree.ts @@ -1,5 +1,6 @@ import {RootHex} from "@lodestar/types"; import {MapDef} from "@lodestar/utils"; +import {BlockInputType} from "../../chain/blocks/types.js"; import { DownloadedBlock, PendingBlock, @@ -7,7 +8,6 @@ import { UnknownAndAncestorBlocks, UnknownBlock, } from "../interface.js"; -import {BlockInputType} from "../../chain/blocks/types.js"; export function getAllDescendantBlocks(blockRootHex: RootHex, blocks: Map): PendingBlock[] { // Do one pass over all blocks to index by parent diff --git a/packages/beacon-node/src/sync/utils/remoteSyncType.ts b/packages/beacon-node/src/sync/utils/remoteSyncType.ts index 247269ab409a..16f1481a2a83 100644 --- a/packages/beacon-node/src/sync/utils/remoteSyncType.ts +++ b/packages/beacon-node/src/sync/utils/remoteSyncType.ts @@ -1,6 +1,6 @@ import {IForkChoice} from "@lodestar/fork-choice"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {phase0, Slot} from "@lodestar/types"; +import {Slot, phase0} from "@lodestar/types"; import {ChainTarget} from "../range/utils/index.js"; /** The type of peer relative to our current state */ diff --git a/packages/beacon-node/src/util/blobs.ts b/packages/beacon-node/src/util/blobs.ts index fcc31092464f..56f1ab21aae9 100644 --- a/packages/beacon-node/src/util/blobs.ts +++ b/packages/beacon-node/src/util/blobs.ts @@ -1,9 +1,9 @@ import {digest as sha256Digest} from "@chainsafe/as-sha256"; import {Tree} from "@chainsafe/persistent-merkle-tree"; -import {VERSIONED_HASH_VERSION_KZG, KZG_COMMITMENT_GINDEX0, ForkName, ForkAll} from "@lodestar/params"; -import {deneb, ssz, BeaconBlockBody, SignedBeaconBlock, SSZTypesFor} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; +import {ForkAll, ForkName, KZG_COMMITMENT_GINDEX0, VERSIONED_HASH_VERSION_KZG} from "@lodestar/params"; import {signedBlockToSignedHeader} from "@lodestar/state-transition"; +import {BeaconBlockBody, SSZTypesFor, SignedBeaconBlock, deneb, ssz} from "@lodestar/types"; type VersionHash = Uint8Array; diff --git a/packages/beacon-node/src/util/clock.ts b/packages/beacon-node/src/util/clock.ts index 197d17f38281..36eb6f6f7f2c 100644 --- a/packages/beacon-node/src/util/clock.ts +++ b/packages/beacon-node/src/util/clock.ts @@ -1,9 +1,9 @@ import EventEmitter from "node:events"; -import type {StrictEventEmitter} from "strict-event-emitter-types"; -import type {Epoch, Slot} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; -import {ErrorAborted} from "@lodestar/utils"; import {computeEpochAtSlot, computeTimeAtSlot, getCurrentSlot} from "@lodestar/state-transition"; +import type {Epoch, Slot} from "@lodestar/types"; +import {ErrorAborted} from "@lodestar/utils"; +import type {StrictEventEmitter} from "strict-event-emitter-types"; import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../constants/constants.js"; export enum ClockEvent { diff --git a/packages/beacon-node/src/util/kzg.ts b/packages/beacon-node/src/util/kzg.ts index 42224d1ebaa6..36a7d19f8d2b 100644 --- a/packages/beacon-node/src/util/kzg.ts +++ b/packages/beacon-node/src/util/kzg.ts @@ -1,5 +1,5 @@ -import path from "node:path"; import fs from "node:fs"; +import path from "node:path"; import {fileURLToPath} from "node:url"; import {fromHex, toHex} from "@lodestar/utils"; diff --git a/packages/beacon-node/src/util/multifork.ts b/packages/beacon-node/src/util/multifork.ts index 0a00677afadf..952498c5a4d1 100644 --- a/packages/beacon-node/src/util/multifork.ts +++ b/packages/beacon-node/src/util/multifork.ts @@ -1,7 +1,7 @@ import {ChainForkConfig} from "@lodestar/config"; +import {ForkAll, ForkLightClient} from "@lodestar/params"; import {SSZTypesFor, Slot} from "@lodestar/types"; import {bytesToInt} from "@lodestar/utils"; -import {ForkAll, ForkLightClient} from "@lodestar/params"; import {getSlotFromSignedBeaconBlockSerialized} from "./sszBytes.js"; /** diff --git a/packages/beacon-node/src/util/peerId.ts b/packages/beacon-node/src/util/peerId.ts index 2afb9bed390e..6fee7db855da 100644 --- a/packages/beacon-node/src/util/peerId.ts +++ b/packages/beacon-node/src/util/peerId.ts @@ -1,6 +1,6 @@ import {PeerId} from "@libp2p/interface"; -import {base58btc} from "multiformats/bases/base58"; import {peerIdFromString} from "@libp2p/peer-id"; +import {base58btc} from "multiformats/bases/base58"; // Ensure consistent serialization of PeerId to string diff --git a/packages/beacon-node/src/util/queue/fnQueue.ts b/packages/beacon-node/src/util/queue/fnQueue.ts index 80e179f8e8f3..1e4f68b7b9b6 100644 --- a/packages/beacon-node/src/util/queue/fnQueue.ts +++ b/packages/beacon-node/src/util/queue/fnQueue.ts @@ -1,5 +1,5 @@ import {JobItemQueue} from "./itemQueue.js"; -import {QueueMetrics, JobQueueOpts} from "./options.js"; +import {JobQueueOpts, QueueMetrics} from "./options.js"; // biome-ignore lint/suspicious/noExplicitAny: type Fn = (...args: any) => Promise; diff --git a/packages/beacon-node/src/util/queue/itemQueue.ts b/packages/beacon-node/src/util/queue/itemQueue.ts index f380a15f5eaf..8713340ec9a4 100644 --- a/packages/beacon-node/src/util/queue/itemQueue.ts +++ b/packages/beacon-node/src/util/queue/itemQueue.ts @@ -1,7 +1,7 @@ -import {LinkedList} from "../array.js"; import {callInNextEventLoop, nextEventLoop} from "../../util/eventLoop.js"; +import {LinkedList} from "../array.js"; import {QueueError, QueueErrorCode} from "./errors.js"; -import {defaultQueueOpts, QueueMetrics, JobQueueOpts, QueueType} from "./options.js"; +import {JobQueueOpts, QueueMetrics, QueueType, defaultQueueOpts} from "./options.js"; /** * JobQueue that stores arguments in the job array instead of closures. diff --git a/packages/beacon-node/src/util/sszBytes.ts b/packages/beacon-node/src/util/sszBytes.ts index c27df1a0fbf3..cb80d5d1bb4b 100644 --- a/packages/beacon-node/src/util/sszBytes.ts +++ b/packages/beacon-node/src/util/sszBytes.ts @@ -1,5 +1,4 @@ import {BitArray, deserializeUint8ArrayBitListFromBytes} from "@chainsafe/ssz"; -import {BLSSignature, RootHex, Slot} from "@lodestar/types"; import { BYTES_PER_FIELD_ELEMENT, FIELD_ELEMENTS_PER_BLOB, @@ -7,6 +6,7 @@ import { ForkSeq, MAX_COMMITTEES_PER_SLOT, } from "@lodestar/params"; +import {BLSSignature, RootHex, Slot} from "@lodestar/types"; export type BlockRootHex = RootHex; // pre-electra, AttestationData is used to cache attestations diff --git a/packages/beacon-node/test/e2e/api/impl/beacon/block/endpoint.test.ts b/packages/beacon-node/test/e2e/api/impl/beacon/block/endpoint.test.ts index b8939b54c294..16a3dd0c80b0 100644 --- a/packages/beacon-node/test/e2e/api/impl/beacon/block/endpoint.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/beacon/block/endpoint.test.ts @@ -1,6 +1,6 @@ -import {describe, beforeAll, afterAll, it, expect, vi} from "vitest"; -import {createBeaconConfig} from "@lodestar/config"; import {ApiClient, WireFormat, getClient} from "@lodestar/api"; +import {createBeaconConfig} from "@lodestar/config"; +import {ForkName} from "@lodestar/params"; import { SignedBeaconBlock, SignedBlindedBeaconBlock, @@ -8,11 +8,11 @@ import { isExecutionPayload, isExecutionPayloadHeader, } from "@lodestar/types"; -import {ForkName} from "@lodestar/params"; -import {LogLevel, testLogger} from "../../../../../utils/logger.js"; -import {getDevBeaconNode} from "../../../../../utils/node/beacon.js"; +import {afterAll, beforeAll, describe, expect, it, vi} from "vitest"; import {BeaconNode} from "../../../../../../src/node/nodejs.js"; import {getConfig} from "../../../../../utils/config.js"; +import {LogLevel, testLogger} from "../../../../../utils/logger.js"; +import {getDevBeaconNode} from "../../../../../utils/node/beacon.js"; describe("beacon block api", () => { vi.setConfig({testTimeout: 60_000, hookTimeout: 60_000}); diff --git a/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts b/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts index 6dc01870a844..18747fd2f735 100644 --- a/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/beacon/node/endpoints.test.ts @@ -1,12 +1,12 @@ -import {describe, beforeAll, afterAll, it, expect, vi} from "vitest"; -import {createBeaconConfig} from "@lodestar/config"; -import {chainConfig as chainConfigDef} from "@lodestar/config/default"; import {routes} from "@lodestar/api"; import {ApiClient, getClient} from "@lodestar/api/beacon"; +import {createBeaconConfig} from "@lodestar/config"; +import {chainConfig as chainConfigDef} from "@lodestar/config/default"; import {sleep} from "@lodestar/utils"; +import {afterAll, beforeAll, describe, expect, it, vi} from "vitest"; +import {BeaconNode} from "../../../../../../src/node/nodejs.js"; import {LogLevel, testLogger} from "../../../../../utils/logger.js"; import {getDevBeaconNode} from "../../../../../utils/node/beacon.js"; -import {BeaconNode} from "../../../../../../src/node/nodejs.js"; import {getAndInitDevValidators} from "../../../../../utils/node/validator.js"; describe("beacon node api", () => { diff --git a/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts b/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts index d8c87a3ba6b8..1b2c6b902f20 100644 --- a/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts @@ -1,12 +1,12 @@ -import {describe, beforeAll, afterAll, it, expect} from "vitest"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ApiClient, getClient} from "@lodestar/api"; import {createBeaconConfig} from "@lodestar/config"; import {chainConfig as chainConfigDef} from "@lodestar/config/default"; -import {ApiClient, getClient} from "@lodestar/api"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {computeCommitteeCount} from "@lodestar/state-transition"; +import {afterAll, beforeAll, describe, expect, it} from "vitest"; +import {BeaconNode} from "../../../../../../src/node/nodejs.js"; import {LogLevel, testLogger} from "../../../../../utils/logger.js"; import {getDevBeaconNode} from "../../../../../utils/node/beacon.js"; -import {BeaconNode} from "../../../../../../src/node/nodejs.js"; describe("beacon state api", () => { const restPort = 9596; diff --git a/packages/beacon-node/test/e2e/api/impl/config.test.ts b/packages/beacon-node/test/e2e/api/impl/config.test.ts index 3ffdbc4beb21..a878d41a36f0 100644 --- a/packages/beacon-node/test/e2e/api/impl/config.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/config.test.ts @@ -1,9 +1,9 @@ -import {describe, it} from "vitest"; import {fetch} from "@lodestar/api"; -import {ForkName, activePreset} from "@lodestar/params"; import {chainConfig} from "@lodestar/config/default"; -import {ethereumConsensusSpecsTests} from "../../../spec/specTestVersioning.js"; +import {ForkName, activePreset} from "@lodestar/params"; +import {describe, it} from "vitest"; import {specConstants} from "../../../../src/api/impl/config/constants.js"; +import {ethereumConsensusSpecsTests} from "../../../spec/specTestVersioning.js"; const CONSTANT_NAMES_SKIP_LIST = new Set([ // This constant is an array, so it's skipped due to not being just a string. diff --git a/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts b/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts index effbed19fc2c..a836024aab01 100644 --- a/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts @@ -1,17 +1,17 @@ -import {describe, it, beforeEach, afterEach, expect} from "vitest"; import {aggregateSerializedPublicKeys} from "@chainsafe/blst"; -import {createBeaconConfig, ChainConfig} from "@lodestar/config"; +import {HttpHeader, getClient, routes} from "@lodestar/api"; +import {ChainConfig, createBeaconConfig} from "@lodestar/config"; import {chainConfig as chainConfigDef} from "@lodestar/config/default"; -import {getClient, HttpHeader, routes} from "@lodestar/api"; -import {sleep} from "@lodestar/utils"; import {ForkName, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; -import {Validator} from "@lodestar/validator"; import {phase0, ssz} from "@lodestar/types"; -import {LogLevel, testLogger, TestLoggerOpts} from "../../../../utils/logger.js"; -import {getDevBeaconNode} from "../../../../utils/node/beacon.js"; -import {getAndInitDevValidators} from "../../../../utils/node/validator.js"; +import {sleep} from "@lodestar/utils"; +import {Validator} from "@lodestar/validator"; +import {afterEach, beforeEach, describe, expect, it} from "vitest"; import {BeaconNode} from "../../../../../src/node/nodejs.js"; import {waitForEvent} from "../../../../utils/events/resolver.js"; +import {LogLevel, TestLoggerOpts, testLogger} from "../../../../utils/logger.js"; +import {getDevBeaconNode} from "../../../../utils/node/beacon.js"; +import {getAndInitDevValidators} from "../../../../utils/node/validator.js"; describe("lightclient api", () => { const SECONDS_PER_SLOT = 1; diff --git a/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts b/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts index bc847b47e9a9..7501460779f3 100644 --- a/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts +++ b/packages/beacon-node/test/e2e/api/lodestar/lodestar.test.ts @@ -1,14 +1,14 @@ -import {describe, it, afterEach, expect, vi} from "vitest"; -import {createBeaconConfig, ChainConfig} from "@lodestar/config"; +import {getClient} from "@lodestar/api"; +import {ChainConfig, createBeaconConfig} from "@lodestar/config"; import {chainConfig as chainConfigDef} from "@lodestar/config/default"; -import {phase0} from "@lodestar/types"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {getClient} from "@lodestar/api"; -import {LogLevel, testLogger, TestLoggerOpts} from "../../../utils/logger.js"; -import {getDevBeaconNode} from "../../../utils/node/beacon.js"; -import {waitForEvent} from "../../../utils/events/resolver.js"; -import {ClockEvent} from "../../../../src/util/clock.js"; +import {phase0} from "@lodestar/types"; +import {afterEach, describe, expect, it, vi} from "vitest"; import {BeaconNode} from "../../../../src/index.js"; +import {ClockEvent} from "../../../../src/util/clock.js"; +import {waitForEvent} from "../../../utils/events/resolver.js"; +import {LogLevel, TestLoggerOpts, testLogger} from "../../../utils/logger.js"; +import {getDevBeaconNode} from "../../../utils/node/beacon.js"; describe("api / impl / validator", () => { vi.setConfig({testTimeout: 60_000}); diff --git a/packages/beacon-node/test/e2e/chain/bls/multithread.test.ts b/packages/beacon-node/test/e2e/chain/bls/multithread.test.ts index a544b3231e87..f8c3a47fb824 100644 --- a/packages/beacon-node/test/e2e/chain/bls/multithread.test.ts +++ b/packages/beacon-node/test/e2e/chain/bls/multithread.test.ts @@ -1,9 +1,9 @@ -import {describe, it, beforeAll, expect, beforeEach, afterEach} from "vitest"; import {PublicKey, SecretKey} from "@chainsafe/blst"; import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition"; +import {afterEach, beforeAll, beforeEach, describe, expect, it} from "vitest"; +import {VerifySignatureOpts} from "../../../../src/chain/bls/interface.js"; import {BlsMultiThreadWorkerPool} from "../../../../src/chain/bls/multithread/index.js"; import {testLogger} from "../../../utils/logger.js"; -import {VerifySignatureOpts} from "../../../../src/chain/bls/interface.js"; describe("chain / bls / multithread queue", () => { const logger = testLogger(); diff --git a/packages/beacon-node/test/e2e/chain/lightclient.test.ts b/packages/beacon-node/test/e2e/chain/lightclient.test.ts index ed698f2844a1..2fc983b8d488 100644 --- a/packages/beacon-node/test/e2e/chain/lightclient.test.ts +++ b/packages/beacon-node/test/e2e/chain/lightclient.test.ts @@ -1,18 +1,18 @@ -import {describe, it, expect, afterEach, vi} from "vitest"; -import {JsonPath, toHexString, fromHexString} from "@chainsafe/ssz"; import {CompactMultiProof, computeDescriptor} from "@chainsafe/persistent-merkle-tree"; +import {JsonPath, fromHexString, toHexString} from "@chainsafe/ssz"; +import {ApiClient, getClient, routes} from "@lodestar/api"; import {ChainConfig} from "@lodestar/config"; -import {ssz, altair} from "@lodestar/types"; +import {Lightclient} from "@lodestar/light-client"; +import {LightClientRestTransport} from "@lodestar/light-client/transport"; import {TimestampFormatCode} from "@lodestar/logger"; import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {Lightclient} from "@lodestar/light-client"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {LightClientRestTransport} from "@lodestar/light-client/transport"; -import {ApiClient, getClient, routes} from "@lodestar/api"; -import {testLogger, LogLevel, TestLoggerOpts} from "../../utils/logger.js"; +import {altair, ssz} from "@lodestar/types"; +import {afterEach, describe, expect, it, vi} from "vitest"; +import {HeadEventData} from "../../../src/chain/index.js"; +import {LogLevel, TestLoggerOpts, testLogger} from "../../utils/logger.js"; import {getDevBeaconNode} from "../../utils/node/beacon.js"; import {getAndInitDevValidators} from "../../utils/node/validator.js"; -import {HeadEventData} from "../../../src/chain/index.js"; describe("chain / lightclient", () => { vi.setConfig({testTimeout: 600_000}); diff --git a/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts b/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts index fd6af72ad6cb..70f2d87e2456 100644 --- a/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts +++ b/packages/beacon-node/test/e2e/chain/proposerBoostReorg.test.ts @@ -1,16 +1,16 @@ -import {describe, it, afterEach, expect, vi} from "vitest"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {TimestampFormatCode} from "@lodestar/logger"; +import {routes} from "@lodestar/api"; import {ChainConfig} from "@lodestar/config"; +import {TimestampFormatCode} from "@lodestar/logger"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {RootHex, Slot} from "@lodestar/types"; -import {routes} from "@lodestar/api"; import {toHexString} from "@lodestar/utils"; +import {afterEach, describe, expect, it, vi} from "vitest"; +import {ReorgEventData} from "../../../src/chain/emitter.js"; +import {TimelinessForkChoice} from "../../mocks/fork-choice/timeliness.js"; +import {waitForEvent} from "../../utils/events/resolver.js"; import {LogLevel, TestLoggerOpts, testLogger} from "../../utils/logger.js"; import {getDevBeaconNode} from "../../utils/node/beacon.js"; -import {TimelinessForkChoice} from "../../mocks/fork-choice/timeliness.js"; import {getAndInitDevValidators} from "../../utils/node/validator.js"; -import {waitForEvent} from "../../utils/events/resolver.js"; -import {ReorgEventData} from "../../../src/chain/emitter.js"; describe("proposer boost reorg", () => { vi.setConfig({testTimeout: 60000}); diff --git a/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts b/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts index fcac715e1719..875e3fe13b03 100644 --- a/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts +++ b/packages/beacon-node/test/e2e/chain/stateCache/nHistoricalStates.test.ts @@ -1,18 +1,18 @@ -import {describe, it, afterEach, expect, vi} from "vitest"; -import {Gauge, Histogram} from "prom-client"; +import {routes} from "@lodestar/api"; import {ChainConfig} from "@lodestar/config"; -import {Slot, phase0} from "@lodestar/types"; import {TimestampFormatCode} from "@lodestar/logger"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {routes} from "@lodestar/api"; -import {LogLevel, TestLoggerOpts, testLogger} from "../../../utils/logger.js"; -import {getDevBeaconNode} from "../../../utils/node/beacon.js"; -import {getAndInitDevValidators} from "../../../utils/node/validator.js"; -import {waitForEvent} from "../../../utils/events/resolver.js"; +import {Slot, phase0} from "@lodestar/types"; +import {Gauge, Histogram} from "prom-client"; +import {afterEach, describe, expect, it, vi} from "vitest"; import {ChainEvent, ReorgEventData} from "../../../../src/chain/emitter.js"; -import {connect, onPeerConnect} from "../../../utils/network.js"; import {CacheItemType} from "../../../../src/chain/stateCache/types.js"; import {ReorgedForkChoice} from "../../../mocks/fork-choice/reorg.js"; +import {waitForEvent} from "../../../utils/events/resolver.js"; +import {LogLevel, TestLoggerOpts, testLogger} from "../../../utils/logger.js"; +import {connect, onPeerConnect} from "../../../utils/network.js"; +import {getDevBeaconNode} from "../../../utils/node/beacon.js"; +import {getAndInitDevValidators} from "../../../utils/node/validator.js"; /** * Test different reorg scenarios to make sure the StateCache implementations are correct. diff --git a/packages/beacon-node/test/e2e/db/api/beacon/repositories/blockArchive.test.ts b/packages/beacon-node/test/e2e/db/api/beacon/repositories/blockArchive.test.ts index 3c7a37e52a8b..a08be8922d2a 100644 --- a/packages/beacon-node/test/e2e/db/api/beacon/repositories/blockArchive.test.ts +++ b/packages/beacon-node/test/e2e/db/api/beacon/repositories/blockArchive.test.ts @@ -1,6 +1,6 @@ -import {beforeAll, afterAll, describe, it, expect} from "vitest"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; +import {afterAll, beforeAll, describe, expect, it} from "vitest"; import {BeaconDb} from "../../../../../../src/db/index.js"; import {startTmpBeaconDb} from "../../../../../utils/db.js"; diff --git a/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts b/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts index 949d0104d641..c83a2896530c 100644 --- a/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts +++ b/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts @@ -1,18 +1,18 @@ -import {describe, afterEach, it, expect} from "vitest"; import {fromHexString} from "@chainsafe/ssz"; import {routes} from "@lodestar/api/beacon"; -import {BLSPubkey, Epoch, phase0, Slot, ssz} from "@lodestar/types"; import {ChainConfig} from "@lodestar/config"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {BLSPubkey, Epoch, Slot, phase0, ssz} from "@lodestar/types"; import {Validator} from "@lodestar/validator"; import {PubkeyHex} from "@lodestar/validator/src/types"; -import {getAndInitDevValidators} from "../../utils/node/validator.js"; +import {afterEach, describe, expect, it} from "vitest"; +import {BeaconNode} from "../../../src/node/index.js"; import {ClockEvent} from "../../../src/util/clock.js"; +import {waitForEvent} from "../../utils/events/resolver.js"; +import {LogLevel, TestLoggerOpts, testLogger} from "../../utils/logger.js"; import {connect} from "../../utils/network.js"; -import {testLogger, LogLevel, TestLoggerOpts} from "../../utils/logger.js"; import {getDevBeaconNode} from "../../utils/node/beacon.js"; -import {waitForEvent} from "../../utils/events/resolver.js"; -import {BeaconNode} from "../../../src/node/index.js"; +import {getAndInitDevValidators} from "../../utils/node/validator.js"; // TODO: Reconsider this tests latter. // Doppelganger testing can be split in two items: diff --git a/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts b/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts index 21cadeb55d2c..f72be5ed3e94 100644 --- a/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts +++ b/packages/beacon-node/test/e2e/eth1/eth1ForBlockProduction.test.ts @@ -1,18 +1,18 @@ -import {describe, it, beforeAll, afterAll, expect} from "vitest"; import {fromHexString, toHexString} from "@chainsafe/ssz"; -import {sleep} from "@lodestar/utils"; import {LevelDbController} from "@lodestar/db"; +import {sleep} from "@lodestar/utils"; +import {afterAll, beforeAll, describe, expect, it} from "vitest"; import {ssz} from "@lodestar/types"; +import {BeaconDb} from "../../../src/db/index.js"; import {Eth1ForBlockProduction} from "../../../src/eth1/index.js"; import {Eth1Options} from "../../../src/eth1/options.js"; -import {getTestnetConfig, medallaTestnetConfig} from "../../utils/testnet.js"; -import {testLogger} from "../../utils/logger.js"; -import {BeaconDb} from "../../../src/db/index.js"; -import {generateState} from "../../utils/state.js"; import {Eth1Provider} from "../../../src/eth1/provider/eth1Provider.js"; import {getGoerliRpcUrl} from "../../testParams.js"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; +import {testLogger} from "../../utils/logger.js"; +import {generateState} from "../../utils/state.js"; +import {getTestnetConfig, medallaTestnetConfig} from "../../utils/testnet.js"; const dbLocation = "./.__testdb"; diff --git a/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts b/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts index 9423bb716b3f..79ff059e2b82 100644 --- a/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts +++ b/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts @@ -1,14 +1,14 @@ -import {describe, it, beforeAll, expect, beforeEach, afterEach} from "vitest"; import {fromHexString} from "@chainsafe/ssz"; import {ChainConfig} from "@lodestar/config"; import {sleep} from "@lodestar/utils"; -import {Eth1Provider, IEth1Provider} from "../../../src/index.js"; +import {afterEach, beforeAll, beforeEach, describe, expect, it} from "vitest"; +import {ZERO_HASH} from "../../../src/constants/index.js"; import {Eth1MergeBlockTracker, StatusCode} from "../../../src/eth1/eth1MergeBlockTracker.js"; import {Eth1Options} from "../../../src/eth1/options.js"; -import {testLogger} from "../../utils/logger.js"; import {quantityToBigint} from "../../../src/eth1/provider/utils.js"; -import {ZERO_HASH} from "../../../src/constants/index.js"; +import {Eth1Provider, IEth1Provider} from "../../../src/index.js"; import {getGoerliRpcUrl} from "../../testParams.js"; +import {testLogger} from "../../utils/logger.js"; // This test is constantly failing. We must unblock PR so this issue is a TODO to debug it and re-enable latter. // It's OKAY to disable temporarily since this functionality is tested indirectly by the sim merge tests. diff --git a/packages/beacon-node/test/e2e/eth1/eth1Provider.test.ts b/packages/beacon-node/test/e2e/eth1/eth1Provider.test.ts index 606845f40337..d571a695c648 100644 --- a/packages/beacon-node/test/e2e/eth1/eth1Provider.test.ts +++ b/packages/beacon-node/test/e2e/eth1/eth1Provider.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect, beforeEach, afterEach} from "vitest"; import {fromHexString} from "@chainsafe/ssz"; +import {afterEach, beforeEach, describe, expect, it} from "vitest"; +import {Eth1Block} from "../../../src/eth1/interface.js"; import {Eth1Options} from "../../../src/eth1/options.js"; -import {getTestnetConfig} from "../../utils/testnet.js"; -import {goerliTestnetDepositEvents} from "../../utils/testnet.js"; import {Eth1Provider, parseEth1Block} from "../../../src/eth1/provider/eth1Provider.js"; -import {Eth1Block} from "../../../src/eth1/interface.js"; import {getGoerliRpcUrl} from "../../testParams.js"; +import {getTestnetConfig} from "../../utils/testnet.js"; +import {goerliTestnetDepositEvents} from "../../utils/testnet.js"; // https://github.com/ChainSafe/lodestar/issues/5967 describe.skip("eth1 / Eth1Provider", () => { diff --git a/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts b/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts index 91131a89f379..ee2476549737 100644 --- a/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts +++ b/packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts @@ -1,11 +1,11 @@ import crypto from "node:crypto"; import http from "node:http"; -import {describe, it, expect, afterEach, vi} from "vitest"; import {FetchError} from "@lodestar/api"; import {sleep} from "@lodestar/utils"; +import {afterEach, describe, expect, it, vi} from "vitest"; +import {RpcPayload} from "../../../src/eth1/interface.js"; import {JsonRpcHttpClient} from "../../../src/eth1/provider/jsonRpcHttpClient.js"; import {getGoerliRpcUrl} from "../../testParams.js"; -import {RpcPayload} from "../../../src/eth1/interface.js"; describe("eth1 / jsonRpcHttpClient", () => { vi.setConfig({testTimeout: 10_000}); diff --git a/packages/beacon-node/test/e2e/eth1/stream.test.ts b/packages/beacon-node/test/e2e/eth1/stream.test.ts index ce65d4353f0e..1ec20608cfd7 100644 --- a/packages/beacon-node/test/e2e/eth1/stream.test.ts +++ b/packages/beacon-node/test/e2e/eth1/stream.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect, beforeEach, afterEach} from "vitest"; -import {getTestnetConfig, medallaTestnetConfig} from "../../utils/testnet.js"; -import {getDepositsStream, getDepositsAndBlockStreamForGenesis} from "../../../src/eth1/stream.js"; +import {afterEach, beforeEach, describe, expect, it} from "vitest"; +import {Eth1Options} from "../../../src/eth1/options.js"; import {Eth1Provider} from "../../../src/eth1/provider/eth1Provider.js"; +import {getDepositsAndBlockStreamForGenesis, getDepositsStream} from "../../../src/eth1/stream.js"; import {getGoerliRpcUrl} from "../../testParams.js"; -import {Eth1Options} from "../../../src/eth1/options.js"; +import {getTestnetConfig, medallaTestnetConfig} from "../../utils/testnet.js"; // https://github.com/ChainSafe/lodestar/issues/5967 describe.skip("Eth1 streams", () => { diff --git a/packages/beacon-node/test/e2e/interop/genesisState.test.ts b/packages/beacon-node/test/e2e/interop/genesisState.test.ts index 739319a4257c..91d67fae91ce 100644 --- a/packages/beacon-node/test/e2e/interop/genesisState.test.ts +++ b/packages/beacon-node/test/e2e/interop/genesisState.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect} from "vitest"; import {toHexString} from "@chainsafe/ssz"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; -import {initDevState} from "../../../src/node/utils/state.js"; +import {describe, expect, it} from "vitest"; import {interopDeposits} from "../../../src/node/utils/interop/deposits.js"; +import {initDevState} from "../../../src/node/utils/state.js"; describe("interop / initDevState", () => { it("Create interop deposits", () => { diff --git a/packages/beacon-node/test/e2e/network/gossipsub.test.ts b/packages/beacon-node/test/e2e/network/gossipsub.test.ts index 29a745455561..e63b26d026db 100644 --- a/packages/beacon-node/test/e2e/network/gossipsub.test.ts +++ b/packages/beacon-node/test/e2e/network/gossipsub.test.ts @@ -1,12 +1,12 @@ -import {describe, it, expect, afterEach, vi} from "vitest"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {sleep} from "@lodestar/utils"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; +import {sleep} from "@lodestar/utils"; +import {afterEach, describe, expect, it, vi} from "vitest"; +import {GossipHandlerParamGeneric, GossipHandlers, GossipType} from "../../../src/network/gossip/index.js"; import {Network} from "../../../src/network/index.js"; -import {GossipType, GossipHandlers, GossipHandlerParamGeneric} from "../../../src/network/gossip/index.js"; -import {getNetworkForTest} from "../../utils/networkWithMockDb.js"; import {connect, onPeerConnect} from "../../utils/network.js"; +import {getNetworkForTest} from "../../utils/networkWithMockDb.js"; describe("gossipsub / main thread", () => { vi.setConfig({testTimeout: 3000}); diff --git a/packages/beacon-node/test/e2e/network/mdns.test.ts b/packages/beacon-node/test/e2e/network/mdns.test.ts index f8b55d8afae7..f1df1f1e94d6 100644 --- a/packages/beacon-node/test/e2e/network/mdns.test.ts +++ b/packages/beacon-node/test/e2e/network/mdns.test.ts @@ -1,21 +1,21 @@ -import {describe, it, afterEach, beforeEach, expect, vi} from "vitest"; +import {SignableENR} from "@chainsafe/enr"; import {PeerId} from "@libp2p/interface"; -import {multiaddr} from "@multiformats/multiaddr"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; -import {SignableENR} from "@chainsafe/enr"; import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; -import {ssz} from "@lodestar/types"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; +import {ssz} from "@lodestar/types"; +import {multiaddr} from "@multiformats/multiaddr"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; +import {GossipHandlers} from "../../../src/network/gossip/index.js"; +import {Network, NetworkInitModules, getReqRespHandlers} from "../../../src/network/index.js"; +import {NetworkOptions, defaultNetworkOptions} from "../../../src/network/options.js"; import {getMockedBeaconChain} from "../../mocks/mockedBeaconChain.js"; import {getMockedBeaconDb} from "../../mocks/mockedBeaconDb.js"; -import {Network, NetworkInitModules, getReqRespHandlers} from "../../../src/network/index.js"; -import {defaultNetworkOptions, NetworkOptions} from "../../../src/network/options.js"; +import {memoOnce} from "../../utils/cache.js"; +import {testLogger} from "../../utils/logger.js"; import {createNetworkModules, onPeerConnect} from "../../utils/network.js"; import {generateState, zeroProtoBlock} from "../../utils/state.js"; -import {testLogger} from "../../utils/logger.js"; -import {GossipHandlers} from "../../../src/network/gossip/index.js"; -import {memoOnce} from "../../utils/cache.js"; let port = 9000; const mu = "/ip4/127.0.0.1/tcp/0"; diff --git a/packages/beacon-node/test/e2e/network/network.test.ts b/packages/beacon-node/test/e2e/network/network.test.ts index 2435b005efa1..fee80d6f48b5 100644 --- a/packages/beacon-node/test/e2e/network/network.test.ts +++ b/packages/beacon-node/test/e2e/network/network.test.ts @@ -1,10 +1,10 @@ -import {describe, it, expect, afterEach, beforeEach, vi} from "vitest"; import {PeerId} from "@libp2p/interface"; import {config} from "@lodestar/config/default"; import {phase0} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; -import {Network, NetworkEvent, ReqRespMethod} from "../../../src/network/index.js"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {GoodByeReasonCode} from "../../../src/constants/index.js"; +import {Network, NetworkEvent, ReqRespMethod} from "../../../src/network/index.js"; import {connect, disconnect, onPeerConnect, onPeerDisconnect} from "../../utils/network.js"; import {getNetworkForTest} from "../../utils/networkWithMockDb.js"; import {getValidPeerId} from "../../utils/peer.js"; 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 12d9e393af09..e4056ca9671e 100644 --- a/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts +++ b/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts @@ -1,12 +1,20 @@ -import {describe, it, beforeAll, afterAll, expect} from "vitest"; -import {TopicValidatorResult} from "@libp2p/interface"; import {BitArray} from "@chainsafe/ssz"; -import {ssz} from "@lodestar/types"; +import {TopicValidatorResult} from "@libp2p/interface"; import {routes} from "@lodestar/api"; import {ForkName} from "@lodestar/params"; -import {getValidPeerId, validPeerIdStr} from "../../../utils/peer.js"; +import {ssz} from "@lodestar/types"; +import {afterAll, beforeAll, describe, expect, it} from "vitest"; +import { + BlockInput, + BlockInputDataBlobs, + BlockInputType, + BlockSource, + CachedData, +} from "../../../../src/chain/blocks/types.js"; +import {ZERO_HASH, ZERO_HASH_HEX} from "../../../../src/constants/constants.js"; import {ReqRespBridgeEventData} from "../../../../src/network/core/events.js"; import {ReqRespBridgeEvent} from "../../../../src/network/core/events.js"; +import {NetworkWorkerApi} from "../../../../src/network/core/index.js"; import { GossipType, NetworkEvent, @@ -15,18 +23,10 @@ import { ReqRespMethod, networkEventDirection, } from "../../../../src/network/index.js"; -import { - BlockInputType, - BlockSource, - BlockInput, - BlockInputDataBlobs, - CachedData, -} from "../../../../src/chain/blocks/types.js"; -import {ZERO_HASH, ZERO_HASH_HEX} from "../../../../src/constants/constants.js"; +import {CommitteeSubscription} from "../../../../src/network/subnets/interface.js"; import {IteratorEventType} from "../../../../src/util/asyncIterableToEvents.js"; -import {NetworkWorkerApi} from "../../../../src/network/core/index.js"; import {EventDirection} from "../../../../src/util/workerEvents.js"; -import {CommitteeSubscription} from "../../../../src/network/subnets/interface.js"; +import {getValidPeerId, validPeerIdStr} from "../../../utils/peer.js"; import {EchoWorker, getEchoWorker} from "./workerEchoHandler.js"; describe("data serialization through worker boundary", () => { diff --git a/packages/beacon-node/test/e2e/network/onWorker/workerEchoHandler.ts b/packages/beacon-node/test/e2e/network/onWorker/workerEchoHandler.ts index b2c0f6b56aa0..f4b5df8189a0 100644 --- a/packages/beacon-node/test/e2e/network/onWorker/workerEchoHandler.ts +++ b/packages/beacon-node/test/e2e/network/onWorker/workerEchoHandler.ts @@ -1,5 +1,5 @@ import workerThreads from "node:worker_threads"; -import {spawn, Worker} from "@chainsafe/threads"; +import {Worker, spawn} from "@chainsafe/threads"; export type EchoWorker = { send(data: T): Promise; diff --git a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts index d0b94399c01d..e0b1e6b357fc 100644 --- a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts +++ b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts @@ -1,24 +1,24 @@ -import {describe, it, afterEach, expect, vi} from "vitest"; +import {BitArray} from "@chainsafe/ssz"; import {Connection} from "@libp2p/interface"; import {CustomEvent} from "@libp2p/interface"; -import {BitArray} from "@chainsafe/ssz"; +import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {altair, phase0, ssz} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; -import {createBeaconConfig} from "@lodestar/config"; -import {ReqRespMethod} from "../../../../src/network/reqresp/ReqRespBeaconNode.js"; -import {PeerRpcScoreStore, PeerManager, IReqRespBeaconNodePeerManager} from "../../../../src/network/peers/index.js"; -import {Eth2Gossipsub, getConnectionsMap, NetworkEvent, NetworkEventBus} from "../../../../src/network/index.js"; +import {afterEach, describe, expect, it, vi} from "vitest"; +import {Eth2Gossipsub, NetworkEvent, NetworkEventBus, getConnectionsMap} from "../../../../src/network/index.js"; +import {IReqRespBeaconNodePeerManager, PeerManager, PeerRpcScoreStore} from "../../../../src/network/peers/index.js"; import {PeersData} from "../../../../src/network/peers/peersData.js"; -import {createNode} from "../../../utils/network.js"; -import {getAttnets, getSyncnets} from "../../../utils/network.js"; -import {generateState} from "../../../utils/state.js"; +import {ReqRespMethod} from "../../../../src/network/reqresp/ReqRespBeaconNode.js"; +import {LocalStatusCache} from "../../../../src/network/statusCache.js"; +import {IAttnetsService} from "../../../../src/network/subnets/index.js"; +import {Clock} from "../../../../src/util/clock.js"; import {waitForEvent} from "../../../utils/events/resolver.js"; import {testLogger} from "../../../utils/logger.js"; +import {createNode} from "../../../utils/network.js"; +import {getAttnets, getSyncnets} from "../../../utils/network.js"; import {getValidPeerId} from "../../../utils/peer.js"; -import {IAttnetsService} from "../../../../src/network/subnets/index.js"; -import {Clock} from "../../../../src/util/clock.js"; -import {LocalStatusCache} from "../../../../src/network/statusCache.js"; +import {generateState} from "../../../utils/state.js"; const logger = testLogger("peerManager"); diff --git a/packages/beacon-node/test/e2e/network/reqresp.test.ts b/packages/beacon-node/test/e2e/network/reqresp.test.ts index b7ab190166e7..854a2a2482ff 100644 --- a/packages/beacon-node/test/e2e/network/reqresp.test.ts +++ b/packages/beacon-node/test/e2e/network/reqresp.test.ts @@ -1,17 +1,17 @@ -import {describe, it, expect, afterEach, beforeEach, vi} from "vitest"; -import {createChainForkConfig, ChainForkConfig} from "@lodestar/config"; +import {ChainForkConfig, createChainForkConfig} from "@lodestar/config"; import {chainConfig} from "@lodestar/config/default"; import {ForkName} from "@lodestar/params"; import {RequestError, RequestErrorCode, ResponseOutgoing} from "@lodestar/reqresp"; -import {altair, phase0, Root, SignedBeaconBlock, ssz} from "@lodestar/types"; +import {Root, SignedBeaconBlock, altair, phase0, ssz} from "@lodestar/types"; import {sleep as _sleep} from "@lodestar/utils"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {Network, ReqRespBeaconNodeOpts} from "../../../src/network/index.js"; +import {GetReqRespHandlerFn, ReqRespMethod} from "../../../src/network/reqresp/types.js"; +import {PeerIdStr} from "../../../src/util/peerId.js"; +import {arrToSource} from "../../unit/network/reqresp/utils.js"; import {expectRejectedWithLodestarError} from "../../utils/errors.js"; import {connect, getPeerIdOf, onPeerConnect} from "../../utils/network.js"; import {getNetworkForTest} from "../../utils/networkWithMockDb.js"; -import {arrToSource} from "../../unit/network/reqresp/utils.js"; -import {GetReqRespHandlerFn, ReqRespMethod} from "../../../src/network/reqresp/types.js"; -import {PeerIdStr} from "../../../src/util/peerId.js"; /* eslint-disable require-yield, @typescript-eslint/naming-convention */ diff --git a/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts b/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts index ae916bdd0ab7..4634870c40fe 100644 --- a/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts +++ b/packages/beacon-node/test/e2e/network/reqrespEncode.test.ts @@ -1,26 +1,26 @@ -import {describe, it, afterEach, expect} from "vitest"; -import all from "it-all"; -import {Libp2p, createLibp2p} from "libp2p"; -import {tcp} from "@libp2p/tcp"; -import {mplex} from "@libp2p/mplex"; -import {Multiaddr, multiaddr} from "@multiformats/multiaddr"; import {noise} from "@chainsafe/libp2p-noise"; -import {ssz} from "@lodestar/types"; +import {mplex} from "@libp2p/mplex"; +import {tcp} from "@libp2p/tcp"; import {createBeaconConfig} from "@lodestar/config"; import {ForkName} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; import {fromHex, sleep, toHex} from "@lodestar/utils"; +import {Multiaddr, multiaddr} from "@multiformats/multiaddr"; +import all from "it-all"; +import {Libp2p, createLibp2p} from "libp2p"; +import {afterEach, describe, expect, it} from "vitest"; +import {ZERO_HASH} from "../../../src/constants/constants.js"; import { NetworkEventBus, PeerRpcScoreStore, ReqRespBeaconNode, ReqRespBeaconNodeModules, } from "../../../src/network/index.js"; -import {PeersData} from "../../../src/network/peers/peersData.js"; -import {ZERO_HASH} from "../../../src/constants/constants.js"; import {MetadataController} from "../../../src/network/metadata.js"; -import {testLogger} from "../../utils/logger.js"; +import {PeersData} from "../../../src/network/peers/peersData.js"; import {GetReqRespHandlerFn} from "../../../src/network/reqresp/types.js"; import {LocalStatusCache} from "../../../src/network/statusCache.js"; +import {testLogger} from "../../utils/logger.js"; /* eslint-disable require-yield */ diff --git a/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts b/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts index ba98f2a1facd..38e3f59adf54 100644 --- a/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts +++ b/packages/beacon-node/test/e2e/sync/finalizedSync.test.ts @@ -1,18 +1,18 @@ -import {describe, it, afterEach, vi} from "vitest"; -import {assert} from "chai"; import {fromHexString} from "@chainsafe/ssz"; +import {routes} from "@lodestar/api"; +import {EventData, EventType} from "@lodestar/api/lib/beacon/routes/events.js"; import {ChainConfig} from "@lodestar/config"; -import {phase0} from "@lodestar/types"; import {TimestampFormatCode} from "@lodestar/logger"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {routes} from "@lodestar/api"; -import {EventData, EventType} from "@lodestar/api/lib/beacon/routes/events.js"; -import {getDevBeaconNode} from "../../utils/node/beacon.js"; -import {waitForEvent} from "../../utils/events/resolver.js"; -import {getAndInitDevValidators} from "../../utils/node/validator.js"; +import {phase0} from "@lodestar/types"; +import {assert} from "chai"; +import {afterEach, describe, it, vi} from "vitest"; import {ChainEvent} from "../../../src/chain/index.js"; +import {waitForEvent} from "../../utils/events/resolver.js"; +import {LogLevel, TestLoggerOpts, testLogger} from "../../utils/logger.js"; import {connect, onPeerConnect} from "../../utils/network.js"; -import {testLogger, LogLevel, TestLoggerOpts} from "../../utils/logger.js"; +import {getDevBeaconNode} from "../../utils/node/beacon.js"; +import {getAndInitDevValidators} from "../../utils/node/validator.js"; describe("sync / finalized sync", () => { // chain is finalized at slot 32, plus 4 slots for genesis delay => ~72s it should sync pretty fast diff --git a/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts b/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts index 290213d2b1ee..28ec0871b275 100644 --- a/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts +++ b/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts @@ -1,21 +1,21 @@ -import {describe, it, afterEach, vi} from "vitest"; import {fromHexString} from "@chainsafe/ssz"; +import {routes} from "@lodestar/api"; +import {EventData, EventType} from "@lodestar/api/lib/beacon/routes/events.js"; import {ChainConfig} from "@lodestar/config"; -import {phase0} from "@lodestar/types"; import {config} from "@lodestar/config/default"; import {TimestampFormatCode} from "@lodestar/logger"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {routes} from "@lodestar/api"; -import {EventData, EventType} from "@lodestar/api/lib/beacon/routes/events.js"; -import {getDevBeaconNode} from "../../utils/node/beacon.js"; -import {waitForEvent} from "../../utils/events/resolver.js"; -import {getAndInitDevValidators} from "../../utils/node/validator.js"; +import {phase0} from "@lodestar/types"; +import {afterEach, describe, it, vi} from "vitest"; +import {BlockSource, getBlockInput} from "../../../src/chain/blocks/types.js"; +import {BlockError, BlockErrorCode} from "../../../src/chain/errors/index.js"; import {ChainEvent} from "../../../src/chain/index.js"; import {NetworkEvent} from "../../../src/network/index.js"; +import {waitForEvent} from "../../utils/events/resolver.js"; +import {LogLevel, TestLoggerOpts, testLogger} from "../../utils/logger.js"; import {connect, onPeerConnect} from "../../utils/network.js"; -import {testLogger, LogLevel, TestLoggerOpts} from "../../utils/logger.js"; -import {BlockError, BlockErrorCode} from "../../../src/chain/errors/index.js"; -import {BlockSource, getBlockInput} from "../../../src/chain/blocks/types.js"; +import {getDevBeaconNode} from "../../utils/node/beacon.js"; +import {getAndInitDevValidators} from "../../utils/node/validator.js"; describe("sync / unknown block sync", () => { vi.setConfig({testTimeout: 40_000}); diff --git a/packages/beacon-node/test/globalSetup.ts b/packages/beacon-node/test/globalSetup.ts index f41a7f249b9b..784633baf2c4 100644 --- a/packages/beacon-node/test/globalSetup.ts +++ b/packages/beacon-node/test/globalSetup.ts @@ -1,4 +1,4 @@ -import {setActivePreset, PresetName} from "@lodestar/params/setPreset"; +import {PresetName, setActivePreset} from "@lodestar/params/setPreset"; export async function setup(): Promise { process.env.NODE_ENV = "test"; diff --git a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts index 1a317a7fe9d3..294dde750865 100644 --- a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts +++ b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts @@ -1,8 +1,8 @@ import crypto from "node:crypto"; +import {toMemoryEfficientHexStr} from "@lodestar/state-transition/src/cache/pubkeyCache.js"; +import {ValidatorIndex} from "@lodestar/types"; // biome-ignore lint/suspicious/noShadowRestrictedNames: We explicitly want `Map` name to be imported import {Map} from "immutable"; -import {ValidatorIndex} from "@lodestar/types"; -import {toMemoryEfficientHexStr} from "@lodestar/state-transition/src/cache/pubkeyCache.js"; import {testRunnerMemory} from "./testRunnerMemory.js"; // Results in MacOS Nov 2023 diff --git a/packages/beacon-node/test/mocks/clock.ts b/packages/beacon-node/test/mocks/clock.ts index 6f09bd292491..dc06fcd6922a 100644 --- a/packages/beacon-node/test/mocks/clock.ts +++ b/packages/beacon-node/test/mocks/clock.ts @@ -1,7 +1,7 @@ import EventEmitter from "node:events"; -import {Mocked, vi} from "vitest"; import {computeEpochAtSlot} from "@lodestar/state-transition"; import {Epoch, Slot} from "@lodestar/types"; +import {Mocked, vi} from "vitest"; import {IClock} from "../../src/util/clock.js"; /** diff --git a/packages/beacon-node/test/mocks/loggerMock.ts b/packages/beacon-node/test/mocks/loggerMock.ts index ee25ede93475..99984ba87e9f 100644 --- a/packages/beacon-node/test/mocks/loggerMock.ts +++ b/packages/beacon-node/test/mocks/loggerMock.ts @@ -1,5 +1,5 @@ -import {vi, Mocked} from "vitest"; import {Logger} from "@lodestar/logger"; +import {Mocked, vi} from "vitest"; export type MockedLogger = Mocked; diff --git a/packages/beacon-node/test/mocks/mockedBeaconChain.ts b/packages/beacon-node/test/mocks/mockedBeaconChain.ts index a69efc55836c..b274284e3ab1 100644 --- a/packages/beacon-node/test/mocks/mockedBeaconChain.ts +++ b/packages/beacon-node/test/mocks/mockedBeaconChain.ts @@ -1,22 +1,22 @@ -import {vi, Mocked, Mock} from "vitest"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; -import {config as defaultConfig} from "@lodestar/config/default"; import {ChainForkConfig} from "@lodestar/config"; -import {ForkChoice, ProtoBlock, EpochDifference} from "@lodestar/fork-choice"; +import {config as defaultConfig} from "@lodestar/config/default"; +import {EpochDifference, ForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {Logger} from "@lodestar/utils"; +import {Mock, Mocked, vi} from "vitest"; +import {BeaconProposerCache} from "../../src/chain/beaconProposerCache.js"; import {BeaconChain} from "../../src/chain/chain.js"; import {ChainEventEmitter} from "../../src/chain/emitter.js"; -import {ExecutionEngineHttp} from "../../src/execution/engine/index.js"; -import {ExecutionBuilderHttp} from "../../src/execution/builder/http.js"; -import {Eth1ForBlockProduction} from "../../src/eth1/index.js"; -import {OpPool, AggregatedAttestationPool} from "../../src/chain/opPools/index.js"; -import {BeaconProposerCache} from "../../src/chain/beaconProposerCache.js"; import {LightClientServer} from "../../src/chain/lightClient/index.js"; -import {Clock} from "../../src/util/clock.js"; +import {AggregatedAttestationPool, OpPool} from "../../src/chain/opPools/index.js"; import {QueuedStateRegenerator} from "../../src/chain/regen/index.js"; import {ShufflingCache} from "../../src/chain/shufflingCache.js"; -import {getMockedLogger} from "./loggerMock.js"; +import {Eth1ForBlockProduction} from "../../src/eth1/index.js"; +import {ExecutionBuilderHttp} from "../../src/execution/builder/http.js"; +import {ExecutionEngineHttp} from "../../src/execution/engine/index.js"; +import {Clock} from "../../src/util/clock.js"; import {getMockedClock} from "./clock.js"; +import {getMockedLogger} from "./loggerMock.js"; export type MockedBeaconChain = Mocked & { logger: Mocked; diff --git a/packages/beacon-node/test/mocks/mockedBeaconDb.ts b/packages/beacon-node/test/mocks/mockedBeaconDb.ts index eb209c9b44fb..87404a8965a6 100644 --- a/packages/beacon-node/test/mocks/mockedBeaconDb.ts +++ b/packages/beacon-node/test/mocks/mockedBeaconDb.ts @@ -1,20 +1,20 @@ -import {vi, Mocked} from "vitest"; import {config as minimalConfig} from "@lodestar/config/default"; +import {Mocked, vi} from "vitest"; +import {BeaconDb} from "../../src/db/index.js"; import { AttesterSlashingRepository, + BLSToExecutionChangeRepository, + BlobSidecarsArchiveRepository, + BlobSidecarsRepository, BlockArchiveRepository, BlockRepository, - DepositEventRepository, DepositDataRootRepository, + DepositEventRepository, Eth1DataRepository, ProposerSlashingRepository, StateArchiveRepository, VoluntaryExitRepository, - BLSToExecutionChangeRepository, - BlobSidecarsRepository, - BlobSidecarsArchiveRepository, } from "../../src/db/repositories/index.js"; -import {BeaconDb} from "../../src/db/index.js"; export type MockedBeaconDb = Mocked & { block: Mocked; diff --git a/packages/beacon-node/test/mocks/mockedNetwork.ts b/packages/beacon-node/test/mocks/mockedNetwork.ts index 9258acc9bc1b..27b9c3deaf79 100644 --- a/packages/beacon-node/test/mocks/mockedNetwork.ts +++ b/packages/beacon-node/test/mocks/mockedNetwork.ts @@ -1,5 +1,5 @@ -import {vi, Mocked} from "vitest"; -import {Network, INetwork} from "../../src/network/index.js"; +import {Mocked, vi} from "vitest"; +import {INetwork, Network} from "../../src/network/index.js"; vi.mock("../../src/network/index.js", async (importActual) => { const mod = await importActual(); diff --git a/packages/beacon-node/test/mocks/regenMocks.ts b/packages/beacon-node/test/mocks/regenMocks.ts index 39f7fa382760..f0be21989e83 100644 --- a/packages/beacon-node/test/mocks/regenMocks.ts +++ b/packages/beacon-node/test/mocks/regenMocks.ts @@ -1,4 +1,4 @@ -import {vi, Mocked} from "vitest"; +import {Mocked, vi} from "vitest"; import {QueuedStateRegenerator} from "../../src/chain/regen/index.js"; export type MockedQueuedStateRegenerator = Mocked; diff --git a/packages/beacon-node/test/mocks/shufflingMock.ts b/packages/beacon-node/test/mocks/shufflingMock.ts index 76482f760872..e13d8d6dce5d 100644 --- a/packages/beacon-node/test/mocks/shufflingMock.ts +++ b/packages/beacon-node/test/mocks/shufflingMock.ts @@ -1,4 +1,4 @@ -import {vi, Mocked} from "vitest"; +import {Mocked, vi} from "vitest"; import {ShufflingCache} from "../../src/chain/shufflingCache.js"; export type MockedShufflingCache = Mocked; diff --git a/packages/beacon-node/test/perf/bls/bls.test.ts b/packages/beacon-node/test/perf/bls/bls.test.ts index 9f1f90a4d879..1c6cde5e20ac 100644 --- a/packages/beacon-node/test/perf/bls/bls.test.ts +++ b/packages/beacon-node/test/perf/bls/bls.test.ts @@ -1,5 +1,4 @@ import crypto from "node:crypto"; -import {itBench} from "@dapplion/benchmark"; import { PublicKey, SecretKey, @@ -9,6 +8,7 @@ import { verify, verifyMultipleAggregateSignatures, } from "@chainsafe/blst"; +import {itBench} from "@dapplion/benchmark"; import {linspace} from "../../../src/util/numpy.js"; describe("BLS ops", () => { diff --git a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts index 89bd76f34eb3..28c1f198da28 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -1,5 +1,7 @@ -import {itBench} from "@dapplion/benchmark"; import {BitArray, toHexString} from "@chainsafe/ssz"; +import {itBench} from "@dapplion/benchmark"; +import {DataAvailabilityStatus, ExecutionStatus, ForkChoice, IForkChoiceStore, ProtoArray} from "@lodestar/fork-choice"; +import {HISTORICAL_ROOTS_LIMIT, SLOTS_PER_EPOCH} from "@lodestar/params"; import { CachedBeaconStateAltair, computeAnchorCheckpoint, @@ -8,8 +10,6 @@ import { getBlockRootAtSlot, newFilledArray, } from "@lodestar/state-transition"; -import {HISTORICAL_ROOTS_LIMIT, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {ExecutionStatus, ForkChoice, IForkChoiceStore, ProtoArray, DataAvailabilityStatus} from "@lodestar/fork-choice"; import {ssz} from "@lodestar/types"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; diff --git a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts index 9d518c03eec9..d685ec36c6b7 100644 --- a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts @@ -8,6 +8,7 @@ import { import {CachedBeaconStateAltair} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; import {generatePerfTestCachedStateAltair} from "../../../../../state-transition/test/perf/util.js"; +import {BlockType} from "../../../../src/chain/interface.js"; import {OpPool} from "../../../../src/chain/opPools/opPool.js"; import {generateBlsToExecutionChanges} from "../../../fixtures/capella.js"; import { @@ -15,7 +16,6 @@ import { generateSignedBeaconBlockHeader, generateVoluntaryExits, } from "../../../fixtures/phase0.js"; -import {BlockType} from "../../../../src/chain/interface.js"; describe("opPool", () => { let originalState: CachedBeaconStateAltair; diff --git a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts index c08cf64fc974..6d411ca09cd5 100644 --- a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts +++ b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts @@ -3,14 +3,14 @@ import {itBench} from "@dapplion/benchmark"; import {config} from "@lodestar/config/default"; import {LevelDbController} from "@lodestar/db"; import {SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY} from "@lodestar/params"; -import {defaultOptions as defaultValidatorOptions} from "@lodestar/validator"; import {CachedBeaconStateAltair} from "@lodestar/state-transition"; +import {defaultOptions as defaultValidatorOptions} from "@lodestar/validator"; import {generatePerfTestCachedStateAltair} from "../../../../../state-transition/test/perf/util.js"; import {BeaconChain} from "../../../../src/chain/index.js"; import {BlockType, produceBlockBody} from "../../../../src/chain/produceBlock/produceBlockBody.js"; import {Eth1ForBlockProductionDisabled} from "../../../../src/eth1/index.js"; import {ExecutionEngineDisabled} from "../../../../src/execution/engine/index.js"; -import {StateArchiveMode, BeaconDb} from "../../../../src/index.js"; +import {BeaconDb, StateArchiveMode} from "../../../../src/index.js"; import {testLogger} from "../../../utils/logger.js"; const logger = testLogger(); diff --git a/packages/beacon-node/test/perf/chain/seenCache/seenAggregateAndProof.test.ts b/packages/beacon-node/test/perf/chain/seenCache/seenAggregateAndProof.test.ts index 49c3123c14dd..b119fccdd562 100644 --- a/packages/beacon-node/test/perf/chain/seenCache/seenAggregateAndProof.test.ts +++ b/packages/beacon-node/test/perf/chain/seenCache/seenAggregateAndProof.test.ts @@ -1,5 +1,5 @@ -import {itBench} from "@dapplion/benchmark"; import {BitArray} from "@chainsafe/ssz"; +import {itBench} from "@dapplion/benchmark"; import {TARGET_AGGREGATORS_PER_COMMITTEE} from "@lodestar/params"; import {SeenAggregatedAttestations} from "../../../../src/chain/seenCache/seenAggregateAndProof.js"; diff --git a/packages/beacon-node/test/perf/chain/stateCache/inMemoryCheckpointsCache.test.ts b/packages/beacon-node/test/perf/chain/stateCache/inMemoryCheckpointsCache.test.ts index 17a46b09af8d..9f3db45cb827 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/inMemoryCheckpointsCache.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/inMemoryCheckpointsCache.test.ts @@ -1,8 +1,8 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; -import {ssz, phase0} from "@lodestar/types"; -import {generateCachedState} from "../../../utils/state.js"; +import {phase0, ssz} from "@lodestar/types"; import {InMemoryCheckpointStateCache, toCheckpointHex} from "../../../../src/chain/stateCache/index.js"; +import {generateCachedState} from "../../../utils/state.js"; describe("InMemoryCheckpointStateCache perf tests", () => { setBenchOpts({noThreshold: true}); diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index a4bdbe9710cb..8009f36c6301 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -1,13 +1,13 @@ -import {itBench, setBenchOpts} from "@dapplion/benchmark"; -import {Map as ImmutableMap} from "immutable"; -import {toBufferBE} from "bigint-buffer"; import {digest} from "@chainsafe/as-sha256"; import {SecretKey} from "@chainsafe/blst"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; -import {ValidatorIndex, ssz} from "@lodestar/types"; +import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {type CachedBeaconStateAllForks, toMemoryEfficientHexStr} from "@lodestar/state-transition"; +import {ValidatorIndex, ssz} from "@lodestar/types"; import {bytesToBigInt, intToBytes} from "@lodestar/utils"; -import {InMemoryCheckpointStateCache, BlockStateCacheImpl} from "../../../../src/chain/stateCache/index.js"; +import {toBufferBE} from "bigint-buffer"; +import {Map as ImmutableMap} from "immutable"; +import {BlockStateCacheImpl, InMemoryCheckpointStateCache} from "../../../../src/chain/stateCache/index.js"; import {BlockStateCache} from "../../../../src/chain/stateCache/types.js"; import {generateCachedElectraState} from "../../../utils/state.js"; diff --git a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts index 696b6bdb1871..4814c59cce9a 100644 --- a/packages/beacon-node/test/perf/chain/validation/attestation.test.ts +++ b/packages/beacon-node/test/perf/chain/validation/attestation.test.ts @@ -1,10 +1,10 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; -import {expect} from "chai"; import {ssz} from "@lodestar/types"; +import {expect} from "chai"; import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../state-transition/test/perf/util.js"; import {validateGossipAttestationsSameAttData} from "../../../../src/chain/validation/index.js"; -import {getAttestationValidData} from "../../../utils/validationData/attestation.js"; import {getAttDataFromAttestationSerialized} from "../../../../src/util/sszBytes.js"; +import {getAttestationValidData} from "../../../utils/validationData/attestation.js"; describe("validate gossip attestation", () => { setBenchOpts({ diff --git a/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts b/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts index 6f1cf2ef3da6..35165aa3c38f 100644 --- a/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts +++ b/packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts @@ -1,19 +1,19 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {config} from "@lodestar/config/default"; -import {SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY, SLOTS_PER_EPOCH} from "@lodestar/params"; import {LevelDbController} from "@lodestar/db"; +import {SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY, SLOTS_PER_EPOCH} from "@lodestar/params"; import {sleep} from "@lodestar/utils"; import {defaultOptions as defaultValidatorOptions} from "@lodestar/validator"; import {rangeSyncTest} from "../../../../state-transition/test/perf/params.js"; -import {getNetworkCachedState, getNetworkCachedBlock} from "../../../../state-transition/test/utils/testFileCache.js"; import {beforeValue} from "../../../../state-transition/test/utils/beforeValueMocha.js"; +import {getNetworkCachedBlock, getNetworkCachedState} from "../../../../state-transition/test/utils/testFileCache.js"; +import {AttestationImportOpt, BlockSource, getBlockInput} from "../../../src/chain/blocks/types.js"; import {BeaconChain} from "../../../src/chain/index.js"; -import {ExecutionEngineDisabled} from "../../../src/execution/engine/index.js"; import {Eth1ForBlockProductionDisabled} from "../../../src/eth1/index.js"; -import {testLogger} from "../../utils/logger.js"; +import {ExecutionEngineDisabled} from "../../../src/execution/engine/index.js"; +import {BeaconDb, StateArchiveMode} from "../../../src/index.js"; import {linspace} from "../../../src/util/numpy.js"; -import {StateArchiveMode, BeaconDb} from "../../../src/index.js"; -import {getBlockInput, AttestationImportOpt, BlockSource} from "../../../src/chain/blocks/types.js"; +import {testLogger} from "../../utils/logger.js"; // Define this params in `packages/state-transition/test/perf/params.ts` // to trigger Github actions CI cache diff --git a/packages/beacon-node/test/perf/eth1/pickEth1Vote.test.ts b/packages/beacon-node/test/perf/eth1/pickEth1Vote.test.ts index 20efeefe0923..dfc5fb560b27 100644 --- a/packages/beacon-node/test/perf/eth1/pickEth1Vote.test.ts +++ b/packages/beacon-node/test/perf/eth1/pickEth1Vote.test.ts @@ -1,7 +1,7 @@ -import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {ContainerType, ListCompositeType} from "@chainsafe/ssz"; +import {itBench, setBenchOpts} from "@dapplion/benchmark"; +import {BeaconStateAllForks, newFilledArray} from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; -import {newFilledArray, BeaconStateAllForks} from "@lodestar/state-transition"; import {fastSerializeEth1Data, pickEth1Vote} from "../../../src/eth1/utils/eth1Vote.js"; describe("eth1 / pickEth1Vote", () => { diff --git a/packages/beacon-node/test/perf/misc/bytesHex.test.ts b/packages/beacon-node/test/perf/misc/bytesHex.test.ts index aa4443a65a61..bb5e2b252960 100644 --- a/packages/beacon-node/test/perf/misc/bytesHex.test.ts +++ b/packages/beacon-node/test/perf/misc/bytesHex.test.ts @@ -1,6 +1,6 @@ import crypto from "node:crypto"; -import {itBench} from "@dapplion/benchmark"; import {toHexString} from "@chainsafe/ssz"; +import {itBench} from "@dapplion/benchmark"; // Results in Linux Dec 2021 // diff --git a/packages/beacon-node/test/perf/network/gossip/fastMsgIdFn.test.ts b/packages/beacon-node/test/perf/network/gossip/fastMsgIdFn.test.ts index 4daeb64f5d79..3b31e38655db 100644 --- a/packages/beacon-node/test/perf/network/gossip/fastMsgIdFn.test.ts +++ b/packages/beacon-node/test/perf/network/gossip/fastMsgIdFn.test.ts @@ -1,7 +1,7 @@ import {randomBytes} from "node:crypto"; -import xxhashFactory from "xxhash-wasm"; -import {itBench} from "@dapplion/benchmark"; import {digest} from "@chainsafe/as-sha256"; +import {itBench} from "@dapplion/benchmark"; +import xxhashFactory from "xxhash-wasm"; const hasher = await xxhashFactory(); diff --git a/packages/beacon-node/test/perf/network/noise/sendData.test.ts b/packages/beacon-node/test/perf/network/noise/sendData.test.ts index 35538a417adf..ee4d734fd5cb 100644 --- a/packages/beacon-node/test/perf/network/noise/sendData.test.ts +++ b/packages/beacon-node/test/perf/network/noise/sendData.test.ts @@ -1,10 +1,10 @@ +import {noise} from "@chainsafe/libp2p-noise"; import {itBench} from "@dapplion/benchmark"; -import {duplexPair} from "it-pair/duplex"; +import {defaultLogger} from "@libp2p/logger"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; -import {pipe} from "it-pipe"; import drain from "it-drain"; -import {defaultLogger} from "@libp2p/logger"; -import {noise} from "@chainsafe/libp2p-noise"; +import {duplexPair} from "it-pair/duplex"; +import {pipe} from "it-pipe"; import {Uint8ArrayList} from "uint8arraylist"; describe("network / noise / sendData", () => { diff --git a/packages/beacon-node/test/perf/network/peers/enrSubnetsDeserialize.test.ts b/packages/beacon-node/test/perf/network/peers/enrSubnetsDeserialize.test.ts index 2507c43bcc9c..ffe22cf5bac5 100644 --- a/packages/beacon-node/test/perf/network/peers/enrSubnetsDeserialize.test.ts +++ b/packages/beacon-node/test/perf/network/peers/enrSubnetsDeserialize.test.ts @@ -1,7 +1,7 @@ import {itBench} from "@dapplion/benchmark"; -import {expect} from "chai"; -import {SYNC_COMMITTEE_SUBNET_COUNT, ATTESTATION_SUBNET_COUNT} from "@lodestar/params"; +import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {ssz} from "@lodestar/types"; +import {expect} from "chai"; import {deserializeEnrSubnets} from "../../../../src/network/peers/utils/enrSubnetsDeserialize.js"; /** diff --git a/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts b/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts index d5a6b4e9cb25..a8d6365be691 100644 --- a/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts +++ b/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts @@ -4,7 +4,7 @@ import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {altair, phase0} from "@lodestar/types"; import {defaultNetworkOptions} from "../../../../../src/network/options.js"; -import {prioritizePeers, RequestedSubnet} from "../../../../../src/network/peers/utils/index.js"; +import {RequestedSubnet, prioritizePeers} from "../../../../../src/network/peers/utils/index.js"; import {getAttnets, getSyncnets} from "../../../../utils/network.js"; describe("prioritizePeers", () => { diff --git a/packages/beacon-node/test/perf/util/bitArray.test.ts b/packages/beacon-node/test/perf/util/bitArray.test.ts index fe421a8f9bd8..fae525def3c4 100644 --- a/packages/beacon-node/test/perf/util/bitArray.test.ts +++ b/packages/beacon-node/test/perf/util/bitArray.test.ts @@ -1,6 +1,6 @@ import crypto from "node:crypto"; -import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {BitArray} from "@chainsafe/ssz"; +import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {intersectUint8Arrays} from "../../../src/util/bitArray.js"; /** diff --git a/packages/beacon-node/test/setupPreset.ts b/packages/beacon-node/test/setupPreset.ts index 968c6e12c668..7d64d1336ed5 100644 --- a/packages/beacon-node/test/setupPreset.ts +++ b/packages/beacon-node/test/setupPreset.ts @@ -1,4 +1,4 @@ -import {setActivePreset, PresetName} from "@lodestar/params/setPreset"; +import {PresetName, setActivePreset} from "@lodestar/params/setPreset"; // Set minimal if (process.env.LODESTAR_PRESET === undefined) { process.env.LODESTAR_PRESET = "minimal"; diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index 20fedd3d4b0f..47b7d127fb42 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -1,29 +1,29 @@ -import fs from "node:fs"; import assert from "node:assert"; -import {describe, it, vi, afterAll, afterEach} from "vitest"; +import fs from "node:fs"; +import {afterAll, afterEach, describe, it, vi} from "vitest"; -import {LogLevel, sleep} from "@lodestar/utils"; import {ForkName, SLOTS_PER_EPOCH, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; -import {electra, Epoch, Slot} from "@lodestar/types"; +import {Epoch, Slot, electra} from "@lodestar/types"; +import {LogLevel, sleep} from "@lodestar/utils"; import {ValidatorProposerConfig} from "@lodestar/validator"; import {ChainConfig} from "@lodestar/config"; import {TimestampFormatCode} from "@lodestar/logger"; import {CachedBeaconStateElectra} from "@lodestar/state-transition"; -import {initializeExecutionEngine} from "../../src/execution/index.js"; import {ExecutionPayloadStatus, PayloadAttributes} from "../../src/execution/engine/interface.js"; +import {initializeExecutionEngine} from "../../src/execution/index.js"; -import {testLogger, TestLoggerOpts} from "../utils/logger.js"; -import {runEL, ELStartMode, ELClient, sendRawTransactionBig} from "../utils/runEl.js"; +import {bytesToData} from "../../lib/eth1/provider/utils.js"; +import {BeaconRestApiServerOpts} from "../../src/api/index.js"; +import {dataToBytes} from "../../src/eth1/provider/utils.js"; import {defaultExecutionEngineHttpOpts} from "../../src/execution/engine/http.js"; +import {BeaconNode} from "../../src/index.js"; +import {ClockEvent} from "../../src/util/clock.js"; +import {TestLoggerOpts, testLogger} from "../utils/logger.js"; import {getDevBeaconNode} from "../utils/node/beacon.js"; -import {BeaconRestApiServerOpts} from "../../src/api/index.js"; import {simTestInfoTracker} from "../utils/node/simTest.js"; import {getAndInitDevValidators} from "../utils/node/validator.js"; -import {ClockEvent} from "../../src/util/clock.js"; -import {dataToBytes} from "../../src/eth1/provider/utils.js"; -import {bytesToData} from "../../lib/eth1/provider/utils.js"; -import {BeaconNode} from "../../src/index.js"; +import {ELClient, ELStartMode, runEL, sendRawTransactionBig} from "../utils/runEl.js"; import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; diff --git a/packages/beacon-node/test/sim/mergemock.test.ts b/packages/beacon-node/test/sim/mergemock.test.ts index 64020b070e11..230856291f64 100644 --- a/packages/beacon-node/test/sim/mergemock.test.ts +++ b/packages/beacon-node/test/sim/mergemock.test.ts @@ -1,23 +1,23 @@ import fs from "node:fs"; -import {describe, it, afterAll, afterEach, vi} from "vitest"; import {fromHexString, toHexString} from "@chainsafe/ssz"; -import {LogLevel, sleep} from "@lodestar/utils"; +import {routes} from "@lodestar/api"; +import {ChainConfig} from "@lodestar/config"; import {TimestampFormatCode} from "@lodestar/logger"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {ChainConfig} from "@lodestar/config"; import {Epoch, SignedBeaconBlock, bellatrix} from "@lodestar/types"; +import {LogLevel, sleep} from "@lodestar/utils"; import {ValidatorProposerConfig} from "@lodestar/validator"; -import {routes} from "@lodestar/api"; +import {afterAll, afterEach, describe, it, vi} from "vitest"; +import {BeaconRestApiServerOpts} from "../../src/api/index.js"; +import {ZERO_HASH} from "../../src/constants/index.js"; +import {Eth1Provider} from "../../src/index.js"; import {ClockEvent} from "../../src/util/clock.js"; -import {testLogger, TestLoggerOpts} from "../utils/logger.js"; +import {TestLoggerOpts, testLogger} from "../utils/logger.js"; import {getDevBeaconNode} from "../utils/node/beacon.js"; -import {BeaconRestApiServerOpts} from "../../src/api/index.js"; import {simTestInfoTracker} from "../utils/node/simTest.js"; import {getAndInitDevValidators} from "../utils/node/validator.js"; -import {Eth1Provider} from "../../src/index.js"; -import {ZERO_HASH} from "../../src/constants/index.js"; -import {runEL, ELStartMode, ELClient} from "../utils/runEl.js"; +import {ELClient, ELStartMode, runEL} from "../utils/runEl.js"; import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; diff --git a/packages/beacon-node/test/spec/bls/bls.ts b/packages/beacon-node/test/spec/bls/bls.ts index 76c511215b61..61c86e69b47e 100644 --- a/packages/beacon-node/test/spec/bls/bls.ts +++ b/packages/beacon-node/test/spec/bls/bls.ts @@ -2,11 +2,11 @@ import { PublicKey, SecretKey, Signature, + verify as _verify, aggregateSignatures, aggregateVerify, fastAggregateVerify, verifyMultipleAggregateSignatures, - verify as _verify, } from "@chainsafe/blst"; import {fromHexString} from "@chainsafe/ssz"; diff --git a/packages/beacon-node/test/spec/bls/index.test.ts b/packages/beacon-node/test/spec/bls/index.test.ts index 32baa00d9fbc..cf1da723698f 100644 --- a/packages/beacon-node/test/spec/bls/index.test.ts +++ b/packages/beacon-node/test/spec/bls/index.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; import jsyaml from "js-yaml"; -import {expect, describe, it} from "vitest"; +import {describe, expect, it} from "vitest"; import {blsSpecTests} from "../specTestVersioning.js"; import {readdirSyncSpec} from "../utils/specTestIterator.js"; import {testFnByType} from "./bls.js"; diff --git a/packages/beacon-node/test/spec/downloadTests.ts b/packages/beacon-node/test/spec/downloadTests.ts index 57efd3ca2183..7790e52ea9e1 100644 --- a/packages/beacon-node/test/spec/downloadTests.ts +++ b/packages/beacon-node/test/spec/downloadTests.ts @@ -1,5 +1,5 @@ import {downloadTests} from "@lodestar/spec-test-util/downloadTests"; -import {ethereumConsensusSpecsTests, blsSpecTests} from "./specTestVersioning.js"; +import {blsSpecTests, ethereumConsensusSpecsTests} from "./specTestVersioning.js"; /* eslint-disable no-console */ diff --git a/packages/beacon-node/test/spec/general/bls.ts b/packages/beacon-node/test/spec/general/bls.ts index 128b5b4f5613..7d4a94481025 100644 --- a/packages/beacon-node/test/spec/general/bls.ts +++ b/packages/beacon-node/test/spec/general/bls.ts @@ -1,14 +1,14 @@ -import {fromHexString} from "@chainsafe/ssz"; import { + aggregateVerify as BLSAggregateVerify, + fastAggregateVerify as BLSFastAggregateVerify, PublicKey, SecretKey, Signature, + verify as _verify, aggregateSerializedPublicKeys, aggregateSignatures, - aggregateVerify as BLSAggregateVerify, - fastAggregateVerify as BLSFastAggregateVerify, - verify as _verify, } from "@chainsafe/blst"; +import {fromHexString} from "@chainsafe/ssz"; import {InputType} from "@lodestar/spec-test-util"; import {TestRunnerFn} from "../utils/types.js"; diff --git a/packages/beacon-node/test/spec/general/index.test.ts b/packages/beacon-node/test/spec/general/index.test.ts index 063f128c3142..c539061d217e 100644 --- a/packages/beacon-node/test/spec/general/index.test.ts +++ b/packages/beacon-node/test/spec/general/index.test.ts @@ -1,7 +1,7 @@ import path from "node:path"; -import {RunnerType} from "../utils/types.js"; -import {SkipOpts, specTestIterator} from "../utils/specTestIterator.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; +import {SkipOpts, specTestIterator} from "../utils/specTestIterator.js"; +import {RunnerType} from "../utils/types.js"; import {blsTestRunner} from "./bls.js"; import {sszGeneric} from "./ssz_generic.js"; diff --git a/packages/beacon-node/test/spec/general/ssz_generic.ts b/packages/beacon-node/test/spec/general/ssz_generic.ts index 64e6b4455941..6cfb7686c9e7 100644 --- a/packages/beacon-node/test/spec/general/ssz_generic.ts +++ b/packages/beacon-node/test/spec/general/ssz_generic.ts @@ -1,9 +1,9 @@ import fs from "node:fs"; import path from "node:path"; import {expect, it} from "vitest"; -import {TestRunnerCustom} from "../utils/types.js"; -import {parseSszGenericInvalidTestcase, parseSszGenericValidTestcase} from "../utils/sszTestCaseParser.js"; import {runValidSszTest} from "../utils/runValidSszTest.js"; +import {parseSszGenericInvalidTestcase, parseSszGenericValidTestcase} from "../utils/sszTestCaseParser.js"; +import {TestRunnerCustom} from "../utils/types.js"; import {getTestType} from "./ssz_generic_types.js"; // Mapping of sszGeneric() fn arguments to the path in spec tests diff --git a/packages/beacon-node/test/spec/general/ssz_generic_types.ts b/packages/beacon-node/test/spec/general/ssz_generic_types.ts index fe19f08149b4..2386f770fe60 100644 --- a/packages/beacon-node/test/spec/general/ssz_generic_types.ts +++ b/packages/beacon-node/test/spec/general/ssz_generic_types.ts @@ -1,12 +1,12 @@ import { - Type, - BooleanType, - UintBigintType, - UintNumberType, - BitVectorType, BitListType, + BitVectorType, + BooleanType, ContainerType, ListBasicType, + Type, + UintBigintType, + UintNumberType, VectorBasicType, VectorCompositeType, } from "@chainsafe/ssz"; diff --git a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts index c61aec40fee3..05ce8c4c70e3 100644 --- a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts +++ b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts @@ -1,22 +1,22 @@ import path from "node:path"; -import {expect} from "vitest"; +import {ACTIVE_PRESET} from "@lodestar/params"; import { + BeaconStateAllForks, CachedBeaconStateAllForks, + CachedBeaconStateAltair, EpochTransitionCache, - BeaconStateAllForks, beforeProcessEpoch, - CachedBeaconStateAltair, } from "@lodestar/state-transition"; import * as epochFns from "@lodestar/state-transition/epoch"; import {ssz} from "@lodestar/types"; -import {ACTIVE_PRESET} from "@lodestar/params"; +import {expect} from "vitest"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; -import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {getConfig} from "../../utils/config.js"; -import {RunnerType, TestRunnerFn} from "../utils/types.js"; import {assertCorrectProgressiveBalances} from "../config.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; +import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {specTestIterator} from "../utils/specTestIterator.js"; +import {RunnerType, TestRunnerFn} from "../utils/types.js"; export type EpochTransitionFn = (state: CachedBeaconStateAllForks, epochTransitionCache: EpochTransitionCache) => void; diff --git a/packages/beacon-node/test/spec/presets/finality.test.ts b/packages/beacon-node/test/spec/presets/finality.test.ts index 1dce91e360e5..a183d7c2197a 100644 --- a/packages/beacon-node/test/spec/presets/finality.test.ts +++ b/packages/beacon-node/test/spec/presets/finality.test.ts @@ -1,4 +1,5 @@ import path from "node:path"; +import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; import { BeaconStateAllForks, DataAvailableStatus, @@ -6,14 +7,13 @@ import { stateTransition, } from "@lodestar/state-transition"; import {altair, bellatrix, ssz} from "@lodestar/types"; -import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; -import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; -import {RunnerType, shouldVerify, TestRunnerFn} from "../utils/types.js"; import {getConfig} from "../../utils/config.js"; import {assertCorrectProgressiveBalances} from "../config.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; +import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {specTestIterator} from "../utils/specTestIterator.js"; +import {RunnerType, TestRunnerFn, shouldVerify} from "../utils/types.js"; const finality: TestRunnerFn = (fork) => { return { diff --git a/packages/beacon-node/test/spec/presets/fork.test.ts b/packages/beacon-node/test/spec/presets/fork.test.ts index 626d6477bcb1..bc66bccb279e 100644 --- a/packages/beacon-node/test/spec/presets/fork.test.ts +++ b/packages/beacon-node/test/spec/presets/fork.test.ts @@ -1,21 +1,21 @@ import path from "node:path"; +import {ChainForkConfig, createChainForkConfig} from "@lodestar/config"; +import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; import { BeaconStateAllForks, - CachedBeaconStateBellatrix, CachedBeaconStateAltair, - CachedBeaconStatePhase0, + CachedBeaconStateBellatrix, CachedBeaconStateCapella, CachedBeaconStateDeneb, + CachedBeaconStatePhase0, } from "@lodestar/state-transition"; import * as slotFns from "@lodestar/state-transition/slot"; import {phase0, ssz} from "@lodestar/types"; -import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; -import {createChainForkConfig, ChainForkConfig} from "@lodestar/config"; -import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; -import {RunnerType, TestRunnerFn} from "../utils/types.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; +import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {specTestIterator} from "../utils/specTestIterator.js"; +import {RunnerType, TestRunnerFn} from "../utils/types.js"; const fork: TestRunnerFn = (forkNext) => { const config = createChainForkConfig({}); 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 72515e703582..a12e6e0ac467 100644 --- a/packages/beacon-node/test/spec/presets/fork_choice.test.ts +++ b/packages/beacon-node/test/spec/presets/fork_choice.test.ts @@ -1,50 +1,50 @@ import path from "node:path"; -import {expect} from "vitest"; import {toHexString} from "@chainsafe/ssz"; -import {BeaconStateAllForks, isExecutionStateType, signedBlockToSignedHeader} from "@lodestar/state-transition"; -import {InputType} from "@lodestar/spec-test-util"; +import {createBeaconConfig} from "@lodestar/config"; import {CheckpointWithHex, ForkChoice} from "@lodestar/fork-choice"; +import {ACTIVE_PRESET, ForkName, ForkSeq, isForkBlobs} from "@lodestar/params"; +import {InputType} from "@lodestar/spec-test-util"; +import {BeaconStateAllForks, isExecutionStateType, signedBlockToSignedHeader} from "@lodestar/state-transition"; import { - bellatrix, - ssz, - RootHex, - deneb, + Attestation, + AttesterSlashing, BeaconBlock, + RootHex, SignedBeaconBlock, + bellatrix, + deneb, + ssz, sszTypesFor, - Attestation, - AttesterSlashing, } from "@lodestar/types"; import {bnToNum, fromHex} from "@lodestar/utils"; -import {createBeaconConfig} from "@lodestar/config"; -import {ACTIVE_PRESET, ForkSeq, isForkBlobs, ForkName} from "@lodestar/params"; -import {BeaconChain, ChainEvent} from "../../../src/chain/index.js"; -import {ClockEvent} from "../../../src/util/clock.js"; -import {computeInclusionProof} from "../../../src/util/blobs.js"; -import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; -import {testLogger} from "../../utils/logger.js"; -import {getConfig} from "../../utils/config.js"; -import {RunnerType, TestRunnerFn} from "../utils/types.js"; -import {Eth1ForBlockProductionDisabled} from "../../../src/eth1/index.js"; -import {getExecutionEngineFromBackend} from "../../../src/execution/index.js"; -import {ExecutionPayloadStatus} from "../../../src/execution/engine/interface.js"; -import {ExecutionEngineMockBackend} from "../../../src/execution/engine/mock.js"; -import {defaultChainOptions} from "../../../src/chain/options.js"; -import {getMockedBeaconDb} from "../../mocks/mockedBeaconDb.js"; -import {ClockStopped} from "../../mocks/clock.js"; +import {expect} from "vitest"; import { - getBlockInput, AttestationImportOpt, - BlockSource, BlobSidecarValidation, BlobsSource, + BlockSource, + getBlockInput, } from "../../../src/chain/blocks/types.js"; +import {BeaconChain, ChainEvent} from "../../../src/chain/index.js"; +import {defaultChainOptions} from "../../../src/chain/options.js"; import {ZERO_HASH_HEX} from "../../../src/constants/constants.js"; +import {Eth1ForBlockProductionDisabled} from "../../../src/eth1/index.js"; import {PowMergeBlock} from "../../../src/eth1/interface.js"; -import {assertCorrectProgressiveBalances} from "../config.js"; +import {ExecutionPayloadStatus} from "../../../src/execution/engine/interface.js"; +import {ExecutionEngineMockBackend} from "../../../src/execution/engine/mock.js"; +import {getExecutionEngineFromBackend} from "../../../src/execution/index.js"; +import {computeInclusionProof} from "../../../src/util/blobs.js"; +import {ClockEvent} from "../../../src/util/clock.js"; import {initCKZG, loadEthereumTrustedSetup} from "../../../src/util/kzg.js"; +import {ClockStopped} from "../../mocks/clock.js"; +import {getMockedBeaconDb} from "../../mocks/mockedBeaconDb.js"; +import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; +import {getConfig} from "../../utils/config.js"; +import {testLogger} from "../../utils/logger.js"; +import {assertCorrectProgressiveBalances} from "../config.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; +import {RunnerType, TestRunnerFn} from "../utils/types.js"; const ANCHOR_STATE_FILE_NAME = "anchor_state"; const ANCHOR_BLOCK_FILE_NAME = "anchor_block"; diff --git a/packages/beacon-node/test/spec/presets/genesis.test.ts b/packages/beacon-node/test/spec/presets/genesis.test.ts index 140fa3686e67..7b19e205dc05 100644 --- a/packages/beacon-node/test/spec/presets/genesis.test.ts +++ b/packages/beacon-node/test/spec/presets/genesis.test.ts @@ -1,6 +1,5 @@ import path from "node:path"; -import {expect} from "vitest"; -import {phase0, Root, ssz, TimeSeconds, ExecutionPayloadHeader, sszTypesFor} from "@lodestar/types"; +import {ForkName} from "@lodestar/params"; import {InputType} from "@lodestar/spec-test-util"; import { BeaconStateAllForks, @@ -8,17 +7,18 @@ import { initializeBeaconStateFromEth1, isValidGenesisState, } from "@lodestar/state-transition"; +import {ExecutionPayloadHeader, Root, TimeSeconds, phase0, ssz, sszTypesFor} from "@lodestar/types"; import {bnToNum} from "@lodestar/utils"; -import {ForkName} from "@lodestar/params"; +import {expect} from "vitest"; import {ACTIVE_PRESET} from "@lodestar/params"; +import {getConfig} from "../../utils/config.js"; import {expectEqualBeaconState} from "../utils/expectEqualBeaconState.js"; import {TestRunnerFn} from "../utils/types.js"; -import {getConfig} from "../../utils/config.js"; -import {RunnerType} from "../utils/types.js"; -import {specTestIterator} from "../utils/specTestIterator.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; +import {specTestIterator} from "../utils/specTestIterator.js"; +import {RunnerType} from "../utils/types.js"; // The aim of the genesis tests is to provide a baseline to test genesis-state initialization and test if the // proposed genesis-validity conditions are working. diff --git a/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts b/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts index 08dcd0ab8acf..3aa73f72ee40 100644 --- a/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts +++ b/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts @@ -1,10 +1,10 @@ -import {expect} from "vitest"; import {Tree} from "@chainsafe/persistent-merkle-tree"; import {TreeViewDU, Type} from "@chainsafe/ssz"; -import {RootHex, ssz} from "@lodestar/types"; -import {InputType} from "@lodestar/spec-test-util"; import {ForkName} from "@lodestar/params"; +import {InputType} from "@lodestar/spec-test-util"; +import {RootHex, ssz} from "@lodestar/types"; import {toHex} from "@lodestar/utils"; +import {expect} from "vitest"; import {TestRunnerFn} from "../../utils/types.js"; // https://github.com/ethereum/consensus-specs/blob/da3f5af919be4abb5a6db5a80b235deb8b4b5cba/tests/formats/light_client/single_merkle_proof.md diff --git a/packages/beacon-node/test/spec/presets/light_client/sync.ts b/packages/beacon-node/test/spec/presets/light_client/sync.ts index 3e82256fab1d..5ac51b95de3b 100644 --- a/packages/beacon-node/test/spec/presets/light_client/sync.ts +++ b/packages/beacon-node/test/spec/presets/light_client/sync.ts @@ -1,13 +1,13 @@ -import {expect} from "vitest"; +import {ChainConfig, createBeaconConfig} from "@lodestar/config"; +import {LightclientSpec, toLightClientUpdateSummary} from "@lodestar/light-client/spec"; import {isForkLightClient} from "@lodestar/params"; -import {altair, phase0, RootHex, Slot, ssz, sszTypesFor} from "@lodestar/types"; import {InputType} from "@lodestar/spec-test-util"; -import {createBeaconConfig, ChainConfig} from "@lodestar/config"; -import {fromHex, toHex} from "@lodestar/utils"; -import {LightclientSpec, toLightClientUpdateSummary} from "@lodestar/light-client/spec"; import {computeSyncPeriodAtSlot} from "@lodestar/state-transition"; -import {TestRunnerFn} from "../../utils/types.js"; +import {RootHex, Slot, altair, phase0, ssz, sszTypesFor} from "@lodestar/types"; +import {fromHex, toHex} from "@lodestar/utils"; +import {expect} from "vitest"; import {testLogger} from "../../../utils/logger.js"; +import {TestRunnerFn} from "../../utils/types.js"; // https://github.com/ethereum/consensus-specs/blob/da3f5af919be4abb5a6db5a80b235deb8b4b5cba/tests/formats/light_client/single_merkle_proof.md type SyncTestCase = { diff --git a/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts b/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts index b51219dd4e54..97cd7639a176 100644 --- a/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts +++ b/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts @@ -1,8 +1,8 @@ -import {expect} from "vitest"; -import {LightClientUpdate, altair, ssz, sszTypesFor} from "@lodestar/types"; +import {LightClientUpdateSummary, isBetterUpdate, toLightClientUpdateSummary} from "@lodestar/light-client/spec"; import {isForkLightClient} from "@lodestar/params"; import {InputType} from "@lodestar/spec-test-util"; -import {isBetterUpdate, LightClientUpdateSummary, toLightClientUpdateSummary} from "@lodestar/light-client/spec"; +import {LightClientUpdate, altair, ssz, sszTypesFor} from "@lodestar/types"; +import {expect} from "vitest"; import {TestRunnerFn} from "../../utils/types.js"; // https://github.com/ethereum/consensus-specs/blob/da3f5af919be4abb5a6db5a80b235deb8b4b5cba/tests/formats/light_client/update_ranking.md diff --git a/packages/beacon-node/test/spec/presets/merkle.test.ts b/packages/beacon-node/test/spec/presets/merkle.test.ts index 71cebdbd0b5b..2bc70374bdf5 100644 --- a/packages/beacon-node/test/spec/presets/merkle.test.ts +++ b/packages/beacon-node/test/spec/presets/merkle.test.ts @@ -1,15 +1,15 @@ import path from "node:path"; -import {expect} from "vitest"; import {ProofType, SingleProof, Tree} from "@chainsafe/persistent-merkle-tree"; import {fromHexString, toHexString} from "@chainsafe/ssz"; -import {ssz} from "@lodestar/types"; -import {BeaconStateAllForks} from "@lodestar/state-transition"; +import {ACTIVE_PRESET} from "@lodestar/params"; import {InputType} from "@lodestar/spec-test-util"; +import {BeaconStateAllForks} from "@lodestar/state-transition"; +import {ssz} from "@lodestar/types"; import {verifyMerkleBranch} from "@lodestar/utils"; -import {ACTIVE_PRESET} from "@lodestar/params"; -import {RunnerType, TestRunnerFn} from "../utils/types.js"; +import {expect} from "vitest"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; +import {RunnerType, TestRunnerFn} from "../utils/types.js"; const merkle: TestRunnerFn = (fork) => { return { diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index 4c90831ef155..0a9996c0a2b1 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -1,4 +1,6 @@ import path from "node:path"; +import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; +import {InputType} from "@lodestar/spec-test-util"; import { BeaconStateAllForks, CachedBeaconStateAllForks, @@ -9,16 +11,14 @@ import { getBlockRootAtSlot, } from "@lodestar/state-transition"; import * as blockFns from "@lodestar/state-transition/block"; -import {ssz, phase0, altair, bellatrix, capella, electra, sszTypesFor} from "@lodestar/types"; -import {InputType} from "@lodestar/spec-test-util"; -import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; +import {altair, bellatrix, capella, electra, phase0, ssz, sszTypesFor} from "@lodestar/types"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; -import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {getConfig} from "../../utils/config.js"; -import {BaseSpecTest, RunnerType, shouldVerify, TestRunnerFn} from "../utils/types.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; +import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {specTestIterator} from "../utils/specTestIterator.js"; +import {BaseSpecTest, RunnerType, TestRunnerFn, shouldVerify} from "../utils/types.js"; // Define above to re-use in sync_aggregate and sync_aggregate_random const syncAggregate: BlockProcessFn = ( diff --git a/packages/beacon-node/test/spec/presets/rewards.test.ts b/packages/beacon-node/test/spec/presets/rewards.test.ts index df43c8ca612e..299bf208eb62 100644 --- a/packages/beacon-node/test/spec/presets/rewards.test.ts +++ b/packages/beacon-node/test/spec/presets/rewards.test.ts @@ -1,17 +1,17 @@ import path from "node:path"; -import {expect} from "vitest"; import {VectorCompositeType} from "@chainsafe/ssz"; +import {ACTIVE_PRESET} from "@lodestar/params"; import {BeaconStateAllForks, beforeProcessEpoch} from "@lodestar/state-transition"; import {getRewardsAndPenalties} from "@lodestar/state-transition/epoch"; import {ssz} from "@lodestar/types"; -import {ACTIVE_PRESET} from "@lodestar/params"; +import {expect} from "vitest"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; -import {inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {getConfig} from "../../utils/config.js"; -import {RunnerType, TestRunnerFn} from "../utils/types.js"; import {assertCorrectProgressiveBalances} from "../config.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; +import {inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {specTestIterator} from "../utils/specTestIterator.js"; +import {RunnerType, TestRunnerFn} from "../utils/types.js"; const deltasType = new VectorCompositeType(ssz.phase0.Balances, 2); diff --git a/packages/beacon-node/test/spec/presets/sanity.test.ts b/packages/beacon-node/test/spec/presets/sanity.test.ts index cd266483c7f8..223587d63ccc 100644 --- a/packages/beacon-node/test/spec/presets/sanity.test.ts +++ b/packages/beacon-node/test/spec/presets/sanity.test.ts @@ -1,4 +1,5 @@ import path from "node:path"; +import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; import {InputType} from "@lodestar/spec-test-util"; import { BeaconStateAllForks, @@ -8,15 +9,14 @@ import { stateTransition, } from "@lodestar/state-transition"; import {SignedBeaconBlock, deneb, ssz} from "@lodestar/types"; -import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; import {bnToNum} from "@lodestar/utils"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; -import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; -import {RunnerType, shouldVerify, TestRunnerFn} from "../utils/types.js"; import {getConfig} from "../../utils/config.js"; import {assertCorrectProgressiveBalances} from "../config.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; +import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {specTestIterator} from "../utils/specTestIterator.js"; +import {RunnerType, TestRunnerFn, shouldVerify} from "../utils/types.js"; const sanity: TestRunnerFn = (fork, testName, testSuite) => { switch (testName) { diff --git a/packages/beacon-node/test/spec/presets/shuffling.test.ts b/packages/beacon-node/test/spec/presets/shuffling.test.ts index 7b0f38ecf581..ad5fff527bac 100644 --- a/packages/beacon-node/test/spec/presets/shuffling.test.ts +++ b/packages/beacon-node/test/spec/presets/shuffling.test.ts @@ -1,11 +1,11 @@ import path from "node:path"; import {unshuffleList} from "@chainsafe/swap-or-not-shuffle"; +import {ACTIVE_PRESET, SHUFFLE_ROUND_COUNT} from "@lodestar/params"; import {InputType} from "@lodestar/spec-test-util"; import {bnToNum, fromHex} from "@lodestar/utils"; -import {ACTIVE_PRESET, SHUFFLE_ROUND_COUNT} from "@lodestar/params"; -import {RunnerType, TestRunnerFn} from "../utils/types.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; +import {RunnerType, TestRunnerFn} from "../utils/types.js"; const shuffling: TestRunnerFn = () => { return { diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index f5cdcc719b6a..34a252052f65 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -1,14 +1,14 @@ import fs from "node:fs"; import path from "node:path"; -import {expect, it, vi} from "vitest"; import {Type} from "@chainsafe/ssz"; -import {ssz, sszTypesFor} from "@lodestar/types"; import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; +import {ssz, sszTypesFor} from "@lodestar/types"; +import {expect, it, vi} from "vitest"; +import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {replaceUintTypeWithUintBigintType} from "../utils/replaceUintTypeWithUintBigintType.js"; -import {parseSszStaticTestcase} from "../utils/sszTestCaseParser.js"; import {runValidSszTest} from "../utils/runValidSszTest.js"; -import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; import {specTestIterator} from "../utils/specTestIterator.js"; +import {parseSszStaticTestcase} from "../utils/sszTestCaseParser.js"; import {RunnerType} from "../utils/types.js"; // ssz_static diff --git a/packages/beacon-node/test/spec/presets/transition.test.ts b/packages/beacon-node/test/spec/presets/transition.test.ts index 76ad772f8dfb..0b1aa1b522e5 100644 --- a/packages/beacon-node/test/spec/presets/transition.test.ts +++ b/packages/beacon-node/test/spec/presets/transition.test.ts @@ -1,4 +1,7 @@ import path from "node:path"; +import {ChainConfig, createChainForkConfig} from "@lodestar/config"; +import {config} from "@lodestar/config/default"; +import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; import { BeaconStateAllForks, DataAvailableStatus, @@ -6,16 +9,13 @@ import { stateTransition, } from "@lodestar/state-transition"; import {SignedBeaconBlock, ssz} from "@lodestar/types"; -import {createChainForkConfig, ChainConfig} from "@lodestar/config"; -import {ACTIVE_PRESET, ForkName} from "@lodestar/params"; import {bnToNum} from "@lodestar/utils"; -import {config} from "@lodestar/config/default"; -import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; -import {RunnerType, TestRunnerFn} from "../utils/types.js"; import {assertCorrectProgressiveBalances} from "../config.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; +import {expectEqualBeaconState, inputTypeSszTreeViewDU} from "../utils/expectEqualBeaconState.js"; import {specTestIterator} from "../utils/specTestIterator.js"; +import {RunnerType, TestRunnerFn} from "../utils/types.js"; import {getPreviousFork} from "./fork.test.js"; const transition = diff --git a/packages/beacon-node/test/spec/utils/expectEqualBeaconState.ts b/packages/beacon-node/test/spec/utils/expectEqualBeaconState.ts index 160310160054..a3f6cc149148 100644 --- a/packages/beacon-node/test/spec/utils/expectEqualBeaconState.ts +++ b/packages/beacon-node/test/spec/utils/expectEqualBeaconState.ts @@ -1,8 +1,8 @@ -import {expect} from "vitest"; -import {SSZTypesFor, ssz} from "@lodestar/types"; import {ForkAll, ForkName} from "@lodestar/params"; import {InputType} from "@lodestar/spec-test-util"; import {BeaconStateAllForks} from "@lodestar/state-transition"; +import {SSZTypesFor, ssz} from "@lodestar/types"; +import {expect} from "vitest"; /** Compare each field in BeaconState to help debug failed test easier. */ export function expectEqualBeaconState( diff --git a/packages/beacon-node/test/spec/utils/replaceUintTypeWithUintBigintType.ts b/packages/beacon-node/test/spec/utils/replaceUintTypeWithUintBigintType.ts index 8e0063291d98..356d384e5f6a 100644 --- a/packages/beacon-node/test/spec/utils/replaceUintTypeWithUintBigintType.ts +++ b/packages/beacon-node/test/spec/utils/replaceUintTypeWithUintBigintType.ts @@ -1,12 +1,12 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */ import { - Type, - UintNumberType, - UintBigintType, ContainerType, ListBasicType, ListCompositeType, + Type, + UintBigintType, + UintNumberType, VectorBasicType, VectorCompositeType, } from "@chainsafe/ssz"; diff --git a/packages/beacon-node/test/spec/utils/runValidSszTest.ts b/packages/beacon-node/test/spec/utils/runValidSszTest.ts index a8d3060af08d..03c4e543f276 100644 --- a/packages/beacon-node/test/spec/utils/runValidSszTest.ts +++ b/packages/beacon-node/test/spec/utils/runValidSszTest.ts @@ -1,6 +1,6 @@ -import {expect} from "vitest"; import {Node} from "@chainsafe/persistent-merkle-tree"; -import {Type, CompositeType, fromHexString, toHexString} from "@chainsafe/ssz"; +import {CompositeType, Type, fromHexString, toHexString} from "@chainsafe/ssz"; +import {expect} from "vitest"; type ValidTestCaseData = { root: string; diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index d8b4f9c0574c..0868183295cf 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -1,8 +1,8 @@ import fs from "node:fs"; import path from "node:path"; -import {describe, it} from "vitest"; import {ForkName} from "@lodestar/params"; import {describeDirectorySpecTest} from "@lodestar/spec-test-util"; +import {describe, it} from "vitest"; import {RunnerType, TestRunner} from "./types.js"; const ARTIFACT_FILENAMES = new Set([ diff --git a/packages/beacon-node/test/spec/utils/sszTestCaseParser.ts b/packages/beacon-node/test/spec/utils/sszTestCaseParser.ts index d4108a2eb011..f594a5b88193 100644 --- a/packages/beacon-node/test/spec/utils/sszTestCaseParser.ts +++ b/packages/beacon-node/test/spec/utils/sszTestCaseParser.ts @@ -1,8 +1,8 @@ -import path from "node:path"; import fs from "node:fs"; -import {uncompress} from "snappyjs"; -import jsyaml from "js-yaml"; +import path from "node:path"; import {loadYaml} from "@lodestar/utils"; +import jsyaml from "js-yaml"; +import {uncompress} from "snappyjs"; /* eslint-disable @typescript-eslint/explicit-function-return-type */ diff --git a/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts b/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts index b3137755857f..bf9e92ee2ddd 100644 --- a/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts +++ b/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts @@ -1,12 +1,12 @@ -import {describe, it, expect} from "vitest"; import {TopicScoreParams} from "@chainsafe/libp2p-gossipsub/score"; -import {ATTESTATION_SUBNET_COUNT, ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {createBeaconConfig} from "@lodestar/config"; import {mainnetChainConfig} from "@lodestar/config/configs"; +import {ATTESTATION_SUBNET_COUNT, ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {describe, expect, it} from "vitest"; +import {ZERO_HASH} from "../../../../src/constants/index.js"; import {computeGossipPeerScoreParams, gossipScoreThresholds} from "../../../../src/network/gossip/scoringParameters.js"; import {stringifyGossipTopic} from "../../../../src/network/gossip/topic.js"; import {GossipType} from "../../../../src/network/index.js"; -import {ZERO_HASH} from "../../../../src/constants/index.js"; /** * Refer to Teku tests at diff --git a/packages/beacon-node/test/unit-mainnet/network/subnets/util.test.ts b/packages/beacon-node/test/unit-mainnet/network/subnets/util.test.ts index af12ad3d80e8..5509b51ebd0a 100644 --- a/packages/beacon-node/test/unit-mainnet/network/subnets/util.test.ts +++ b/packages/beacon-node/test/unit-mainnet/network/subnets/util.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {bigIntToBytes} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; import {computeSubscribedSubnet} from "../../../../src/network/subnets/util.js"; describe("computeSubscribedSubnet", () => { diff --git a/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts index 99bac5de7ef4..9bfb305b7e7e 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect, beforeAll} from "vitest"; import {phase0} from "@lodestar/types"; -import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; +import {beforeAll, describe, expect, it} from "vitest"; import {getBeaconApi} from "../../../../../src/api/impl/beacon/index.js"; +import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; import {Mutable} from "../../../../utils/types.js"; describe("beacon api implementation", () => { diff --git a/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts index 5e4e8a31ec7f..ce8d770d86ff 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts @@ -1,11 +1,11 @@ import {toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, vi, afterEach} from "vitest"; -import {when} from "vitest-when"; import {routes} from "@lodestar/api"; import {ssz} from "@lodestar/types"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; +import {when} from "vitest-when"; +import {getBeaconBlockApi} from "../../../../../../src/api/impl/beacon/blocks/index.js"; import {ApiTestModules, getApiTestModules} from "../../../../../utils/api.js"; import {generateProtoBlock, generateSignedBlockAtSlot} from "../../../../../utils/typeGenerator.js"; -import {getBeaconBlockApi} from "../../../../../../src/api/impl/beacon/blocks/index.js"; describe("api - beacon - getBlockHeaders", () => { let modules: ApiTestModules; diff --git a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts index 958093ffba6d..149e0236c448 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {toHexString} from "@chainsafe/ssz"; +import {describe, expect, it} from "vitest"; import {getStateValidatorIndex} from "../../../../../../src/api/impl/beacon/state/utils.js"; import {generateCachedAltairState} from "../../../../../utils/state.js"; diff --git a/packages/beacon-node/test/unit/api/impl/config/config.test.ts b/packages/beacon-node/test/unit/api/impl/config/config.test.ts index 7d0adebbea89..8e67d5d6b156 100644 --- a/packages/beacon-node/test/unit/api/impl/config/config.test.ts +++ b/packages/beacon-node/test/unit/api/impl/config/config.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect, beforeEach} from "vitest"; import {routes} from "@lodestar/api"; import {config} from "@lodestar/config/default"; +import {beforeEach, describe, expect, it} from "vitest"; import {getConfigApi, renderJsonSpec} from "../../../../../src/api/impl/config/index.js"; describe("config api implementation", () => { diff --git a/packages/beacon-node/test/unit/api/impl/events/events.test.ts b/packages/beacon-node/test/unit/api/impl/events/events.test.ts index 5b1686d42f57..cd42945830bc 100644 --- a/packages/beacon-node/test/unit/api/impl/events/events.test.ts +++ b/packages/beacon-node/test/unit/api/impl/events/events.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect, beforeEach, afterEach, vi, MockedObject} from "vitest"; import {routes} from "@lodestar/api"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; -import {BeaconChain, ChainEventEmitter, HeadEventData} from "../../../../../src/chain/index.js"; +import {MockedObject, afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {getEventsApi} from "../../../../../src/api/impl/events/index.js"; +import {BeaconChain, ChainEventEmitter, HeadEventData} from "../../../../../src/chain/index.js"; import {ZERO_HASH_HEX} from "../../../../../src/constants/constants.js"; vi.mock("../../../../../src/chain/index.js", async (importActual) => { diff --git a/packages/beacon-node/test/unit/api/impl/swaggerUI.test.ts b/packages/beacon-node/test/unit/api/impl/swaggerUI.test.ts index 7ae2382e6404..1b7aecb0a234 100644 --- a/packages/beacon-node/test/unit/api/impl/swaggerUI.test.ts +++ b/packages/beacon-node/test/unit/api/impl/swaggerUI.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {getFavicon, getLogo} from "../../../../src/api/rest/swaggerUI.js"; describe("swaggerUI", () => { diff --git a/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts b/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts index b954f983adcc..66cc4f79407d 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts @@ -1,17 +1,17 @@ -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; import {routes} from "@lodestar/api"; import {config} from "@lodestar/config/default"; import {MAX_EFFECTIVE_BALANCE, SLOTS_PER_EPOCH} from "@lodestar/params"; import {BeaconStateAllForks} from "@lodestar/state-transition"; import {Slot} from "@lodestar/types"; -import {ApiTestModules, getApiTestModules} from "../../../../../utils/api.js"; -import {FAR_FUTURE_EPOCH} from "../../../../../../src/constants/index.js"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {SYNC_TOLERANCE_EPOCHS, getValidatorApi} from "../../../../../../src/api/impl/validator/index.js"; +import {defaultApiOptions} from "../../../../../../src/api/options.js"; +import {FAR_FUTURE_EPOCH} from "../../../../../../src/constants/index.js"; +import {SyncState} from "../../../../../../src/sync/interface.js"; +import {ApiTestModules, getApiTestModules} from "../../../../../utils/api.js"; +import {createCachedBeaconStateTest} from "../../../../../utils/cachedBeaconState.js"; import {generateState, zeroProtoBlock} from "../../../../../utils/state.js"; import {generateValidators} from "../../../../../utils/validator.js"; -import {createCachedBeaconStateTest} from "../../../../../utils/cachedBeaconState.js"; -import {SyncState} from "../../../../../../src/sync/interface.js"; -import {defaultApiOptions} from "../../../../../../src/api/options.js"; describe("get proposers api impl", () => { const currentEpoch = 2; diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts index fdbfec5ac503..0486c3489800 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect, beforeEach, vi} from "vitest"; import {ProtoBlock} from "@lodestar/fork-choice"; -import {SyncState} from "../../../../../src/sync/interface.js"; -import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; +import {beforeEach, describe, expect, it, vi} from "vitest"; import {getValidatorApi} from "../../../../../src/api/impl/validator/index.js"; import {defaultApiOptions} from "../../../../../src/api/options.js"; +import {SyncState} from "../../../../../src/sync/interface.js"; +import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; describe("api - validator - produceAttestationData", () => { let modules: ApiTestModules; diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts index 306b18481c1f..52f600b7174c 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts @@ -1,20 +1,20 @@ import {fromHexString, toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; -import {ssz} from "@lodestar/types"; import {ProtoBlock} from "@lodestar/fork-choice"; import {ForkName} from "@lodestar/params"; -import {computeTimeAtSlot, CachedBeaconStateBellatrix} from "@lodestar/state-transition"; -import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; -import {SyncState} from "../../../../../src/sync/interface.js"; +import {CachedBeaconStateBellatrix, computeTimeAtSlot} from "@lodestar/state-transition"; +import {ssz} from "@lodestar/types"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {getValidatorApi} from "../../../../../src/api/impl/validator/index.js"; +import {defaultApiOptions} from "../../../../../src/api/options.js"; import {BeaconChain} from "../../../../../src/chain/index.js"; -import {generateCachedBellatrixState} from "../../../../utils/state.js"; +import {BlockType, produceBlockBody} from "../../../../../src/chain/produceBlock/produceBlockBody.js"; +import {ZERO_HASH_HEX} from "../../../../../src/constants/index.js"; import {PayloadIdCache} from "../../../../../src/execution/engine/payloadIdCache.js"; +import {SyncState} from "../../../../../src/sync/interface.js"; import {toGraffitiBuffer} from "../../../../../src/util/graffiti.js"; -import {BlockType, produceBlockBody} from "../../../../../src/chain/produceBlock/produceBlockBody.js"; +import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; +import {generateCachedBellatrixState} from "../../../../utils/state.js"; import {generateProtoBlock} from "../../../../utils/typeGenerator.js"; -import {ZERO_HASH_HEX} from "../../../../../src/constants/index.js"; -import {defaultApiOptions} from "../../../../../src/api/options.js"; describe("api/validator - produceBlockV2", () => { let api: ReturnType; diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts index f705e4b38e14..a93529aa4858 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts @@ -1,16 +1,16 @@ -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; import {toHexString} from "@chainsafe/ssz"; -import {ssz} from "@lodestar/types"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {routes} from "@lodestar/api"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {ProtoBlock} from "@lodestar/fork-choice"; -import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; -import {SyncState} from "../../../../../src/sync/interface.js"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {getValidatorApi} from "../../../../../src/api/impl/validator/index.js"; +import {defaultApiOptions} from "../../../../../src/api/options.js"; import {CommonBlockBody} from "../../../../../src/chain/interface.js"; +import {SyncState} from "../../../../../src/sync/interface.js"; +import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; import {zeroProtoBlock} from "../../../../utils/state.js"; -import {defaultApiOptions} from "../../../../../src/api/options.js"; describe("api/validator - produceBlockV3", () => { let modules: ApiTestModules; diff --git a/packages/beacon-node/test/unit/api/impl/validator/utils.test.ts b/packages/beacon-node/test/unit/api/impl/validator/utils.test.ts index 32ef5be5d213..2579fe3224b1 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/utils.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/utils.test.ts @@ -1,7 +1,7 @@ import {toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeAll} from "vitest"; -import {BLSPubkey, ssz, ValidatorIndex} from "@lodestar/types"; import {BeaconStateAllForks} from "@lodestar/state-transition"; +import {BLSPubkey, ValidatorIndex, ssz} from "@lodestar/types"; +import {beforeAll, describe, expect, it} from "vitest"; import {getPubkeysForIndices} from "../../../../../src/api/impl/validator/utils.js"; describe("api / impl / validator / utils", () => { diff --git a/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts b/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts index dc7c9bb75291..f34e2c85f1a1 100644 --- a/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts +++ b/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts @@ -1,13 +1,13 @@ import {fromHexString, toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, vi, afterEach} from "vitest"; -import {ssz} from "@lodestar/types"; import {config} from "@lodestar/config/default"; -import {ZERO_HASH_HEX} from "../../../../src/constants/index.js"; -import {generateProtoBlock} from "../../../utils/typeGenerator.js"; -import {testLogger} from "../../../utils/logger.js"; +import {ssz} from "@lodestar/types"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {archiveBlocks} from "../../../../src/chain/archiver/archiveBlocks.js"; -import {MockedBeaconDb, getMockedBeaconDb} from "../../../mocks/mockedBeaconDb.js"; +import {ZERO_HASH_HEX} from "../../../../src/constants/index.js"; import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; +import {MockedBeaconDb, getMockedBeaconDb} from "../../../mocks/mockedBeaconDb.js"; +import {testLogger} from "../../../utils/logger.js"; +import {generateProtoBlock} from "../../../utils/typeGenerator.js"; describe("block archiver task", () => { const logger = testLogger(); diff --git a/packages/beacon-node/test/unit/chain/archive/nonCheckpoint.test.ts b/packages/beacon-node/test/unit/chain/archive/nonCheckpoint.test.ts index c58a873fe1db..c3dc5f031893 100644 --- a/packages/beacon-node/test/unit/chain/archive/nonCheckpoint.test.ts +++ b/packages/beacon-node/test/unit/chain/archive/nonCheckpoint.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect, beforeAll} from "vitest"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {Slot} from "@lodestar/types"; +import {beforeAll, describe, expect, it} from "vitest"; import {getNonCheckpointBlocks} from "../../../../src/chain/archiver/archiveBlocks.js"; describe("chain / archive / getNonCheckpointBlocks", () => { diff --git a/packages/beacon-node/test/unit/chain/archive/stateArchiver.test.ts b/packages/beacon-node/test/unit/chain/archive/stateArchiver.test.ts index cbfba0a362df..80ef6b885ae4 100644 --- a/packages/beacon-node/test/unit/chain/archive/stateArchiver.test.ts +++ b/packages/beacon-node/test/unit/chain/archive/stateArchiver.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; +import {describe, expect, it} from "vitest"; import {computeStateSlotsToDelete} from "../../../../src/chain/archiver/strategies/frequencyStateArchiveStrategy.js"; describe("state archiver task", () => { diff --git a/packages/beacon-node/test/unit/chain/beaconProposerCache.ts b/packages/beacon-node/test/unit/chain/beaconProposerCache.ts index b75bbf546a98..96178d508732 100644 --- a/packages/beacon-node/test/unit/chain/beaconProposerCache.ts +++ b/packages/beacon-node/test/unit/chain/beaconProposerCache.ts @@ -1,4 +1,4 @@ -import {expect, describe, it, beforeEach} from "vitest"; +import {beforeEach, describe, expect, it} from "vitest"; import {BeaconProposerCache} from "../../../src/chain/beaconProposerCache.js"; const suggestedFeeRecipient = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; diff --git a/packages/beacon-node/test/unit/chain/blocks/rejectFirstInvalidResolveAllValid.test.ts b/packages/beacon-node/test/unit/chain/blocks/rejectFirstInvalidResolveAllValid.test.ts index 2e032f558fe2..5de44a532631 100644 --- a/packages/beacon-node/test/unit/chain/blocks/rejectFirstInvalidResolveAllValid.test.ts +++ b/packages/beacon-node/test/unit/chain/blocks/rejectFirstInvalidResolveAllValid.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {rejectFirstInvalidResolveAllValid} from "../../../../src/chain/blocks/verifyBlocksSignatures.js"; /* eslint-disable @typescript-eslint/explicit-function-return-type */ diff --git a/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts b/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts index 1296a79d5eab..48ffe51e4636 100644 --- a/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts +++ b/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts @@ -1,17 +1,17 @@ -import {describe, it, expect, beforeEach} from "vitest"; +import {ChainForkConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {toHex} from "@lodestar/utils"; -import {ChainForkConfig} from "@lodestar/config"; import {SignedBeaconBlock, Slot, ssz} from "@lodestar/types"; +import {toHex} from "@lodestar/utils"; +import {beforeEach, describe, expect, it} from "vitest"; +import {BlockSource, getBlockInput} from "../../../../src/chain/blocks/types.js"; import {verifyBlocksSanityChecks as verifyBlocksImportSanityChecks} from "../../../../src/chain/blocks/verifyBlocksSanityChecks.js"; import {BlockErrorCode} from "../../../../src/chain/errors/index.js"; -import {expectThrowsLodestarError} from "../../../utils/errors.js"; import {IClock} from "../../../../src/util/clock.js"; import {ClockStopped} from "../../../mocks/clock.js"; -import {BlockSource, getBlockInput} from "../../../../src/chain/blocks/types.js"; import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; +import {expectThrowsLodestarError} from "../../../utils/errors.js"; describe("chain / blocks / verifyBlocksSanityChecks", () => { let forkChoice: MockedBeaconChain["forkChoice"]; diff --git a/packages/beacon-node/test/unit/chain/bls/bls.test.ts b/packages/beacon-node/test/unit/chain/bls/bls.test.ts index 137f2c4dd9df..fbc602785a68 100644 --- a/packages/beacon-node/test/unit/chain/bls/bls.test.ts +++ b/packages/beacon-node/test/unit/chain/bls/bls.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect, beforeEach} from "vitest"; import {PublicKey, SecretKey, Signature} from "@chainsafe/blst"; import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition"; -import {BlsSingleThreadVerifier} from "../../../../src/chain/bls/singleThread.js"; +import {beforeEach, describe, expect, it} from "vitest"; import {BlsMultiThreadWorkerPool} from "../../../../src/chain/bls/multithread/index.js"; +import {BlsSingleThreadVerifier} from "../../../../src/chain/bls/singleThread.js"; import {testLogger} from "../../../utils/logger.js"; describe("BlsVerifier ", () => { diff --git a/packages/beacon-node/test/unit/chain/bls/utils.test.ts b/packages/beacon-node/test/unit/chain/bls/utils.test.ts index d492a36b4d56..5e5259b8649f 100644 --- a/packages/beacon-node/test/unit/chain/bls/utils.test.ts +++ b/packages/beacon-node/test/unit/chain/bls/utils.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {chunkifyMaximizeChunkSize} from "../../../../src/chain/bls/multithread/utils.js"; import {linspace} from "../../../../src/util/numpy.js"; diff --git a/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts b/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts index 7cb5d23ba296..017e46f6294b 100644 --- a/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts +++ b/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts @@ -1,7 +1,6 @@ import {toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, beforeAll, vi} from "vitest"; import {config} from "@lodestar/config/default"; -import {CheckpointWithHex, ExecutionStatus, ForkChoice, DataAvailabilityStatus} from "@lodestar/fork-choice"; +import {CheckpointWithHex, DataAvailabilityStatus, ExecutionStatus, ForkChoice} from "@lodestar/fork-choice"; import {FAR_FUTURE_EPOCH, MAX_EFFECTIVE_BALANCE} from "@lodestar/params"; import { CachedBeaconStateAllForks, @@ -9,12 +8,13 @@ import { computeEpochAtSlot, getEffectiveBalanceIncrementsZeroed, } from "@lodestar/state-transition"; -import {phase0, Slot, ssz, ValidatorIndex} from "@lodestar/types"; import {getTemporaryBlockHeader, processSlots} from "@lodestar/state-transition"; +import {Slot, ValidatorIndex, phase0, ssz} from "@lodestar/types"; +import {beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; import {ChainEventEmitter, initializeForkChoice} from "../../../../src/chain/index.js"; -import {generateSignedBlockAtSlot} from "../../../utils/typeGenerator.js"; import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; import {generateState} from "../../../utils/state.js"; +import {generateSignedBlockAtSlot} from "../../../utils/typeGenerator.js"; import {generateValidators} from "../../../utils/validator.js"; // We mock this package globally diff --git a/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts b/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts index 40570fcd26e1..40c76bb48045 100644 --- a/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts +++ b/packages/beacon-node/test/unit/chain/genesis/genesis.test.ts @@ -1,15 +1,15 @@ -import {toHexString} from "@chainsafe/ssz"; -import {describe, it, expect} from "vitest"; import {PublicKey, SecretKey} from "@chainsafe/blst"; -import {DOMAIN_DEPOSIT, MAX_EFFECTIVE_BALANCE} from "@lodestar/params"; +import {toHexString} from "@chainsafe/ssz"; import {config} from "@lodestar/config/default"; -import {computeDomain, computeSigningRoot, interopSecretKey, ZERO_HASH} from "@lodestar/state-transition"; +import {DOMAIN_DEPOSIT, MAX_EFFECTIVE_BALANCE} from "@lodestar/params"; +import {ZERO_HASH, computeDomain, computeSigningRoot, interopSecretKey} from "@lodestar/state-transition"; import {ValidatorIndex, phase0, ssz} from "@lodestar/types"; import {ErrorAborted} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; import {GenesisBuilder} from "../../../../src/chain/genesis/genesis.js"; -import {testLogger} from "../../../utils/logger.js"; import {ZERO_HASH_HEX} from "../../../../src/constants/index.js"; import {Eth1ProviderState, EthJsonRpcBlockRaw, IEth1Provider} from "../../../../src/eth1/interface.js"; +import {testLogger} from "../../../utils/logger.js"; describe("genesis builder", () => { const logger = testLogger(); diff --git a/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts b/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts index b30e0f9a9ddb..1ae4812ea200 100644 --- a/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts +++ b/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect, beforeAll} from "vitest"; -import {BeaconStateAltair} from "@lodestar/state-transition"; import {SYNC_COMMITTEE_SIZE} from "@lodestar/params"; +import {BeaconStateAltair} from "@lodestar/state-transition"; import {altair, ssz} from "@lodestar/types"; -import {verifyMerkleBranch, hash} from "@lodestar/utils"; +import {hash, verifyMerkleBranch} from "@lodestar/utils"; +import {beforeAll, describe, expect, it} from "vitest"; import {getNextSyncCommitteeBranch, getSyncCommitteesWitness} from "../../../../src/chain/lightClient/proofs.js"; const currentSyncCommitteeGindex = 54; diff --git a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts index 3c2f5a664c77..9e602040b315 100644 --- a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts +++ b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect, beforeEach} from "vitest"; -import {LightClientHeader, ssz} from "@lodestar/types"; -import {ForkName, ForkSeq} from "@lodestar/params"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {upgradeLightClientHeader} from "@lodestar/light-client/spec"; +import {ForkName, ForkSeq} from "@lodestar/params"; +import {LightClientHeader, ssz} from "@lodestar/types"; +import {beforeEach, describe, expect, it} from "vitest"; describe("UpgradeLightClientHeader", () => { let lcHeaderByFork: Record; diff --git a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts index 8742d7da9147..b5bfe191a9f3 100644 --- a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts @@ -1,7 +1,6 @@ +import {SecretKey, Signature, aggregateSignatures, fastAggregateVerify} from "@chainsafe/blst"; import {BitArray, fromHexString, toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, beforeAll, afterEach, vi} from "vitest"; -import {SecretKey, Signature, fastAggregateVerify, aggregateSignatures} from "@chainsafe/blst"; -import {CachedBeaconStateAllForks, newFilledArray} from "@lodestar/state-transition"; +import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; import { FAR_FUTURE_EPOCH, ForkName, @@ -9,23 +8,24 @@ import { MAX_EFFECTIVE_BALANCE, SLOTS_PER_EPOCH, } from "@lodestar/params"; -import {ssz, phase0} from "@lodestar/types"; +import {CachedBeaconStateAllForks, newFilledArray} from "@lodestar/state-transition"; import {CachedBeaconStateAltair} from "@lodestar/state-transition/src/types.js"; -import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {MockedForkChoice, getMockedForkChoice} from "../../../mocks/mockedBeaconChain.js"; +import {phase0, ssz} from "@lodestar/types"; +import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; import { - aggregateConsolidation, AggregatedAttestationPool, - aggregateInto, AttestationsConsolidation, - getNotSeenValidatorsFn, MatchingDataAttestationGroup, + aggregateConsolidation, + aggregateInto, + getNotSeenValidatorsFn, } from "../../../../src/chain/opPools/aggregatedAttestationPool.js"; import {InsertOutcome} from "../../../../src/chain/opPools/types.js"; +import {ZERO_HASH_HEX} from "../../../../src/constants/constants.js"; import {linspace} from "../../../../src/util/numpy.js"; -import {generateCachedAltairState} from "../../../utils/state.js"; +import {MockedForkChoice, getMockedForkChoice} from "../../../mocks/mockedBeaconChain.js"; import {renderBitArray} from "../../../utils/render.js"; -import {ZERO_HASH_HEX} from "../../../../src/constants/constants.js"; +import {generateCachedAltairState} from "../../../utils/state.js"; import {generateProtoBlock} from "../../../utils/typeGenerator.js"; import {generateValidators} from "../../../utils/validator.js"; diff --git a/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts index 98453efaa3b6..fd22f9a7c6a5 100644 --- a/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/attestationPool.test.ts @@ -1,10 +1,10 @@ import {fromHexString, toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, vi} from "vitest"; +import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ssz} from "@lodestar/types"; -import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {InsertOutcome} from "../../../../src/chain/opPools/types.js"; +import {beforeEach, describe, expect, it, vi} from "vitest"; import {AttestationPool} from "../../../../src/chain/opPools/attestationPool.js"; +import {InsertOutcome} from "../../../../src/chain/opPools/types.js"; import {getMockedClock} from "../../../mocks/clock.js"; /** Valid signature of random data to prevent BLS errors */ diff --git a/packages/beacon-node/test/unit/chain/opPools/syncCommittee.test.ts b/packages/beacon-node/test/unit/chain/opPools/syncCommittee.test.ts index e91eaa58aa73..9af19cc84c71 100644 --- a/packages/beacon-node/test/unit/chain/opPools/syncCommittee.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/syncCommittee.test.ts @@ -1,7 +1,7 @@ -import {toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, beforeAll, afterEach, vi, MockedObject} from "vitest"; import {SecretKey} from "@chainsafe/blst"; +import {toHexString} from "@chainsafe/ssz"; import {altair} from "@lodestar/types"; +import {MockedObject, afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; import {SyncCommitteeMessagePool} from "../../../../src/chain/opPools/index.js"; import {Clock} from "../../../../src/util/clock.js"; diff --git a/packages/beacon-node/test/unit/chain/opPools/syncCommitteeContribution.test.ts b/packages/beacon-node/test/unit/chain/opPools/syncCommitteeContribution.test.ts index e1bd60a2305e..c0a639633f37 100644 --- a/packages/beacon-node/test/unit/chain/opPools/syncCommitteeContribution.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/syncCommitteeContribution.test.ts @@ -1,14 +1,14 @@ -import {BitArray} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, beforeAll} from "vitest"; import {SecretKey, Signature, fastAggregateVerify} from "@chainsafe/blst"; +import {BitArray} from "@chainsafe/ssz"; +import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {newFilledArray} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; -import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; +import {beforeAll, beforeEach, describe, expect, it} from "vitest"; import { - aggregate, - replaceIfBetter, SyncContributionAndProofPool, SyncContributionFast, + aggregate, + replaceIfBetter, } from "../../../../src/chain/opPools/syncContributionAndProofPool.js"; import {InsertOutcome} from "../../../../src/chain/opPools/types.js"; import {EMPTY_SIGNATURE} from "../../../../src/constants/index.js"; diff --git a/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts b/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts index c7d0a7801fec..fa95a00eebfd 100644 --- a/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts +++ b/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts @@ -1,14 +1,14 @@ -import {describe, it, expect, beforeEach, afterEach, vi, Mock, MockInstance} from "vitest"; -import {config} from "@lodestar/config/default"; -import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {routes} from "@lodestar/api"; +import {config} from "@lodestar/config/default"; import {ProtoBlock} from "@lodestar/fork-choice"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../mocks/mockedBeaconChain.js"; -import {MockedLogger, getMockedLogger} from "../../mocks/loggerMock.js"; +import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {Mock, MockInstance, afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {IChainOptions} from "../../../src/chain/options.js"; import {PrepareNextSlotScheduler} from "../../../src/chain/prepareNextSlot.js"; -import {generateCachedBellatrixState, zeroProtoBlock} from "../../utils/state.js"; import {PayloadIdCache} from "../../../src/execution/engine/payloadIdCache.js"; +import {MockedLogger, getMockedLogger} from "../../mocks/loggerMock.js"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../mocks/mockedBeaconChain.js"; +import {generateCachedBellatrixState, zeroProtoBlock} from "../../utils/state.js"; describe("PrepareNextSlot scheduler", () => { const abortController = new AbortController(); diff --git a/packages/beacon-node/test/unit/chain/reprocess.test.ts b/packages/beacon-node/test/unit/chain/reprocess.test.ts index 927e4cf8d05f..339dc20de27f 100644 --- a/packages/beacon-node/test/unit/chain/reprocess.test.ts +++ b/packages/beacon-node/test/unit/chain/reprocess.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, beforeEach} from "vitest"; +import {beforeEach, describe, expect, it} from "vitest"; import {ReprocessController} from "../../../src/chain/reprocess.js"; describe("ReprocessController", () => { diff --git a/packages/beacon-node/test/unit/chain/rewards/blockRewards.test.ts b/packages/beacon-node/test/unit/chain/rewards/blockRewards.test.ts index d417d83e2da9..ec42395641f4 100644 --- a/packages/beacon-node/test/unit/chain/rewards/blockRewards.test.ts +++ b/packages/beacon-node/test/unit/chain/rewards/blockRewards.test.ts @@ -1,17 +1,17 @@ -import {describe, it, expect} from "vitest"; import {SYNC_COMMITTEE_SIZE} from "@lodestar/params"; -import {ssz} from "@lodestar/types"; import { CachedBeaconStateAllForks, DataAvailableStatus, ExecutionPayloadStatus, stateTransition, } from "@lodestar/state-transition"; +import {ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; +import {BlockAltairOpts, getBlockAltair} from "../../../../../state-transition/test/perf/block/util.js"; import { - generatePerfTestCachedStateAltair, cachedStateAltairPopulateCaches, + generatePerfTestCachedStateAltair, } from "../../../../../state-transition/test/perf/util.js"; -import {BlockAltairOpts, getBlockAltair} from "../../../../../state-transition/test/perf/block/util.js"; import {computeBlockRewards} from "../../../../src/chain/rewards/blockRewards.js"; describe("chain / rewards / blockRewards", () => { diff --git a/packages/beacon-node/test/unit/chain/seenCache/aggregateAndProof.test.ts b/packages/beacon-node/test/unit/chain/seenCache/aggregateAndProof.test.ts index d83433a649ca..c69004ac98b9 100644 --- a/packages/beacon-node/test/unit/chain/seenCache/aggregateAndProof.test.ts +++ b/packages/beacon-node/test/unit/chain/seenCache/aggregateAndProof.test.ts @@ -1,9 +1,9 @@ import {BitArray} from "@chainsafe/ssz"; -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import { AggregationInfo, - insertDesc, SeenAggregatedAttestations, + insertDesc, } from "../../../../src/chain/seenCache/seenAggregateAndProof.js"; describe("SeenAggregatedAttestations.isKnown", () => { diff --git a/packages/beacon-node/test/unit/chain/seenCache/seenAttestationData.test.ts b/packages/beacon-node/test/unit/chain/seenCache/seenAttestationData.test.ts index b4857226267e..ee5cb94ae959 100644 --- a/packages/beacon-node/test/unit/chain/seenCache/seenAttestationData.test.ts +++ b/packages/beacon-node/test/unit/chain/seenCache/seenAttestationData.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, beforeEach} from "vitest"; +import {beforeEach, describe, expect, it} from "vitest"; import {InsertOutcome} from "../../../../src/chain/opPools/types.js"; import {AttestationDataCacheEntry, SeenAttestationDatas} from "../../../../src/chain/seenCache/seenAttestationData.js"; diff --git a/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts b/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts index 27b5eadecf11..2af9f40d2de3 100644 --- a/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts +++ b/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect} from "vitest"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; +import {BlockInput, BlockInputType, GossipedInputType} from "../../../../src/chain/blocks/types.js"; import {SeenGossipBlockInput} from "../../../../src/chain/seenCache/seenGossipBlockInput.js"; -import {BlockInputType, GossipedInputType, BlockInput} from "../../../../src/chain/blocks/types.js"; describe("SeenGossipBlockInput", () => { const chainConfig = createChainForkConfig({ diff --git a/packages/beacon-node/test/unit/chain/seenCache/syncCommittee.test.ts b/packages/beacon-node/test/unit/chain/seenCache/syncCommittee.test.ts index 59c67f9cedc2..a24fcc41443d 100644 --- a/packages/beacon-node/test/unit/chain/seenCache/syncCommittee.test.ts +++ b/packages/beacon-node/test/unit/chain/seenCache/syncCommittee.test.ts @@ -1,7 +1,7 @@ import {BitArray} from "@chainsafe/ssz"; -import {describe, it, expect} from "vitest"; import {ssz} from "@lodestar/types"; -import {SeenSyncCommitteeMessages, SeenContributionAndProof} from "../../../../src/chain/seenCache/index.js"; +import {describe, expect, it} from "vitest"; +import {SeenContributionAndProof, SeenSyncCommitteeMessages} from "../../../../src/chain/seenCache/index.js"; const NUM_SLOTS_IN_CACHE = 3; diff --git a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts index d417e555872c..b8a9602ea6ce 100644 --- a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts +++ b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, beforeEach} from "vitest"; +import {beforeEach, describe, expect, it} from "vitest"; import {generateTestCachedBeaconStateOnlyValidators} from "../../../../state-transition/test/perf/util.js"; import {ShufflingCache} from "../../../src/chain/shufflingCache.js"; diff --git a/packages/beacon-node/test/unit/chain/stateCache/blockStateCacheImpl.test.ts b/packages/beacon-node/test/unit/chain/stateCache/blockStateCacheImpl.test.ts index 19dc0f3a2c60..50ec0b6fc63d 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/blockStateCacheImpl.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/blockStateCacheImpl.test.ts @@ -1,11 +1,11 @@ import {toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach} from "vitest"; -import {EpochShuffling} from "@lodestar/state-transition"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {EpochShuffling} from "@lodestar/state-transition"; import {Root} from "@lodestar/types"; +import {beforeEach, describe, expect, it} from "vitest"; import {BlockStateCacheImpl} from "../../../../src/chain/stateCache/index.js"; -import {generateCachedState} from "../../../utils/state.js"; import {ZERO_HASH} from "../../../../src/constants/index.js"; +import {generateCachedState} from "../../../utils/state.js"; describe("BlockStateCacheImpl", () => { let cache: BlockStateCacheImpl; diff --git a/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts index 07a8ec12093d..9a341438479d 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect, beforeEach} from "vitest"; import {toHexString} from "@chainsafe/ssz"; -import {EpochShuffling, CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {CachedBeaconStateAllForks, EpochShuffling} from "@lodestar/state-transition"; +import {beforeEach, describe, expect, it} from "vitest"; import {FIFOBlockStateCache} from "../../../../src/chain/stateCache/index.js"; import {generateCachedState} from "../../../utils/state.js"; diff --git a/packages/beacon-node/test/unit/chain/stateCache/inMemoryCheckpointsCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/inMemoryCheckpointsCache.test.ts index 23a792bef0a8..edfec599b6eb 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/inMemoryCheckpointsCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/inMemoryCheckpointsCache.test.ts @@ -1,7 +1,7 @@ -import {describe, beforeAll, it, expect, beforeEach} from "vitest"; +import {SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; import {CachedBeaconStateAllForks, computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {phase0} from "@lodestar/types"; -import {SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; +import {beforeAll, beforeEach, describe, expect, it} from "vitest"; import { CheckpointHex, InMemoryCheckpointStateCache, diff --git a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts index f98b180fa983..5ab3da532948 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts @@ -1,16 +1,16 @@ -import {describe, it, expect, beforeAll, beforeEach} from "vitest"; import {SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; import {CachedBeaconStateAllForks, computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {RootHex, phase0} from "@lodestar/types"; import {mapValues, toHexString} from "@lodestar/utils"; -import {PersistentCheckpointStateCache} from "../../../../src/chain/stateCache/persistentCheckpointsCache.js"; -import {checkpointToDatastoreKey} from "../../../../src/chain/stateCache/datastore/index.js"; -import {generateCachedState} from "../../../utils/state.js"; +import {beforeAll, beforeEach, describe, expect, it} from "vitest"; +import {FIFOBlockStateCache, toCheckpointHex} from "../../../../src/chain/index.js"; import {ShufflingCache} from "../../../../src/chain/shufflingCache.js"; -import {testLogger} from "../../../utils/logger.js"; -import {getTestDatastore} from "../../../utils/chain/stateCache/datastore.js"; +import {checkpointToDatastoreKey} from "../../../../src/chain/stateCache/datastore/index.js"; +import {PersistentCheckpointStateCache} from "../../../../src/chain/stateCache/persistentCheckpointsCache.js"; import {CheckpointHex} from "../../../../src/chain/stateCache/types.js"; -import {FIFOBlockStateCache, toCheckpointHex} from "../../../../src/chain/index.js"; +import {getTestDatastore} from "../../../utils/chain/stateCache/datastore.js"; +import {testLogger} from "../../../utils/logger.js"; +import {generateCachedState} from "../../../utils/state.js"; describe("PersistentCheckpointStateCache", () => { let root0a: Buffer, root0b: Buffer, root1: Buffer, root2: Buffer; 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 e2bc392b4ea2..d9833740a9a5 100644 --- a/packages/beacon-node/test/unit/chain/validation/aggregateAndProof.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/aggregateAndProof.test.ts @@ -1,16 +1,16 @@ import {BitArray, toHexString} from "@chainsafe/ssz"; -import {describe, it} from "vitest"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {phase0, ssz} from "@lodestar/types"; +import {describe, it} from "vitest"; import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../state-transition/test/perf/util.js"; -import {IBeaconChain} from "../../../../src/chain/index.js"; import {AttestationErrorCode} from "../../../../src/chain/errors/index.js"; +import {IBeaconChain} from "../../../../src/chain/index.js"; import {validateApiAggregateAndProof, validateGossipAggregateAndProof} from "../../../../src/chain/validation/index.js"; -import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {memoOnce} from "../../../utils/cache.js"; +import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import { - getAggregateAndProofValidData, AggregateAndProofValidDataOpts, + getAggregateAndProofValidData, } from "../../../utils/validationData/aggregateAndProof.js"; describe("chain / validation / aggregateAndProof", () => { diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts index 4ba65270e17a..729c03d9d6e5 100644 --- a/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts @@ -1,11 +1,11 @@ -import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; -// We need to import the mock before the packages -import {MockedBeaconChain, getMockedBeaconChain} from "../../../../mocks/mockedBeaconChain.js"; -import {EpochShuffling, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {EpochDifference, ProtoBlock} from "@lodestar/fork-choice"; +import {EpochShuffling, computeStartSlotAtEpoch} from "@lodestar/state-transition"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {RegenCaller} from "../../../../../src/chain/regen/interface.js"; import {getShufflingForAttestationVerification} from "../../../../../src/chain/validation/index.js"; import {ZERO_HASH_HEX} from "../../../../../src/constants/constants.js"; +// We need to import the mock before the packages +import {MockedBeaconChain, getMockedBeaconChain} from "../../../../mocks/mockedBeaconChain.js"; describe("getShufflingForAttestationVerification", () => { let chain: MockedBeaconChain; diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts index be9fd3587b7c..1ffbf7696111 100644 --- a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts @@ -1,8 +1,8 @@ import {BitArray} from "@chainsafe/ssz"; -import {describe, expect, it} from "vitest"; import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ssz} from "@lodestar/types"; import {LodestarError} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../../state-transition/test/perf/util.js"; import {AttestationErrorCode, GossipErrorCode} from "../../../../../src/chain/errors/index.js"; import {IBeaconChain} from "../../../../../src/chain/index.js"; diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/validateGossipAttestationsSameAttData.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/validateGossipAttestationsSameAttData.test.ts index 24fae8a03f0b..1b3688fc2e33 100644 --- a/packages/beacon-node/test/unit/chain/validation/attestation/validateGossipAttestationsSameAttData.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attestation/validateGossipAttestationsSameAttData.test.ts @@ -1,8 +1,8 @@ -import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {PublicKey, SecretKey} from "@chainsafe/blst"; import {ForkName} from "@lodestar/params"; import {SignatureSetType} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {BlsSingleThreadVerifier} from "../../../../../src/chain/bls/singleThread.js"; import {AttestationError, AttestationErrorCode, GossipAction} from "../../../../../src/chain/errors/index.js"; import {IBeaconChain} from "../../../../../src/chain/index.js"; diff --git a/packages/beacon-node/test/unit/chain/validation/attesterSlashing.test.ts b/packages/beacon-node/test/unit/chain/validation/attesterSlashing.test.ts index 629753824669..c9577767f78f 100644 --- a/packages/beacon-node/test/unit/chain/validation/attesterSlashing.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attesterSlashing.test.ts @@ -1,10 +1,10 @@ -import {describe, it, beforeEach, afterEach, vi} from "vitest"; import {phase0, ssz} from "@lodestar/types"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; -import {generateCachedState} from "../../../utils/state.js"; -import {validateGossipAttesterSlashing} from "../../../../src/chain/validation/attesterSlashing.js"; +import {afterEach, beforeEach, describe, it, vi} from "vitest"; import {AttesterSlashingErrorCode} from "../../../../src/chain/errors/attesterSlashingError.js"; +import {validateGossipAttesterSlashing} from "../../../../src/chain/validation/attesterSlashing.js"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; +import {generateCachedState} from "../../../utils/state.js"; describe("GossipMessageValidator", () => { let chainStub: MockedBeaconChain; diff --git a/packages/beacon-node/test/unit/chain/validation/block.test.ts b/packages/beacon-node/test/unit/chain/validation/block.test.ts index f8a2b7245ef7..4b236181b038 100644 --- a/packages/beacon-node/test/unit/chain/validation/block.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/block.test.ts @@ -1,14 +1,14 @@ -import {Mock, Mocked, beforeEach, describe, it, vi} from "vitest"; import {config} from "@lodestar/config/default"; import {ProtoBlock} from "@lodestar/fork-choice"; import {ForkName} from "@lodestar/params"; import {SignedBeaconBlock, ssz} from "@lodestar/types"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; +import {Mock, Mocked, beforeEach, describe, it, vi} from "vitest"; import {BlockErrorCode} from "../../../../src/chain/errors/index.js"; import {QueuedStateRegenerator} from "../../../../src/chain/regen/index.js"; import {SeenBlockProposers} from "../../../../src/chain/seenCache/index.js"; import {validateGossipBlock} from "../../../../src/chain/validation/index.js"; import {EMPTY_SIGNATURE, ZERO_HASH} from "../../../../src/constants/index.js"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {generateCachedState} from "../../../utils/state.js"; diff --git a/packages/beacon-node/test/unit/chain/validation/blsToExecutionChange.test.ts b/packages/beacon-node/test/unit/chain/validation/blsToExecutionChange.test.ts index 8d5032ed3ec7..6c1d1def3d9d 100644 --- a/packages/beacon-node/test/unit/chain/validation/blsToExecutionChange.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/blsToExecutionChange.test.ts @@ -1,24 +1,24 @@ import {digest} from "@chainsafe/as-sha256"; -import {describe, it, beforeEach, afterEach, vi} from "vitest"; import {SecretKey} from "@chainsafe/blst"; +import {createBeaconConfig} from "@lodestar/config"; import {config as defaultConfig} from "@lodestar/config/default"; -import {computeSigningRoot} from "@lodestar/state-transition"; -import {capella, ssz} from "@lodestar/types"; import { BLS_WITHDRAWAL_PREFIX, - ETH1_ADDRESS_WITHDRAWAL_PREFIX, DOMAIN_BLS_TO_EXECUTION_CHANGE, + ETH1_ADDRESS_WITHDRAWAL_PREFIX, FAR_FUTURE_EPOCH, - SLOTS_PER_EPOCH, ForkName, + SLOTS_PER_EPOCH, } from "@lodestar/params"; -import {createBeaconConfig} from "@lodestar/config"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; -import {generateState} from "../../../utils/state.js"; -import {validateGossipBlsToExecutionChange} from "../../../../src/chain/validation/blsToExecutionChange.js"; +import {computeSigningRoot} from "@lodestar/state-transition"; +import {capella, ssz} from "@lodestar/types"; +import {afterEach, beforeEach, describe, it, vi} from "vitest"; import {BlsToExecutionChangeErrorCode} from "../../../../src/chain/errors/blsToExecutionChangeError.js"; -import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; +import {validateGossipBlsToExecutionChange} from "../../../../src/chain/validation/blsToExecutionChange.js"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; +import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; +import {generateState} from "../../../utils/state.js"; describe("validate bls to execution change", () => { let chainStub: MockedBeaconChain; diff --git a/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts b/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts index cbd231c926ce..4288b7f440c9 100644 --- a/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {altair, ssz} from "@lodestar/types"; import {computeTimeAtSlot} from "@lodestar/state-transition"; +import {altair, ssz} from "@lodestar/types"; import {RequiredSelective} from "@lodestar/utils"; -import {validateLightClientFinalityUpdate} from "../../../../src/chain/validation/lightClientFinalityUpdate.js"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {LightClientErrorCode} from "../../../../src/chain/errors/lightClientError.js"; import {IBeaconChain} from "../../../../src/chain/index.js"; +import {validateLightClientFinalityUpdate} from "../../../../src/chain/validation/lightClientFinalityUpdate.js"; import {getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; describe("Light Client Finality Update validation", () => { diff --git a/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts b/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts index 7665b4f89179..85a1ebb16330 100644 --- a/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {altair, ssz} from "@lodestar/types"; import {computeTimeAtSlot} from "@lodestar/state-transition"; +import {altair, ssz} from "@lodestar/types"; import {RequiredSelective} from "@lodestar/utils"; -import {validateLightClientOptimisticUpdate} from "../../../../src/chain/validation/lightClientOptimisticUpdate.js"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {LightClientErrorCode} from "../../../../src/chain/errors/lightClientError.js"; import {IBeaconChain} from "../../../../src/chain/index.js"; +import {validateLightClientOptimisticUpdate} from "../../../../src/chain/validation/lightClientOptimisticUpdate.js"; import {getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; describe("Light Client Optimistic Update validation", () => { diff --git a/packages/beacon-node/test/unit/chain/validation/proposerSlashing.test.ts b/packages/beacon-node/test/unit/chain/validation/proposerSlashing.test.ts index f5eb7310a39c..4d1fcb3f2490 100644 --- a/packages/beacon-node/test/unit/chain/validation/proposerSlashing.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/proposerSlashing.test.ts @@ -1,10 +1,10 @@ -import {describe, it, beforeEach, afterEach, vi} from "vitest"; import {phase0, ssz} from "@lodestar/types"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; -import {generateCachedState} from "../../../utils/state.js"; +import {afterEach, beforeEach, describe, it, vi} from "vitest"; import {ProposerSlashingErrorCode} from "../../../../src/chain/errors/proposerSlashingError.js"; import {validateGossipProposerSlashing} from "../../../../src/chain/validation/proposerSlashing.js"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; +import {generateCachedState} from "../../../utils/state.js"; describe("validate proposer slashing", () => { let chainStub: MockedBeaconChain; diff --git a/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts b/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts index cbffc2a4ffd9..6ed254254154 100644 --- a/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts @@ -1,15 +1,15 @@ import {toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, afterEach, beforeEach, beforeAll, afterAll, vi, Mock} from "vitest"; -import {altair, Epoch, Slot} from "@lodestar/types"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {Epoch, Slot, altair} from "@lodestar/types"; +import {Mock, afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; import {SyncCommitteeErrorCode} from "../../../../src/chain/errors/syncCommitteeError.js"; +import {SeenSyncCommitteeMessages} from "../../../../src/chain/seenCache/index.js"; import {validateGossipSyncCommittee} from "../../../../src/chain/validation/syncCommittee.js"; +import {ZERO_HASH} from "../../../../src/constants/constants.js"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {generateCachedAltairState} from "../../../utils/state.js"; -import {SeenSyncCommitteeMessages} from "../../../../src/chain/seenCache/index.js"; -import {ZERO_HASH} from "../../../../src/constants/constants.js"; // https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/altair/p2p-interface.md describe("Sync Committee Signature validation", () => { diff --git a/packages/beacon-node/test/unit/chain/validation/voluntaryExit.test.ts b/packages/beacon-node/test/unit/chain/validation/voluntaryExit.test.ts index d556ff610961..697489b8523d 100644 --- a/packages/beacon-node/test/unit/chain/validation/voluntaryExit.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/voluntaryExit.test.ts @@ -1,21 +1,21 @@ -import {describe, it, beforeEach, beforeAll, vi, afterEach} from "vitest"; import {SecretKey} from "@chainsafe/blst"; +import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; +import {DOMAIN_VOLUNTARY_EXIT, FAR_FUTURE_EPOCH, SLOTS_PER_EPOCH} from "@lodestar/params"; import { CachedBeaconStateAllForks, - computeEpochAtSlot, computeDomain, + computeEpochAtSlot, computeSigningRoot, } from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; -import {DOMAIN_VOLUNTARY_EXIT, FAR_FUTURE_EPOCH, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {createBeaconConfig} from "@lodestar/config"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; -import {generateState} from "../../../utils/state.js"; -import {validateGossipVoluntaryExit} from "../../../../src/chain/validation/voluntaryExit.js"; +import {afterEach, beforeAll, beforeEach, describe, it, vi} from "vitest"; import {VoluntaryExitErrorCode} from "../../../../src/chain/errors/voluntaryExitError.js"; -import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; +import {validateGossipVoluntaryExit} from "../../../../src/chain/validation/voluntaryExit.js"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; +import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; +import {generateState} from "../../../utils/state.js"; describe("validate voluntary exit", () => { let chainStub: MockedBeaconChain; diff --git a/packages/beacon-node/test/unit/db/api/repositories/blockArchive.test.ts b/packages/beacon-node/test/unit/db/api/repositories/blockArchive.test.ts index b87e9b926fdd..923a143b6766 100644 --- a/packages/beacon-node/test/unit/db/api/repositories/blockArchive.test.ts +++ b/packages/beacon-node/test/unit/db/api/repositories/blockArchive.test.ts @@ -1,13 +1,13 @@ -import {rimraf} from "rimraf"; -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; -import {ssz} from "@lodestar/types"; import {config} from "@lodestar/config/default"; -import {intToBytes} from "@lodestar/utils"; import {LevelDbController, encodeKey} from "@lodestar/db"; +import {ssz} from "@lodestar/types"; +import {intToBytes} from "@lodestar/utils"; +import {rimraf} from "rimraf"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; +import {Bucket} from "../../../../../src/db/buckets.js"; import {BlockArchiveRepository} from "../../../../../src/db/repositories/index.js"; import {testLogger} from "../../../../utils/logger.js"; -import {Bucket} from "../../../../../src/db/buckets.js"; describe("block archive repository", () => { const testDir = "./.tmp"; diff --git a/packages/beacon-node/test/unit/db/api/repository.test.ts b/packages/beacon-node/test/unit/db/api/repository.test.ts index 3b2840b3f0be..e2b908bac777 100644 --- a/packages/beacon-node/test/unit/db/api/repository.test.ts +++ b/packages/beacon-node/test/unit/db/api/repository.test.ts @@ -1,9 +1,9 @@ -import all from "it-all"; import {ContainerType} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, vi, afterEach, MockedObject} from "vitest"; -import {Bytes32, ssz} from "@lodestar/types"; import {config} from "@lodestar/config/default"; import {Db, LevelDbController, Repository} from "@lodestar/db"; +import {Bytes32, ssz} from "@lodestar/types"; +import all from "it-all"; +import {MockedObject, afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {Bucket} from "../../../../src/db/buckets.js"; vi.mock("@lodestar/db", async (importOriginal) => { diff --git a/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts b/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts index 40988ed21728..d46e2870fd41 100644 --- a/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts +++ b/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts @@ -1,12 +1,12 @@ -import {describe, it, expect, beforeEach, afterEach, vi, MockInstance} from "vitest"; import {config} from "@lodestar/config/default"; import {TimeoutError} from "@lodestar/utils"; +import {MockInstance, afterEach, beforeEach, describe, expect, it, vi} from "vitest"; +import {BeaconDb} from "../../../src/db/beacon.js"; import {Eth1DepositDataTracker} from "../../../src/eth1/eth1DepositDataTracker.js"; -import {Eth1Provider} from "../../../src/eth1/provider/eth1Provider.js"; -import {testLogger} from "../../utils/logger.js"; import {defaultEth1Options} from "../../../src/eth1/options.js"; -import {BeaconDb} from "../../../src/db/beacon.js"; +import {Eth1Provider} from "../../../src/eth1/provider/eth1Provider.js"; import {getMockedBeaconDb} from "../../mocks/mockedBeaconDb.js"; +import {testLogger} from "../../utils/logger.js"; describe("Eth1DepositDataTracker", () => { const controller = new AbortController(); diff --git a/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts b/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts index c7f4c8fb7aa4..38ac5dd87fb7 100644 --- a/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts +++ b/packages/beacon-node/test/unit/eth1/eth1MergeBlockTracker.test.ts @@ -1,11 +1,11 @@ import {toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, afterEach} from "vitest"; import {ChainConfig} from "@lodestar/config"; import {sleep} from "@lodestar/utils"; -import {IEth1Provider} from "../../../src/index.js"; +import {afterEach, beforeEach, describe, expect, it} from "vitest"; import {ZERO_HASH} from "../../../src/constants/index.js"; import {Eth1MergeBlockTracker, StatusCode, toPowBlock} from "../../../src/eth1/eth1MergeBlockTracker.js"; import {Eth1ProviderState, EthJsonRpcBlockRaw} from "../../../src/eth1/interface.js"; +import {IEth1Provider} from "../../../src/index.js"; import {testLogger} from "../../utils/logger.js"; describe("eth1 / Eth1MergeBlockTracker", () => { diff --git a/packages/beacon-node/test/unit/eth1/hexEncoding.test.ts b/packages/beacon-node/test/unit/eth1/hexEncoding.test.ts index 5e5dd953cd61..bb2782f2f735 100644 --- a/packages/beacon-node/test/unit/eth1/hexEncoding.test.ts +++ b/packages/beacon-node/test/unit/eth1/hexEncoding.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import { QUANTITY, + bytesToQuantity, + numToQuantity, + quantityToBigint, quantityToBytes, quantityToNum, - quantityToBigint, - numToQuantity, - bytesToQuantity, } from "../../../src/eth1/provider/utils.js"; describe("eth1 / hex encoding", () => { diff --git a/packages/beacon-node/test/unit/eth1/jwt.test.ts b/packages/beacon-node/test/unit/eth1/jwt.test.ts index 5ebcdc17e355..c96344b37c6a 100644 --- a/packages/beacon-node/test/unit/eth1/jwt.test.ts +++ b/packages/beacon-node/test/unit/eth1/jwt.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; -import {encodeJwtToken, decodeJwtToken} from "../../../src/eth1/provider/jwt.js"; +import {describe, expect, it} from "vitest"; +import {decodeJwtToken, encodeJwtToken} from "../../../src/eth1/provider/jwt.js"; describe("ExecutionEngine / jwt", () => { it("encode/decode correctly", () => { diff --git a/packages/beacon-node/test/unit/eth1/utils/depositContract.test.ts b/packages/beacon-node/test/unit/eth1/utils/depositContract.test.ts index 22ca95765a9a..260cb4fef4bd 100644 --- a/packages/beacon-node/test/unit/eth1/utils/depositContract.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/depositContract.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {goerliTestnetLogs, goerliTestnetDepositEvents} from "../../../utils/testnet.js"; +import {describe, expect, it} from "vitest"; import {parseDepositLog} from "../../../../src/eth1/utils/depositContract.js"; +import {goerliTestnetDepositEvents, goerliTestnetLogs} from "../../../utils/testnet.js"; describe("eth1 / util / depositContract", () => { it("Should parse a raw deposit log", () => { diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index 34334d1b3f8b..2853bff0f8dd 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -1,15 +1,15 @@ -import {describe, it, expect} from "vitest"; -import {phase0, ssz} from "@lodestar/types"; +import {createChainForkConfig} from "@lodestar/config"; import {MAX_DEPOSITS, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {phase0, ssz} from "@lodestar/types"; import {verifyMerkleBranch} from "@lodestar/utils"; -import {createChainForkConfig} from "@lodestar/config"; -import {filterBy} from "../../../utils/db.js"; -import {Eth1ErrorCode} from "../../../../src/eth1/errors.js"; -import {generateState} from "../../../utils/state.js"; -import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; -import {getDeposits, getDepositsWithProofs, DepositGetter} from "../../../../src/eth1/utils/deposits.js"; +import {describe, expect, it} from "vitest"; import {DepositTree} from "../../../../src/db/repositories/depositDataRoot.js"; +import {Eth1ErrorCode} from "../../../../src/eth1/errors.js"; +import {DepositGetter, getDeposits, getDepositsWithProofs} from "../../../../src/eth1/utils/deposits.js"; import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; +import {filterBy} from "../../../utils/db.js"; +import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; +import {generateState} from "../../../utils/state.js"; describe("eth1 / util / deposits", () => { describe("getDeposits", () => { diff --git a/packages/beacon-node/test/unit/eth1/utils/eth1Data.test.ts b/packages/beacon-node/test/unit/eth1/utils/eth1Data.test.ts index dff98500b293..c4107d06e43e 100644 --- a/packages/beacon-node/test/unit/eth1/utils/eth1Data.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/eth1Data.test.ts @@ -1,16 +1,16 @@ -import {describe, it, expect} from "vitest"; import {Root, phase0, ssz} from "@lodestar/types"; import {toHex} from "@lodestar/utils"; -import {iteratorFromArray} from "../../../utils/interator.js"; +import {describe, expect, it} from "vitest"; +import {DepositTree} from "../../../../src/db/repositories/depositDataRoot.js"; +import {Eth1ErrorCode} from "../../../../src/eth1/errors.js"; +import {Eth1Block} from "../../../../src/eth1/interface.js"; import { - getEth1DataForBlocks, - getDepositsByBlockNumber, getDepositRootByDepositCount, + getDepositsByBlockNumber, + getEth1DataForBlocks, } from "../../../../src/eth1/utils/eth1Data.js"; -import {Eth1Block} from "../../../../src/eth1/interface.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; -import {Eth1ErrorCode} from "../../../../src/eth1/errors.js"; -import {DepositTree} from "../../../../src/db/repositories/depositDataRoot.js"; +import {iteratorFromArray} from "../../../utils/interator.js"; describe("eth1 / util / getEth1DataForBlocks", () => { type TestCase = { diff --git a/packages/beacon-node/test/unit/eth1/utils/eth1DepositEvent.test.ts b/packages/beacon-node/test/unit/eth1/utils/eth1DepositEvent.test.ts index ea504464778c..a1de0fa748e3 100644 --- a/packages/beacon-node/test/unit/eth1/utils/eth1DepositEvent.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/eth1DepositEvent.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {assertConsecutiveDeposits} from "../../../../src/eth1/utils/eth1DepositEvent.js"; describe("eth1 / util / assertConsecutiveDeposits", () => { diff --git a/packages/beacon-node/test/unit/eth1/utils/eth1Vote.test.ts b/packages/beacon-node/test/unit/eth1/utils/eth1Vote.test.ts index e9a9ab5aad24..f8221f76a0f5 100644 --- a/packages/beacon-node/test/unit/eth1/utils/eth1Vote.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/eth1Vote.test.ts @@ -1,16 +1,16 @@ -import {describe, it, expect} from "vitest"; -import {config} from "@lodestar/config/default"; -import {phase0, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; +import {config} from "@lodestar/config/default"; import {BeaconStateAllForks} from "@lodestar/state-transition"; -import {generateState} from "../../../utils/state.js"; -import {filterBy} from "../../../utils/db.js"; +import {phase0, ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import { + Eth1DataGetter, getEth1VotesToConsider, pickEth1Vote, votingPeriodStartTime, - Eth1DataGetter, } from "../../../../src/eth1/utils/eth1Vote.js"; +import {filterBy} from "../../../utils/db.js"; +import {generateState} from "../../../utils/state.js"; describe("eth1 / util / eth1Vote", () => { function generateEth1Vote(i: number): phase0.Eth1Data { diff --git a/packages/beacon-node/test/unit/eth1/utils/groupDepositEventsByBlock.test.ts b/packages/beacon-node/test/unit/eth1/utils/groupDepositEventsByBlock.test.ts index a4e786b3aa68..6c9e9b47c1ae 100644 --- a/packages/beacon-node/test/unit/eth1/utils/groupDepositEventsByBlock.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/groupDepositEventsByBlock.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {phase0} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import {groupDepositEventsByBlock} from "../../../../src/eth1/utils/groupDepositEventsByBlock.js"; describe("eth1 / util / groupDepositEventsByBlock", () => { diff --git a/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts b/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts index 39c4a4d6e773..38a4e6fa83e2 100644 --- a/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/optimizeNextBlockDiffForGenesis.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {optimizeNextBlockDiffForGenesis} from "../../../../src/eth1/utils/optimizeNextBlockDiffForGenesis.js"; +import {describe, expect, it} from "vitest"; import {Eth1Block} from "../../../../src/eth1/interface.js"; +import {optimizeNextBlockDiffForGenesis} from "../../../../src/eth1/utils/optimizeNextBlockDiffForGenesis.js"; describe("eth1 / utils / optimizeNextBlockDiffForGenesis", () => { it("should return optimized block diff to find genesis time", () => { diff --git a/packages/beacon-node/test/unit/execution/engine/utils.test.ts b/packages/beacon-node/test/unit/execution/engine/utils.test.ts index b81c3e965390..c181166c2aea 100644 --- a/packages/beacon-node/test/unit/execution/engine/utils.test.ts +++ b/packages/beacon-node/test/unit/execution/engine/utils.test.ts @@ -1,14 +1,14 @@ -import {describe, it, expect} from "vitest"; -import {ErrorAborted} from "@lodestar/utils"; import {FetchError} from "@lodestar/api"; -import {ExecutionPayloadStatus, ExecutionEngineState} from "../../../../src/execution/index.js"; +import {ErrorAborted} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; +import {ErrorJsonRpcResponse, HttpRpcError} from "../../../../src/eth1/provider/jsonRpcHttpClient.js"; import { HTTP_CONNECTION_ERROR_CODES, HTTP_FATAL_ERROR_CODES, getExecutionEngineState, } from "../../../../src/execution/engine/utils.js"; +import {ExecutionEngineState, ExecutionPayloadStatus} from "../../../../src/execution/index.js"; import {QueueError, QueueErrorCode} from "../../../../src/util/queue/errors.js"; -import {ErrorJsonRpcResponse, HttpRpcError} from "../../../../src/eth1/provider/jsonRpcHttpClient.js"; describe("execution / engine / utils", () => { describe("getExecutionEngineState", () => { diff --git a/packages/beacon-node/test/unit/executionEngine/http.test.ts b/packages/beacon-node/test/unit/executionEngine/http.test.ts index c9f4ae671e53..5c7078500640 100644 --- a/packages/beacon-node/test/unit/executionEngine/http.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/http.test.ts @@ -1,16 +1,16 @@ -import {fastify} from "fastify"; -import {describe, it, expect, beforeAll, afterAll} from "vitest"; -import {ForkName} from "@lodestar/params"; import {Logger} from "@lodestar/logger"; +import {ForkName} from "@lodestar/params"; +import {fastify} from "fastify"; +import {afterAll, beforeAll, describe, expect, it} from "vitest"; +import {RpcPayload} from "../../../src/eth1/interface.js"; +import {numToQuantity} from "../../../src/eth1/provider/utils.js"; import {defaultExecutionEngineHttpOpts} from "../../../src/execution/engine/http.js"; -import {IExecutionEngine, initializeExecutionEngine} from "../../../src/execution/index.js"; import { parseExecutionPayload, serializeExecutionPayload, serializeExecutionPayloadBody, } from "../../../src/execution/engine/types.js"; -import {RpcPayload} from "../../../src/eth1/interface.js"; -import {numToQuantity} from "../../../src/eth1/provider/utils.js"; +import {IExecutionEngine, initializeExecutionEngine} from "../../../src/execution/index.js"; describe("ExecutionEngine / http", () => { const afterCallbacks: (() => Promise | void)[] = []; diff --git a/packages/beacon-node/test/unit/executionEngine/httpRetry.test.ts b/packages/beacon-node/test/unit/executionEngine/httpRetry.test.ts index b254fc9d8b45..e84a1edd1e4f 100644 --- a/packages/beacon-node/test/unit/executionEngine/httpRetry.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/httpRetry.test.ts @@ -1,11 +1,11 @@ -import {fastify} from "fastify"; import {fromHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeAll, afterAll} from "vitest"; -import {ForkName} from "@lodestar/params"; import {Logger} from "@lodestar/logger"; -import {defaultExecutionEngineHttpOpts} from "../../../src/execution/engine/http.js"; +import {ForkName} from "@lodestar/params"; +import {fastify} from "fastify"; +import {afterAll, beforeAll, describe, expect, it} from "vitest"; import {bytesToData, numToQuantity} from "../../../src/eth1/provider/utils.js"; -import {IExecutionEngine, initializeExecutionEngine, PayloadAttributes} from "../../../src/execution/index.js"; +import {defaultExecutionEngineHttpOpts} from "../../../src/execution/engine/http.js"; +import {IExecutionEngine, PayloadAttributes, initializeExecutionEngine} from "../../../src/execution/index.js"; describe("ExecutionEngine / http ", () => { const afterCallbacks: (() => Promise | void)[] = []; diff --git a/packages/beacon-node/test/unit/metrics/beacon.test.ts b/packages/beacon-node/test/unit/metrics/beacon.test.ts index 070ea9064be5..b1d32166fe33 100644 --- a/packages/beacon-node/test/unit/metrics/beacon.test.ts +++ b/packages/beacon-node/test/unit/metrics/beacon.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {createMetricsTest} from "./utils.js"; describe("BeaconMetrics", () => { diff --git a/packages/beacon-node/test/unit/metrics/metrics.test.ts b/packages/beacon-node/test/unit/metrics/metrics.test.ts index 327142a81b5f..f654f97180af 100644 --- a/packages/beacon-node/test/unit/metrics/metrics.test.ts +++ b/packages/beacon-node/test/unit/metrics/metrics.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {createMetricsTest} from "./utils.js"; describe("Metrics", () => { diff --git a/packages/beacon-node/test/unit/metrics/server/http.test.ts b/packages/beacon-node/test/unit/metrics/server/http.test.ts index 623410ccd7ae..4356a2e579e8 100644 --- a/packages/beacon-node/test/unit/metrics/server/http.test.ts +++ b/packages/beacon-node/test/unit/metrics/server/http.test.ts @@ -1,6 +1,6 @@ -import {describe, it, afterAll} from "vitest"; import {fetch} from "@lodestar/api"; -import {getHttpMetricsServer, HttpMetricsServer} from "../../../../src/metrics/index.js"; +import {afterAll, describe, it} from "vitest"; +import {HttpMetricsServer, getHttpMetricsServer} from "../../../../src/metrics/index.js"; import {testLogger} from "../../../utils/logger.js"; import {createMetricsTest} from "../utils.js"; diff --git a/packages/beacon-node/test/unit/metrics/utils.test.ts b/packages/beacon-node/test/unit/metrics/utils.test.ts index 921a549eaf5c..8932d601c273 100644 --- a/packages/beacon-node/test/unit/metrics/utils.test.ts +++ b/packages/beacon-node/test/unit/metrics/utils.test.ts @@ -1,5 +1,5 @@ import {Gauge, Registry} from "prom-client"; -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {GaugeExtra} from "../../../src/metrics/utils/gauge.js"; type MetricValue = { diff --git a/packages/beacon-node/test/unit/metrics/utils.ts b/packages/beacon-node/test/unit/metrics/utils.ts index 53e61826250c..93c635d15b85 100644 --- a/packages/beacon-node/test/unit/metrics/utils.ts +++ b/packages/beacon-node/test/unit/metrics/utils.ts @@ -1,6 +1,6 @@ import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; -import {createMetrics, Metrics} from "../../../src/metrics/index.js"; +import {Metrics, createMetrics} from "../../../src/metrics/index.js"; import {testLogger} from "../../utils/logger.js"; export function createMetricsTest(): Metrics { diff --git a/packages/beacon-node/test/unit/monitoring/clientStats.test.ts b/packages/beacon-node/test/unit/monitoring/clientStats.test.ts index d14fd88796f2..e4e1e3714a6e 100644 --- a/packages/beacon-node/test/unit/monitoring/clientStats.test.ts +++ b/packages/beacon-node/test/unit/monitoring/clientStats.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {ClientStats} from "../../../src/monitoring/types.js"; +import {describe, expect, it} from "vitest"; import {createClientStats} from "../../../src/monitoring/clientStats.js"; +import {ClientStats} from "../../../src/monitoring/types.js"; import {BEACON_NODE_STATS_SCHEMA, ClientStatsSchema, SYSTEM_STATS_SCHEMA, VALIDATOR_STATS_SCHEMA} from "./schemas.js"; describe("monitoring / clientStats", () => { diff --git a/packages/beacon-node/test/unit/monitoring/properties.test.ts b/packages/beacon-node/test/unit/monitoring/properties.test.ts index 1a2e2c58377a..184617389443 100644 --- a/packages/beacon-node/test/unit/monitoring/properties.test.ts +++ b/packages/beacon-node/test/unit/monitoring/properties.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, beforeAll} from "vitest"; +import {beforeAll, describe, expect, it} from "vitest"; import {Metrics} from "../../../src/metrics/index.js"; import {DynamicProperty, MetricProperty, StaticProperty} from "../../../src/monitoring/properties.js"; import {JsonType} from "../../../src/monitoring/types.js"; diff --git a/packages/beacon-node/test/unit/monitoring/service.test.ts b/packages/beacon-node/test/unit/monitoring/service.test.ts index fed64b9bc553..06fd0d1f511a 100644 --- a/packages/beacon-node/test/unit/monitoring/service.test.ts +++ b/packages/beacon-node/test/unit/monitoring/service.test.ts @@ -1,12 +1,12 @@ -import {describe, it, expect, beforeEach, beforeAll, afterAll, vi, afterEach, MockInstance} from "vitest"; -import {Histogram} from "prom-client"; import {ErrorAborted, TimeoutError} from "@lodestar/utils"; +import {Histogram} from "prom-client"; +import {MockInstance, afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; import {RegistryMetricCreator} from "../../../src/index.js"; -import {MonitoringService} from "../../../src/monitoring/service.js"; import {MonitoringOptions} from "../../../src/monitoring/options.js"; -import {sleep} from "../../utils/sleep.js"; +import {MonitoringService} from "../../../src/monitoring/service.js"; import {MockedLogger, getMockedLogger} from "../../mocks/loggerMock.js"; -import {startRemoteService, remoteServiceRoutes, remoteServiceError} from "./remoteService.js"; +import {sleep} from "../../utils/sleep.js"; +import {remoteServiceError, remoteServiceRoutes, startRemoteService} from "./remoteService.js"; describe("monitoring / service", () => { const endpoint = "https://test.example.com/api/v1/client/metrics"; diff --git a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts index 2104235e7215..2d9c0967a409 100644 --- a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts +++ b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts @@ -1,13 +1,13 @@ -import {describe, it, expect, beforeAll} from "vitest"; -import {ssz, deneb} from "@lodestar/types"; -import {ForkName} from "@lodestar/params"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; +import {ForkName} from "@lodestar/params"; +import {deneb, ssz} from "@lodestar/types"; +import {beforeAll, describe, expect, it} from "vitest"; +import {BlobsSource, BlockSource, getBlockInput} from "../../../src/chain/blocks/types.js"; +import {ZERO_HASH} from "../../../src/constants/constants.js"; +import {INetwork} from "../../../src/network/interface.js"; import {beaconBlocksMaybeBlobsByRange} from "../../../src/network/reqresp/index.js"; -import {BlockSource, BlobsSource, getBlockInput} 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"; describe("beaconBlocksMaybeBlobsByRange", () => { beforeAll(async () => { diff --git a/packages/beacon-node/test/unit/network/fork.test.ts b/packages/beacon-node/test/unit/network/fork.test.ts index bbe1c0870d30..ed11ce979ef0 100644 --- a/packages/beacon-node/test/unit/network/fork.test.ts +++ b/packages/beacon-node/test/unit/network/fork.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; -import {ForkName, ForkSeq} from "@lodestar/params"; import {BeaconConfig, ForkInfo} from "@lodestar/config"; -import {getCurrentAndNextFork, getActiveForks} from "../../../src/network/forks.js"; +import {ForkName, ForkSeq} from "@lodestar/params"; +import {describe, expect, it} from "vitest"; +import {getActiveForks, getCurrentAndNextFork} from "../../../src/network/forks.js"; function getForkConfig({ phase0, diff --git a/packages/beacon-node/test/unit/network/gossip/topic.test.ts b/packages/beacon-node/test/unit/network/gossip/topic.test.ts index 2a61d8604439..f68c2d737fd6 100644 --- a/packages/beacon-node/test/unit/network/gossip/topic.test.ts +++ b/packages/beacon-node/test/unit/network/gossip/topic.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; import {ForkName} from "@lodestar/params"; -import {GossipType, GossipEncoding, GossipTopicMap} from "../../../../src/network/gossip/index.js"; +import {describe, expect, it} from "vitest"; +import {GossipEncoding, GossipTopicMap, GossipType} from "../../../../src/network/gossip/index.js"; import {parseGossipTopic, stringifyGossipTopic} from "../../../../src/network/gossip/topic.js"; import {config} from "../../../utils/config.js"; diff --git a/packages/beacon-node/test/unit/network/metadata.test.ts b/packages/beacon-node/test/unit/network/metadata.test.ts index 50e4157a29cd..90b75a16df66 100644 --- a/packages/beacon-node/test/unit/network/metadata.test.ts +++ b/packages/beacon-node/test/unit/network/metadata.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {toHex} from "@lodestar/utils"; import {ssz} from "@lodestar/types"; +import {toHex} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; import {getENRForkID} from "../../../src/network/metadata.js"; import {config} from "../../utils/config.js"; 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 44d16ad4bb8f..6d280d82ddcf 100644 --- a/packages/beacon-node/test/unit/network/peers/client.test.ts +++ b/packages/beacon-node/test/unit/network/peers/client.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; -import {getKnownClientFromAgentVersion, ClientKind} from "../../../../src/network/peers/client.js"; +import {describe, expect, it} from "vitest"; +import {ClientKind, getKnownClientFromAgentVersion} from "../../../../src/network/peers/client.js"; describe("clientFromAgentVersion", () => { const testCases: {name: string; agentVersion: string; client: ClientKind | null}[] = [ diff --git a/packages/beacon-node/test/unit/network/peers/datastore.test.ts b/packages/beacon-node/test/unit/network/peers/datastore.test.ts index 6ef60b0962e5..01bdc5b058e5 100644 --- a/packages/beacon-node/test/unit/network/peers/datastore.test.ts +++ b/packages/beacon-node/test/unit/network/peers/datastore.test.ts @@ -1,6 +1,6 @@ import {LevelDatastore} from "datastore-level"; import {Key} from "interface-datastore"; -import {describe, it, expect, beforeEach, afterEach, vi, MockedObject} from "vitest"; +import {MockedObject, afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {Eth2PeerDataStore} from "../../../../src/network/peers/datastore.js"; vi.mock("datastore-level"); diff --git a/packages/beacon-node/test/unit/network/peers/discover.test.ts b/packages/beacon-node/test/unit/network/peers/discover.test.ts index 52e254ec70aa..40614a3c55d1 100644 --- a/packages/beacon-node/test/unit/network/peers/discover.test.ts +++ b/packages/beacon-node/test/unit/network/peers/discover.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {getValidPeerId} from "../../../utils/peer.js"; +import {describe, expect, it} from "vitest"; import {peerIdFromString} from "../../../../src/util/peerId.js"; +import {getValidPeerId} from "../../../utils/peer.js"; describe("network / peers / discover", () => { it("PeerId API", () => { diff --git a/packages/beacon-node/test/unit/network/peers/priorization.test.ts b/packages/beacon-node/test/unit/network/peers/priorization.test.ts index 26f8d8c9e535..168335a4bd31 100644 --- a/packages/beacon-node/test/unit/network/peers/priorization.test.ts +++ b/packages/beacon-node/test/unit/network/peers/priorization.test.ts @@ -1,16 +1,16 @@ +import {BitArray} from "@chainsafe/ssz"; import {PeerId} from "@libp2p/interface"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; -import {BitArray} from "@chainsafe/ssz"; -import {describe, it, expect} from "vitest"; import {ATTESTATION_SUBNET_COUNT} from "@lodestar/params"; +import {describe, expect, it} from "vitest"; +import {RequestedSubnet} from "../../../../src/network/peers/utils/index.js"; import { ExcessPeerDisconnectReason, - prioritizePeers, PrioritizePeersOpts, + prioritizePeers, sortPeersToPrune, } from "../../../../src/network/peers/utils/prioritizePeers.js"; import {getAttnets, getSyncnets} from "../../../utils/network.js"; -import {RequestedSubnet} from "../../../../src/network/peers/utils/index.js"; type Result = ReturnType; diff --git a/packages/beacon-node/test/unit/network/peers/score.test.ts b/packages/beacon-node/test/unit/network/peers/score.test.ts index 8962b282e0ad..2a5c7d51be59 100644 --- a/packages/beacon-node/test/unit/network/peers/score.test.ts +++ b/packages/beacon-node/test/unit/network/peers/score.test.ts @@ -1,13 +1,13 @@ -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; import {MapDef} from "@lodestar/utils"; -import {peerIdFromString} from "../../../../src/util/peerId.js"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import { PeerAction, - ScoreState, PeerRpcScoreStore, - updateGossipsubScores, RealScore, + ScoreState, + updateGossipsubScores, } from "../../../../src/network/peers/score/index.js"; +import {peerIdFromString} from "../../../../src/util/peerId.js"; vi.mock("../../../../src/network/peers/score/index.js", async (importActual) => { const mod = await importActual(); diff --git a/packages/beacon-node/test/unit/network/peers/utils/assertPeerRelevance.test.ts b/packages/beacon-node/test/unit/network/peers/utils/assertPeerRelevance.test.ts index 19cf4a9e9c5e..b3ee9e49b3ed 100644 --- a/packages/beacon-node/test/unit/network/peers/utils/assertPeerRelevance.test.ts +++ b/packages/beacon-node/test/unit/network/peers/utils/assertPeerRelevance.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; import {phase0} from "@lodestar/types"; -import {assertPeerRelevance, IrrelevantPeerCode} from "../../../../../src/network/peers/utils/assertPeerRelevance.js"; +import {describe, expect, it} from "vitest"; +import {IrrelevantPeerCode, assertPeerRelevance} from "../../../../../src/network/peers/utils/assertPeerRelevance.js"; describe("network / peers / utils / assertPeerRelevance", () => { const correctForkDigest = Buffer.alloc(4, 0); diff --git a/packages/beacon-node/test/unit/network/peers/utils/enrSubnets.test.ts b/packages/beacon-node/test/unit/network/peers/utils/enrSubnets.test.ts index 1c738c764404..c13cc6152f36 100644 --- a/packages/beacon-node/test/unit/network/peers/utils/enrSubnets.test.ts +++ b/packages/beacon-node/test/unit/network/peers/utils/enrSubnets.test.ts @@ -1,8 +1,8 @@ import {BitArray} from "@chainsafe/ssz"; -import {describe, it, expect} from "vitest"; import {SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {ssz} from "@lodestar/types"; import {toHex} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; import {deserializeEnrSubnets} from "../../../../../src/network/peers/utils/enrSubnetsDeserialize.js"; describe("ENR syncnets", () => { diff --git a/packages/beacon-node/test/unit/network/processor/aggregatorTracker.test.ts b/packages/beacon-node/test/unit/network/processor/aggregatorTracker.test.ts index da907fd737e9..f211ebbeffae 100644 --- a/packages/beacon-node/test/unit/network/processor/aggregatorTracker.test.ts +++ b/packages/beacon-node/test/unit/network/processor/aggregatorTracker.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, beforeEach} from "vitest"; +import {beforeEach, describe, expect, it} from "vitest"; import {AggregatorTracker} from "../../../../src/network/processor/aggregatorTracker.js"; describe("AggregatorTracker", () => { diff --git a/packages/beacon-node/test/unit/network/processor/gossipQueues/indexed.test.ts b/packages/beacon-node/test/unit/network/processor/gossipQueues/indexed.test.ts index 97f6bb804c99..3776f3e6cfd1 100644 --- a/packages/beacon-node/test/unit/network/processor/gossipQueues/indexed.test.ts +++ b/packages/beacon-node/test/unit/network/processor/gossipQueues/indexed.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {IndexedGossipQueueMinSize} from "../../../../../src/network/processor/gossipQueues/indexed.js"; type Item = { diff --git a/packages/beacon-node/test/unit/network/processor/gossipQueues/linear.test.ts b/packages/beacon-node/test/unit/network/processor/gossipQueues/linear.test.ts index 5848e1885622..9ad7c8e8b4ad 100644 --- a/packages/beacon-node/test/unit/network/processor/gossipQueues/linear.test.ts +++ b/packages/beacon-node/test/unit/network/processor/gossipQueues/linear.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, beforeEach} from "vitest"; +import {beforeEach, describe, expect, it} from "vitest"; import {LinearGossipQueue} from "../../../../../src/network/processor/gossipQueues/linear.js"; import {DropType} from "../../../../../src/network/processor/gossipQueues/types.js"; import {QueueType} from "../../../../../src/util/queue/index.js"; diff --git a/packages/beacon-node/test/unit/network/processorQueues.test.ts b/packages/beacon-node/test/unit/network/processorQueues.test.ts index 07a10591c0ad..23caae9dd774 100644 --- a/packages/beacon-node/test/unit/network/processorQueues.test.ts +++ b/packages/beacon-node/test/unit/network/processorQueues.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {sleep} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; type ValidateOpts = { skipAsync1: boolean; diff --git a/packages/beacon-node/test/unit/network/reqresp/collectSequentialBlocksInRange.test.ts b/packages/beacon-node/test/unit/network/reqresp/collectSequentialBlocksInRange.test.ts index fa9b47ebf026..79f076c828a7 100644 --- a/packages/beacon-node/test/unit/network/reqresp/collectSequentialBlocksInRange.test.ts +++ b/packages/beacon-node/test/unit/network/reqresp/collectSequentialBlocksInRange.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; -import {SignedBeaconBlock, phase0, ssz} from "@lodestar/types"; -import {ResponseIncoming} from "@lodestar/reqresp"; import {ForkName} from "@lodestar/params"; +import {ResponseIncoming} from "@lodestar/reqresp"; +import {SignedBeaconBlock, phase0, ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import { BlocksByRangeError, BlocksByRangeErrorCode, diff --git a/packages/beacon-node/test/unit/network/reqresp/utils.ts b/packages/beacon-node/test/unit/network/reqresp/utils.ts index 231bd0cc42fb..01ec743b5258 100644 --- a/packages/beacon-node/test/unit/network/reqresp/utils.ts +++ b/packages/beacon-node/test/unit/network/reqresp/utils.ts @@ -1,9 +1,9 @@ -import {expect} from "vitest"; +import {toHexString} from "@chainsafe/ssz"; import {Direction, ReadStatus, Stream, StreamStatus, WriteStatus} from "@libp2p/interface"; import {logger} from "@libp2p/logger"; -import {Uint8ArrayList} from "uint8arraylist"; -import {toHexString} from "@chainsafe/ssz"; import {Root} from "@lodestar/types"; +import {Uint8ArrayList} from "uint8arraylist"; +import {expect} from "vitest"; export function generateRoots(count: number, offset = 0): Root[] { const roots: Root[] = []; diff --git a/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts b/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts index d279a5d759d7..5e7149f4d7f8 100644 --- a/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts +++ b/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts @@ -1,6 +1,4 @@ -import {describe, it, expect, beforeEach, vi, MockedObject, afterEach} from "vitest"; import {createBeaconConfig} from "@lodestar/config"; -import {ZERO_HASH} from "@lodestar/state-transition"; import { ATTESTATION_SUBNET_COUNT, EPOCHS_PER_SUBNET_SUBSCRIPTION, @@ -8,14 +6,16 @@ import { SLOTS_PER_EPOCH, SUBNETS_PER_NODE, } from "@lodestar/params"; +import {ZERO_HASH} from "@lodestar/state-transition"; import {getCurrentSlot} from "@lodestar/state-transition"; import {bigIntToBytes} from "@lodestar/utils"; -import {Clock, IClock} from "../../../../src/util/clock.js"; +import {MockedObject, afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {Eth2Gossipsub} from "../../../../src/network/gossip/gossipsub.js"; import {MetadataController} from "../../../../src/network/metadata.js"; -import {testLogger} from "../../../utils/logger.js"; import {AttnetsService} from "../../../../src/network/subnets/attnetsService.js"; import {CommitteeSubscription} from "../../../../src/network/subnets/interface.js"; +import {Clock, IClock} from "../../../../src/util/clock.js"; +import {testLogger} from "../../../utils/logger.js"; vi.mock("../../../../src/network/gossip/gossipsub.js"); diff --git a/packages/beacon-node/test/unit/network/subnets/util.test.ts b/packages/beacon-node/test/unit/network/subnets/util.test.ts index dc2f261d021e..edcc96a772da 100644 --- a/packages/beacon-node/test/unit/network/subnets/util.test.ts +++ b/packages/beacon-node/test/unit/network/subnets/util.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {bigIntToBytes} from "@lodestar/utils"; import {ATTESTATION_SUBNET_PREFIX_BITS, NODE_ID_BITS} from "@lodestar/params"; +import {bigIntToBytes} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; import {getNodeIdPrefix, getNodeOffset} from "../../../../src/network/subnets/util.js"; const nodeIds: string[] = [ diff --git a/packages/beacon-node/test/unit/network/util.test.ts b/packages/beacon-node/test/unit/network/util.test.ts index 70da41bd2c2a..57e18a34a77b 100644 --- a/packages/beacon-node/test/unit/network/util.test.ts +++ b/packages/beacon-node/test/unit/network/util.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect, afterEach} from "vitest"; import {config} from "@lodestar/config/default"; import {ForkName} from "@lodestar/params"; -import {getDiscv5Multiaddrs} from "../../../src/network/libp2p/index.js"; +import {afterEach, describe, expect, it} from "vitest"; import {getCurrentAndNextFork} from "../../../src/network/forks.js"; +import {getDiscv5Multiaddrs} from "../../../src/network/libp2p/index.js"; describe("getCurrentAndNextFork", () => { const altairEpoch = config.forks.altair.epoch; diff --git a/packages/beacon-node/test/unit/sync/backfill/verify.test.ts b/packages/beacon-node/test/unit/sync/backfill/verify.test.ts index 3197013455e3..fb00e5840317 100644 --- a/packages/beacon-node/test/unit/sync/backfill/verify.test.ts +++ b/packages/beacon-node/test/unit/sync/backfill/verify.test.ts @@ -1,13 +1,13 @@ import fs from "node:fs"; import path from "node:path"; import {fileURLToPath} from "node:url"; -import {describe, it, expect} from "vitest"; import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; -import {phase0, ssz, WithBytes} from "@lodestar/types"; -import {verifyBlockSequence} from "../../../../src/sync/backfill/verify.js"; +import {WithBytes, phase0, ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import {ZERO_HASH} from "../../../../src/constants/constants.js"; -import {BackfillSyncErrorCode, BackfillSyncError} from "./../../../../src/sync/backfill/errors.js"; +import {verifyBlockSequence} from "../../../../src/sync/backfill/verify.js"; +import {BackfillSyncError, BackfillSyncErrorCode} from "./../../../../src/sync/backfill/errors.js"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules diff --git a/packages/beacon-node/test/unit/sync/range/batch.test.ts b/packages/beacon-node/test/unit/sync/range/batch.test.ts index 02f49226c11f..2a140760e827 100644 --- a/packages/beacon-node/test/unit/sync/range/batch.test.ts +++ b/packages/beacon-node/test/unit/sync/range/batch.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect} from "vitest"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {config} from "@lodestar/config/default"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {ssz} from "@lodestar/types"; -import {expectThrowsLodestarError} from "../../../utils/errors.js"; -import {Batch, BatchStatus, BatchErrorCode, BatchError} from "../../../../src/sync/range/batch.js"; -import {EPOCHS_PER_BATCH} from "../../../../src/sync/constants.js"; +import {describe, expect, it} from "vitest"; import {BlockSource, getBlockInput} from "../../../../src/chain/blocks/types.js"; +import {EPOCHS_PER_BATCH} from "../../../../src/sync/constants.js"; +import {Batch, BatchError, BatchErrorCode, BatchStatus} from "../../../../src/sync/range/batch.js"; +import {expectThrowsLodestarError} from "../../../utils/errors.js"; import {validPeerIdStr} from "../../../utils/peer.js"; describe("sync / range / batch", () => { // Common mock data diff --git a/packages/beacon-node/test/unit/sync/range/chain.test.ts b/packages/beacon-node/test/unit/sync/range/chain.test.ts index 658f950b2c18..a761cd3a739a 100644 --- a/packages/beacon-node/test/unit/sync/range/chain.test.ts +++ b/packages/beacon-node/test/unit/sync/range/chain.test.ts @@ -1,16 +1,16 @@ -import {describe, it, afterEach} from "vitest"; import {config} from "@lodestar/config/default"; -import {Logger} from "@lodestar/utils"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {Epoch, phase0, Slot, ssz} from "@lodestar/types"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {linspace} from "../../../../src/util/numpy.js"; -import {SyncChain, SyncChainFns, ChainTarget} from "../../../../src/sync/range/chain.js"; -import {RangeSyncType} from "../../../../src/sync/utils/remoteSyncType.js"; +import {Epoch, Slot, phase0, ssz} from "@lodestar/types"; +import {Logger} from "@lodestar/utils"; +import {afterEach, describe, it} from "vitest"; +import {BlockInput, BlockSource, getBlockInput} from "../../../../src/chain/blocks/types.js"; import {ZERO_HASH} from "../../../../src/constants/index.js"; +import {ChainTarget, SyncChain, SyncChainFns} from "../../../../src/sync/range/chain.js"; +import {RangeSyncType} from "../../../../src/sync/utils/remoteSyncType.js"; +import {linspace} from "../../../../src/util/numpy.js"; import {testLogger} from "../../../utils/logger.js"; import {validPeerIdStr} from "../../../utils/peer.js"; -import {BlockInput, BlockSource, getBlockInput} from "../../../../src/chain/blocks/types.js"; describe("sync / range / chain", () => { const testCases: { diff --git a/packages/beacon-node/test/unit/sync/range/utils/batches.test.ts b/packages/beacon-node/test/unit/sync/range/utils/batches.test.ts index c3c6a273dd8d..fcc5f9a1561a 100644 --- a/packages/beacon-node/test/unit/sync/range/utils/batches.test.ts +++ b/packages/beacon-node/test/unit/sync/range/utils/batches.test.ts @@ -1,15 +1,15 @@ -import {describe, it, expect} from "vitest"; import {config} from "@lodestar/config/default"; -import {Epoch, Slot} from "@lodestar/types"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {validPeerIdStr} from "../../../../utils/peer.js"; +import {Epoch, Slot} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import {Batch, BatchStatus} from "../../../../../src/sync/range/batch.js"; import { - validateBatchesStatus, getNextBatchToProcess, isSyncChainDone, toBeDownloadedStartEpoch, + validateBatchesStatus, } from "../../../../../src/sync/range/utils/batches.js"; +import {validPeerIdStr} from "../../../../utils/peer.js"; describe("sync / range / batches", () => { const peer = validPeerIdStr; diff --git a/packages/beacon-node/test/unit/sync/range/utils/peerBalancer.test.ts b/packages/beacon-node/test/unit/sync/range/utils/peerBalancer.test.ts index a495c41683d6..0eac008d2ecf 100644 --- a/packages/beacon-node/test/unit/sync/range/utils/peerBalancer.test.ts +++ b/packages/beacon-node/test/unit/sync/range/utils/peerBalancer.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {config} from "@lodestar/config/default"; +import {describe, expect, it} from "vitest"; import {Batch} from "../../../../../src/sync/range/batch.js"; import {ChainPeersBalancer} from "../../../../../src/sync/range/utils/peerBalancer.js"; import {getRandPeerIdStr} from "../../../../utils/peer.js"; diff --git a/packages/beacon-node/test/unit/sync/range/utils/updateChains.test.ts b/packages/beacon-node/test/unit/sync/range/utils/updateChains.test.ts index 4ff2da3d4441..cfdad515fb3c 100644 --- a/packages/beacon-node/test/unit/sync/range/utils/updateChains.test.ts +++ b/packages/beacon-node/test/unit/sync/range/utils/updateChains.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {updateChains} from "../../../../../src/sync/range/utils/updateChains.js"; +import {describe, expect, it} from "vitest"; import {SyncChain} from "../../../../../src/sync/range/chain.js"; +import {updateChains} from "../../../../../src/sync/range/utils/updateChains.js"; import {RangeSyncType} from "../../../../../src/sync/utils/remoteSyncType.js"; describe("sync / range / utils / updateChains", () => { diff --git a/packages/beacon-node/test/unit/sync/unknownBlock.test.ts b/packages/beacon-node/test/unit/sync/unknownBlock.test.ts index 0694cb97f4ab..8476d025d4f9 100644 --- a/packages/beacon-node/test/unit/sync/unknownBlock.test.ts +++ b/packages/beacon-node/test/unit/sync/unknownBlock.test.ts @@ -1,23 +1,23 @@ import EventEmitter from "node:events"; import {toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; -import {config as minimalConfig} from "@lodestar/config/default"; import {createChainForkConfig} from "@lodestar/config"; +import {config as minimalConfig} from "@lodestar/config/default"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {ssz} from "@lodestar/types"; import {notNullish, sleep} from "@lodestar/utils"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../mocks/mockedBeaconChain.js"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; +import {BlockSource, getBlockInput} from "../../../src/chain/blocks/types.js"; +import {BlockError, BlockErrorCode} from "../../../src/chain/errors/blockError.js"; import {IBeaconChain} from "../../../src/chain/index.js"; +import {SeenBlockProposers} from "../../../src/chain/seenCache/seenBlockProposers.js"; +import {ZERO_HASH} from "../../../src/constants/constants.js"; import {INetwork, NetworkEvent, NetworkEventBus, PeerAction} from "../../../src/network/index.js"; +import {defaultSyncOptions} from "../../../src/sync/options.js"; import {UnknownBlockSync} from "../../../src/sync/unknownBlock.js"; +import {ClockStopped} from "../../mocks/clock.js"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../mocks/mockedBeaconChain.js"; import {testLogger} from "../../utils/logger.js"; import {getRandPeerIdStr} from "../../utils/peer.js"; -import {BlockSource, getBlockInput} from "../../../src/chain/blocks/types.js"; -import {ClockStopped} from "../../mocks/clock.js"; -import {SeenBlockProposers} from "../../../src/chain/seenCache/seenBlockProposers.js"; -import {BlockError, BlockErrorCode} from "../../../src/chain/errors/blockError.js"; -import {defaultSyncOptions} from "../../../src/sync/options.js"; -import {ZERO_HASH} from "../../../src/constants/constants.js"; describe("sync by UnknownBlockSync", () => { const logger = testLogger(); diff --git a/packages/beacon-node/test/unit/sync/utils/pendingBlocksTree.test.ts b/packages/beacon-node/test/unit/sync/utils/pendingBlocksTree.test.ts index 8e343acc80df..9251c1159c64 100644 --- a/packages/beacon-node/test/unit/sync/utils/pendingBlocksTree.test.ts +++ b/packages/beacon-node/test/unit/sync/utils/pendingBlocksTree.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {RootHex} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import {PendingBlock, PendingBlockStatus, UnknownAndAncestorBlocks} from "../../../../src/sync/index.js"; import { getAllDescendantBlocks, diff --git a/packages/beacon-node/test/unit/sync/utils/remoteSyncType.test.ts b/packages/beacon-node/test/unit/sync/utils/remoteSyncType.test.ts index 0c74170e8029..7404362d8805 100644 --- a/packages/beacon-node/test/unit/sync/utils/remoteSyncType.test.ts +++ b/packages/beacon-node/test/unit/sync/utils/remoteSyncType.test.ts @@ -1,13 +1,13 @@ import {toHexString} from "@chainsafe/ssz"; -import {describe, it, expect} from "vitest"; import {IForkChoice} from "@lodestar/fork-choice"; import {Root, phase0} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import {ZERO_HASH} from "../../../../src/constants/index.js"; import { - getPeerSyncType, - getRangeSyncType, PeerSyncType, RangeSyncType, + getPeerSyncType, + getRangeSyncType, } from "../../../../src/sync/utils/remoteSyncType.js"; describe("network / peers / remoteSyncType", () => { diff --git a/packages/beacon-node/test/unit/util/address.test.ts b/packages/beacon-node/test/unit/util/address.test.ts index 27f7eba48e0c..cdc01f52797b 100644 --- a/packages/beacon-node/test/unit/util/address.test.ts +++ b/packages/beacon-node/test/unit/util/address.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {isValidAddress} from "../../../src/util/address.js"; describe("Eth address helper", () => { diff --git a/packages/beacon-node/test/unit/util/array.test.ts b/packages/beacon-node/test/unit/util/array.test.ts index 75d3a1b0856d..343a152bb857 100644 --- a/packages/beacon-node/test/unit/util/array.test.ts +++ b/packages/beacon-node/test/unit/util/array.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect, beforeEach} from "vitest"; -import {findLastIndex, LinkedList} from "../../../src/util/array.js"; +import {beforeEach, describe, expect, it} from "vitest"; +import {LinkedList, findLastIndex} from "../../../src/util/array.js"; describe("findLastIndex", () => { it("should return the last index that matches a predicate", () => { diff --git a/packages/beacon-node/test/unit/util/binarySearch.test.ts b/packages/beacon-node/test/unit/util/binarySearch.test.ts index a64420400c24..cccddbd9ffd8 100644 --- a/packages/beacon-node/test/unit/util/binarySearch.test.ts +++ b/packages/beacon-node/test/unit/util/binarySearch.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; -import {binarySearchLte, ErrorNoValues, ErrorNoValueMinValue} from "../../../src/util/binarySearch.js"; +import {describe, expect, it} from "vitest"; +import {ErrorNoValueMinValue, ErrorNoValues, binarySearchLte} from "../../../src/util/binarySearch.js"; describe("util / binarySearch", () => { describe("binarySearchLte", () => { diff --git a/packages/beacon-node/test/unit/util/bitArray.test.ts b/packages/beacon-node/test/unit/util/bitArray.test.ts index 516b4ae79155..7e569b71a8e2 100644 --- a/packages/beacon-node/test/unit/util/bitArray.test.ts +++ b/packages/beacon-node/test/unit/util/bitArray.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {IntersectResult, intersectUint8Arrays} from "../../../src/util/bitArray.js"; describe("util / bitArray / intersectUint8Arrays", () => { diff --git a/packages/beacon-node/test/unit/util/bufferPool.test.ts b/packages/beacon-node/test/unit/util/bufferPool.test.ts index ff66504ae65f..5c97a05a58e4 100644 --- a/packages/beacon-node/test/unit/util/bufferPool.test.ts +++ b/packages/beacon-node/test/unit/util/bufferPool.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {AllocSource, BufferPool} from "../../../src/util/bufferPool.js"; describe("BufferPool", () => { diff --git a/packages/beacon-node/test/unit/util/bytes.test.ts b/packages/beacon-node/test/unit/util/bytes.test.ts index 1942307cde75..38823939d48b 100644 --- a/packages/beacon-node/test/unit/util/bytes.test.ts +++ b/packages/beacon-node/test/unit/util/bytes.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {describe, expect, it} from "vitest"; import {byteArrayEquals} from "../../../src/util/bytes.js"; diff --git a/packages/beacon-node/test/unit/util/chunkify.test.ts b/packages/beacon-node/test/unit/util/chunkify.test.ts index 595c5807e1b3..c8af022ccf8e 100644 --- a/packages/beacon-node/test/unit/util/chunkify.test.ts +++ b/packages/beacon-node/test/unit/util/chunkify.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {chunkifyInclusiveRange} from "../../../src/util/chunkify.js"; describe("chunkifyInclusiveRange", () => { diff --git a/packages/beacon-node/test/unit/util/clock.test.ts b/packages/beacon-node/test/unit/util/clock.test.ts index 87955b98182c..cdb4aa39e1aa 100644 --- a/packages/beacon-node/test/unit/util/clock.test.ts +++ b/packages/beacon-node/test/unit/util/clock.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; import {config} from "@lodestar/config/default"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {Clock, ClockEvent} from "../../../src/util/clock.js"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../../../src/constants/index.js"; +import {Clock, ClockEvent} from "../../../src/util/clock.js"; describe("Clock", () => { let abortController: AbortController; diff --git a/packages/beacon-node/test/unit/util/dependentRoot.test.ts b/packages/beacon-node/test/unit/util/dependentRoot.test.ts index c8044f332e34..3961c3e1730b 100644 --- a/packages/beacon-node/test/unit/util/dependentRoot.test.ts +++ b/packages/beacon-node/test/unit/util/dependentRoot.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect, beforeEach, afterEach, vi, Mocked} from "vitest"; -import {EpochDifference, ProtoBlock, ForkChoice} from "@lodestar/fork-choice"; +import {EpochDifference, ForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {computeEpochAtSlot} from "@lodestar/state-transition"; +import {Mocked, afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {getShufflingDependentRoot} from "../../../src/util/dependentRoot.js"; vi.mock("@lodestar/fork-choice"); diff --git a/packages/beacon-node/test/unit/util/error.test.ts b/packages/beacon-node/test/unit/util/error.test.ts index 61aa4e42d35e..0293acf3f2ba 100644 --- a/packages/beacon-node/test/unit/util/error.test.ts +++ b/packages/beacon-node/test/unit/util/error.test.ts @@ -1,6 +1,6 @@ import v8 from "node:v8"; -import {describe, it, expect} from "vitest"; import {RequestError, RequestErrorCode, RespStatus, ResponseError} from "@lodestar/reqresp"; +import {describe, expect, it} from "vitest"; import {fromThreadBoundaryError, toThreadBoundaryError} from "../../../src/util/error.js"; function structuredClone(value: T): T { diff --git a/packages/beacon-node/test/unit/util/file.test.ts b/packages/beacon-node/test/unit/util/file.test.ts index 6040e14b4263..ad8a1a324fff 100644 --- a/packages/beacon-node/test/unit/util/file.test.ts +++ b/packages/beacon-node/test/unit/util/file.test.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import path from "node:path"; -import {describe, it, expect, beforeAll, afterAll} from "vitest"; +import {afterAll, beforeAll, describe, expect, it} from "vitest"; import {ensureDir, writeIfNotExist} from "../../../src/util/file.js"; describe("file util", () => { diff --git a/packages/beacon-node/test/unit/util/graffiti.test.ts b/packages/beacon-node/test/unit/util/graffiti.test.ts index 0197e39c5e52..89750d423790 100644 --- a/packages/beacon-node/test/unit/util/graffiti.test.ts +++ b/packages/beacon-node/test/unit/util/graffiti.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {getDefaultGraffiti, toGraffitiBuffer} from "../../../src/util/graffiti.js"; +import {describe, expect, it} from "vitest"; import {ClientCode} from "../../../src/execution/index.js"; +import {getDefaultGraffiti, toGraffitiBuffer} from "../../../src/util/graffiti.js"; describe("Graffiti helper", () => { describe("toGraffitiBuffer", () => { diff --git a/packages/beacon-node/test/unit/util/itTrigger.test.ts b/packages/beacon-node/test/unit/util/itTrigger.test.ts index 942791c118bd..ff76cf13eafa 100644 --- a/packages/beacon-node/test/unit/util/itTrigger.test.ts +++ b/packages/beacon-node/test/unit/util/itTrigger.test.ts @@ -1,5 +1,5 @@ import all from "it-all"; -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {ItTrigger} from "../../../src/util/itTrigger.js"; describe("util / itTrigger", () => { diff --git a/packages/beacon-node/test/unit/util/kzg.test.ts b/packages/beacon-node/test/unit/util/kzg.test.ts index 3b1de419ae93..616505268ae1 100644 --- a/packages/beacon-node/test/unit/util/kzg.test.ts +++ b/packages/beacon-node/test/unit/util/kzg.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect, afterEach, beforeAll} from "vitest"; -import {bellatrix, deneb, ssz} from "@lodestar/types"; -import {BYTES_PER_FIELD_ELEMENT, BLOB_TX_TYPE} from "@lodestar/params"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {getMockedBeaconChain} from "../../mocks/mockedBeaconChain.js"; -import {computeBlobSidecars, kzgCommitmentToVersionedHash} from "../../../src/util/blobs.js"; -import {loadEthereumTrustedSetup, initCKZG, ckzg, FIELD_ELEMENTS_PER_BLOB_MAINNET} from "../../../src/util/kzg.js"; +import {BLOB_TX_TYPE, BYTES_PER_FIELD_ELEMENT} from "@lodestar/params"; +import {bellatrix, deneb, ssz} from "@lodestar/types"; +import {afterEach, beforeAll, describe, expect, it} from "vitest"; import {validateBlobSidecars, validateGossipBlobSidecar} from "../../../src/chain/validation/blobSidecar.js"; +import {computeBlobSidecars, kzgCommitmentToVersionedHash} from "../../../src/util/blobs.js"; +import {FIELD_ELEMENTS_PER_BLOB_MAINNET, ckzg, initCKZG, loadEthereumTrustedSetup} from "../../../src/util/kzg.js"; +import {getMockedBeaconChain} from "../../mocks/mockedBeaconChain.js"; describe("C-KZG", () => { const afterEachCallbacks: (() => Promise | void)[] = []; diff --git a/packages/beacon-node/test/unit/util/map.test.ts b/packages/beacon-node/test/unit/util/map.test.ts index 2d568b89ae3f..f336ac1d3d8e 100644 --- a/packages/beacon-node/test/unit/util/map.test.ts +++ b/packages/beacon-node/test/unit/util/map.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, beforeEach} from "vitest"; +import {beforeEach, describe, expect, it} from "vitest"; import {OrderedMap} from "../../../src/util/map.js"; describe("OrderedMap", () => { diff --git a/packages/beacon-node/test/unit/util/metadata.test.ts b/packages/beacon-node/test/unit/util/metadata.test.ts index 4e732d93e5d0..17e2ba04ce37 100644 --- a/packages/beacon-node/test/unit/util/metadata.test.ts +++ b/packages/beacon-node/test/unit/util/metadata.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {getLodestarClientVersion} from "../../../src/util/metadata.js"; +import {describe, expect, it} from "vitest"; import {ClientCode} from "../../../src/execution/index.js"; +import {getLodestarClientVersion} from "../../../src/util/metadata.js"; describe("util / metadata", () => { describe("getLodestarClientVersion", () => { diff --git a/packages/beacon-node/test/unit/util/peerId.test.ts b/packages/beacon-node/test/unit/util/peerId.test.ts index 92205c5d0334..5014741aa4b9 100644 --- a/packages/beacon-node/test/unit/util/peerId.test.ts +++ b/packages/beacon-node/test/unit/util/peerId.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {peerIdFromString, peerIdToString} from "../../../src/util/peerId.js"; describe("network peerid", () => { diff --git a/packages/beacon-node/test/unit/util/queue.test.ts b/packages/beacon-node/test/unit/util/queue.test.ts index 10c411547c89..3263ec12a0b7 100644 --- a/packages/beacon-node/test/unit/util/queue.test.ts +++ b/packages/beacon-node/test/unit/util/queue.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {sleep} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; import {JobFnQueue, QueueError, QueueErrorCode, QueueType} from "../../../src/util/queue/index.js"; import {expectLodestarError, expectRejectedWithLodestarError} from "../../utils/errors.js"; diff --git a/packages/beacon-node/test/unit/util/set.test.ts b/packages/beacon-node/test/unit/util/set.test.ts index 482819b3b77d..361680d2930c 100644 --- a/packages/beacon-node/test/unit/util/set.test.ts +++ b/packages/beacon-node/test/unit/util/set.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, beforeEach} from "vitest"; +import {beforeEach, describe, expect, it} from "vitest"; import {OrderedSet} from "../../../src/util/set.js"; describe("OrderedSet", () => { diff --git a/packages/beacon-node/test/unit/util/shuffle.test.ts b/packages/beacon-node/test/unit/util/shuffle.test.ts index 2ba879514020..faa99ef67737 100644 --- a/packages/beacon-node/test/unit/util/shuffle.test.ts +++ b/packages/beacon-node/test/unit/util/shuffle.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {shuffle} from "../../../src/util/shuffle.js"; describe("util / shuffle", () => { diff --git a/packages/beacon-node/test/unit/util/sortBy.test.ts b/packages/beacon-node/test/unit/util/sortBy.test.ts index 747327cc2bbd..1c648640ffff 100644 --- a/packages/beacon-node/test/unit/util/sortBy.test.ts +++ b/packages/beacon-node/test/unit/util/sortBy.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {sortBy} from "../../../src/util/sortBy.js"; describe("util / sortBy", () => { diff --git a/packages/beacon-node/test/unit/util/sszBytes.test.ts b/packages/beacon-node/test/unit/util/sszBytes.test.ts index 8b72c31df6c8..8fd6011e6255 100644 --- a/packages/beacon-node/test/unit/util/sszBytes.test.ts +++ b/packages/beacon-node/test/unit/util/sszBytes.test.ts @@ -1,22 +1,22 @@ -import {describe, it, expect} from "vitest"; import {BitArray} from "@chainsafe/ssz"; -import {deneb, electra, Epoch, isElectraAttestation, phase0, RootHex, Slot, ssz} from "@lodestar/types"; -import {fromHex, toHex} from "@lodestar/utils"; import {ForkName, MAX_COMMITTEES_PER_SLOT} from "@lodestar/params"; +import {Epoch, RootHex, Slot, deneb, electra, isElectraAttestation, phase0, ssz} from "@lodestar/types"; +import {fromHex, toHex} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; import { + getAggregationBitsFromAttestationSerialized, getAttDataFromAttestationSerialized, + getAttDataFromSignedAggregateAndProofElectra, getAttDataFromSignedAggregateAndProofPhase0, - getAggregationBitsFromAttestationSerialized, getBlockRootFromAttestationSerialized, getBlockRootFromSignedAggregateAndProofSerialized, + getCommitteeBitsFromAttestationSerialized, + getCommitteeBitsFromSignedAggregateAndProofElectra, + getSignatureFromAttestationSerialized, getSlotFromAttestationSerialized, + getSlotFromBlobSidecarSerialized, getSlotFromSignedAggregateAndProofSerialized, - getSignatureFromAttestationSerialized, getSlotFromSignedBeaconBlockSerialized, - getSlotFromBlobSidecarSerialized, - getCommitteeBitsFromAttestationSerialized, - getCommitteeBitsFromSignedAggregateAndProofElectra, - getAttDataFromSignedAggregateAndProofElectra, } from "../../../src/util/sszBytes.js"; describe("attestation SSZ serialized picking", () => { diff --git a/packages/beacon-node/test/unit/util/time.test.ts b/packages/beacon-node/test/unit/util/time.test.ts index ccf1b9e308c8..2f32729a5225 100644 --- a/packages/beacon-node/test/unit/util/time.test.ts +++ b/packages/beacon-node/test/unit/util/time.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {prettyTimeDiffSec} from "../../../src/util/time.js"; describe("util / time / prettyTimeDiffSec", () => { diff --git a/packages/beacon-node/test/unit/util/timeSeries.test.ts b/packages/beacon-node/test/unit/util/timeSeries.test.ts index b338310c83b1..f273508e885f 100644 --- a/packages/beacon-node/test/unit/util/timeSeries.test.ts +++ b/packages/beacon-node/test/unit/util/timeSeries.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {TimeSeries} from "../../../src/util/timeSeries.js"; // Even with rounding to 3 decimals, the test still breaks sometimes... diff --git a/packages/beacon-node/test/unit/util/wrapError.test.ts b/packages/beacon-node/test/unit/util/wrapError.test.ts index 2a8e5ca15ceb..f972a1bff148 100644 --- a/packages/beacon-node/test/unit/util/wrapError.test.ts +++ b/packages/beacon-node/test/unit/util/wrapError.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {wrapError} from "../../../src/util/wrapError.js"; describe("util / wrapError", () => { diff --git a/packages/beacon-node/test/utils/api.ts b/packages/beacon-node/test/utils/api.ts index 593bae0c2643..17126defc2c2 100644 --- a/packages/beacon-node/test/utils/api.ts +++ b/packages/beacon-node/test/utils/api.ts @@ -1,11 +1,11 @@ -import {Mocked} from "vitest"; import {config} from "@lodestar/config/default"; import {ForkChoice} from "@lodestar/fork-choice"; -import {MockedBeaconChain, MockedBeaconChainOptions, getMockedBeaconChain} from "../mocks/mockedBeaconChain.js"; +import {Mocked} from "vitest"; +import {ApiModules} from "../../src/api/index.js"; import {getMockedBeaconSync} from "../mocks/beaconSyncMock.js"; +import {MockedBeaconChain, MockedBeaconChainOptions, getMockedBeaconChain} from "../mocks/mockedBeaconChain.js"; import {MockedBeaconDb, getMockedBeaconDb} from "../mocks/mockedBeaconDb.js"; import {getMockedNetwork} from "../mocks/mockedNetwork.js"; -import {ApiModules} from "../../src/api/index.js"; type ApiModulesWithoutConfig = Omit; diff --git a/packages/beacon-node/test/utils/cachedBeaconState.ts b/packages/beacon-node/test/utils/cachedBeaconState.ts index 3efb16b6250f..1c092f2ba4a2 100644 --- a/packages/beacon-node/test/utils/cachedBeaconState.ts +++ b/packages/beacon-node/test/utils/cachedBeaconState.ts @@ -1,10 +1,10 @@ +import {ChainForkConfig} from "@lodestar/config"; import { BeaconStateAllForks, BeaconStateCache, createCachedBeaconState, createEmptyEpochCacheImmutableData, } from "@lodestar/state-transition"; -import {ChainForkConfig} from "@lodestar/config"; export function createCachedBeaconStateTest( state: T, diff --git a/packages/beacon-node/test/utils/cliTools/kzgTrustedSetupFromJson.ts b/packages/beacon-node/test/utils/cliTools/kzgTrustedSetupFromJson.ts index 731f44df59c8..d3cb51458c56 100644 --- a/packages/beacon-node/test/utils/cliTools/kzgTrustedSetupFromJson.ts +++ b/packages/beacon-node/test/utils/cliTools/kzgTrustedSetupFromJson.ts @@ -1,5 +1,5 @@ import fs from "node:fs"; -import {TrustedSetupJSON, trustedSetupJsonToBin, TRUSTED_SETUP_BIN_FILEPATH} from "../../../src/util/kzg.js"; +import {TRUSTED_SETUP_BIN_FILEPATH, TrustedSetupJSON, trustedSetupJsonToBin} from "../../../src/util/kzg.js"; // CLI TOOL: Use to transform a JSON trusted setup into .ssz // diff --git a/packages/beacon-node/test/utils/clock.ts b/packages/beacon-node/test/utils/clock.ts index 390d7dd095dd..1e44b1c42551 100644 --- a/packages/beacon-node/test/utils/clock.ts +++ b/packages/beacon-node/test/utils/clock.ts @@ -1,6 +1,6 @@ import EventEmitter from "node:events"; import {computeEpochAtSlot} from "@lodestar/state-transition"; -import {Slot, Epoch} from "@lodestar/types"; +import {Epoch, Slot} from "@lodestar/types"; import {IClock} from "../../src/util/clock.js"; export class ClockStatic extends EventEmitter implements IClock { diff --git a/packages/beacon-node/test/utils/config.ts b/packages/beacon-node/test/utils/config.ts index f5d566560b65..6822b546de1e 100644 --- a/packages/beacon-node/test/utils/config.ts +++ b/packages/beacon-node/test/utils/config.ts @@ -1,5 +1,5 @@ +import {ChainForkConfig, createBeaconConfig, createChainForkConfig} from "@lodestar/config"; import {config as chainConfig} from "@lodestar/config/default"; -import {createBeaconConfig, ChainForkConfig, createChainForkConfig} from "@lodestar/config"; import {ForkName} from "@lodestar/params"; import {ZERO_HASH} from "../../src/constants/index.js"; diff --git a/packages/beacon-node/test/utils/db.ts b/packages/beacon-node/test/utils/db.ts index c44aa7f878dc..88f8de8c0b30 100644 --- a/packages/beacon-node/test/utils/db.ts +++ b/packages/beacon-node/test/utils/db.ts @@ -1,6 +1,6 @@ import childProcess from "node:child_process"; -import {FilterOptions, LevelDbController} from "@lodestar/db"; import {ChainForkConfig} from "@lodestar/config"; +import {FilterOptions, LevelDbController} from "@lodestar/db"; import {BeaconDb} from "../../src/index.js"; import {testLogger} from "./logger.js"; diff --git a/packages/beacon-node/test/utils/errors.ts b/packages/beacon-node/test/utils/errors.ts index 1bf31a2ce9af..7380433292f2 100644 --- a/packages/beacon-node/test/utils/errors.ts +++ b/packages/beacon-node/test/utils/errors.ts @@ -1,5 +1,5 @@ -import {expect} from "vitest"; import {LodestarError, mapValues} from "@lodestar/utils"; +import {expect} from "vitest"; export function expectThrowsLodestarError(fn: () => void, expectedErr: LodestarError | string): void { try { diff --git a/packages/beacon-node/test/utils/logger.ts b/packages/beacon-node/test/utils/logger.ts index 10f27565216f..7d67dd6fbd16 100644 --- a/packages/beacon-node/test/utils/logger.ts +++ b/packages/beacon-node/test/utils/logger.ts @@ -1,6 +1,6 @@ -import {LogLevel} from "@lodestar/utils"; -import {getNodeLogger, LoggerNode, LoggerNodeOpts} from "@lodestar/logger/node"; import {getEnvLogLevel} from "@lodestar/logger/env"; +import {LoggerNode, LoggerNodeOpts, getNodeLogger} from "@lodestar/logger/node"; +import {LogLevel} from "@lodestar/utils"; export {LogLevel}; export type TestLoggerOpts = LoggerNodeOpts; diff --git a/packages/beacon-node/test/utils/networkWithMockDb.ts b/packages/beacon-node/test/utils/networkWithMockDb.ts index 689d332ebbce..d3b7e70e8168 100644 --- a/packages/beacon-node/test/utils/networkWithMockDb.ts +++ b/packages/beacon-node/test/utils/networkWithMockDb.ts @@ -4,6 +4,7 @@ import {ssz} from "@lodestar/types"; import {BeaconChain} from "../../src/chain/chain.js"; import {Eth1ForBlockProductionDisabled} from "../../src/eth1/index.js"; import {ExecutionEngineDisabled} from "../../src/execution/index.js"; +import {StateArchiveMode} from "../../src/index.js"; import {GossipHandlers, Network, NetworkInitModules, getReqRespHandlers} from "../../src/network/index.js"; import {NetworkOptions, defaultNetworkOptions} from "../../src/network/options.js"; import {GetReqRespHandlerFn} from "../../src/network/reqresp/types.js"; @@ -12,7 +13,6 @@ import {createCachedBeaconStateTest} from "./cachedBeaconState.js"; import {ClockStatic} from "./clock.js"; import {testLogger} from "./logger.js"; import {generateState} from "./state.js"; -import {StateArchiveMode} from "../../src/index.js"; export type NetworkForTestOpts = { startSlot?: number; diff --git a/packages/beacon-node/test/utils/node/beacon.ts b/packages/beacon-node/test/utils/node/beacon.ts index 0163fa148102..ea1d7aa3300d 100644 --- a/packages/beacon-node/test/utils/node/beacon.ts +++ b/packages/beacon-node/test/utils/node/beacon.ts @@ -1,24 +1,24 @@ -import deepmerge from "deepmerge"; -import tmp from "tmp"; import {PeerId} from "@libp2p/interface"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; +import {ChainConfig, createBeaconConfig, createChainForkConfig} from "@lodestar/config"; import {config as minimalConfig} from "@lodestar/config/default"; -import {createBeaconConfig, createChainForkConfig, ChainConfig} from "@lodestar/config"; -import {RecursivePartial} from "@lodestar/utils"; import {LevelDbController} from "@lodestar/db"; -import {phase0, ssz} from "@lodestar/types"; +import {LoggerNode} from "@lodestar/logger/node"; import {ForkSeq, GENESIS_SLOT} from "@lodestar/params"; import {BeaconStateAllForks} from "@lodestar/state-transition"; +import {phase0, ssz} from "@lodestar/types"; +import {RecursivePartial} from "@lodestar/utils"; import {isPlainObject} from "@lodestar/utils"; -import {LoggerNode} from "@lodestar/logger/node"; +import deepmerge from "deepmerge"; +import tmp from "tmp"; +import {BeaconDb} from "../../../src/db/index.js"; import {BeaconNode} from "../../../src/index.js"; import {defaultNetworkOptions} from "../../../src/network/options.js"; -import {initDevState, writeDeposits} from "../../../src/node/utils/state.js"; import {IBeaconNodeOptions} from "../../../src/node/options.js"; import {defaultOptions} from "../../../src/node/options.js"; -import {BeaconDb} from "../../../src/db/index.js"; -import {testLogger} from "../logger.js"; import {InteropStateOpts} from "../../../src/node/utils/interop/state.js"; +import {initDevState, writeDeposits} from "../../../src/node/utils/state.js"; +import {testLogger} from "../logger.js"; export async function getDevBeaconNode( opts: { diff --git a/packages/beacon-node/test/utils/node/simTest.ts b/packages/beacon-node/test/utils/node/simTest.ts index 7b771b8534ed..391fc6345b22 100644 --- a/packages/beacon-node/test/utils/node/simTest.ts +++ b/packages/beacon-node/test/utils/node/simTest.ts @@ -1,20 +1,20 @@ import {toHexString} from "@chainsafe/ssz"; +import {routes} from "@lodestar/api"; +import {BeaconConfig} from "@lodestar/config"; +import {SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; import { - computeEpochAtSlot, - computeStartSlotAtEpoch, CachedBeaconStateAllForks, beforeProcessEpoch, + computeEpochAtSlot, + computeStartSlotAtEpoch, } from "@lodestar/state-transition"; -import {BeaconConfig} from "@lodestar/config"; -import {SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; import {BeaconBlock, Epoch, Slot} from "@lodestar/types"; import {Checkpoint} from "@lodestar/types/phase0"; import {Logger, mapValues} from "@lodestar/utils"; -import {routes} from "@lodestar/api"; -import {BeaconNode} from "../../../src/index.js"; import {ChainEvent, HeadEventData} from "../../../src/chain/index.js"; -import {linspace} from "../../../src/util/numpy.js"; import {RegenCaller} from "../../../src/chain/regen/index.js"; +import {BeaconNode} from "../../../src/index.js"; +import {linspace} from "../../../src/util/numpy.js"; /* eslint-disable no-console */ diff --git a/packages/beacon-node/test/utils/node/validator.ts b/packages/beacon-node/test/utils/node/validator.ts index 285fa13fd01f..f841d0681992 100644 --- a/packages/beacon-node/test/utils/node/validator.ts +++ b/packages/beacon-node/test/utils/node/validator.ts @@ -1,14 +1,14 @@ -import tmp from "tmp"; -import {vi} from "vitest"; import {SecretKey} from "@chainsafe/blst"; +import {ApiClient, ApiError, ApiResponse, HttpStatusCode} from "@lodestar/api"; +import {BeaconApiMethods} from "@lodestar/api/beacon/server"; import {LevelDbController} from "@lodestar/db"; import {interopSecretKey} from "@lodestar/state-transition"; -import {SlashingProtection, Validator, Signer, SignerType, ValidatorProposerConfig} from "@lodestar/validator"; -import {ApiClient, ApiError, HttpStatusCode, ApiResponse} from "@lodestar/api"; -import {BeaconApiMethods} from "@lodestar/api/beacon/server"; import {mapValues} from "@lodestar/utils"; +import {Signer, SignerType, SlashingProtection, Validator, ValidatorProposerConfig} from "@lodestar/validator"; +import tmp from "tmp"; +import {vi} from "vitest"; import {BeaconNode} from "../../../src/index.js"; -import {testLogger, TestLoggerOpts} from "../logger.js"; +import {TestLoggerOpts, testLogger} from "../logger.js"; export async function getAndInitDevValidators({ node, diff --git a/packages/beacon-node/test/utils/peer.ts b/packages/beacon-node/test/utils/peer.ts index 8bd5c6c67be8..81cb83665007 100644 --- a/packages/beacon-node/test/utils/peer.ts +++ b/packages/beacon-node/test/utils/peer.ts @@ -1,6 +1,6 @@ import {PeerId} from "@libp2p/interface"; -import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {peerIdFromBytes} from "@libp2p/peer-id"; +import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {peerIdToString} from "../../src/util/peerId.js"; /** diff --git a/packages/beacon-node/test/utils/runEl.ts b/packages/beacon-node/test/utils/runEl.ts index 9a407f91d414..0cd3189329f8 100644 --- a/packages/beacon-node/test/utils/runEl.ts +++ b/packages/beacon-node/test/utils/runEl.ts @@ -1,10 +1,10 @@ +import {spawn} from "node:child_process"; import fs from "node:fs"; import net from "node:net"; -import {spawn} from "node:child_process"; -import {sleep} from "@lodestar/utils"; import {ChainConfig} from "@lodestar/config"; -import {Eth1Provider} from "../../src/index.js"; +import {sleep} from "@lodestar/utils"; import {ZERO_HASH} from "../../src/constants/index.js"; +import {Eth1Provider} from "../../src/index.js"; import {shell} from "../sim/shell.js"; /* eslint-disable no-console */ diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index 6ad85f3422f7..3e14ccf7630b 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -1,23 +1,23 @@ import {SecretKey} from "@chainsafe/blst"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; +import {ChainForkConfig, createBeaconConfig} from "@lodestar/config"; import {config as minimalConfig} from "@lodestar/config/default"; +import {FAR_FUTURE_EPOCH, ForkName, ForkSeq, MAX_EFFECTIVE_BALANCE, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; import { BeaconStateAllForks, + BeaconStateBellatrix, + BeaconStateElectra, CachedBeaconStateAllForks, - createCachedBeaconState, CachedBeaconStateBellatrix, - BeaconStateBellatrix, CachedBeaconStateElectra, - BeaconStateElectra, + createCachedBeaconState, } from "@lodestar/state-transition"; import {BeaconState, altair, bellatrix, electra, ssz} from "@lodestar/types"; -import {createBeaconConfig, ChainForkConfig} from "@lodestar/config"; -import {FAR_FUTURE_EPOCH, ForkName, ForkSeq, MAX_EFFECTIVE_BALANCE, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; -import {ExecutionStatus, ProtoBlock, DataAvailabilityStatus} from "@lodestar/fork-choice"; +import {DataAvailabilityStatus, ExecutionStatus, ProtoBlock} from "@lodestar/fork-choice"; import {ZERO_HASH_HEX} from "../../src/constants/constants.js"; -import {generateValidator, generateValidators} from "./validator.js"; import {getConfig} from "./config.js"; +import {generateValidator, generateValidators} from "./validator.js"; /** * Copy of BeaconState, but all fields are marked optional to allow for swapping out variables as needed. diff --git a/packages/beacon-node/test/utils/testnet.ts b/packages/beacon-node/test/utils/testnet.ts index 0c0c7a8369c8..95abc185b62d 100644 --- a/packages/beacon-node/test/utils/testnet.ts +++ b/packages/beacon-node/test/utils/testnet.ts @@ -1,7 +1,7 @@ import {fromHexString} from "@chainsafe/ssz"; -import {phase0} from "@lodestar/types"; -import {createChainForkConfig, ChainForkConfig} from "@lodestar/config"; +import {ChainForkConfig, createChainForkConfig} from "@lodestar/config"; import {chainConfig} from "@lodestar/config/default"; +import {phase0} from "@lodestar/types"; /** Generic testnet data taken from the Medalla testnet */ export const medallaTestnetConfig = { diff --git a/packages/beacon-node/test/utils/typeGenerator.ts b/packages/beacon-node/test/utils/typeGenerator.ts index dde169ebce26..329060e6eb31 100644 --- a/packages/beacon-node/test/utils/typeGenerator.ts +++ b/packages/beacon-node/test/utils/typeGenerator.ts @@ -1,6 +1,6 @@ +import {DataAvailabilityStatus, ExecutionStatus, ProtoBlock} from "@lodestar/fork-choice"; import {Slot} from "@lodestar/types"; import {phase0} from "@lodestar/types"; -import {ProtoBlock, ExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; import {ssz} from "@lodestar/types"; import {fromHex} from "@lodestar/utils"; import {ZERO_HASH_HEX} from "../../src/constants/index.js"; diff --git a/packages/beacon-node/test/utils/validationData/aggregateAndProof.ts b/packages/beacon-node/test/utils/validationData/aggregateAndProof.ts index 462502719134..a8ac5833fbd5 100644 --- a/packages/beacon-node/test/utils/validationData/aggregateAndProof.ts +++ b/packages/beacon-node/test/utils/validationData/aggregateAndProof.ts @@ -1,11 +1,11 @@ -import {computeSigningRoot} from "@lodestar/state-transition"; import {DOMAIN_AGGREGATE_AND_PROOF, DOMAIN_SELECTION_PROOF} from "@lodestar/params"; +import {computeSigningRoot} from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; import {getSecretKeyFromIndexCached} from "../../../../state-transition/test/perf/util.js"; import {IBeaconChain} from "../../../src/chain/index.js"; import {SeenAggregators} from "../../../src/chain/seenCache/index.js"; import {signCached} from "../cache.js"; -import {getAttestationValidData, AttestationValidDataOpts} from "./attestation.js"; +import {AttestationValidDataOpts, getAttestationValidData} from "./attestation.js"; export type AggregateAndProofValidDataOpts = AttestationValidDataOpts; diff --git a/packages/beacon-node/test/utils/validationData/attestation.ts b/packages/beacon-node/test/utils/validationData/attestation.ts index 6715512ac667..40dccbd77f18 100644 --- a/packages/beacon-node/test/utils/validationData/attestation.ts +++ b/packages/beacon-node/test/utils/validationData/attestation.ts @@ -1,24 +1,24 @@ import {BitArray, toHexString} from "@chainsafe/ssz"; -import {computeEpochAtSlot, computeSigningRoot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {ProtoBlock, IForkChoice, ExecutionStatus, DataAvailabilityStatus} from "@lodestar/fork-choice"; +import {DataAvailabilityStatus, ExecutionStatus, IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; -import {phase0, Slot, ssz} from "@lodestar/types"; +import {computeEpochAtSlot, computeSigningRoot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; +import {Slot, phase0, ssz} from "@lodestar/types"; import { generateTestCachedBeaconStateOnlyValidators, getSecretKeyFromIndexCached, } from "../../../../state-transition/test/perf/util.js"; +import {BlsMultiThreadWorkerPool, BlsSingleThreadVerifier} from "../../../src/chain/bls/index.js"; import {IBeaconChain} from "../../../src/chain/index.js"; +import {defaultChainOptions} from "../../../src/chain/options.js"; import {IStateRegenerator} from "../../../src/chain/regen/index.js"; -import {ZERO_HASH, ZERO_HASH_HEX} from "../../../src/constants/index.js"; import {SeenAttesters} from "../../../src/chain/seenCache/index.js"; -import {BlsMultiThreadWorkerPool, BlsSingleThreadVerifier} from "../../../src/chain/bls/index.js"; -import {signCached} from "../cache.js"; -import {ClockStatic} from "../clock.js"; import {SeenAggregatedAttestations} from "../../../src/chain/seenCache/seenAggregateAndProof.js"; import {SeenAttestationDatas} from "../../../src/chain/seenCache/seenAttestationData.js"; -import {defaultChainOptions} from "../../../src/chain/options.js"; -import {testLogger} from "../logger.js"; import {ShufflingCache} from "../../../src/chain/shufflingCache.js"; +import {ZERO_HASH, ZERO_HASH_HEX} from "../../../src/constants/index.js"; +import {signCached} from "../cache.js"; +import {ClockStatic} from "../clock.js"; +import {testLogger} from "../logger.js"; export type AttestationValidDataOpts = { currentSlot?: Slot; diff --git a/packages/cli/src/applyPreset.ts b/packages/cli/src/applyPreset.ts index 612c5d648c63..06d29d353af8 100644 --- a/packages/cli/src/applyPreset.ts +++ b/packages/cli/src/applyPreset.ts @@ -21,7 +21,7 @@ setHasher(hasher); // set LODESTAR_PRESET manually every time. // IMPORTANT: only import Lodestar code here which does not import any other Lodestar libraries -import {setActivePreset, presetFromJson, PresetName} from "@lodestar/params/setPreset"; +import {PresetName, presetFromJson, setActivePreset} from "@lodestar/params/setPreset"; import {readFile} from "./util/file.js"; const network = valueOfArg("network"); diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index e8f4aeba8ebc..d64661f6ec66 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -1,7 +1,7 @@ +import {registerCommandToYargs} from "@lodestar/utils"; // Must not use `* as yargs`, see https://github.com/yargs/yargs/issues/1131 import yargs from "yargs"; import {hideBin} from "yargs/helpers"; -import {registerCommandToYargs} from "@lodestar/utils"; import {cmds} from "./cmds/index.js"; import {globalOptions, rcConfigOption} from "./options/index.js"; import {getVersionData} from "./util/version.js"; diff --git a/packages/cli/src/cmds/beacon/handler.ts b/packages/cli/src/cmds/beacon/handler.ts index ea424e04824a..389bcea25223 100644 --- a/packages/cli/src/cmds/beacon/handler.ts +++ b/packages/cli/src/cmds/beacon/handler.ts @@ -1,30 +1,30 @@ import path from "node:path"; import {getHeapStatistics} from "node:v8"; -import {ErrorAborted} from "@lodestar/utils"; -import {LevelDbController} from "@lodestar/db"; -import {BeaconNode, BeaconDb} from "@lodestar/beacon-node"; +import {BeaconDb, BeaconNode} from "@lodestar/beacon-node"; import {ChainForkConfig, createBeaconConfig} from "@lodestar/config"; +import {LevelDbController} from "@lodestar/db"; +import {LoggerNode, getNodeLogger} from "@lodestar/logger/node"; import {ACTIVE_PRESET, PresetName} from "@lodestar/params"; +import {ErrorAborted} from "@lodestar/utils"; import {ProcessShutdownCallback} from "@lodestar/validator"; -import {LoggerNode, getNodeLogger} from "@lodestar/logger/node"; -import {GlobalArgs, parseBeaconNodeArgs} from "../../options/index.js"; import {BeaconNodeOptions, getBeaconConfigFromArgs} from "../../config/index.js"; import {getNetworkBootnodes, getNetworkData, isKnownNetworkName, readBootnodes} from "../../networks/index.js"; +import {GlobalArgs, parseBeaconNodeArgs} from "../../options/index.js"; +import {LogArgs} from "../../options/logOptions.js"; import { - onGracefulShutdown, - mkdir, - writeFile600Perm, cleanOldLogFiles, + mkdir, + onGracefulShutdown, parseLoggerArgs, pruneOldFilesInDir, + writeFile600Perm, } from "../../util/index.js"; import {getVersionData} from "../../util/version.js"; -import {LogArgs} from "../../options/logOptions.js"; -import {BeaconArgs} from "./options.js"; -import {getBeaconPaths} from "./paths.js"; import {initBeaconState} from "./initBeaconState.js"; import {initPeerIdAndEnr} from "./initPeerIdAndEnr.js"; +import {BeaconArgs} from "./options.js"; +import {getBeaconPaths} from "./paths.js"; const DEFAULT_RETENTION_SSZ_OBJECTS_HOURS = 15 * 24; const HOURS_TO_MS = 3600 * 1000; diff --git a/packages/cli/src/cmds/beacon/index.ts b/packages/cli/src/cmds/beacon/index.ts index d1d91b9fe424..9746a43d40fb 100644 --- a/packages/cli/src/cmds/beacon/index.ts +++ b/packages/cli/src/cmds/beacon/index.ts @@ -1,7 +1,7 @@ import {CliCommand, CliCommandOptions} from "@lodestar/utils"; import {GlobalArgs} from "../../options/index.js"; -import {beaconOptions, BeaconArgs} from "./options.js"; import {beaconHandler} from "./handler.js"; +import {BeaconArgs, beaconOptions} from "./options.js"; export const beacon: CliCommand = { command: "beacon", diff --git a/packages/cli/src/cmds/beacon/initBeaconState.ts b/packages/cli/src/cmds/beacon/initBeaconState.ts index 8dc9e9317c65..5fc32d63de6b 100644 --- a/packages/cli/src/cmds/beacon/initBeaconState.ts +++ b/packages/cli/src/cmds/beacon/initBeaconState.ts @@ -1,30 +1,30 @@ -import {ssz} from "@lodestar/types"; -import {createBeaconConfig, BeaconConfig, ChainForkConfig} from "@lodestar/config"; -import {Logger, formatBytes} from "@lodestar/utils"; -import { - isWithinWeakSubjectivityPeriod, - ensureWithinWeakSubjectivityPeriod, - BeaconStateAllForks, - loadState, - loadStateAndValidators, -} from "@lodestar/state-transition"; import { IBeaconDb, IBeaconNodeOptions, checkAndPersistAnchorState, - initStateFromEth1, getStateTypeFromBytes, + initStateFromEth1, } from "@lodestar/beacon-node"; +import {BeaconConfig, ChainForkConfig, createBeaconConfig} from "@lodestar/config"; +import { + BeaconStateAllForks, + ensureWithinWeakSubjectivityPeriod, + isWithinWeakSubjectivityPeriod, + loadState, + loadStateAndValidators, +} from "@lodestar/state-transition"; +import {ssz} from "@lodestar/types"; import {Checkpoint} from "@lodestar/types/phase0"; +import {Logger, formatBytes} from "@lodestar/utils"; -import {downloadOrLoadFile, wrapFnError} from "../../util/index.js"; -import {defaultNetwork, GlobalArgs} from "../../options/globalOptions.js"; import { fetchWeakSubjectivityState, getCheckpointFromArg, - getGenesisFileUrl, getCheckpointFromState, + getGenesisFileUrl, } from "../../networks/index.js"; +import {GlobalArgs, defaultNetwork} from "../../options/globalOptions.js"; +import {downloadOrLoadFile, wrapFnError} from "../../util/index.js"; import {BeaconArgs} from "./options.js"; type StateWithBytes = {state: BeaconStateAllForks; stateBytes: Uint8Array}; diff --git a/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts b/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts index 3e5963797c3d..cac34d65b194 100644 --- a/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts +++ b/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts @@ -1,14 +1,14 @@ import fs from "node:fs"; -import path from "node:path"; import os from "node:os"; +import path from "node:path"; +import {SignableENR, createPrivateKeyFromPeerId} from "@chainsafe/enr"; import type {PeerId} from "@libp2p/interface"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; -import {Multiaddr} from "@multiformats/multiaddr"; -import {createPrivateKeyFromPeerId, SignableENR} from "@chainsafe/enr"; import {Logger} from "@lodestar/utils"; +import {Multiaddr} from "@multiformats/multiaddr"; import {exportToJSON, readPeerId} from "../../config/index.js"; -import {writeFile600Perm} from "../../util/file.js"; import {parseListenArgs} from "../../options/beaconNodeOptions/network.js"; +import {writeFile600Perm} from "../../util/file.js"; import {BeaconArgs} from "./options.js"; /** diff --git a/packages/cli/src/cmds/beacon/options.ts b/packages/cli/src/cmds/beacon/options.ts index 5b57b58e82e2..a623ca99512c 100644 --- a/packages/cli/src/cmds/beacon/options.ts +++ b/packages/cli/src/cmds/beacon/options.ts @@ -1,7 +1,7 @@ import {CliCommandOptions, CliOptionDefinition} from "@lodestar/utils"; -import {beaconNodeOptions, paramsOptions, BeaconNodeArgs} from "../../options/index.js"; +import {BeaconNodeArgs, beaconNodeOptions, paramsOptions} from "../../options/index.js"; import {LogArgs, logOptions} from "../../options/logOptions.js"; -import {defaultBeaconPaths, BeaconPaths} from "./paths.js"; +import {BeaconPaths, defaultBeaconPaths} from "./paths.js"; type BeaconExtraArgs = { forceGenesis?: boolean; diff --git a/packages/cli/src/cmds/beacon/paths.ts b/packages/cli/src/cmds/beacon/paths.ts index f92732b2a94e..9485bc5fca8a 100644 --- a/packages/cli/src/cmds/beacon/paths.ts +++ b/packages/cli/src/cmds/beacon/paths.ts @@ -1,6 +1,6 @@ import path from "node:path"; import {GlobalArgs} from "../../options/index.js"; -import {getGlobalPaths, GlobalPaths} from "../../paths/global.js"; +import {GlobalPaths, getGlobalPaths} from "../../paths/global.js"; export type BeaconPathsPartial = Partial<{ beaconDir: string; diff --git a/packages/cli/src/cmds/bootnode/handler.ts b/packages/cli/src/cmds/bootnode/handler.ts index 8a262d8f12b7..4dc044a87006 100644 --- a/packages/cli/src/cmds/bootnode/handler.ts +++ b/packages/cli/src/cmds/bootnode/handler.ts @@ -1,21 +1,21 @@ import path from "node:path"; -import {Multiaddr, multiaddr} from "@multiformats/multiaddr"; import {Discv5} from "@chainsafe/discv5"; import {ENR} from "@chainsafe/enr"; -import {ErrorAborted} from "@lodestar/utils"; import {HttpMetricsServer, RegistryMetricCreator, getHttpMetricsServer} from "@lodestar/beacon-node"; +import {ErrorAborted} from "@lodestar/utils"; +import {Multiaddr, multiaddr} from "@multiformats/multiaddr"; -import {GlobalArgs} from "../../options/index.js"; import {getBeaconConfigFromArgs} from "../../config/index.js"; import {getNetworkBootnodes, isKnownNetworkName, readBootnodes} from "../../networks/index.js"; -import {onGracefulShutdown, mkdir, writeFile600Perm} from "../../util/index.js"; -import {getVersionData} from "../../util/version.js"; -import {initPeerIdAndEnr} from "../beacon/initPeerIdAndEnr.js"; import {parseArgs as parseMetricsArgs} from "../../options/beaconNodeOptions/metrics.js"; import {parseArgs as parseNetworkArgs} from "../../options/beaconNodeOptions/network.js"; -import {getBeaconPaths} from "../beacon/paths.js"; -import {BeaconArgs} from "../beacon/options.js"; +import {GlobalArgs} from "../../options/index.js"; +import {mkdir, onGracefulShutdown, writeFile600Perm} from "../../util/index.js"; +import {getVersionData} from "../../util/version.js"; import {initLogger} from "../beacon/handler.js"; +import {initPeerIdAndEnr} from "../beacon/initPeerIdAndEnr.js"; +import {BeaconArgs} from "../beacon/options.js"; +import {getBeaconPaths} from "../beacon/paths.js"; import {BootnodeArgs} from "./options.js"; /** diff --git a/packages/cli/src/cmds/bootnode/index.ts b/packages/cli/src/cmds/bootnode/index.ts index 6fc3c01247d6..3143f7a77ba7 100644 --- a/packages/cli/src/cmds/bootnode/index.ts +++ b/packages/cli/src/cmds/bootnode/index.ts @@ -1,7 +1,7 @@ import {CliCommand, CliCommandOptions} from "@lodestar/utils"; import {GlobalArgs} from "../../options/index.js"; -import {bootnodeOptions, BootnodeArgs} from "./options.js"; import {bootnodeHandler} from "./handler.js"; +import {BootnodeArgs, bootnodeOptions} from "./options.js"; export const bootnode: CliCommand = { command: "bootnode", diff --git a/packages/cli/src/cmds/bootnode/options.ts b/packages/cli/src/cmds/bootnode/options.ts index f3422b4029a1..e4e943bfef0c 100644 --- a/packages/cli/src/cmds/bootnode/options.ts +++ b/packages/cli/src/cmds/bootnode/options.ts @@ -1,7 +1,7 @@ -import {CliOptionDefinition, CliCommandOptions} from "@lodestar/utils"; -import {LogArgs, logOptions} from "../../options/logOptions.js"; +import {CliCommandOptions, CliOptionDefinition} from "@lodestar/utils"; import {MetricsArgs, options as metricsOptions} from "../../options/beaconNodeOptions/metrics.js"; import {defaultListenAddress, defaultP2pPort, defaultP2pPort6} from "../../options/beaconNodeOptions/network.js"; +import {LogArgs, logOptions} from "../../options/logOptions.js"; type BootnodeExtraArgs = { listenAddress?: string; diff --git a/packages/cli/src/cmds/dev/files.ts b/packages/cli/src/cmds/dev/files.ts index 9baf0dc845dd..e5b019c4b48e 100644 --- a/packages/cli/src/cmds/dev/files.ts +++ b/packages/cli/src/cmds/dev/files.ts @@ -2,9 +2,9 @@ import fs from "node:fs"; import path from "node:path"; import {Keystore} from "@chainsafe/bls-keystore"; import {nodeUtils} from "@lodestar/beacon-node"; -import {chainConfigToJson, ChainForkConfig} from "@lodestar/config"; -import {dumpYaml} from "@lodestar/utils"; +import {ChainForkConfig, chainConfigToJson} from "@lodestar/config"; import {interopSecretKey} from "@lodestar/state-transition"; +import {dumpYaml} from "@lodestar/utils"; import {PersistedKeysBackend} from "../validator/keymanager/persistedKeys.js"; /* eslint-disable no-console */ diff --git a/packages/cli/src/cmds/dev/handler.ts b/packages/cli/src/cmds/dev/handler.ts index 3018bb8790a6..43fe12435a9a 100644 --- a/packages/cli/src/cmds/dev/handler.ts +++ b/packages/cli/src/cmds/dev/handler.ts @@ -1,16 +1,16 @@ import fs from "node:fs"; -import {rimraf} from "rimraf"; -import {toHex, fromHex} from "@lodestar/utils"; import {nodeUtils} from "@lodestar/beacon-node"; +import {fromHex, toHex} from "@lodestar/utils"; +import {rimraf} from "rimraf"; +import {getBeaconConfigFromArgs} from "../../config/beaconParams.js"; import {GlobalArgs} from "../../options/index.js"; import {mkdir, onGracefulShutdown} from "../../util/index.js"; -import {getBeaconConfigFromArgs} from "../../config/beaconParams.js"; -import {getBeaconPaths} from "../beacon/paths.js"; -import {getValidatorPaths} from "../validator/paths.js"; import {beaconHandler} from "../beacon/handler.js"; +import {getBeaconPaths} from "../beacon/paths.js"; import {validatorHandler} from "../validator/handler.js"; -import {IDevArgs} from "./options.js"; +import {getValidatorPaths} from "../validator/paths.js"; import {writeTestnetFiles} from "./files.js"; +import {IDevArgs} from "./options.js"; /** * Run a beacon node with validator diff --git a/packages/cli/src/cmds/dev/index.ts b/packages/cli/src/cmds/dev/index.ts index 6c0f73327816..b628d116c526 100644 --- a/packages/cli/src/cmds/dev/index.ts +++ b/packages/cli/src/cmds/dev/index.ts @@ -1,7 +1,7 @@ import {CliCommand, CliCommandOptions} from "@lodestar/utils"; import {GlobalArgs} from "../../options/index.js"; -import {devOptions, IDevArgs} from "./options.js"; import {devHandler} from "./handler.js"; +import {IDevArgs, devOptions} from "./options.js"; export const dev: CliCommand = { command: "dev", diff --git a/packages/cli/src/cmds/dev/options.ts b/packages/cli/src/cmds/dev/options.ts index e442b0605cdc..3bbc32f0ab0e 100644 --- a/packages/cli/src/cmds/dev/options.ts +++ b/packages/cli/src/cmds/dev/options.ts @@ -1,7 +1,7 @@ import {CliCommandOptions, CliOptionDefinition} from "@lodestar/utils"; -import {beaconOptions, BeaconArgs} from "../beacon/options.js"; import {NetworkName} from "../../networks/index.js"; import {beaconNodeOptions, globalOptions} from "../../options/index.js"; +import {BeaconArgs, beaconOptions} from "../beacon/options.js"; import {IValidatorCliArgs, validatorOptions} from "../validator/options.js"; type IDevOwnArgs = { diff --git a/packages/cli/src/cmds/index.ts b/packages/cli/src/cmds/index.ts index 7f701379b097..36217ef1b622 100644 --- a/packages/cli/src/cmds/index.ts +++ b/packages/cli/src/cmds/index.ts @@ -1,10 +1,10 @@ import {CliCommand} from "@lodestar/utils"; import {GlobalArgs} from "../options/index.js"; import {beacon} from "./beacon/index.js"; +import {bootnode} from "./bootnode/index.js"; import {dev} from "./dev/index.js"; -import {validator} from "./validator/index.js"; import {lightclient} from "./lightclient/index.js"; -import {bootnode} from "./bootnode/index.js"; +import {validator} from "./validator/index.js"; export const cmds: Required>>["subcommands"] = [ beacon, diff --git a/packages/cli/src/cmds/lightclient/handler.ts b/packages/cli/src/cmds/lightclient/handler.ts index 5af8f84d8959..b51a7227ce4c 100644 --- a/packages/cli/src/cmds/lightclient/handler.ts +++ b/packages/cli/src/cmds/lightclient/handler.ts @@ -5,9 +5,9 @@ import {LightClientRestTransport} from "@lodestar/light-client/transport"; import {getNodeLogger} from "@lodestar/logger/node"; import {fromHex} from "@lodestar/utils"; import {getBeaconConfigFromArgs} from "../../config/beaconParams.js"; +import {GlobalArgs} from "../../options/index.js"; import {getGlobalPaths} from "../../paths/global.js"; import {parseLoggerArgs} from "../../util/logger.js"; -import {GlobalArgs} from "../../options/index.js"; import {ILightClientArgs} from "./options.js"; export async function lightclientHandler(args: ILightClientArgs & GlobalArgs): Promise { diff --git a/packages/cli/src/cmds/lightclient/index.ts b/packages/cli/src/cmds/lightclient/index.ts index bf85df50800f..55c56697bd0a 100644 --- a/packages/cli/src/cmds/lightclient/index.ts +++ b/packages/cli/src/cmds/lightclient/index.ts @@ -1,7 +1,7 @@ import {CliCommand} from "@lodestar/utils"; import {GlobalArgs} from "../../options/index.js"; -import {ILightClientArgs, lightclientOptions} from "./options.js"; import {lightclientHandler} from "./handler.js"; +import {ILightClientArgs, lightclientOptions} from "./options.js"; export const lightclient: CliCommand = { command: "lightclient", diff --git a/packages/cli/src/cmds/validator/blsToExecutionChange.ts b/packages/cli/src/cmds/validator/blsToExecutionChange.ts index 7fbdbb029bf5..2eeaab846589 100644 --- a/packages/cli/src/cmds/validator/blsToExecutionChange.ts +++ b/packages/cli/src/cmds/validator/blsToExecutionChange.ts @@ -1,13 +1,13 @@ import {SecretKey} from "@chainsafe/blst"; -import {computeSigningRoot} from "@lodestar/state-transition"; -import {DOMAIN_BLS_TO_EXECUTION_CHANGE, ForkName} from "@lodestar/params"; -import {createBeaconConfig} from "@lodestar/config"; -import {ssz, capella} from "@lodestar/types"; import {getClient} from "@lodestar/api"; +import {createBeaconConfig} from "@lodestar/config"; +import {DOMAIN_BLS_TO_EXECUTION_CHANGE, ForkName} from "@lodestar/params"; +import {computeSigningRoot} from "@lodestar/state-transition"; +import {capella, ssz} from "@lodestar/types"; import {CliCommand, fromHex} from "@lodestar/utils"; -import {GlobalArgs} from "../../options/index.js"; import {getBeaconConfigFromArgs} from "../../config/index.js"; +import {GlobalArgs} from "../../options/index.js"; import {IValidatorCliArgs} from "./options.js"; /* eslint-disable no-console */ diff --git a/packages/cli/src/cmds/validator/handler.ts b/packages/cli/src/cmds/validator/handler.ts index 66e66400a3fd..6cb48f862bda 100644 --- a/packages/cli/src/cmds/validator/handler.ts +++ b/packages/cli/src/cmds/validator/handler.ts @@ -1,6 +1,14 @@ -import path from "node:path"; import {setMaxListeners} from "node:events"; +import path from "node:path"; +import {WireFormat, routes} from "@lodestar/api"; +import { + MonitoringService, + RegistryMetricCreator, + collectNodeJSMetrics, + getHttpMetricsServer, +} from "@lodestar/beacon-node"; import {LevelDbController} from "@lodestar/db"; +import {getNodeLogger} from "@lodestar/logger/node"; import { ProcessShutdownCallback, SlashingProtection, @@ -8,29 +16,21 @@ import { ValidatorProposerConfig, defaultOptions, } from "@lodestar/validator"; -import {WireFormat, routes} from "@lodestar/api"; import {getMetrics} from "@lodestar/validator"; -import { - RegistryMetricCreator, - collectNodeJSMetrics, - getHttpMetricsServer, - MonitoringService, -} from "@lodestar/beacon-node"; -import {getNodeLogger} from "@lodestar/logger/node"; import {getBeaconConfigFromArgs} from "../../config/index.js"; import {GlobalArgs} from "../../options/index.js"; import {YargsError, cleanOldLogFiles, mkdir, parseLoggerArgs} from "../../util/index.js"; import {onGracefulShutdown, parseFeeRecipient, parseProposerConfig} from "../../util/index.js"; +import {parseBuilderBoostFactor, parseBuilderSelection} from "../../util/proposerConfig.js"; import {getVersionData} from "../../util/version.js"; -import {parseBuilderSelection, parseBuilderBoostFactor} from "../../util/proposerConfig.js"; -import {getAccountPaths, getValidatorPaths} from "./paths.js"; -import {IValidatorCliArgs, validatorMetricsDefaultOptions, validatorMonitoringDefaultOptions} from "./options.js"; -import {getSignersFromArgs} from "./signers/index.js"; -import {logSigners, warnOrExitNoSigners} from "./signers/logSigners.js"; import {KeymanagerApi} from "./keymanager/impl.js"; -import {PersistedKeysBackend} from "./keymanager/persistedKeys.js"; import {IPersistedKeysBackend} from "./keymanager/interface.js"; +import {PersistedKeysBackend} from "./keymanager/persistedKeys.js"; import {KeymanagerRestApiServer} from "./keymanager/server.js"; +import {IValidatorCliArgs, validatorMetricsDefaultOptions, validatorMonitoringDefaultOptions} from "./options.js"; +import {getAccountPaths, getValidatorPaths} from "./paths.js"; +import {getSignersFromArgs} from "./signers/index.js"; +import {logSigners, warnOrExitNoSigners} from "./signers/logSigners.js"; /** * Runs a validator client. diff --git a/packages/cli/src/cmds/validator/import.ts b/packages/cli/src/cmds/validator/import.ts index 48e5205549f1..2c9343cf71e2 100644 --- a/packages/cli/src/cmds/validator/import.ts +++ b/packages/cli/src/cmds/validator/import.ts @@ -1,13 +1,13 @@ import fs from "node:fs"; import {Keystore} from "@chainsafe/bls-keystore"; import {CliCommand} from "@lodestar/utils"; -import {YargsError, getPubkeyHexFromKeystore} from "../../util/index.js"; import {getBeaconConfigFromArgs} from "../../config/beaconParams.js"; import {GlobalArgs} from "../../options/index.js"; -import {validatorOptions, IValidatorCliArgs} from "./options.js"; +import {YargsError, getPubkeyHexFromKeystore} from "../../util/index.js"; +import {PersistedKeysBackend} from "./keymanager/persistedKeys.js"; +import {IValidatorCliArgs, validatorOptions} from "./options.js"; import {getAccountPaths} from "./paths.js"; import {importKeystoreDefinitionsFromExternalDir, readPassphraseOrPrompt} from "./signers/importExternalKeystores.js"; -import {PersistedKeysBackend} from "./keymanager/persistedKeys.js"; /* eslint-disable no-console */ diff --git a/packages/cli/src/cmds/validator/index.ts b/packages/cli/src/cmds/validator/index.ts index d0c7ea86c042..0c41744e49fd 100644 --- a/packages/cli/src/cmds/validator/index.ts +++ b/packages/cli/src/cmds/validator/index.ts @@ -1,13 +1,13 @@ import {CliCommand} from "@lodestar/utils"; import {GlobalArgs} from "../../options/index.js"; -import {getAccountPaths} from "./paths.js"; -import {slashingProtection} from "./slashingProtection/index.js"; +import {blsToExecutionChange} from "./blsToExecutionChange.js"; +import {validatorHandler} from "./handler.js"; import {importCmd} from "./import.js"; import {list} from "./list.js"; +import {IValidatorCliArgs, validatorOptions} from "./options.js"; +import {getAccountPaths} from "./paths.js"; +import {slashingProtection} from "./slashingProtection/index.js"; import {voluntaryExit} from "./voluntaryExit.js"; -import {blsToExecutionChange} from "./blsToExecutionChange.js"; -import {validatorOptions, IValidatorCliArgs} from "./options.js"; -import {validatorHandler} from "./handler.js"; export const validator: CliCommand = { command: "validator", diff --git a/packages/cli/src/cmds/validator/keymanager/decryptKeystoreDefinitions.ts b/packages/cli/src/cmds/validator/keymanager/decryptKeystoreDefinitions.ts index 7cfaa9768494..2c17f70e8255 100644 --- a/packages/cli/src/cmds/validator/keymanager/decryptKeystoreDefinitions.ts +++ b/packages/cli/src/cmds/validator/keymanager/decryptKeystoreDefinitions.ts @@ -1,13 +1,13 @@ import fs from "node:fs"; import path from "node:path"; -import {SecretKey} from "@chainsafe/blst"; import {Keystore} from "@chainsafe/bls-keystore"; -import {SignerLocal, SignerType} from "@lodestar/validator"; +import {SecretKey} from "@chainsafe/blst"; import {LogLevel, Logger} from "@lodestar/utils"; +import {SignerLocal, SignerType} from "@lodestar/validator"; import {lockFilepath, unlockFilepath} from "../../../util/lockfile.js"; +import {DecryptKeystoresThreadPool} from "./decryptKeystores/index.js"; import {LocalKeystoreDefinition} from "./interface.js"; import {clearKeystoreCache, loadKeystoreCache, writeKeystoreCache} from "./keystoreCache.js"; -import {DecryptKeystoresThreadPool} from "./decryptKeystores/index.js"; export type KeystoreDecryptOptions = { ignoreLockFile?: boolean; diff --git a/packages/cli/src/cmds/validator/keymanager/decryptKeystores/threadPool.ts b/packages/cli/src/cmds/validator/keymanager/decryptKeystores/threadPool.ts index 169ddb74ffda..4203e0640e39 100644 --- a/packages/cli/src/cmds/validator/keymanager/decryptKeystores/threadPool.ts +++ b/packages/cli/src/cmds/validator/keymanager/decryptKeystores/threadPool.ts @@ -1,7 +1,7 @@ import path from "node:path"; -import {spawn, Pool, Worker, ModuleThread, QueuedTask} from "@chainsafe/threads"; -import {DecryptKeystoreArgs, DecryptKeystoreWorkerAPI} from "./types.js"; +import {ModuleThread, Pool, QueuedTask, Worker, spawn} from "@chainsafe/threads"; import {maxPoolSize} from "./poolSize.js"; +import {DecryptKeystoreArgs, DecryptKeystoreWorkerAPI} from "./types.js"; // Worker constructor consider the path relative to the current working directory const workerDir = diff --git a/packages/cli/src/cmds/validator/keymanager/decryptKeystores/worker.ts b/packages/cli/src/cmds/validator/keymanager/decryptKeystores/worker.ts index 711ec4f88b00..9ebebb3a73d9 100644 --- a/packages/cli/src/cmds/validator/keymanager/decryptKeystores/worker.ts +++ b/packages/cli/src/cmds/validator/keymanager/decryptKeystores/worker.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; -import {expose} from "@chainsafe/threads/worker"; -import {Transfer, TransferDescriptor} from "@chainsafe/threads"; import {Keystore} from "@chainsafe/bls-keystore"; +import {Transfer, TransferDescriptor} from "@chainsafe/threads"; +import {expose} from "@chainsafe/threads/worker"; import {DecryptKeystoreArgs, DecryptKeystoreWorkerAPI, isLocalKeystoreDefinition} from "./types.js"; /** diff --git a/packages/cli/src/cmds/validator/keymanager/impl.ts b/packages/cli/src/cmds/validator/keymanager/impl.ts index 545f2f74f06e..8816f964a8ce 100644 --- a/packages/cli/src/cmds/validator/keymanager/impl.ts +++ b/packages/cli/src/cmds/validator/keymanager/impl.ts @@ -1,27 +1,27 @@ import {Keystore} from "@chainsafe/bls-keystore"; import {SecretKey} from "@chainsafe/blst"; import { + BuilderBoostFactorData, DeleteRemoteKeyStatus, DeletionStatus, + FeeRecipientData, + GasLimitData, + GraffitiData, + ImportRemoteKeyStatus, ImportStatus, - ResponseStatus, KeystoreStr, + ProposerConfigResponse, PubkeyHex, - SlashingProtectionData, - SignerDefinition, RemoteSignerDefinition, - ImportRemoteKeyStatus, - FeeRecipientData, - GraffitiData, - GasLimitData, - BuilderBoostFactorData, - ProposerConfigResponse, + ResponseStatus, + SignerDefinition, + SlashingProtectionData, } from "@lodestar/api/keymanager"; import {KeymanagerApiMethods as Api} from "@lodestar/api/keymanager/server"; -import {Interchange, SignerType, Validator} from "@lodestar/validator"; import {ApiError} from "@lodestar/api/server"; import {Epoch} from "@lodestar/types"; import {fromHex, isValidHttpUrl} from "@lodestar/utils"; +import {Interchange, SignerType, Validator} from "@lodestar/validator"; import {getPubkeyHexFromKeystore, isValidatePubkeyHex} from "../../../util/format.js"; import {parseFeeRecipient} from "../../../util/index.js"; import {DecryptKeystoresThreadPool} from "./decryptKeystores/index.js"; diff --git a/packages/cli/src/cmds/validator/keymanager/keystoreCache.ts b/packages/cli/src/cmds/validator/keymanager/keystoreCache.ts index 2997a6b6b113..1f8643621bdc 100644 --- a/packages/cli/src/cmds/validator/keymanager/keystoreCache.ts +++ b/packages/cli/src/cmds/validator/keymanager/keystoreCache.ts @@ -2,8 +2,8 @@ import fs from "node:fs"; import path from "node:path"; import {Keystore} from "@chainsafe/bls-keystore"; import {SecretKey} from "@chainsafe/blst"; -import {SignerLocal, SignerType} from "@lodestar/validator"; import {fromHex, toHex, toPubkeyHex} from "@lodestar/utils"; +import {SignerLocal, SignerType} from "@lodestar/validator"; import {writeFile600Perm} from "../../../util/file.js"; import {lockFilepath, unlockFilepath} from "../../../util/lockfile.js"; import {LocalKeystoreDefinition} from "./interface.js"; diff --git a/packages/cli/src/cmds/validator/keymanager/persistedKeys.ts b/packages/cli/src/cmds/validator/keymanager/persistedKeys.ts index 6a1324dcbaa2..56d508fa4e2f 100644 --- a/packages/cli/src/cmds/validator/keymanager/persistedKeys.ts +++ b/packages/cli/src/cmds/validator/keymanager/persistedKeys.ts @@ -1,15 +1,15 @@ import fs from "node:fs"; import path from "node:path"; import {Keystore} from "@chainsafe/bls-keystore"; -import {ProposerConfig} from "@lodestar/validator"; import {DeletionStatus, ImportStatus, PubkeyHex, SignerDefinition} from "@lodestar/api/keymanager"; +import {ProposerConfig} from "@lodestar/validator"; import { getPubkeyHexFromKeystore, readPassphraseFile, + readProposerConfigDir, rmdirSyncMaybe, unlinkSyncMaybe, writeFile600Perm, - readProposerConfigDir, } from "../../../util/index.js"; import {lockFilepath} from "../../../util/lockfile.js"; import {IPersistedKeysBackend, LocalKeystoreDefinition} from "./interface.js"; diff --git a/packages/cli/src/cmds/validator/keymanager/server.ts b/packages/cli/src/cmds/validator/keymanager/server.ts index e48c708c96a8..4fec2295f293 100644 --- a/packages/cli/src/cmds/validator/keymanager/server.ts +++ b/packages/cli/src/cmds/validator/keymanager/server.ts @@ -1,8 +1,8 @@ import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; -import {RestApiServer, RestApiServerOpts, RestApiServerModules} from "@lodestar/beacon-node"; import {KeymanagerApiMethods, registerRoutes} from "@lodestar/api/keymanager/server"; +import {RestApiServer, RestApiServerModules, RestApiServerOpts} from "@lodestar/beacon-node"; import {ChainForkConfig} from "@lodestar/config"; import {toHex} from "@lodestar/utils"; import {writeFile600Perm} from "../../../util/index.js"; diff --git a/packages/cli/src/cmds/validator/options.ts b/packages/cli/src/cmds/validator/options.ts index 3beb8197793c..b20caeccb268 100644 --- a/packages/cli/src/cmds/validator/options.ts +++ b/packages/cli/src/cmds/validator/options.ts @@ -1,6 +1,6 @@ import {WireFormat, defaultInit} from "@lodestar/api"; -import {defaultOptions} from "@lodestar/validator"; import {CliCommandOptions} from "@lodestar/utils"; +import {defaultOptions} from "@lodestar/validator"; import {LogArgs, logOptions} from "../../options/logOptions.js"; import {ensure0xPrefix} from "../../util/index.js"; import {keymanagerRestApiServerOptsDefault} from "./keymanager/server.js"; diff --git a/packages/cli/src/cmds/validator/signers/index.ts b/packages/cli/src/cmds/validator/signers/index.ts index 950be2db1cf5..ebe3ed72cdba 100644 --- a/packages/cli/src/cmds/validator/signers/index.ts +++ b/packages/cli/src/cmds/validator/signers/index.ts @@ -2,15 +2,15 @@ import path from "node:path"; import {deriveEth2ValidatorKeys, deriveKeyFromMnemonic} from "@chainsafe/bls-keygen"; import {SecretKey} from "@chainsafe/blst"; import {interopSecretKey} from "@lodestar/state-transition"; -import {externalSignerGetKeys, Signer, SignerType} from "@lodestar/validator"; import {LogLevel, Logger, isValidHttpUrl} from "@lodestar/utils"; -import {defaultNetwork, GlobalArgs} from "../../../options/index.js"; -import {assertValidPubkeysHex, parseRange, YargsError} from "../../../util/index.js"; -import {getAccountPaths} from "../paths.js"; -import {IValidatorCliArgs} from "../options.js"; -import {PersistedKeysBackend} from "../keymanager/persistedKeys.js"; -import {decryptKeystoreDefinitions} from "../keymanager/decryptKeystoreDefinitions.js"; +import {Signer, SignerType, externalSignerGetKeys} from "@lodestar/validator"; +import {GlobalArgs, defaultNetwork} from "../../../options/index.js"; +import {YargsError, assertValidPubkeysHex, parseRange} from "../../../util/index.js"; import {showProgress} from "../../../util/progress.js"; +import {decryptKeystoreDefinitions} from "../keymanager/decryptKeystoreDefinitions.js"; +import {PersistedKeysBackend} from "../keymanager/persistedKeys.js"; +import {IValidatorCliArgs} from "../options.js"; +import {getAccountPaths} from "../paths.js"; import {importKeystoreDefinitionsFromExternalDir, readPassphraseOrPrompt} from "./importExternalKeystores.js"; const KEYSTORE_IMPORT_PROGRESS_MS = 10000; diff --git a/packages/cli/src/cmds/validator/signers/logSigners.ts b/packages/cli/src/cmds/validator/signers/logSigners.ts index d245ee75883a..9f65befb1cc7 100644 --- a/packages/cli/src/cmds/validator/signers/logSigners.ts +++ b/packages/cli/src/cmds/validator/signers/logSigners.ts @@ -1,5 +1,5 @@ -import {Signer, SignerLocal, SignerRemote, SignerType} from "@lodestar/validator"; import {LogLevel, Logger, toPrintableUrl} from "@lodestar/utils"; +import {Signer, SignerLocal, SignerRemote, SignerType} from "@lodestar/validator"; import {YargsError} from "../../../util/errors.js"; import {IValidatorCliArgs} from "../options.js"; diff --git a/packages/cli/src/cmds/validator/slashingProtection/export.ts b/packages/cli/src/cmds/validator/slashingProtection/export.ts index f57f9d3ec0bd..be7caae12e49 100644 --- a/packages/cli/src/cmds/validator/slashingProtection/export.ts +++ b/packages/cli/src/cmds/validator/slashingProtection/export.ts @@ -1,16 +1,16 @@ import path from "node:path"; -import {InterchangeFormatVersion} from "@lodestar/validator"; import {getNodeLogger} from "@lodestar/logger/node"; import {CliCommand, toPubkeyHex} from "@lodestar/utils"; -import {YargsError, ensure0xPrefix, isValidatePubkeyHex, writeFile600Perm} from "../../../util/index.js"; -import {parseLoggerArgs} from "../../../util/logger.js"; +import {InterchangeFormatVersion} from "@lodestar/validator"; +import {getBeaconConfigFromArgs} from "../../../config/index.js"; import {GlobalArgs} from "../../../options/index.js"; import {LogArgs} from "../../../options/logOptions.js"; +import {YargsError, ensure0xPrefix, isValidatePubkeyHex, writeFile600Perm} from "../../../util/index.js"; +import {parseLoggerArgs} from "../../../util/logger.js"; import {AccountValidatorArgs} from "../options.js"; -import {getBeaconConfigFromArgs} from "../../../config/index.js"; import {getValidatorPaths} from "../paths.js"; -import {getGenesisValidatorsRoot, getSlashingProtection} from "./utils.js"; import {ISlashingProtectionArgs} from "./options.js"; +import {getGenesisValidatorsRoot, getSlashingProtection} from "./utils.js"; type ExportArgs = { file: string; diff --git a/packages/cli/src/cmds/validator/slashingProtection/import.ts b/packages/cli/src/cmds/validator/slashingProtection/import.ts index 78be9e6126f7..e0e0cb5744c7 100644 --- a/packages/cli/src/cmds/validator/slashingProtection/import.ts +++ b/packages/cli/src/cmds/validator/slashingProtection/import.ts @@ -1,16 +1,16 @@ import fs from "node:fs"; import path from "node:path"; -import {Interchange} from "@lodestar/validator"; import {getNodeLogger} from "@lodestar/logger/node"; import {CliCommand} from "@lodestar/utils"; -import {parseLoggerArgs} from "../../../util/logger.js"; +import {Interchange} from "@lodestar/validator"; +import {getBeaconConfigFromArgs} from "../../../config/index.js"; import {GlobalArgs} from "../../../options/index.js"; import {LogArgs} from "../../../options/logOptions.js"; +import {parseLoggerArgs} from "../../../util/logger.js"; import {AccountValidatorArgs} from "../options.js"; -import {getBeaconConfigFromArgs} from "../../../config/index.js"; import {getValidatorPaths} from "../paths.js"; -import {getGenesisValidatorsRoot, getSlashingProtection} from "./utils.js"; import {ISlashingProtectionArgs} from "./options.js"; +import {getGenesisValidatorsRoot, getSlashingProtection} from "./utils.js"; type ImportArgs = { file: string; diff --git a/packages/cli/src/cmds/validator/slashingProtection/index.ts b/packages/cli/src/cmds/validator/slashingProtection/index.ts index 9c180c59c378..92d8bba619af 100644 --- a/packages/cli/src/cmds/validator/slashingProtection/index.ts +++ b/packages/cli/src/cmds/validator/slashingProtection/index.ts @@ -1,8 +1,8 @@ import {CliCommand} from "@lodestar/utils"; import {AccountValidatorArgs} from "../options.js"; -import {ISlashingProtectionArgs, slashingProtectionOptions} from "./options.js"; -import {importCmd} from "./import.js"; import {exportCmd} from "./export.js"; +import {importCmd} from "./import.js"; +import {ISlashingProtectionArgs, slashingProtectionOptions} from "./options.js"; export const slashingProtection: CliCommand = { command: "slashing-protection ", diff --git a/packages/cli/src/cmds/validator/slashingProtection/utils.ts b/packages/cli/src/cmds/validator/slashingProtection/utils.ts index fe0af1cb2633..48a25b6d83b9 100644 --- a/packages/cli/src/cmds/validator/slashingProtection/utils.ts +++ b/packages/cli/src/cmds/validator/slashingProtection/utils.ts @@ -1,12 +1,12 @@ -import {Root} from "@lodestar/types"; import {getClient} from "@lodestar/api"; -import {fromHex, Logger} from "@lodestar/utils"; -import {genesisData, NetworkName} from "@lodestar/config/networks"; -import {SlashingProtection, MetaDataRepository} from "@lodestar/validator"; +import {NetworkName, genesisData} from "@lodestar/config/networks"; import {LevelDbController} from "@lodestar/db"; +import {Root} from "@lodestar/types"; +import {Logger, fromHex} from "@lodestar/utils"; +import {MetaDataRepository, SlashingProtection} from "@lodestar/validator"; +import {getBeaconConfigFromArgs} from "../../../config/index.js"; import {GlobalArgs} from "../../../options/index.js"; import {getValidatorPaths} from "../paths.js"; -import {getBeaconConfigFromArgs} from "../../../config/index.js"; import {ISlashingProtectionArgs} from "./options.js"; /** diff --git a/packages/cli/src/cmds/validator/voluntaryExit.ts b/packages/cli/src/cmds/validator/voluntaryExit.ts index 5b4cfdf270f0..9b8b33c8601f 100644 --- a/packages/cli/src/cmds/validator/voluntaryExit.ts +++ b/packages/cli/src/cmds/validator/voluntaryExit.ts @@ -1,19 +1,19 @@ -import inquirer from "inquirer"; import {Signature} from "@chainsafe/blst"; +import {ApiClient, getClient} from "@lodestar/api"; +import {BeaconConfig, createBeaconConfig} from "@lodestar/config"; import { computeEpochAtSlot, computeSigningRoot, computeStartSlotAtEpoch, getCurrentSlot, } from "@lodestar/state-transition"; -import {createBeaconConfig, BeaconConfig} from "@lodestar/config"; -import {phase0, ssz, ValidatorIndex, Epoch} from "@lodestar/types"; +import {Epoch, ValidatorIndex, phase0, ssz} from "@lodestar/types"; import {CliCommand, fromHex, toPubkeyHex} from "@lodestar/utils"; -import {externalSignerPostSignature, SignableMessageType, Signer, SignerType} from "@lodestar/validator"; -import {ApiClient, getClient} from "@lodestar/api"; -import {ensure0xPrefix, YargsError, wrapError} from "../../util/index.js"; -import {GlobalArgs} from "../../options/index.js"; +import {SignableMessageType, Signer, SignerType, externalSignerPostSignature} from "@lodestar/validator"; +import inquirer from "inquirer"; import {getBeaconConfigFromArgs} from "../../config/index.js"; +import {GlobalArgs} from "../../options/index.js"; +import {YargsError, ensure0xPrefix, wrapError} from "../../util/index.js"; import {IValidatorCliArgs} from "./options.js"; import {getSignersFromArgs} from "./signers/index.js"; diff --git a/packages/cli/src/config/beaconNodeOptions.ts b/packages/cli/src/config/beaconNodeOptions.ts index edab28e1ed21..f99ced67d40b 100644 --- a/packages/cli/src/config/beaconNodeOptions.ts +++ b/packages/cli/src/config/beaconNodeOptions.ts @@ -1,6 +1,6 @@ +import {IBeaconNodeOptions, defaultOptions} from "@lodestar/beacon-node"; +import {RecursivePartial, isPlainObject} from "@lodestar/utils"; import deepmerge from "deepmerge"; -import {defaultOptions, IBeaconNodeOptions} from "@lodestar/beacon-node"; -import {isPlainObject, RecursivePartial} from "@lodestar/utils"; export class BeaconNodeOptions { /** diff --git a/packages/cli/src/config/beaconParams.ts b/packages/cli/src/config/beaconParams.ts index 54a4155a3914..7abb0e9a5537 100644 --- a/packages/cli/src/config/beaconParams.ts +++ b/packages/cli/src/config/beaconParams.ts @@ -1,19 +1,19 @@ import { ChainConfig, - createChainForkConfig, - createChainConfig, ChainForkConfig, chainConfigFromJson, + createChainConfig, + createChainForkConfig, } from "@lodestar/config"; -import {readFile} from "../util/index.js"; -import {getNetworkBeaconParams, NetworkName} from "../networks/index.js"; +import {NetworkName, getNetworkBeaconParams} from "../networks/index.js"; import { - parseBeaconParamsArgs, - parseTerminalPowArgs, - ITerminalPowArgs, GlobalArgs, + ITerminalPowArgs, defaultNetwork, + parseBeaconParamsArgs, + parseTerminalPowArgs, } from "../options/index.js"; +import {readFile} from "../util/index.js"; import {IBeaconParamsUnparsed} from "./types.js"; type BeaconParamsArgs = { diff --git a/packages/cli/src/config/peerId.ts b/packages/cli/src/config/peerId.ts index 576a99e6980e..dd45ff408d0c 100644 --- a/packages/cli/src/config/peerId.ts +++ b/packages/cli/src/config/peerId.ts @@ -1,10 +1,10 @@ +import {unmarshalPrivateKey, unmarshalPublicKey} from "@libp2p/crypto/keys"; import type {PeerId} from "@libp2p/interface"; import {peerIdFromBytes} from "@libp2p/peer-id"; import {createFromPrivKey, createFromPubKey} from "@libp2p/peer-id-factory"; -import {unmarshalPrivateKey, unmarshalPublicKey} from "@libp2p/crypto/keys"; import {fromString as uint8ArrayFromString} from "uint8arrays/from-string"; import {toString as uint8ArrayToString} from "uint8arrays/to-string"; -import {writeFile600Perm, readFile} from "../util/index.js"; +import {readFile, writeFile600Perm} from "../util/index.js"; // Peer id to / from JSON taken from peer-id-factory // See https://github.com/libp2p/js-libp2p-peer-id/pull/9 for more details diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 0d509af17ab0..bc232bf0cce3 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -2,8 +2,8 @@ // MUST import first to apply preset from args and set ssz hasher import "./applyPreset.js"; -import {YargsError} from "./util/index.js"; import {getLodestarCli, yarg} from "./cli.js"; +import {YargsError} from "./util/index.js"; import "source-map-support/register.js"; const lodestar = getLodestarCli(); diff --git a/packages/cli/src/networks/dev.ts b/packages/cli/src/networks/dev.ts index 6ce87273b3cb..3ae54051ea37 100644 --- a/packages/cli/src/networks/dev.ts +++ b/packages/cli/src/networks/dev.ts @@ -1,7 +1,7 @@ +import {ChainConfig} from "@lodestar/config"; +import {mainnetChainConfig, minimalChainConfig} from "@lodestar/config/configs"; import {gnosisChainConfig} from "@lodestar/config/networks"; -import {minimalChainConfig, mainnetChainConfig} from "@lodestar/config/configs"; import {ACTIVE_PRESET, PresetName} from "@lodestar/params"; -import {ChainConfig} from "@lodestar/config"; let chainConfig: ChainConfig; switch (ACTIVE_PRESET) { diff --git a/packages/cli/src/networks/index.ts b/packages/cli/src/networks/index.ts index 13e55685e353..b81fe7094fdd 100644 --- a/packages/cli/src/networks/index.ts +++ b/packages/cli/src/networks/index.ts @@ -1,28 +1,28 @@ import fs from "node:fs"; -import got from "got"; import {ENR} from "@chainsafe/enr"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {HttpHeader, MediaType, WireFormat, getClient} from "@lodestar/api"; import {getStateSlotFromBytes} from "@lodestar/beacon-node"; import {ChainConfig, ChainForkConfig} from "@lodestar/config"; -import {Checkpoint} from "@lodestar/types/phase0"; -import {Slot} from "@lodestar/types"; -import {fromHex, callFnWhenAwait, Logger, formatBytes} from "@lodestar/utils"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; import { BeaconStateAllForks, - getLatestBlockRoot, computeCheckpointEpochAtStateSlot, + getLatestBlockRoot, loadState, } from "@lodestar/state-transition"; +import {Slot} from "@lodestar/types"; +import {Checkpoint} from "@lodestar/types/phase0"; +import {Logger, callFnWhenAwait, formatBytes, fromHex} from "@lodestar/utils"; +import got from "got"; import {parseBootnodesFile} from "../util/format.js"; -import * as mainnet from "./mainnet.js"; +import * as chiado from "./chiado.js"; import * as dev from "./dev.js"; +import * as ephemery from "./ephemery.js"; import * as gnosis from "./gnosis.js"; -import * as sepolia from "./sepolia.js"; import * as holesky from "./holesky.js"; -import * as chiado from "./chiado.js"; -import * as ephemery from "./ephemery.js"; +import * as mainnet from "./mainnet.js"; import * as mekong from "./mekong.js"; +import * as sepolia from "./sepolia.js"; export type NetworkName = "mainnet" | "dev" | "gnosis" | "sepolia" | "holesky" | "chiado" | "ephemery" | "mekong"; export const networkNames: NetworkName[] = [ diff --git a/packages/cli/src/options/beaconNodeOptions/api.ts b/packages/cli/src/options/beaconNodeOptions/api.ts index ea4d4ebccf84..7ee3bd9caa17 100644 --- a/packages/cli/src/options/beaconNodeOptions/api.ts +++ b/packages/cli/src/options/beaconNodeOptions/api.ts @@ -1,4 +1,4 @@ -import {defaultOptions, IBeaconNodeOptions, allNamespaces} from "@lodestar/beacon-node"; +import {IBeaconNodeOptions, allNamespaces, defaultOptions} from "@lodestar/beacon-node"; import {CliCommandOptions} from "@lodestar/utils"; const enabledAll = "*"; diff --git a/packages/cli/src/options/beaconNodeOptions/builder.ts b/packages/cli/src/options/beaconNodeOptions/builder.ts index d0e4089dd81c..01e21125637b 100644 --- a/packages/cli/src/options/beaconNodeOptions/builder.ts +++ b/packages/cli/src/options/beaconNodeOptions/builder.ts @@ -1,4 +1,4 @@ -import {defaultExecutionBuilderHttpOpts, IBeaconNodeOptions} from "@lodestar/beacon-node"; +import {IBeaconNodeOptions, defaultExecutionBuilderHttpOpts} from "@lodestar/beacon-node"; import {CliCommandOptions} from "@lodestar/utils"; import {YargsError} from "../../util/index.js"; diff --git a/packages/cli/src/options/beaconNodeOptions/chain.ts b/packages/cli/src/options/beaconNodeOptions/chain.ts index c5f907804a83..21c05545c43d 100644 --- a/packages/cli/src/options/beaconNodeOptions/chain.ts +++ b/packages/cli/src/options/beaconNodeOptions/chain.ts @@ -1,5 +1,5 @@ import * as path from "node:path"; -import {StateArchiveMode, defaultOptions, IBeaconNodeOptions, DEFAULT_STATE_ARCHIVE_MODE} from "@lodestar/beacon-node"; +import {DEFAULT_STATE_ARCHIVE_MODE, IBeaconNodeOptions, StateArchiveMode, defaultOptions} from "@lodestar/beacon-node"; import {CliCommandOptions} from "@lodestar/utils"; export type ChainArgs = { diff --git a/packages/cli/src/options/beaconNodeOptions/eth1.ts b/packages/cli/src/options/beaconNodeOptions/eth1.ts index f12a1704dec7..cab090a96781 100644 --- a/packages/cli/src/options/beaconNodeOptions/eth1.ts +++ b/packages/cli/src/options/beaconNodeOptions/eth1.ts @@ -1,5 +1,5 @@ import fs from "node:fs"; -import {defaultOptions, IBeaconNodeOptions} from "@lodestar/beacon-node"; +import {IBeaconNodeOptions, defaultOptions} from "@lodestar/beacon-node"; import {CliCommandOptions} from "@lodestar/utils"; import {extractJwtHexSecret} from "../../util/index.js"; import {ExecutionEngineArgs} from "./execution.js"; diff --git a/packages/cli/src/options/beaconNodeOptions/execution.ts b/packages/cli/src/options/beaconNodeOptions/execution.ts index 2d32ee2ae786..79ea4ade98de 100644 --- a/packages/cli/src/options/beaconNodeOptions/execution.ts +++ b/packages/cli/src/options/beaconNodeOptions/execution.ts @@ -1,5 +1,5 @@ import fs from "node:fs"; -import {defaultExecutionEngineHttpOpts, IBeaconNodeOptions} from "@lodestar/beacon-node"; +import {IBeaconNodeOptions, defaultExecutionEngineHttpOpts} from "@lodestar/beacon-node"; import {CliCommandOptions} from "@lodestar/utils"; import {extractJwtHexSecret} from "../../util/index.js"; diff --git a/packages/cli/src/options/beaconNodeOptions/metrics.ts b/packages/cli/src/options/beaconNodeOptions/metrics.ts index ded63b7dc24d..ae4c045fb07c 100644 --- a/packages/cli/src/options/beaconNodeOptions/metrics.ts +++ b/packages/cli/src/options/beaconNodeOptions/metrics.ts @@ -1,4 +1,4 @@ -import {defaultOptions, IBeaconNodeOptions} from "@lodestar/beacon-node"; +import {IBeaconNodeOptions, defaultOptions} from "@lodestar/beacon-node"; import {CliCommandOptions} from "@lodestar/utils"; export type MetricsArgs = { diff --git a/packages/cli/src/options/beaconNodeOptions/monitoring.ts b/packages/cli/src/options/beaconNodeOptions/monitoring.ts index 2143277df2ae..2f35a4a29c5c 100644 --- a/packages/cli/src/options/beaconNodeOptions/monitoring.ts +++ b/packages/cli/src/options/beaconNodeOptions/monitoring.ts @@ -1,4 +1,4 @@ -import {defaultOptions, IBeaconNodeOptions} from "@lodestar/beacon-node"; +import {IBeaconNodeOptions, defaultOptions} from "@lodestar/beacon-node"; import {CliCommandOptions} from "@lodestar/utils"; export type MonitoringArgs = { diff --git a/packages/cli/src/options/beaconNodeOptions/network.ts b/packages/cli/src/options/beaconNodeOptions/network.ts index cfd109bdc50a..56944d90fd0c 100644 --- a/packages/cli/src/options/beaconNodeOptions/network.ts +++ b/packages/cli/src/options/beaconNodeOptions/network.ts @@ -1,7 +1,7 @@ -import {multiaddr} from "@multiformats/multiaddr"; import {ENR} from "@chainsafe/enr"; -import {defaultOptions, IBeaconNodeOptions} from "@lodestar/beacon-node"; +import {IBeaconNodeOptions, defaultOptions} from "@lodestar/beacon-node"; import {CliCommandOptions} from "@lodestar/utils"; +import {multiaddr} from "@multiformats/multiaddr"; import {YargsError} from "../../util/index.js"; export const defaultListenAddress = "0.0.0.0"; diff --git a/packages/cli/src/options/beaconNodeOptions/sync.ts b/packages/cli/src/options/beaconNodeOptions/sync.ts index 789307781ed0..a33fa43db470 100644 --- a/packages/cli/src/options/beaconNodeOptions/sync.ts +++ b/packages/cli/src/options/beaconNodeOptions/sync.ts @@ -1,4 +1,4 @@ -import {defaultOptions, IBeaconNodeOptions} from "@lodestar/beacon-node"; +import {IBeaconNodeOptions, defaultOptions} from "@lodestar/beacon-node"; import {CliCommandOptions} from "@lodestar/utils"; export type SyncArgs = { diff --git a/packages/cli/src/options/globalOptions.ts b/packages/cli/src/options/globalOptions.ts index 52a5090c6794..58ae396b67d1 100644 --- a/packages/cli/src/options/globalOptions.ts +++ b/packages/cli/src/options/globalOptions.ts @@ -2,7 +2,7 @@ import {ACTIVE_PRESET} from "@lodestar/params"; import {CliCommandOptions} from "@lodestar/utils"; import {NetworkName, networkNames} from "../networks/index.js"; import {readFile} from "../util/index.js"; -import {paramsOptions, IParamsArgs} from "./paramsOptions.js"; +import {IParamsArgs, paramsOptions} from "./paramsOptions.js"; type GlobalSingleArgs = { dataDir?: string; diff --git a/packages/cli/src/options/logOptions.ts b/packages/cli/src/options/logOptions.ts index 09eb5b1d56cb..5b8c32c3b796 100644 --- a/packages/cli/src/options/logOptions.ts +++ b/packages/cli/src/options/logOptions.ts @@ -1,5 +1,5 @@ -import {LogLevels, CliCommandOptions} from "@lodestar/utils"; import {LogLevel, logFormats} from "@lodestar/logger"; +import {CliCommandOptions, LogLevels} from "@lodestar/utils"; import {LOG_FILE_DISABLE_KEYWORD} from "../util/logger.js"; export type LogArgs = { diff --git a/packages/cli/src/util/gitData/gitDataPath.ts b/packages/cli/src/util/gitData/gitDataPath.ts index 1ad3104aafc6..b4c7f8c7c62c 100644 --- a/packages/cli/src/util/gitData/gitDataPath.ts +++ b/packages/cli/src/util/gitData/gitDataPath.ts @@ -1,5 +1,5 @@ -import path from "node:path"; import fs from "node:fs"; +import path from "node:path"; import {fileURLToPath} from "node:url"; // Global variable __dirname no longer available in ES6 modules. diff --git a/packages/cli/src/util/gitData/index.ts b/packages/cli/src/util/gitData/index.ts index 0720d39d9e30..c5681660f8ce 100644 --- a/packages/cli/src/util/gitData/index.ts +++ b/packages/cli/src/util/gitData/index.ts @@ -2,7 +2,7 @@ import {execSync} from "node:child_process"; // This file is created in the build step and is distributed through NPM // MUST be in sync with `-/gitDataPath.ts` and `package.json` files. -import {readGitDataFile, GitData} from "./gitDataPath.js"; +import {GitData, readGitDataFile} from "./gitDataPath.js"; /** Reads git data from a persisted file or local git data at build time. */ export function readAndGetGitData(): GitData { diff --git a/packages/cli/src/util/logger.ts b/packages/cli/src/util/logger.ts index 7a394c9ce25f..99504ce5d43b 100644 --- a/packages/cli/src/util/logger.ts +++ b/packages/cli/src/util/logger.ts @@ -1,12 +1,12 @@ -import path from "node:path"; import fs from "node:fs"; +import path from "node:path"; import {ChainForkConfig} from "@lodestar/config"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {LogFormat, TimestampFormatCode, logFormats} from "@lodestar/logger"; import {LoggerNodeOpts} from "@lodestar/logger/node"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {LogLevel} from "@lodestar/utils"; -import {LogArgs} from "../options/logOptions.js"; import {GlobalArgs} from "../options/globalOptions.js"; +import {LogArgs} from "../options/logOptions.js"; export const LOG_FILE_DISABLE_KEYWORD = "none"; diff --git a/packages/cli/src/util/proposerConfig.ts b/packages/cli/src/util/proposerConfig.ts index 4cfa6fa71075..0aa745bc78af 100644 --- a/packages/cli/src/util/proposerConfig.ts +++ b/packages/cli/src/util/proposerConfig.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; -import {ValidatorProposerConfig} from "@lodestar/validator"; import {routes} from "@lodestar/api"; +import {ValidatorProposerConfig} from "@lodestar/validator"; import {parseFeeRecipient} from "./feeRecipient.js"; diff --git a/packages/cli/test/e2e/blsToExecutionchange.test.ts b/packages/cli/test/e2e/blsToExecutionchange.test.ts index 57f32421d313..ec7322caba00 100644 --- a/packages/cli/test/e2e/blsToExecutionchange.test.ts +++ b/packages/cli/test/e2e/blsToExecutionchange.test.ts @@ -1,11 +1,11 @@ import path from "node:path"; -import {describe, it, vi, onTestFinished} from "vitest"; import {toHexString} from "@chainsafe/ssz"; -import {sleep, retry} from "@lodestar/utils"; import {getClient} from "@lodestar/api"; import {config} from "@lodestar/config/default"; import {interopSecretKey} from "@lodestar/state-transition"; import {execCliCommand, spawnCliCommand, stopChildProcess} from "@lodestar/test-utils"; +import {retry, sleep} from "@lodestar/utils"; +import {describe, it, onTestFinished, vi} from "vitest"; import {testFilesDir} from "../utils.js"; describe("bLSToExecutionChange cmd", () => { diff --git a/packages/cli/test/e2e/importFromFsDirect.test.ts b/packages/cli/test/e2e/importFromFsDirect.test.ts index 6f612e84afe6..b65ebf74fede 100644 --- a/packages/cli/test/e2e/importFromFsDirect.test.ts +++ b/packages/cli/test/e2e/importFromFsDirect.test.ts @@ -1,8 +1,8 @@ import fs from "node:fs"; import path from "node:path"; -import {describe, it, beforeAll, vi} from "vitest"; -import {rimraf} from "rimraf"; import {getKeystoresStr} from "@lodestar/test-utils"; +import {rimraf} from "rimraf"; +import {beforeAll, describe, it, vi} from "vitest"; import {testFilesDir} from "../utils.js"; import {cachedPubkeysHex, cachedSeckeysHex} from "../utils/cachedKeys.js"; import {expectKeys, startValidatorWithKeyManager} from "../utils/validator.js"; diff --git a/packages/cli/test/e2e/importFromFsPreStep.test.ts b/packages/cli/test/e2e/importFromFsPreStep.test.ts index 437180ef07e5..2933b6113a32 100644 --- a/packages/cli/test/e2e/importFromFsPreStep.test.ts +++ b/packages/cli/test/e2e/importFromFsPreStep.test.ts @@ -1,9 +1,9 @@ import fs from "node:fs"; import path from "node:path"; -import {describe, it, expect, beforeAll, vi, onTestFinished} from "vitest"; -import {rimraf} from "rimraf"; import {execCliCommand} from "@lodestar/test-utils"; import {getKeystoresStr} from "@lodestar/test-utils"; +import {rimraf} from "rimraf"; +import {beforeAll, describe, expect, it, onTestFinished, vi} from "vitest"; import {testFilesDir} from "../utils.js"; import {cachedPubkeysHex, cachedSeckeysHex} from "../utils/cachedKeys.js"; import {expectKeys, startValidatorWithKeyManager} from "../utils/validator.js"; diff --git a/packages/cli/test/e2e/importKeystoresFromApi.test.ts b/packages/cli/test/e2e/importKeystoresFromApi.test.ts index 7f71e2977a92..6d15cfe13827 100644 --- a/packages/cli/test/e2e/importKeystoresFromApi.test.ts +++ b/packages/cli/test/e2e/importKeystoresFromApi.test.ts @@ -1,12 +1,12 @@ import path from "node:path"; -import {describe, it, expect, beforeAll, vi, onTestFinished} from "vitest"; -import {rimraf} from "rimraf"; -import {DeletionStatus, getClient, ImportStatus} from "@lodestar/api/keymanager"; -import {config} from "@lodestar/config/default"; -import {Interchange} from "@lodestar/validator"; import {HttpStatusCode} from "@lodestar/api"; +import {DeletionStatus, ImportStatus, getClient} from "@lodestar/api/keymanager"; +import {config} from "@lodestar/config/default"; import {bufferStderr, spawnCliCommand} from "@lodestar/test-utils"; import {getKeystoresStr} from "@lodestar/test-utils"; +import {Interchange} from "@lodestar/validator"; +import {rimraf} from "rimraf"; +import {beforeAll, describe, expect, it, onTestFinished, vi} from "vitest"; import {testFilesDir} from "../utils.js"; import {cachedPubkeysHex, cachedSeckeysHex} from "../utils/cachedKeys.js"; import {expectDeepEquals} from "../utils/runUtils.js"; diff --git a/packages/cli/test/e2e/importRemoteKeysFromApi.test.ts b/packages/cli/test/e2e/importRemoteKeysFromApi.test.ts index b66611cbf4f4..2f3efea9425e 100644 --- a/packages/cli/test/e2e/importRemoteKeysFromApi.test.ts +++ b/packages/cli/test/e2e/importRemoteKeysFromApi.test.ts @@ -1,9 +1,9 @@ import path from "node:path"; -import {describe, it, expect, beforeAll, vi, onTestFinished} from "vitest"; -import {rimraf} from "rimraf"; -import {ApiClient, DeleteRemoteKeyStatus, getClient, ImportRemoteKeyStatus} from "@lodestar/api/keymanager"; -import {config} from "@lodestar/config/default"; import {HttpStatusCode} from "@lodestar/api"; +import {ApiClient, DeleteRemoteKeyStatus, ImportRemoteKeyStatus, getClient} from "@lodestar/api/keymanager"; +import {config} from "@lodestar/config/default"; +import {rimraf} from "rimraf"; +import {beforeAll, describe, expect, it, onTestFinished, vi} from "vitest"; import {testFilesDir} from "../utils.js"; import {cachedPubkeysHex} from "../utils/cachedKeys.js"; import {expectDeepEquals} from "../utils/runUtils.js"; diff --git a/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts b/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts index 2f25c82999a7..26bf3e618c2b 100644 --- a/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts +++ b/packages/cli/test/e2e/propserConfigfromKeymanager.test.ts @@ -1,9 +1,9 @@ import path from "node:path"; -import {describe, it, beforeAll, vi, onTestFinished} from "vitest"; -import {rimraf} from "rimraf"; import {ImportStatus} from "@lodestar/api/keymanager"; -import {Interchange} from "@lodestar/validator"; import {getKeystoresStr} from "@lodestar/test-utils"; +import {Interchange} from "@lodestar/validator"; +import {rimraf} from "rimraf"; +import {beforeAll, describe, it, onTestFinished, vi} from "vitest"; import {testFilesDir} from "../utils.js"; import {cachedPubkeysHex, cachedSeckeysHex} from "../utils/cachedKeys.js"; import {expectDeepEquals} from "../utils/runUtils.js"; diff --git a/packages/cli/test/e2e/runDevCmd.test.ts b/packages/cli/test/e2e/runDevCmd.test.ts index 3beb68393815..e935e5eaf411 100644 --- a/packages/cli/test/e2e/runDevCmd.test.ts +++ b/packages/cli/test/e2e/runDevCmd.test.ts @@ -1,8 +1,8 @@ -import {describe, it, vi, onTestFinished} from "vitest"; import {getClient} from "@lodestar/api"; import {config} from "@lodestar/config/default"; -import {retry} from "@lodestar/utils"; import {spawnCliCommand, stopChildProcess} from "@lodestar/test-utils"; +import {retry} from "@lodestar/utils"; +import {describe, it, onTestFinished, vi} from "vitest"; describe("Run dev command", () => { vi.setConfig({testTimeout: 30_000}); diff --git a/packages/cli/test/e2e/validatorList.test.ts b/packages/cli/test/e2e/validatorList.test.ts index 7f86fb8ef89b..6987006bd26a 100644 --- a/packages/cli/test/e2e/validatorList.test.ts +++ b/packages/cli/test/e2e/validatorList.test.ts @@ -1,13 +1,13 @@ /* eslint-disable no-console */ import fs from "node:fs"; import path from "node:path"; -import {describe, it, beforeAll, vi, expect, afterEach, beforeEach} from "vitest"; -import {rimraf} from "rimraf"; import {Keystore} from "@chainsafe/bls-keystore"; -import {fromHex} from "@lodestar/utils"; import {runCliCommand} from "@lodestar/test-utils"; -import {testFilesDir} from "../utils.js"; +import {fromHex} from "@lodestar/utils"; +import {rimraf} from "rimraf"; +import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; import {getLodestarCli} from "../../src/cli.js"; +import {testFilesDir} from "../utils.js"; describe("cmds / validator", () => { vi.setConfig({testTimeout: 30_000}); diff --git a/packages/cli/test/e2e/voluntaryExit.test.ts b/packages/cli/test/e2e/voluntaryExit.test.ts index 0abddcab7652..8c17e8ef8c5b 100644 --- a/packages/cli/test/e2e/voluntaryExit.test.ts +++ b/packages/cli/test/e2e/voluntaryExit.test.ts @@ -1,10 +1,10 @@ import path from "node:path"; -import {describe, it, vi, onTestFinished} from "vitest"; -import {retry} from "@lodestar/utils"; import {getClient} from "@lodestar/api"; import {config} from "@lodestar/config/default"; import {interopSecretKey} from "@lodestar/state-transition"; -import {spawnCliCommand, execCliCommand, stopChildProcess} from "@lodestar/test-utils"; +import {execCliCommand, spawnCliCommand, stopChildProcess} from "@lodestar/test-utils"; +import {retry} from "@lodestar/utils"; +import {describe, it, onTestFinished, vi} from "vitest"; import {testFilesDir} from "../utils.js"; describe("voluntaryExit cmd", () => { diff --git a/packages/cli/test/e2e/voluntaryExitFromApi.test.ts b/packages/cli/test/e2e/voluntaryExitFromApi.test.ts index 97ac06d5fc5c..8421d57658af 100644 --- a/packages/cli/test/e2e/voluntaryExitFromApi.test.ts +++ b/packages/cli/test/e2e/voluntaryExitFromApi.test.ts @@ -1,11 +1,11 @@ import path from "node:path"; -import {describe, it, vi, expect, onTestFinished} from "vitest"; import {getClient} from "@lodestar/api"; import {getClient as getKeymanagerClient} from "@lodestar/api/keymanager"; import {config} from "@lodestar/config/default"; import {interopSecretKey} from "@lodestar/state-transition"; import {spawnCliCommand, stopChildProcess} from "@lodestar/test-utils"; import {retry} from "@lodestar/utils"; +import {describe, expect, it, onTestFinished, vi} from "vitest"; import {testFilesDir} from "../utils.js"; describe("voluntary exit from api", () => { diff --git a/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts b/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts index 769380f2053f..172f79c5191d 100644 --- a/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts +++ b/packages/cli/test/e2e/voluntaryExitRemoteSigner.test.ts @@ -1,17 +1,17 @@ import path from "node:path"; -import {describe, it, beforeAll, afterAll, vi, onTestFinished} from "vitest"; -import {retry} from "@lodestar/utils"; import {getClient} from "@lodestar/api"; import {config} from "@lodestar/config/default"; import {interopSecretKey, interopSecretKeys} from "@lodestar/state-transition"; import { - spawnCliCommand, - execCliCommand, - startExternalSigner, StartedExternalSigner, + execCliCommand, getKeystoresStr, + spawnCliCommand, + startExternalSigner, stopChildProcess, } from "@lodestar/test-utils"; +import {retry} from "@lodestar/utils"; +import {afterAll, beforeAll, describe, it, onTestFinished, vi} from "vitest"; import {testFilesDir} from "../utils.js"; describe("voluntaryExit using remote signer", () => { diff --git a/packages/cli/test/sim/backupEthProvider.test.ts b/packages/cli/test/sim/backupEthProvider.test.ts index 4ccc131a58bc..8b34d57e4d67 100644 --- a/packages/cli/test/sim/backupEthProvider.test.ts +++ b/packages/cli/test/sim/backupEthProvider.test.ts @@ -1,8 +1,8 @@ import path from "node:path"; import {activePreset} from "@lodestar/params"; -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 {BeaconClient, ExecutionClient, Match} from "../utils/crucible/interfaces.js"; +import {Simulation} from "../utils/crucible/simulation.js"; import {defineSimTestConfig, logFilesDir, replaceIpFromUrl} from "../utils/crucible/utils/index.js"; import {connectAllNodes, waitForSlot} from "../utils/crucible/utils/network.js"; diff --git a/packages/cli/test/sim/deneb.test.ts b/packages/cli/test/sim/deneb.test.ts index 865540ae7635..8d3bd3064bc2 100644 --- a/packages/cli/test/sim/deneb.test.ts +++ b/packages/cli/test/sim/deneb.test.ts @@ -1,9 +1,9 @@ import path from "node:path"; -import {Simulation} from "../utils/crucible/simulation.js"; +import {createBlobsAssertion} from "../utils/crucible/assertions/blobsAssertion.js"; import {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 {createBlobsAssertion} from "../utils/crucible/assertions/blobsAssertion.js"; import {assertCheckpointSync, assertRangeSync} from "../utils/crucible/utils/syncing.js"; const runTillEpoch = 6; diff --git a/packages/cli/test/sim/endpoints.test.ts b/packages/cli/test/sim/endpoints.test.ts index 308ac6a0053c..b1492865309a 100644 --- a/packages/cli/test/sim/endpoints.test.ts +++ b/packages/cli/test/sim/endpoints.test.ts @@ -1,10 +1,10 @@ -import path from "node:path"; import assert from "node:assert"; +import path from "node:path"; import {toHexString} from "@chainsafe/ssz"; -import {routes, fetch} from "@lodestar/api"; +import {fetch, routes} from "@lodestar/api"; import {ssz} from "@lodestar/types"; -import {Simulation} from "../utils/crucible/simulation.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 {waitForSlot} from "../utils/crucible/utils/network.js"; diff --git a/packages/cli/test/sim/mixedClient.test.ts b/packages/cli/test/sim/mixedClient.test.ts index 45029a1b26b4..5fe786829cf1 100644 --- a/packages/cli/test/sim/mixedClient.test.ts +++ b/packages/cli/test/sim/mixedClient.test.ts @@ -1,7 +1,7 @@ import path from "node:path"; -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 {BeaconClient, ExecutionClient, Match, 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"; diff --git a/packages/cli/test/sim/multiFork.test.ts b/packages/cli/test/sim/multiFork.test.ts index 047d9196239d..83cb8f234646 100644 --- a/packages/cli/test/sim/multiFork.test.ts +++ b/packages/cli/test/sim/multiFork.test.ts @@ -1,14 +1,14 @@ import path from "node:path"; -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 {createForkAssertion} from "../utils/crucible/assertions/forkAssertion.js"; +import {mergeAssertion} from "../utils/crucible/assertions/mergeAssertion.js"; +import {nodeAssertion} from "../utils/crucible/assertions/nodeAssertion.js"; import {createWithdrawalAssertions} from "../utils/crucible/assertions/withdrawalsAssertion.js"; +import {BeaconClient, ExecutionClient, Match, 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 {assertCheckpointSync, assertRangeSync, assertUnknownBlockSync} from "../utils/crucible/utils/syncing.js"; const altairForkEpoch = 2; diff --git a/packages/cli/test/unit/cmds/beacon.test.ts b/packages/cli/test/unit/cmds/beacon.test.ts index 6e7b7f389a29..a1dac019a7e8 100644 --- a/packages/cli/test/unit/cmds/beacon.test.ts +++ b/packages/cli/test/unit/cmds/beacon.test.ts @@ -1,16 +1,16 @@ -import path from "node:path"; import fs from "node:fs"; -import {describe, it, expect} from "vitest"; +import path from "node:path"; +import {ENR, SignableENR, createPrivateKeyFromPeerId} from "@chainsafe/enr"; import {createFromJSON, createSecp256k1PeerId} from "@libp2p/peer-id-factory"; -import {multiaddr} from "@multiformats/multiaddr"; -import {createPrivateKeyFromPeerId, ENR, SignableENR} from "@chainsafe/enr"; -import {chainConfig} from "@lodestar/config/default"; import {chainConfigToJson} from "@lodestar/config"; +import {chainConfig} from "@lodestar/config/default"; import {LogLevel} from "@lodestar/utils"; -import {exportToJSON} from "../../../src/config/peerId.js"; +import {multiaddr} from "@multiformats/multiaddr"; +import {describe, expect, it} from "vitest"; import {beaconHandlerInit} from "../../../src/cmds/beacon/handler.js"; import {initPeerIdAndEnr, isLocalMultiAddr} from "../../../src/cmds/beacon/initPeerIdAndEnr.js"; import {BeaconArgs} from "../../../src/cmds/beacon/options.js"; +import {exportToJSON} from "../../../src/config/peerId.js"; import {GlobalArgs} from "../../../src/options/globalOptions.js"; import {testFilesDir, testLogger} from "../../utils.js"; diff --git a/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts b/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts index a207e0c0f59d..a7b7ed64e743 100644 --- a/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts +++ b/packages/cli/test/unit/cmds/initPeerIdAndEnr.test.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; -import {describe, it, expect, beforeEach, afterEach} from "vitest"; import tmp from "tmp"; +import {afterEach, beforeEach, describe, expect, it} from "vitest"; import {initPeerIdAndEnr} from "../../../src/cmds/beacon/initPeerIdAndEnr.js"; import {BeaconArgs} from "../../../src/cmds/beacon/options.js"; import {testLogger} from "../../utils.js"; 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 8d3dbb989b5d..a313455f7d8c 100644 --- a/packages/cli/test/unit/cmds/validator/keymanager/keystoreCache.test.ts +++ b/packages/cli/test/unit/cmds/validator/keymanager/keystoreCache.test.ts @@ -1,13 +1,13 @@ -import fs from "node:fs"; import {randomBytes} from "node:crypto"; -import {describe, it, expect, beforeEach, vi} from "vitest"; -import tmp from "tmp"; +import fs from "node:fs"; import {Keystore} from "@chainsafe/bls-keystore"; import {SecretKey} from "@chainsafe/blst"; import {interopSecretKey} from "@lodestar/state-transition"; import {SignerLocal, SignerType} from "@lodestar/validator"; -import {loadKeystoreCache, writeKeystoreCache} from "../../../../../src/cmds/validator/keymanager/keystoreCache.js"; +import tmp from "tmp"; +import {beforeEach, describe, expect, it, vi} from "vitest"; import {LocalKeystoreDefinition} from "../../../../../src/cmds/validator/keymanager/interface.js"; +import {loadKeystoreCache, writeKeystoreCache} from "../../../../../src/cmds/validator/keymanager/keystoreCache.js"; const numberOfSigners = 10; diff --git a/packages/cli/test/unit/config/beaconNodeOptions.test.ts b/packages/cli/test/unit/config/beaconNodeOptions.test.ts index d35cf06ad1a4..cb21a15ce0af 100644 --- a/packages/cli/test/unit/config/beaconNodeOptions.test.ts +++ b/packages/cli/test/unit/config/beaconNodeOptions.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {defaultOptions} from "@lodestar/beacon-node"; +import {describe, expect, it} from "vitest"; import {BeaconNodeOptions} from "../../../src/config/index.js"; describe("config / beaconNodeOptions", () => { diff --git a/packages/cli/test/unit/config/beaconParams.test.ts b/packages/cli/test/unit/config/beaconParams.test.ts index 2a78d498bf89..1d24cda5dda9 100644 --- a/packages/cli/test/unit/config/beaconParams.test.ts +++ b/packages/cli/test/unit/config/beaconParams.test.ts @@ -1,9 +1,9 @@ import fs from "node:fs"; -import {describe, it, expect, beforeAll, afterAll} from "vitest"; -import yaml from "js-yaml"; import {toHexString} from "@chainsafe/ssz"; -import {getTestdirPath} from "../../utils.js"; +import yaml from "js-yaml"; +import {afterAll, beforeAll, describe, expect, it} from "vitest"; import {getBeaconParams} from "../../../src/config/index.js"; +import {getTestdirPath} from "../../utils.js"; describe("config / beaconParams", () => { const GENESIS_FORK_VERSION_MAINNET = "0x00000000"; diff --git a/packages/cli/test/unit/config/peerId.test.ts b/packages/cli/test/unit/config/peerId.test.ts index c0cdc8cff1a9..a85aaf1a5a5c 100644 --- a/packages/cli/test/unit/config/peerId.test.ts +++ b/packages/cli/test/unit/config/peerId.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; +import {describe, expect, it} from "vitest"; +import {readPeerId, writePeerId} from "../../../src/config/index.js"; import {getTestdirPath} from "../../utils.js"; -import {writePeerId, readPeerId} from "../../../src/config/index.js"; describe("config / peerId", () => { const peerIdFilepath = getTestdirPath("./test-peer-id.json"); diff --git a/packages/cli/test/unit/options/beaconNodeOptions.test.ts b/packages/cli/test/unit/options/beaconNodeOptions.test.ts index 8d295197b541..a94079ee0544 100644 --- a/packages/cli/test/unit/options/beaconNodeOptions.test.ts +++ b/packages/cli/test/unit/options/beaconNodeOptions.test.ts @@ -1,8 +1,8 @@ import fs from "node:fs"; -import {describe, it, expect} from "vitest"; -import {StateArchiveMode, IBeaconNodeOptions} from "@lodestar/beacon-node"; +import {IBeaconNodeOptions, StateArchiveMode} from "@lodestar/beacon-node"; import {RecursivePartial} from "@lodestar/utils"; -import {parseBeaconNodeArgs, BeaconNodeArgs} from "../../../src/options/beaconNodeOptions/index.js"; +import {describe, expect, it} from "vitest"; +import {BeaconNodeArgs, parseBeaconNodeArgs} from "../../../src/options/beaconNodeOptions/index.js"; import {getTestdirPath} from "../../utils.js"; describe("options / beaconNodeOptions", () => { diff --git a/packages/cli/test/unit/options/paramsOptions.test.ts b/packages/cli/test/unit/options/paramsOptions.test.ts index d6563203e652..13b3b6e41c6b 100644 --- a/packages/cli/test/unit/options/paramsOptions.test.ts +++ b/packages/cli/test/unit/options/paramsOptions.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {parseBeaconParamsArgs} from "../../../src/options/paramsOptions.js"; +import {describe, expect, it} from "vitest"; import {IBeaconParamsUnparsed} from "../../../src/config/types.js"; +import {parseBeaconParamsArgs} from "../../../src/options/paramsOptions.js"; describe("options / paramsOptions", () => { it("Should parse BeaconParams", () => { diff --git a/packages/cli/test/unit/paths/globalPaths.test.ts b/packages/cli/test/unit/paths/globalPaths.test.ts index 0d301bb56ffb..67655600c25b 100644 --- a/packages/cli/test/unit/paths/globalPaths.test.ts +++ b/packages/cli/test/unit/paths/globalPaths.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {getGlobalPaths} from "../../../src/paths/global.js"; describe("paths / global", () => { diff --git a/packages/cli/test/unit/util/extractJwtHexSecret.test.ts b/packages/cli/test/unit/util/extractJwtHexSecret.test.ts index bb7032390208..9f8543c2b9a1 100644 --- a/packages/cli/test/unit/util/extractJwtHexSecret.test.ts +++ b/packages/cli/test/unit/util/extractJwtHexSecret.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {extractJwtHexSecret} from "../../../src/util/index.js"; describe("parseJwtHexSecret", () => { diff --git a/packages/cli/test/unit/util/format.test.ts b/packages/cli/test/unit/util/format.test.ts index 194cc1dcbde7..f113d400860c 100644 --- a/packages/cli/test/unit/util/format.test.ts +++ b/packages/cli/test/unit/util/format.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {isValidatePubkeyHex, parseRange} from "../../../src/util/index.js"; describe("util / format / parseRange", () => { diff --git a/packages/cli/test/unit/util/gitData.test.ts b/packages/cli/test/unit/util/gitData.test.ts index 9e15fc2f4956..fe1827e58df2 100644 --- a/packages/cli/test/unit/util/gitData.test.ts +++ b/packages/cli/test/unit/util/gitData.test.ts @@ -1,8 +1,8 @@ import fs from "node:fs"; import path from "node:path"; import {fileURLToPath} from "node:url"; -import {describe, it, expect} from "vitest"; import {findUpSync} from "find-up"; +import {describe, expect, it} from "vitest"; import {gitDataPath, readGitDataFile} from "../../../src/util/gitData/gitDataPath.js"; import {getGitData} from "../../../src/util/index.js"; diff --git a/packages/cli/test/unit/util/logger.test.ts b/packages/cli/test/unit/util/logger.test.ts index fa17218bfd1c..dba3a72fda6c 100644 --- a/packages/cli/test/unit/util/logger.test.ts +++ b/packages/cli/test/unit/util/logger.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, vi, beforeEach, afterEach} from "vitest"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {shouldDeleteLogFile} from "../../../src/util/logger.js"; describe("shouldDeleteLogFile", () => { diff --git a/packages/cli/test/unit/util/parseBootnodesFile.test.ts b/packages/cli/test/unit/util/parseBootnodesFile.test.ts index 07338192bc68..87af3c994fb5 100644 --- a/packages/cli/test/unit/util/parseBootnodesFile.test.ts +++ b/packages/cli/test/unit/util/parseBootnodesFile.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {parseBootnodesFile} from "../../../src/util/index.js"; describe("config / bootnodes / parsing", () => { diff --git a/packages/cli/test/unit/util/progress.test.ts b/packages/cli/test/unit/util/progress.test.ts index d04d959d7422..11f443d35678 100644 --- a/packages/cli/test/unit/util/progress.test.ts +++ b/packages/cli/test/unit/util/progress.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, vi, beforeEach, afterEach} from "vitest"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {showProgress} from "../../../src/util/progress.js"; describe("progress", () => { diff --git a/packages/cli/test/unit/util/pruneOldFilesInDir.test.ts b/packages/cli/test/unit/util/pruneOldFilesInDir.test.ts index 76285afff081..a50c59547688 100644 --- a/packages/cli/test/unit/util/pruneOldFilesInDir.test.ts +++ b/packages/cli/test/unit/util/pruneOldFilesInDir.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; -import {describe, it, expect, beforeEach, afterEach} from "vitest"; import {rimraf} from "rimraf"; +import {afterEach, beforeEach, describe, expect, it} from "vitest"; import {pruneOldFilesInDir} from "../../../src/util/index.js"; import {testFilesDir} from "../../utils.js"; diff --git a/packages/cli/test/unit/util/stripOffNewlines.test.ts b/packages/cli/test/unit/util/stripOffNewlines.test.ts index 3a5a5a1f3523..0a118a499e34 100644 --- a/packages/cli/test/unit/util/stripOffNewlines.test.ts +++ b/packages/cli/test/unit/util/stripOffNewlines.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {stripOffNewlines} from "../../../src/util/index.js"; describe("stripOffNewlines", () => { diff --git a/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts b/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts index 10f6b34bd152..5bf19c635139 100644 --- a/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts +++ b/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts @@ -1,16 +1,16 @@ import fs from "node:fs"; import path from "node:path"; -import {describe, it, expect, beforeEach, vi} from "vitest"; -import {rimraf} from "rimraf"; import {getKeystoresStr} from "@lodestar/test-utils"; -import {cachedSeckeysHex} from "../../utils/cachedKeys.js"; -import {testFilesDir} from "../../utils.js"; +import {rimraf} from "rimraf"; +import {beforeEach, describe, expect, it, vi} from "vitest"; import { - decryptKeystoreDefinitions, KeystoreDecryptOptions, + decryptKeystoreDefinitions, } from "../../../src/cmds/validator/keymanager/decryptKeystoreDefinitions.js"; import {LocalKeystoreDefinition} from "../../../src/cmds/validator/keymanager/interface.js"; import {LockfileError, unlockFilepath} from "../../../src/util/lockfile.js"; +import {testFilesDir} from "../../utils.js"; +import {cachedSeckeysHex} from "../../utils/cachedKeys.js"; describe("decryptKeystoreDefinitions", () => { vi.setConfig({testTimeout: 100_000, hookTimeout: 50_000}); diff --git a/packages/cli/test/unit/validator/keys.test.ts b/packages/cli/test/unit/validator/keys.test.ts index 6902d17b3883..589e68db7f0d 100644 --- a/packages/cli/test/unit/validator/keys.test.ts +++ b/packages/cli/test/unit/validator/keys.test.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import path from "node:path"; -import {describe, it, expect, afterEach} from "vitest"; +import {afterEach, describe, expect, it} from "vitest"; import {importKeystoreDefinitionsFromExternalDir} from "../../../src/cmds/validator/signers/importExternalKeystores.js"; describe("validator / signers / importKeystoreDefinitionsFromExternalDir", () => { diff --git a/packages/cli/test/unit/validator/options.test.ts b/packages/cli/test/unit/validator/options.test.ts index 627ee8f59818..85aa0b3f21f7 100644 --- a/packages/cli/test/unit/validator/options.test.ts +++ b/packages/cli/test/unit/validator/options.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {parseFeeRecipient} from "../../../src/util/index.js"; const feeRecipient = Buffer.from(Array.from({length: 20}, () => Math.round(Math.random() * 255))); diff --git a/packages/cli/test/unit/validator/parseProposerConfig.test.ts b/packages/cli/test/unit/validator/parseProposerConfig.test.ts index 40fa57f7feb5..f10d5d7cc080 100644 --- a/packages/cli/test/unit/validator/parseProposerConfig.test.ts +++ b/packages/cli/test/unit/validator/parseProposerConfig.test.ts @@ -1,7 +1,7 @@ import path from "node:path"; import {fileURLToPath} from "node:url"; -import {describe, it, expect} from "vitest"; import {routes} from "@lodestar/api"; +import {describe, expect, it} from "vitest"; import {parseProposerConfig} from "../../../src/util/index.js"; diff --git a/packages/cli/test/utils.ts b/packages/cli/test/utils.ts index 81136c0a18d4..7c20ec0b9c2d 100644 --- a/packages/cli/test/utils.ts +++ b/packages/cli/test/utils.ts @@ -1,9 +1,9 @@ import fs from "node:fs"; import path from "node:path"; -import tmp from "tmp"; import {getEnvLogLevel} from "@lodestar/logger/env"; import {LoggerNode, LoggerNodeOpts, getNodeLogger} from "@lodestar/logger/node"; import {LogLevel} from "@lodestar/utils"; +import tmp from "tmp"; export const networkDev = "dev"; diff --git a/packages/cli/test/utils/crucible/assertions/accountBalanceAssertion.ts b/packages/cli/test/utils/crucible/assertions/accountBalanceAssertion.ts index e6c4f4c744eb..e237bba69dcb 100644 --- a/packages/cli/test/utils/crucible/assertions/accountBalanceAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/accountBalanceAssertion.ts @@ -1,5 +1,5 @@ import {EL_GENESIS_ACCOUNT} from "../constants.js"; -import {Match, AssertionResult, NodePair, Assertion} from "../interfaces.js"; +import {Assertion, AssertionResult, Match, NodePair} from "../interfaces.js"; const transactionAmount = BigInt(2441406250); diff --git a/packages/cli/test/utils/crucible/assertions/blobsAssertion.ts b/packages/cli/test/utils/crucible/assertions/blobsAssertion.ts index 50c9ed13f972..9bea3f1ca1f5 100644 --- a/packages/cli/test/utils/crucible/assertions/blobsAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/blobsAssertion.ts @@ -1,7 +1,7 @@ import {randomBytes} from "node:crypto"; import {fromHex, toHex} from "@lodestar/utils"; -import {Assertion, Match, AssertionResult, NodePair} from "../interfaces.js"; import {EL_GENESIS_ACCOUNT, EL_GENESIS_SECRET_KEY, SIM_ENV_CHAIN_ID} from "../constants.js"; +import {Assertion, AssertionResult, Match, NodePair} from "../interfaces.js"; import {generateBlobsForTransaction} from "../utils/blobs.js"; import {BlobsEIP4844Transaction} from "../web3js/blobsEIP4844Transaction.js"; diff --git a/packages/cli/test/utils/crucible/assertions/defaults/attestationCountAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/attestationCountAssertion.ts index 922ce80ae329..2d0715051fa5 100644 --- a/packages/cli/test/utils/crucible/assertions/defaults/attestationCountAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/attestationCountAssertion.ts @@ -1,6 +1,6 @@ import {MAX_COMMITTEES_PER_SLOT} from "@lodestar/params"; -import {Match, AssertionResult, Assertion} from "../../interfaces.js"; -import {inclusionDelayAssertion, expectedMaxInclusionDelay} from "./inclusionDelayAssertion.js"; +import {Assertion, AssertionResult, Match} from "../../interfaces.js"; +import {expectedMaxInclusionDelay, inclusionDelayAssertion} from "./inclusionDelayAssertion.js"; export const expectedMinAttestationCount = MAX_COMMITTEES_PER_SLOT - 1; diff --git a/packages/cli/test/utils/crucible/assertions/defaults/attestationParticipationAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/attestationParticipationAssertion.ts index 01cd6d29d09a..5715392758f1 100644 --- a/packages/cli/test/utils/crucible/assertions/defaults/attestationParticipationAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/attestationParticipationAssertion.ts @@ -1,7 +1,7 @@ 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 {Match, AssertionResult, Assertion} from "../../interfaces.js"; +import {Assertion, AssertionResult, Match} from "../../interfaces.js"; const TIMELY_HEAD = 1 << TIMELY_HEAD_FLAG_INDEX; const TIMELY_SOURCE = 1 << TIMELY_SOURCE_FLAG_INDEX; diff --git a/packages/cli/test/utils/crucible/assertions/defaults/connectedPeerCountAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/connectedPeerCountAssertion.ts index 83f308e62789..5304731ee8fc 100644 --- a/packages/cli/test/utils/crucible/assertions/defaults/connectedPeerCountAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/connectedPeerCountAssertion.ts @@ -1,4 +1,4 @@ -import {AssertionResult, Assertion} from "../../interfaces.js"; +import {Assertion, AssertionResult} from "../../interfaces.js"; import {everySlotMatcher} from "../matchers.js"; export const connectedPeerCountAssertion: Assertion<"connectedPeerCount", number> = { diff --git a/packages/cli/test/utils/crucible/assertions/defaults/finalizedAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/finalizedAssertion.ts index f03fc41eb8e9..89998fd87627 100644 --- a/packages/cli/test/utils/crucible/assertions/defaults/finalizedAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/finalizedAssertion.ts @@ -1,5 +1,5 @@ import {Slot} from "@lodestar/types"; -import {AssertionResult, Assertion} from "../../interfaces.js"; +import {Assertion, AssertionResult} from "../../interfaces.js"; import {everySlotMatcher} from "../matchers.js"; export const finalizedAssertion: Assertion<"finalized", Slot> = { diff --git a/packages/cli/test/utils/crucible/assertions/defaults/headAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/headAssertion.ts index 6464067d5d7d..3a3f910a4489 100644 --- a/packages/cli/test/utils/crucible/assertions/defaults/headAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/headAssertion.ts @@ -1,6 +1,6 @@ import {RootHex, Slot} from "@lodestar/types"; import {toHexString} from "@lodestar/utils"; -import {AssertionResult, Assertion} from "../../interfaces.js"; +import {Assertion, AssertionResult} from "../../interfaces.js"; import {everySlotMatcher} from "../matchers.js"; export interface HeadSummary { diff --git a/packages/cli/test/utils/crucible/assertions/defaults/inclusionDelayAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/inclusionDelayAssertion.ts index e3ec467099ba..f0f08c92f202 100644 --- a/packages/cli/test/utils/crucible/assertions/defaults/inclusionDelayAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/inclusionDelayAssertion.ts @@ -1,4 +1,4 @@ -import {AssertionResult, Assertion} from "../../interfaces.js"; +import {Assertion, AssertionResult} from "../../interfaces.js"; import {avg} from "../../utils/index.js"; import {everySlotMatcher} from "../matchers.js"; diff --git a/packages/cli/test/utils/crucible/assertions/defaults/missedBlocksAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/missedBlocksAssertion.ts index 1209a6469ca3..8c8d96451f5e 100644 --- a/packages/cli/test/utils/crucible/assertions/defaults/missedBlocksAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/missedBlocksAssertion.ts @@ -1,5 +1,5 @@ import {isNullish} from "../../../../utils.js"; -import {Match, AssertionResult, Assertion} from "../../interfaces.js"; +import {Assertion, AssertionResult, Match} from "../../interfaces.js"; import {arrayEquals} from "../../utils/index.js"; import {headAssertion} from "./headAssertion.js"; diff --git a/packages/cli/test/utils/crucible/assertions/defaults/syncCommitteeParticipationAssertion.ts b/packages/cli/test/utils/crucible/assertions/defaults/syncCommitteeParticipationAssertion.ts index 83b945da0b0a..a0d6f8328187 100644 --- a/packages/cli/test/utils/crucible/assertions/defaults/syncCommitteeParticipationAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/defaults/syncCommitteeParticipationAssertion.ts @@ -1,6 +1,6 @@ import {ForkName} from "@lodestar/params"; import {altair} from "@lodestar/types"; -import {Match, AssertionResult, Assertion} from "../../interfaces.js"; +import {Assertion, AssertionResult, Match} 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 diff --git a/packages/cli/test/utils/crucible/assertions/executionHeadAssertion.ts b/packages/cli/test/utils/crucible/assertions/executionHeadAssertion.ts index 8ea0be1b445c..3f6fedd139fd 100644 --- a/packages/cli/test/utils/crucible/assertions/executionHeadAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/executionHeadAssertion.ts @@ -1,6 +1,6 @@ -import {toHex} from "@lodestar/utils"; import {bellatrix} from "@lodestar/types"; -import {Match, AssertionResult, Assertion} from "../interfaces.js"; +import {toHex} from "@lodestar/utils"; +import {Assertion, AssertionResult, Match} from "../interfaces.js"; export function createExecutionHeadAssertion({ checkForSlot, diff --git a/packages/cli/test/utils/crucible/assertions/forkAssertion.ts b/packages/cli/test/utils/crucible/assertions/forkAssertion.ts index 8f6372f856f6..aeddff9ab13c 100644 --- a/packages/cli/test/utils/crucible/assertions/forkAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/forkAssertion.ts @@ -1,7 +1,7 @@ import {ForkName} from "@lodestar/params"; import {Epoch} from "@lodestar/types"; import {toHexString} from "@lodestar/utils"; -import {Match, AssertionResult, Assertion} from "../interfaces.js"; +import {Assertion, AssertionResult, Match} from "../interfaces.js"; export function createForkAssertion(fork: ForkName, epoch: Epoch): Assertion { return { diff --git a/packages/cli/test/utils/crucible/assertions/lighthousePeerScoreAssertion.ts b/packages/cli/test/utils/crucible/assertions/lighthousePeerScoreAssertion.ts index 29fa36220b3d..d9dd4e0adc55 100644 --- a/packages/cli/test/utils/crucible/assertions/lighthousePeerScoreAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/lighthousePeerScoreAssertion.ts @@ -1,4 +1,4 @@ -import {AssertionResult, BeaconClient, LighthouseAPI, NodePair, Assertion} from "../interfaces.js"; +import {Assertion, AssertionResult, BeaconClient, LighthouseAPI, NodePair} from "../interfaces.js"; import {neverMatcher} from "./matchers.js"; const MIN_GOSSIPSUB_SCORE = 10; diff --git a/packages/cli/test/utils/crucible/assertions/mergeAssertion.ts b/packages/cli/test/utils/crucible/assertions/mergeAssertion.ts index acd686c87bf7..6e0c1a63d7af 100644 --- a/packages/cli/test/utils/crucible/assertions/mergeAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/mergeAssertion.ts @@ -1,5 +1,5 @@ import {BeaconStateAllForks, isExecutionStateType, isMergeTransitionComplete} from "@lodestar/state-transition"; -import {AssertionResult, Assertion} from "../interfaces.js"; +import {Assertion, AssertionResult} from "../interfaces.js"; import {neverMatcher} from "./matchers.js"; export const mergeAssertion: Assertion<"merge", string> = { diff --git a/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts b/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts index 04c9b393d245..6b94f2e701a9 100644 --- a/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts @@ -1,7 +1,7 @@ import {SecretKey} from "@chainsafe/blst"; import {routes} from "@lodestar/api/beacon"; import {toHex} from "@lodestar/utils"; -import {AssertionResult, ValidatorClientKeys, Assertion, ValidatorClient} from "../interfaces.js"; +import {Assertion, AssertionResult, ValidatorClient, ValidatorClientKeys} from "../interfaces.js"; import {arrayEquals} from "../utils/index.js"; import {neverMatcher} from "./matchers.js"; diff --git a/packages/cli/test/utils/crucible/assertions/withdrawalsAssertion.ts b/packages/cli/test/utils/crucible/assertions/withdrawalsAssertion.ts index be256a0b696d..020684682858 100644 --- a/packages/cli/test/utils/crucible/assertions/withdrawalsAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/withdrawalsAssertion.ts @@ -1,6 +1,6 @@ -import {capella} from "@lodestar/types"; import {MAX_WITHDRAWALS_PER_PAYLOAD} from "@lodestar/params"; -import {Match, AssertionResult, Assertion} from "../interfaces.js"; +import {capella} from "@lodestar/types"; +import {Assertion, AssertionResult, Match} from "../interfaces.js"; type WithdrawalsData = { withdrawalCount: number; diff --git a/packages/cli/test/utils/crucible/clients/beacon/lighthouse.ts b/packages/cli/test/utils/crucible/clients/beacon/lighthouse.ts index 515418f7e558..725c08389105 100644 --- a/packages/cli/test/utils/crucible/clients/beacon/lighthouse.ts +++ b/packages/cli/test/utils/crucible/clients/beacon/lighthouse.ts @@ -1,9 +1,9 @@ import {writeFile} from "node:fs/promises"; import path from "node:path"; -import got, {RequestError} from "got"; -import yaml from "js-yaml"; import {getClient} from "@lodestar/api/beacon"; import {chainConfigToJson} from "@lodestar/config"; +import got, {RequestError} from "got"; +import yaml from "js-yaml"; import {BeaconClient, BeaconNodeGenerator, LighthouseAPI, RunnerType} from "../../interfaces.js"; import {getNodeMountedPaths} from "../../utils/paths.js"; import {getNodePorts} from "../../utils/ports.js"; diff --git a/packages/cli/test/utils/crucible/clients/beacon/lodestar.ts b/packages/cli/test/utils/crucible/clients/beacon/lodestar.ts index 2bc7c27ead41..320b9c1fd224 100644 --- a/packages/cli/test/utils/crucible/clients/beacon/lodestar.ts +++ b/packages/cli/test/utils/crucible/clients/beacon/lodestar.ts @@ -1,9 +1,9 @@ import {writeFile} from "node:fs/promises"; import path from "node:path"; -import got from "got"; import {getClient} from "@lodestar/api/beacon"; import {chainConfigToJson} from "@lodestar/config"; import {LogLevel} from "@lodestar/utils"; +import got from "got"; import {BeaconArgs} from "../../../../../src/cmds/beacon/options.js"; import {GlobalArgs} from "../../../../../src/options/globalOptions.js"; import {LODESTAR_BINARY_PATH} from "../../constants.js"; diff --git a/packages/cli/test/utils/crucible/clients/execution/geth.ts b/packages/cli/test/utils/crucible/clients/execution/geth.ts index ca3dee2dcb86..4daa008f0c54 100644 --- a/packages/cli/test/utils/crucible/clients/execution/geth.ts +++ b/packages/cli/test/utils/crucible/clients/execution/geth.ts @@ -9,10 +9,10 @@ import { SHARED_JWT_SECRET, SIM_ENV_NETWORK_ID, } from "../../constants.js"; -import {registerWeb3JsPlugins} from "../../web3js/plugins/index.js"; import {ExecutionClient, ExecutionNodeGenerator, ExecutionStartMode, JobOptions, RunnerType} from "../../interfaces.js"; import {getNodeMountedPaths} from "../../utils/paths.js"; import {getNodePorts} from "../../utils/ports.js"; +import {registerWeb3JsPlugins} from "../../web3js/plugins/index.js"; export const generateGethNode: ExecutionNodeGenerator = (opts, runner) => { if (!process.env.GETH_BINARY_DIR && !process.env.GETH_DOCKER_IMAGE) { diff --git a/packages/cli/test/utils/crucible/clients/execution/index.ts b/packages/cli/test/utils/crucible/clients/execution/index.ts index db6510a7a7d6..b7e83813ce3d 100644 --- a/packages/cli/test/utils/crucible/clients/execution/index.ts +++ b/packages/cli/test/utils/crucible/clients/execution/index.ts @@ -1,5 +1,5 @@ import {writeFile} from "node:fs/promises"; -import {SHARED_JWT_SECRET, CLIQUE_SEALING_PERIOD} from "../../constants.js"; +import {CLIQUE_SEALING_PERIOD, SHARED_JWT_SECRET} from "../../constants.js"; import { AtLeast, ExecutionClient, @@ -8,8 +8,8 @@ import { ExecutionNode, ExecutionStartMode, } from "../../interfaces.js"; -import {getEstimatedForkTime} from "../../utils/index.js"; import {getGethGenesisBlock} from "../../utils/executionGenesis.js"; +import {getEstimatedForkTime} from "../../utils/index.js"; import {ensureDirectories} from "../../utils/paths.js"; import {generateGethNode} from "./geth.js"; import {generateMockNode} from "./mock.js"; diff --git a/packages/cli/test/utils/crucible/clients/execution/nethermind.ts b/packages/cli/test/utils/crucible/clients/execution/nethermind.ts index 1c991afa6189..a59f7e55ece6 100644 --- a/packages/cli/test/utils/crucible/clients/execution/nethermind.ts +++ b/packages/cli/test/utils/crucible/clients/execution/nethermind.ts @@ -2,12 +2,12 @@ import {writeFile} from "node:fs/promises"; import path from "node:path"; import got from "got"; import {Web3} from "web3"; -import {registerWeb3JsPlugins} from "../../web3js/plugins/index.js"; +import {SHARED_JWT_SECRET} from "../../constants.js"; import {ExecutionClient, ExecutionNodeGenerator, JobOptions, RunnerType} from "../../interfaces.js"; import {getNethermindChainSpec} from "../../utils/executionGenesis.js"; import {getNodeMountedPaths} from "../../utils/paths.js"; -import {SHARED_JWT_SECRET} from "../../constants.js"; import {getNodePorts} from "../../utils/ports.js"; +import {registerWeb3JsPlugins} from "../../web3js/plugins/index.js"; export const generateNethermindNode: ExecutionNodeGenerator = (opts, runner) => { if (!process.env.NETHERMIND_DOCKER_IMAGE) { diff --git a/packages/cli/test/utils/crucible/clients/validator/index.ts b/packages/cli/test/utils/crucible/clients/validator/index.ts index 677deca23ff0..74f9734c767a 100644 --- a/packages/cli/test/utils/crucible/clients/validator/index.ts +++ b/packages/cli/test/utils/crucible/clients/validator/index.ts @@ -1,11 +1,11 @@ import {writeFile} from "node:fs/promises"; -import {SHARED_JWT_SECRET, SHARED_VALIDATOR_PASSWORD, BN_REST_BASE_PORT} from "../../constants.js"; +import {BN_REST_BASE_PORT, SHARED_JWT_SECRET, SHARED_VALIDATOR_PASSWORD} from "../../constants.js"; import {AtLeast, BeaconClient, ValidatorClient, ValidatorGeneratorOptions, ValidatorNode} from "../../interfaces.js"; import {makeUniqueArray} from "../../utils/index.js"; import {createKeystores} from "../../utils/keys.js"; import {ensureDirectories} from "../../utils/paths.js"; -import {generateLodestarValidatorNode} from "./lodestar.js"; import {generateLighthouseValidatorNode} from "./lighthouse.js"; +import {generateLodestarValidatorNode} from "./lodestar.js"; export async function createValidatorNode( client: V, diff --git a/packages/cli/test/utils/crucible/clients/validator/lighthouse.ts b/packages/cli/test/utils/crucible/clients/validator/lighthouse.ts index f99310dc7907..a5f137a861d5 100644 --- a/packages/cli/test/utils/crucible/clients/validator/lighthouse.ts +++ b/packages/cli/test/utils/crucible/clients/validator/lighthouse.ts @@ -1,9 +1,9 @@ -import path from "node:path"; import {writeFile} from "node:fs/promises"; -import got, {RequestError} from "got"; -import yaml from "js-yaml"; +import path from "node:path"; import {getClient as keyManagerGetClient} from "@lodestar/api/keymanager"; import {chainConfigToJson} from "@lodestar/config"; +import got, {RequestError} from "got"; +import yaml from "js-yaml"; import {RunnerType, ValidatorClient, ValidatorNodeGenerator} from "../../interfaces.js"; import {updateKeystoresPath} from "../../utils/keys.js"; import {getNodeMountedPaths} from "../../utils/paths.js"; diff --git a/packages/cli/test/utils/crucible/clients/validator/lodestar.ts b/packages/cli/test/utils/crucible/clients/validator/lodestar.ts index a2b928c0a2d5..4e2e88b71cc5 100644 --- a/packages/cli/test/utils/crucible/clients/validator/lodestar.ts +++ b/packages/cli/test/utils/crucible/clients/validator/lodestar.ts @@ -1,10 +1,10 @@ import {writeFile} from "node:fs/promises"; import path from "node:path"; -import got from "got"; import {getClient as keyManagerGetClient} from "@lodestar/api/keymanager"; import {chainConfigToJson} from "@lodestar/config"; import {LogLevel} from "@lodestar/utils"; import {defaultOptions} from "@lodestar/validator"; +import got from "got"; import {IValidatorCliArgs} from "../../../../../src/cmds/validator/options.js"; import {GlobalArgs} from "../../../../../src/options/globalOptions.js"; import {LODESTAR_BINARY_PATH} from "../../constants.js"; diff --git a/packages/cli/test/utils/crucible/externalSignerServer.ts b/packages/cli/test/utils/crucible/externalSignerServer.ts index 4282f1761db9..29789432a0d5 100644 --- a/packages/cli/test/utils/crucible/externalSignerServer.ts +++ b/packages/cli/test/utils/crucible/externalSignerServer.ts @@ -1,6 +1,6 @@ -import {fromHexString} from "@chainsafe/ssz"; -import {fastify, FastifyInstance} from "fastify"; import {SecretKey} from "@chainsafe/blst"; +import {fromHexString} from "@chainsafe/ssz"; +import {FastifyInstance, fastify} from "fastify"; import {EXTERNAL_SIGNER_BASE_PORT} from "./constants.js"; /* eslint-disable no-console */ diff --git a/packages/cli/test/utils/crucible/interfaces.ts b/packages/cli/test/utils/crucible/interfaces.ts index 84b5043ba983..13c56dd5012b 100644 --- a/packages/cli/test/utils/crucible/interfaces.ts +++ b/packages/cli/test/utils/crucible/interfaces.ts @@ -1,12 +1,12 @@ import {ChildProcess} from "node:child_process"; -import {Web3} from "web3"; import {SecretKey} from "@chainsafe/blst"; import {ApiClient} from "@lodestar/api"; import {ApiClient as KeyManagerApi} from "@lodestar/api/keymanager"; import {ChainForkConfig} from "@lodestar/config"; -import {ForkName} from "@lodestar/params"; -import {Slot, Epoch, SignedBeaconBlock} from "@lodestar/types"; import {LogLevel, Logger} from "@lodestar/logger"; +import {ForkName} from "@lodestar/params"; +import {Epoch, SignedBeaconBlock, Slot} from "@lodestar/types"; +import {Web3} from "web3"; import {BeaconArgs} from "../../../src/cmds/beacon/options.js"; import {IValidatorCliArgs} from "../../../src/cmds/validator/options.js"; import {GlobalArgs} from "../../../src/options/index.js"; diff --git a/packages/cli/test/utils/crucible/runner/childProcessRunner.ts b/packages/cli/test/utils/crucible/runner/childProcessRunner.ts index 4c2041d0860f..199d815cc8c3 100644 --- a/packages/cli/test/utils/crucible/runner/childProcessRunner.ts +++ b/packages/cli/test/utils/crucible/runner/childProcessRunner.ts @@ -1,6 +1,6 @@ import {ChildProcess} from "node:child_process"; -import {spawnChildProcess, stopChildProcess, SpawnChildProcessOptions, ChildProcessResolve} from "@lodestar/test-utils"; import {Logger} from "@lodestar/logger"; +import {ChildProcessResolve, SpawnChildProcessOptions, spawnChildProcess, stopChildProcess} from "@lodestar/test-utils"; import {Job, JobOptions, RunnerEnv, RunnerType} from "../interfaces.js"; export class ChildProcessRunner implements RunnerEnv { diff --git a/packages/cli/test/utils/crucible/runner/dockerRunner.ts b/packages/cli/test/utils/crucible/runner/dockerRunner.ts index bc5b97811cf4..33adb5aebbe0 100644 --- a/packages/cli/test/utils/crucible/runner/dockerRunner.ts +++ b/packages/cli/test/utils/crucible/runner/dockerRunner.ts @@ -1,7 +1,7 @@ import {ChildProcess} from "node:child_process"; import {Logger} from "@lodestar/logger"; +import {ChildProcessResolve, SpawnChildProcessOptions, execChildProcess, spawnChildProcess} from "@lodestar/test-utils"; import {sleep} from "@lodestar/utils"; -import {SpawnChildProcessOptions, execChildProcess, spawnChildProcess, ChildProcessResolve} from "@lodestar/test-utils"; import {Job, JobOptions, RunnerEnv, RunnerType} from "../interfaces.js"; const dockerNetworkIpRange = "192.168.0"; diff --git a/packages/cli/test/utils/crucible/simulation.ts b/packages/cli/test/utils/crucible/simulation.ts index c6e58095474a..e9674e5193e2 100644 --- a/packages/cli/test/utils/crucible/simulation.ts +++ b/packages/cli/test/utils/crucible/simulation.ts @@ -1,36 +1,36 @@ import fs from "node:fs"; import {mkdir, writeFile} from "node:fs/promises"; import path from "node:path"; -import tmp from "tmp"; import {fromHexString} from "@chainsafe/ssz"; import {nodeUtils} from "@lodestar/beacon-node"; -import {loadEthereumTrustedSetup, initCKZG} from "@lodestar/beacon-node/util"; +import {initCKZG, loadEthereumTrustedSetup} from "@lodestar/beacon-node/util"; import {ChainForkConfig} from "@lodestar/config"; +import {LogLevel, TimestampFormatCode} from "@lodestar/logger"; +import {LoggerNode, getNodeLogger} from "@lodestar/logger/node"; import {activePreset} from "@lodestar/params"; import {BeaconStateAllForks, interopSecretKey} from "@lodestar/state-transition"; import {prettyMsToTime} from "@lodestar/utils"; -import {LogLevel, TimestampFormatCode} from "@lodestar/logger"; -import {getNodeLogger, LoggerNode} from "@lodestar/logger/node"; -import {EpochClock, MS_IN_SEC} from "./epochClock.js"; -import {ExternalSignerServer} from "./externalSignerServer.js"; -import {SimulationTracker} from "./simulationTracker.js"; +import tmp from "tmp"; import {createBeaconNode} from "./clients/beacon/index.js"; +import {createExecutionNode} from "./clients/execution/index.js"; import {createValidatorNode, getValidatorForBeaconNode} from "./clients/validator/index.js"; import {MOCK_ETH1_GENESIS_HASH} from "./constants.js"; -import {createExecutionNode} from "./clients/execution/index.js"; +import {EpochClock, MS_IN_SEC} from "./epochClock.js"; +import {ExternalSignerServer} from "./externalSignerServer.js"; import { BeaconClient, - ValidatorClientKeys, ExecutionClient, + GeneratorOptions, IRunner, NodePair, NodePairDefinition, SimulationInitOptions, SimulationOptions, ValidatorClient, - GeneratorOptions, + ValidatorClientKeys, } from "./interfaces.js"; import {Runner} from "./runner/index.js"; +import {SimulationTracker} from "./simulationTracker.js"; import {registerProcessHandler, replaceIpFromUrl} from "./utils/index.js"; import {getNodePaths} from "./utils/paths.js"; diff --git a/packages/cli/test/utils/crucible/simulationTracker.ts b/packages/cli/test/utils/crucible/simulationTracker.ts index 778a7ad2a771..3e714ca8950f 100644 --- a/packages/cli/test/utils/crucible/simulationTracker.ts +++ b/packages/cli/test/utils/crucible/simulationTracker.ts @@ -1,25 +1,25 @@ import EventEmitter from "node:events"; -import path from "node:path"; import fs from "node:fs/promises"; -import createDebug from "debug"; +import path from "node:path"; import {routes} from "@lodestar/api/beacon"; import {ChainForkConfig} from "@lodestar/config"; -import {Epoch, Slot} from "@lodestar/types"; import {LoggerNode} from "@lodestar/logger/node"; +import {Epoch, Slot} from "@lodestar/types"; +import createDebug from "debug"; import {isNullish} from "../../utils.js"; +import {defaultAssertions} from "./assertions/defaults/index.js"; import {EpochClock} from "./epochClock.js"; import { - Match, + Assertion, + AssertionError, AtLeast, + Match, NodeId, NodePair, - Assertion, - AssertionError, SimulationReporter, StoreType, StoreTypes, } from "./interfaces.js"; -import {defaultAssertions} from "./assertions/defaults/index.js"; import {TableReporter} from "./tableReporter.js"; import {fetchBlock} from "./utils/network.js"; diff --git a/packages/cli/test/utils/crucible/utils/executionGenesis.ts b/packages/cli/test/utils/crucible/utils/executionGenesis.ts index bd3da4ba7662..02f7d553df16 100644 --- a/packages/cli/test/utils/crucible/utils/executionGenesis.ts +++ b/packages/cli/test/utils/crucible/utils/executionGenesis.ts @@ -1,5 +1,5 @@ import {SIM_ENV_CHAIN_ID, SIM_ENV_NETWORK_ID} from "../constants.js"; -import {ExecutionGenesisOptions, ExecutionStartMode, Eth1GenesisBlock} from "../interfaces.js"; +import {Eth1GenesisBlock, ExecutionGenesisOptions, ExecutionStartMode} from "../interfaces.js"; export const getGethGenesisBlock = ( mode: ExecutionStartMode, diff --git a/packages/cli/test/utils/crucible/utils/index.ts b/packages/cli/test/utils/crucible/utils/index.ts index 0e016778cdce..13b26cfd9318 100644 --- a/packages/cli/test/utils/crucible/utils/index.ts +++ b/packages/cli/test/utils/crucible/utils/index.ts @@ -1,7 +1,7 @@ +import {ChainConfig, ChainForkConfig, createChainForkConfig} from "@lodestar/config"; /* eslint-disable no-console */ import {activePreset} from "@lodestar/params"; import {Epoch} from "@lodestar/types"; -import {ChainConfig, ChainForkConfig, createChainForkConfig} from "@lodestar/config"; import { CLIQUE_SEALING_PERIOD, ETH_TTD_INCREMENT, diff --git a/packages/cli/test/utils/crucible/utils/keys.ts b/packages/cli/test/utils/crucible/utils/keys.ts index 8915e85b529e..1a4da9ffec65 100644 --- a/packages/cli/test/utils/crucible/utils/keys.ts +++ b/packages/cli/test/utils/crucible/utils/keys.ts @@ -1,7 +1,7 @@ import {readFile, writeFile} from "node:fs/promises"; import path from "node:path"; -import yaml from "js-yaml"; import {Keystore} from "@chainsafe/bls-keystore"; +import yaml from "js-yaml"; import {SHARED_VALIDATOR_PASSWORD} from "../constants.js"; import {ValidatorClientKeys, ValidatorPaths} from "../interfaces.js"; diff --git a/packages/cli/test/utils/crucible/utils/paths.ts b/packages/cli/test/utils/crucible/utils/paths.ts index 4ff149d6f308..06ef1bf7fe1f 100644 --- a/packages/cli/test/utils/crucible/utils/paths.ts +++ b/packages/cli/test/utils/crucible/utils/paths.ts @@ -1,6 +1,6 @@ -import path from "node:path"; import fs from "node:fs"; import {mkdir} from "node:fs/promises"; +import path from "node:path"; import { BeaconClient, BeaconPaths, diff --git a/packages/cli/test/utils/crucible/utils/ports.ts b/packages/cli/test/utils/crucible/utils/ports.ts index be430598895e..3b6f51ad1429 100644 --- a/packages/cli/test/utils/crucible/utils/ports.ts +++ b/packages/cli/test/utils/crucible/utils/ports.ts @@ -1,10 +1,10 @@ import { BN_P2P_BASE_PORT, BN_REST_BASE_PORT, - KEY_MANAGER_BASE_PORT, - EL_P2P_BASE_PORT, - EL_ETH_BASE_PORT, EL_ENGINE_BASE_PORT, + EL_ETH_BASE_PORT, + EL_P2P_BASE_PORT, + KEY_MANAGER_BASE_PORT, } from "../constants.js"; export const getNodePorts = ( diff --git a/packages/cli/test/utils/crucible/utils/syncing.ts b/packages/cli/test/utils/crucible/utils/syncing.ts index b720c6bf6ccc..e0232ae7b5ba 100644 --- a/packages/cli/test/utils/crucible/utils/syncing.ts +++ b/packages/cli/test/utils/crucible/utils/syncing.ts @@ -1,9 +1,9 @@ import {routes} from "@lodestar/api"; +import {ForkBlobs} from "@lodestar/params"; import {SignedBeaconBlock, Slot} from "@lodestar/types"; import {sleep, toHex} from "@lodestar/utils"; -import {ForkBlobs} from "@lodestar/params"; -import type {Simulation} from "../simulation.js"; import {BeaconClient, ExecutionClient, NodePair} from "../interfaces.js"; +import type {Simulation} from "../simulation.js"; import {connectNewCLNode, connectNewELNode, connectNewNode, waitForHead, waitForSlot} from "./network.js"; export async function assertRangeSync(env: Simulation): Promise { diff --git a/packages/cli/test/utils/crucible/web3js/blobsEIP4844Transaction.ts b/packages/cli/test/utils/crucible/web3js/blobsEIP4844Transaction.ts index a5dbf9408b7d..b61814e6ae1e 100644 --- a/packages/cli/test/utils/crucible/web3js/blobsEIP4844Transaction.ts +++ b/packages/cli/test/utils/crucible/web3js/blobsEIP4844Transaction.ts @@ -1,4 +1,5 @@ import {RLP} from "@ethereumjs/rlp"; +import {fromHex} from "@lodestar/utils"; import {keccak256} from "ethereum-cryptography/keccak.js"; import { FeeMarketEIP1559Transaction, @@ -7,7 +8,6 @@ import { bigIntToUnpaddedUint8Array, uint8ArrayToBigInt, } from "web3-eth-accounts"; -import {fromHex} from "@lodestar/utils"; function uint8ArrayConcat(...arrays: Uint8Array[]): Uint8Array { const totalLength = arrays.reduce((acc, arr) => acc + arr.length, 0); diff --git a/packages/cli/test/utils/mockBeaconApiServer.ts b/packages/cli/test/utils/mockBeaconApiServer.ts index e7e80338686f..24b8b9c7473b 100644 --- a/packages/cli/test/utils/mockBeaconApiServer.ts +++ b/packages/cli/test/utils/mockBeaconApiServer.ts @@ -1,6 +1,6 @@ -import {RestApiServer, RestApiServerOpts, RestApiServerModules} from "@lodestar/beacon-node"; -import {BeaconApiMethods, registerRoutes} from "@lodestar/api/beacon/server"; import {allNamespaces} from "@lodestar/api"; +import {BeaconApiMethods, registerRoutes} from "@lodestar/api/beacon/server"; +import {RestApiServer, RestApiServerModules, RestApiServerOpts} from "@lodestar/beacon-node"; import {ChainForkConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; diff --git a/packages/cli/test/utils/validator.ts b/packages/cli/test/utils/validator.ts index 139683d5dd6b..fbecf6900d28 100644 --- a/packages/cli/test/utils/validator.ts +++ b/packages/cli/test/utils/validator.ts @@ -1,8 +1,8 @@ import childProcess from "node:child_process"; -import {retry} from "@lodestar/utils"; import {ApiClient, getClient} from "@lodestar/api/keymanager"; import {config} from "@lodestar/config/default"; -import {spawnCliCommand, gracefullyStopChildProcess} from "@lodestar/test-utils"; +import {gracefullyStopChildProcess, spawnCliCommand} from "@lodestar/test-utils"; +import {retry} from "@lodestar/utils"; import {getMockBeaconApiServer} from "./mockBeaconApiServer.js"; import {expectDeepEqualsUnordered, findApiToken} from "./runUtils.js"; diff --git a/packages/config/src/beaconConfig.ts b/packages/config/src/beaconConfig.ts index 634bdc8b5047..7c84dbaeeb8d 100644 --- a/packages/config/src/beaconConfig.ts +++ b/packages/config/src/beaconConfig.ts @@ -1,6 +1,6 @@ import {Root} from "@lodestar/types"; -import {createChainConfig, ChainConfig} from "./chainConfig/index.js"; -import {createForkConfig, ForkConfig} from "./forkConfig/index.js"; +import {ChainConfig, createChainConfig} from "./chainConfig/index.js"; +import {ForkConfig, createForkConfig} from "./forkConfig/index.js"; import {createCachedGenesis} from "./genesisConfig/index.js"; import {CachedGenesis} from "./genesisConfig/types.js"; diff --git a/packages/config/src/chainConfig/configs/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts index 5da5f8d2acb0..4a01d9d062b1 100644 --- a/packages/config/src/chainConfig/configs/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -1,5 +1,5 @@ -import {fromHex as b} from "@lodestar/utils"; import {PresetName} from "@lodestar/params"; +import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; // Mainnet config diff --git a/packages/config/src/chainConfig/configs/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts index f1a52e956f4d..f0e116a553ab 100644 --- a/packages/config/src/chainConfig/configs/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -1,5 +1,5 @@ -import {fromHex as b} from "@lodestar/utils"; import {PresetName} from "@lodestar/params"; +import {fromHex as b} from "@lodestar/utils"; import {ChainConfig} from "../types.js"; // Minimal config diff --git a/packages/config/src/chainConfig/default.ts b/packages/config/src/chainConfig/default.ts index ef2b9743a1d2..8f8acc37a9f3 100644 --- a/packages/config/src/chainConfig/default.ts +++ b/packages/config/src/chainConfig/default.ts @@ -1,7 +1,7 @@ import {ACTIVE_PRESET, PresetName} from "@lodestar/params"; -import {ChainConfig} from "./types.js"; import {chainConfig as mainnet} from "./configs/mainnet.js"; import {chainConfig as minimal} from "./configs/minimal.js"; +import {ChainConfig} from "./types.js"; let defaultChainConfig: ChainConfig; diff --git a/packages/config/src/chainConfig/index.ts b/packages/config/src/chainConfig/index.ts index b202021b0337..cd7d2d9c29f0 100644 --- a/packages/config/src/chainConfig/index.ts +++ b/packages/config/src/chainConfig/index.ts @@ -1,6 +1,6 @@ import {ACTIVE_PRESET} from "@lodestar/params"; -import {ChainConfig} from "./types.js"; import {defaultChainConfig} from "./default.js"; +import {ChainConfig} from "./types.js"; export {chainConfigToJson, chainConfigFromJson, specValuesToJson} from "./json.js"; export * from "./types.js"; diff --git a/packages/config/src/chainConfig/json.ts b/packages/config/src/chainConfig/json.ts index 78db9230c836..de5214d96416 100644 --- a/packages/config/src/chainConfig/json.ts +++ b/packages/config/src/chainConfig/json.ts @@ -1,5 +1,5 @@ import {fromHex, toHex} from "@lodestar/utils"; -import {ChainConfig, chainConfigTypes, SpecValue, SpecValueTypeName} from "./types.js"; +import {ChainConfig, SpecValue, SpecValueTypeName, chainConfigTypes} from "./types.js"; const MAX_UINT64_JSON = "18446744073709551615"; diff --git a/packages/config/src/chainConfig/networks/ephemery.ts b/packages/config/src/chainConfig/networks/ephemery.ts index d1c17c36f0ab..f6349afe1e9a 100644 --- a/packages/config/src/chainConfig/networks/ephemery.ts +++ b/packages/config/src/chainConfig/networks/ephemery.ts @@ -1,6 +1,6 @@ import {fromHex as b} from "@lodestar/utils"; -import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; +import {ChainConfig} from "../types.js"; // Ephemery dynamic beacon chain config: // https://github.com/ephemery-testnet/ephemery-genesis/blob/master/cl-config.yaml diff --git a/packages/config/src/chainConfig/networks/gnosis.ts b/packages/config/src/chainConfig/networks/gnosis.ts index a25162ae5028..a3b2679bd080 100644 --- a/packages/config/src/chainConfig/networks/gnosis.ts +++ b/packages/config/src/chainConfig/networks/gnosis.ts @@ -1,7 +1,7 @@ -import {fromHex as b} from "@lodestar/utils"; import {PresetName} from "@lodestar/params"; -import {ChainConfig} from "../types.js"; +import {fromHex as b} from "@lodestar/utils"; import {chainConfig as mainnet} from "../configs/mainnet.js"; +import {ChainConfig} from "../types.js"; // Gnosis beacon chain config: // https://github.com/gnosischain/configs/blob/main/mainnet/config.yaml diff --git a/packages/config/src/chainConfig/networks/holesky.ts b/packages/config/src/chainConfig/networks/holesky.ts index 46c32606931f..18f356d6bc03 100644 --- a/packages/config/src/chainConfig/networks/holesky.ts +++ b/packages/config/src/chainConfig/networks/holesky.ts @@ -1,6 +1,6 @@ import {fromHex as b} from "@lodestar/utils"; -import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; +import {ChainConfig} from "../types.js"; // Holesky beacon chain config: // https://github.com/eth-clients/holesky/blob/main/metadata/config.yaml diff --git a/packages/config/src/chainConfig/networks/mainnet.ts b/packages/config/src/chainConfig/networks/mainnet.ts index 13225b463da9..d10e3209243b 100644 --- a/packages/config/src/chainConfig/networks/mainnet.ts +++ b/packages/config/src/chainConfig/networks/mainnet.ts @@ -1,6 +1,6 @@ import {fromHex as b} from "@lodestar/utils"; -import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; +import {ChainConfig} from "../types.js"; export const mainnetChainConfig: ChainConfig = { ...mainnet, diff --git a/packages/config/src/chainConfig/networks/mekong.ts b/packages/config/src/chainConfig/networks/mekong.ts index d7f2d15cb525..191d801e22b2 100644 --- a/packages/config/src/chainConfig/networks/mekong.ts +++ b/packages/config/src/chainConfig/networks/mekong.ts @@ -1,6 +1,6 @@ import {fromHex as b} from "@lodestar/utils"; -import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; +import {ChainConfig} from "../types.js"; // Mekong beacon chain config: // https://github.com/ethpandaops/mekong-devnets/blob/master/network-configs/devnet-0/metadata/config.yaml diff --git a/packages/config/src/chainConfig/networks/sepolia.ts b/packages/config/src/chainConfig/networks/sepolia.ts index e7e5dc76f691..f47d73436702 100644 --- a/packages/config/src/chainConfig/networks/sepolia.ts +++ b/packages/config/src/chainConfig/networks/sepolia.ts @@ -1,6 +1,6 @@ import {fromHex as b} from "@lodestar/utils"; -import {ChainConfig} from "../types.js"; import {chainConfig as mainnet} from "../configs/mainnet.js"; +import {ChainConfig} from "../types.js"; // Sepolia beacon chain config: // https://github.com/eth-clients/sepolia/blob/main/metadata/config.yaml diff --git a/packages/config/src/forkConfig/index.ts b/packages/config/src/forkConfig/index.ts index 513cd7559ee3..725e0a3af572 100644 --- a/packages/config/src/forkConfig/index.ts +++ b/packages/config/src/forkConfig/index.ts @@ -1,17 +1,17 @@ import { - GENESIS_EPOCH, + ForkAll, + ForkBlobs, + ForkExecution, + ForkLightClient, ForkName, - SLOTS_PER_EPOCH, ForkSeq, - isForkLightClient, - isForkExecution, + GENESIS_EPOCH, + SLOTS_PER_EPOCH, isForkBlobs, - ForkExecution, - ForkAll, - ForkLightClient, - ForkBlobs, + isForkExecution, + isForkLightClient, } from "@lodestar/params"; -import {Slot, Version, SSZTypesFor, sszTypesFor, Epoch} from "@lodestar/types"; +import {Epoch, SSZTypesFor, Slot, Version, sszTypesFor} from "@lodestar/types"; import {ChainConfig} from "../chainConfig/index.js"; import {ForkConfig, ForkInfo} from "./types.js"; diff --git a/packages/config/src/genesisConfig/index.ts b/packages/config/src/genesisConfig/index.ts index d2dfae2a8e08..dad79df1a98d 100644 --- a/packages/config/src/genesisConfig/index.ts +++ b/packages/config/src/genesisConfig/index.ts @@ -1,8 +1,8 @@ -import {ForkName, SLOTS_PER_EPOCH, DOMAIN_VOLUNTARY_EXIT} from "@lodestar/params"; -import {DomainType, ForkDigest, phase0, Root, Slot, ssz, Version} from "@lodestar/types"; +import {DOMAIN_VOLUNTARY_EXIT, ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {DomainType, ForkDigest, Root, Slot, Version, phase0, ssz} from "@lodestar/types"; import {toHex} from "@lodestar/utils"; import {ChainForkConfig} from "../beaconConfig.js"; -import {ForkDigestHex, CachedGenesis} from "./types.js"; +import {CachedGenesis, ForkDigestHex} from "./types.js"; export type {ForkDigestContext} from "./types.js"; export function createCachedGenesis(chainForkConfig: ChainForkConfig, genesisValidatorsRoot: Root): CachedGenesis { diff --git a/packages/config/src/networks.ts b/packages/config/src/networks.ts index df39ae15d09e..5e377e86a974 100644 --- a/packages/config/src/networks.ts +++ b/packages/config/src/networks.ts @@ -1,11 +1,11 @@ import {ChainConfig} from "./chainConfig/index.js"; -import {mainnetChainConfig} from "./chainConfig/networks/mainnet.js"; -import {gnosisChainConfig} from "./chainConfig/networks/gnosis.js"; -import {sepoliaChainConfig} from "./chainConfig/networks/sepolia.js"; -import {holeskyChainConfig} from "./chainConfig/networks/holesky.js"; import {chiadoChainConfig} from "./chainConfig/networks/chiado.js"; import {ephemeryChainConfig} from "./chainConfig/networks/ephemery.js"; +import {gnosisChainConfig} from "./chainConfig/networks/gnosis.js"; +import {holeskyChainConfig} from "./chainConfig/networks/holesky.js"; +import {mainnetChainConfig} from "./chainConfig/networks/mainnet.js"; import {mekongChainConfig} from "./chainConfig/networks/mekong.js"; +import {sepoliaChainConfig} from "./chainConfig/networks/sepolia.js"; export { mainnetChainConfig, diff --git a/packages/config/test/unit/index.test.ts b/packages/config/test/unit/index.test.ts index bde31f6b1477..9c6e94978504 100644 --- a/packages/config/test/unit/index.test.ts +++ b/packages/config/test/unit/index.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; import {toHexString} from "@chainsafe/ssz"; import {ForkName} from "@lodestar/params"; -import {config, chainConfig} from "../../src/default.js"; +import {describe, expect, it} from "vitest"; +import {chainConfig, config} from "../../src/default.js"; import {createForkConfig} from "../../src/index.js"; describe("forks", () => { diff --git a/packages/config/test/unit/json.test.ts b/packages/config/test/unit/json.test.ts index 96ffd050a088..970a40048540 100644 --- a/packages/config/test/unit/json.test.ts +++ b/packages/config/test/unit/json.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {chainConfigFromJson, chainConfigToJson} from "../../src/index.js"; +import {describe, expect, it} from "vitest"; import {chainConfig} from "../../src/default.js"; +import {chainConfigFromJson, chainConfigToJson} from "../../src/index.js"; describe("chainConfig JSON", () => { it("Convert to and from JSON", () => { diff --git a/packages/db/src/controller/level.ts b/packages/db/src/controller/level.ts index 82fbf631f7ae..ac3688a161ab 100644 --- a/packages/db/src/controller/level.ts +++ b/packages/db/src/controller/level.ts @@ -1,6 +1,6 @@ -import {ClassicLevel} from "classic-level"; import {Logger} from "@lodestar/utils"; -import {DbReqOpts, DatabaseController, DatabaseOptions, FilterOptions, KeyValue} from "./interface.js"; +import {ClassicLevel} from "classic-level"; +import {DatabaseController, DatabaseOptions, DbReqOpts, FilterOptions, KeyValue} from "./interface.js"; import {LevelDbControllerMetrics} from "./metrics.js"; enum Status { diff --git a/packages/db/test/unit/controller/level.test.ts b/packages/db/test/unit/controller/level.test.ts index 16f20e770c93..af9de5a04e46 100644 --- a/packages/db/test/unit/controller/level.test.ts +++ b/packages/db/test/unit/controller/level.test.ts @@ -1,8 +1,8 @@ import {execSync} from "node:child_process"; import os from "node:os"; -import {describe, it, expect, beforeAll, afterAll} from "vitest"; -import all from "it-all"; import {getEnvLogger} from "@lodestar/logger/env"; +import all from "it-all"; +import {afterAll, beforeAll, describe, expect, it} from "vitest"; import {LevelDbController} from "../../../src/controller/index.js"; describe("LevelDB controller", () => { diff --git a/packages/db/test/unit/schema.test.ts b/packages/db/test/unit/schema.test.ts index c72611453e4f..7488e9f5aaef 100644 --- a/packages/db/test/unit/schema.test.ts +++ b/packages/db/test/unit/schema.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {intToBytes} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; import {BUCKET_LENGTH, encodeKey} from "../../src/index.js"; describe("encodeKey", () => { diff --git a/packages/flare/src/cli.ts b/packages/flare/src/cli.ts index 91c4ef83ca09..9b29d22629de 100644 --- a/packages/flare/src/cli.ts +++ b/packages/flare/src/cli.ts @@ -1,7 +1,7 @@ +import {registerCommandToYargs} from "@lodestar/utils"; // Must not use `* as yargs`, see https://github.com/yargs/yargs/issues/1131 import yargs from "yargs"; import {hideBin} from "yargs/helpers"; -import {registerCommandToYargs} from "@lodestar/utils"; import {cmds} from "./cmds/index.js"; const topBanner = `Beacon chain multi-purpose and debugging tool. diff --git a/packages/flare/src/cmds/index.ts b/packages/flare/src/cmds/index.ts index 63e1f316b3b6..58d882040e8a 100644 --- a/packages/flare/src/cmds/index.ts +++ b/packages/flare/src/cmds/index.ts @@ -1,6 +1,6 @@ import {CliCommand} from "@lodestar/utils"; -import {selfSlashProposer} from "./selfSlashProposer.js"; import {selfSlashAttester} from "./selfSlashAttester.js"; +import {selfSlashProposer} from "./selfSlashProposer.js"; export const cmds: Required, Record>>["subcommands"] = [ selfSlashProposer, diff --git a/packages/flare/src/cmds/selfSlashAttester.ts b/packages/flare/src/cmds/selfSlashAttester.ts index 174535ba2e7d..78c10b6451a3 100644 --- a/packages/flare/src/cmds/selfSlashAttester.ts +++ b/packages/flare/src/cmds/selfSlashAttester.ts @@ -1,12 +1,12 @@ import {SecretKey, aggregateSignatures} from "@chainsafe/blst"; import {getClient} from "@lodestar/api"; -import {AttesterSlashing, phase0, ssz} from "@lodestar/types"; +import {BeaconConfig, createBeaconConfig} from "@lodestar/config"; import {config as chainConfig} from "@lodestar/config/default"; -import {createBeaconConfig, BeaconConfig} from "@lodestar/config"; import {DOMAIN_BEACON_ATTESTER, MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; -import {CliCommand, toPubkeyHex} from "@lodestar/utils"; import {computeSigningRoot} from "@lodestar/state-transition"; -import {deriveSecretKeys, SecretKeysArgs, secretKeysOptions} from "../util/deriveSecretKeys.js"; +import {AttesterSlashing, phase0, ssz} from "@lodestar/types"; +import {CliCommand, toPubkeyHex} from "@lodestar/utils"; +import {SecretKeysArgs, deriveSecretKeys, secretKeysOptions} from "../util/deriveSecretKeys.js"; /* eslint-disable no-console */ diff --git a/packages/flare/src/cmds/selfSlashProposer.ts b/packages/flare/src/cmds/selfSlashProposer.ts index dd9580232e71..83992aae7d82 100644 --- a/packages/flare/src/cmds/selfSlashProposer.ts +++ b/packages/flare/src/cmds/selfSlashProposer.ts @@ -1,12 +1,12 @@ import {SecretKey} from "@chainsafe/blst"; import {getClient} from "@lodestar/api"; -import {phase0, ssz} from "@lodestar/types"; +import {BeaconConfig, createBeaconConfig} from "@lodestar/config"; import {config as chainConfig} from "@lodestar/config/default"; -import {createBeaconConfig, BeaconConfig} from "@lodestar/config"; import {DOMAIN_BEACON_PROPOSER} from "@lodestar/params"; -import {CliCommand, toPubkeyHex} from "@lodestar/utils"; import {computeSigningRoot} from "@lodestar/state-transition"; -import {deriveSecretKeys, SecretKeysArgs, secretKeysOptions} from "../util/deriveSecretKeys.js"; +import {phase0, ssz} from "@lodestar/types"; +import {CliCommand, toPubkeyHex} from "@lodestar/utils"; +import {SecretKeysArgs, deriveSecretKeys, secretKeysOptions} from "../util/deriveSecretKeys.js"; /* eslint-disable no-console */ diff --git a/packages/flare/src/index.ts b/packages/flare/src/index.ts index 5f3b85b459c1..b2ef85ce4c10 100644 --- a/packages/flare/src/index.ts +++ b/packages/flare/src/index.ts @@ -1,7 +1,7 @@ #!/usr/bin/env node -import {YargsError} from "./util/errors.js"; import {getCli, yarg} from "./cli.js"; +import {YargsError} from "./util/errors.js"; import "source-map-support/register.js"; const flare = getCli(); diff --git a/packages/flare/test/unit/utils/format.test.ts b/packages/flare/test/unit/utils/format.test.ts index c6ef8805fe7b..846793175d9d 100644 --- a/packages/flare/test/unit/utils/format.test.ts +++ b/packages/flare/test/unit/utils/format.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {parseRange} from "../../../src/util/format.js"; describe("utils / format", () => { diff --git a/packages/fork-choice/src/forkChoice/errors.ts b/packages/fork-choice/src/forkChoice/errors.ts index 43d209106eed..cd0e0cd25274 100644 --- a/packages/fork-choice/src/forkChoice/errors.ts +++ b/packages/fork-choice/src/forkChoice/errors.ts @@ -1,4 +1,4 @@ -import {Slot, Epoch, RootHex} from "@lodestar/types"; +import {Epoch, RootHex, Slot} from "@lodestar/types"; import {LodestarError} from "@lodestar/utils"; export enum InvalidBlockCode { diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index dcc76441865e..2b803c3553a4 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -1,47 +1,47 @@ -import {Logger, MapDef, fromHex, toRootHex} from "@lodestar/utils"; -import {SLOTS_PER_HISTORICAL_ROOT, SLOTS_PER_EPOCH, INTERVALS_PER_SLOT} from "@lodestar/params"; -import {bellatrix, Slot, ValidatorIndex, phase0, ssz, RootHex, Epoch, Root, BeaconBlock} from "@lodestar/types"; +import {ChainConfig, ChainForkConfig} from "@lodestar/config"; +import {INTERVALS_PER_SLOT, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; import { + CachedBeaconStateAllForks, + EffectiveBalanceIncrements, + ZERO_HASH, + computeEpochAtSlot, computeSlotsSinceEpochStart, computeStartSlotAtEpoch, - computeEpochAtSlot, - ZERO_HASH, - EffectiveBalanceIncrements, - CachedBeaconStateAllForks, + getAttesterSlashableIndices, isExecutionBlockBodyType, - isExecutionStateType, isExecutionEnabled, - getAttesterSlashableIndices, + isExecutionStateType, } from "@lodestar/state-transition"; import {computeUnrealizedCheckpoints} from "@lodestar/state-transition/epoch"; -import {ChainConfig, ChainForkConfig} from "@lodestar/config"; +import {BeaconBlock, Epoch, Root, RootHex, Slot, ValidatorIndex, bellatrix, phase0, ssz} from "@lodestar/types"; +import {Logger, MapDef, fromHex, toRootHex} from "@lodestar/utils"; import {computeDeltas} from "../protoArray/computeDeltas.js"; +import {ProtoArrayError, ProtoArrayErrorCode} from "../protoArray/errors.js"; import { - HEX_ZERO_HASH, - VoteTracker, - ProtoBlock, + DataAvailabilityStatus, ExecutionStatus, - MaybeValidExecutionStatus, + HEX_ZERO_HASH, LVHExecResponse, + MaybeValidExecutionStatus, + ProtoBlock, ProtoNode, - DataAvailabilityStatus, + VoteTracker, } from "../protoArray/interface.js"; import {ProtoArray} from "../protoArray/protoArray.js"; -import {ProtoArrayError, ProtoArrayErrorCode} from "../protoArray/errors.js"; -import {ForkChoiceError, ForkChoiceErrorCode, InvalidBlockCode, InvalidAttestationCode} from "./errors.js"; +import {ForkChoiceError, ForkChoiceErrorCode, InvalidAttestationCode, InvalidBlockCode} from "./errors.js"; import { - IForkChoice, - LatestMessage, - PowBlockHex, - EpochDifference, AncestorResult, AncestorStatus, + EpochDifference, ForkChoiceMetrics, + IForkChoice, + LatestMessage, NotReorgedReason, + PowBlockHex, } from "./interface.js"; -import {IForkChoiceStore, CheckpointWithHex, toCheckpointWithHex, JustifiedBalances} from "./store.js"; +import {CheckpointWithHex, IForkChoiceStore, JustifiedBalances, toCheckpointWithHex} from "./store.js"; export type ForkChoiceOpts = { proposerBoost?: boolean; diff --git a/packages/fork-choice/src/forkChoice/interface.ts b/packages/fork-choice/src/forkChoice/interface.ts index 9ac8cdfac81b..05c803b50dc8 100644 --- a/packages/fork-choice/src/forkChoice/interface.ts +++ b/packages/fork-choice/src/forkChoice/interface.ts @@ -1,15 +1,15 @@ import {EffectiveBalanceIncrements} from "@lodestar/state-transition"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; -import {Epoch, Slot, ValidatorIndex, phase0, Root, RootHex, BeaconBlock, IndexedAttestation} from "@lodestar/types"; +import {BeaconBlock, Epoch, IndexedAttestation, Root, RootHex, Slot, ValidatorIndex, phase0} from "@lodestar/types"; import { - ProtoBlock, - MaybeValidExecutionStatus, + DataAvailabilityStatus, LVHExecResponse, + MaybeValidExecutionStatus, + ProtoBlock, ProtoNode, - DataAvailabilityStatus, } from "../protoArray/interface.js"; -import {CheckpointWithHex} from "./store.js"; import {UpdateAndGetHeadOpt} from "./forkChoice.js"; +import {CheckpointWithHex} from "./store.js"; export type CheckpointHex = { epoch: Epoch; diff --git a/packages/fork-choice/src/forkChoice/store.ts b/packages/fork-choice/src/forkChoice/store.ts index 2cd4da512870..fda01689f96c 100644 --- a/packages/fork-choice/src/forkChoice/store.ts +++ b/packages/fork-choice/src/forkChoice/store.ts @@ -1,7 +1,7 @@ +import {CachedBeaconStateAllForks, EffectiveBalanceIncrements} from "@lodestar/state-transition"; +import {RootHex, Slot, ValidatorIndex, phase0} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; -import {EffectiveBalanceIncrements, CachedBeaconStateAllForks} from "@lodestar/state-transition"; -import {phase0, Slot, RootHex, ValidatorIndex} from "@lodestar/types"; -import {CheckpointHexWithTotalBalance, CheckpointHexWithBalance} from "./interface.js"; +import {CheckpointHexWithBalance, CheckpointHexWithTotalBalance} from "./interface.js"; /** * Stores checkpoints in a hybrid format: diff --git a/packages/fork-choice/src/protoArray/computeDeltas.ts b/packages/fork-choice/src/protoArray/computeDeltas.ts index c921e12f751e..928cef8487cb 100644 --- a/packages/fork-choice/src/protoArray/computeDeltas.ts +++ b/packages/fork-choice/src/protoArray/computeDeltas.ts @@ -1,7 +1,7 @@ -import {ValidatorIndex} from "@lodestar/types"; import {EffectiveBalanceIncrements} from "@lodestar/state-transition"; -import {VoteTracker} from "./interface.js"; +import {ValidatorIndex} from "@lodestar/types"; import {ProtoArrayError, ProtoArrayErrorCode} from "./errors.js"; +import {VoteTracker} from "./interface.js"; // reuse arrays to avoid memory reallocation and gc const deltas = new Array(); diff --git a/packages/fork-choice/src/protoArray/interface.ts b/packages/fork-choice/src/protoArray/interface.ts index d60305a6ff72..5e36593697f6 100644 --- a/packages/fork-choice/src/protoArray/interface.ts +++ b/packages/fork-choice/src/protoArray/interface.ts @@ -1,4 +1,4 @@ -import {Epoch, Slot, RootHex, UintNum64} from "@lodestar/types"; +import {Epoch, RootHex, Slot, UintNum64} from "@lodestar/types"; // RootHex is a root as a hex string // Used for lightweight and easy comparison diff --git a/packages/fork-choice/src/protoArray/protoArray.ts b/packages/fork-choice/src/protoArray/protoArray.ts index 82a8b2620880..e1cbf4970920 100644 --- a/packages/fork-choice/src/protoArray/protoArray.ts +++ b/packages/fork-choice/src/protoArray/protoArray.ts @@ -1,11 +1,11 @@ -import {Epoch, RootHex, Slot} from "@lodestar/types"; -import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {GENESIS_EPOCH} from "@lodestar/params"; +import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; +import {Epoch, RootHex, Slot} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {ForkChoiceError, ForkChoiceErrorCode} from "../forkChoice/errors.js"; -import {ProtoBlock, ProtoNode, HEX_ZERO_HASH, ExecutionStatus, LVHExecResponse} from "./interface.js"; -import {ProtoArrayError, ProtoArrayErrorCode, LVHExecError, LVHExecErrorCode} from "./errors.js"; +import {LVHExecError, LVHExecErrorCode, ProtoArrayError, ProtoArrayErrorCode} from "./errors.js"; +import {ExecutionStatus, HEX_ZERO_HASH, LVHExecResponse, ProtoBlock, ProtoNode} from "./interface.js"; export const DEFAULT_PRUNE_THRESHOLD = 0; type ProposerBoost = {root: RootHex; score: number}; diff --git a/packages/fork-choice/test/perf/forkChoice/onAttestation.test.ts b/packages/fork-choice/test/perf/forkChoice/onAttestation.test.ts index ae3b10b45d63..db344de96c57 100644 --- a/packages/fork-choice/test/perf/forkChoice/onAttestation.test.ts +++ b/packages/fork-choice/test/perf/forkChoice/onAttestation.test.ts @@ -1,9 +1,9 @@ -import {itBench} from "@dapplion/benchmark"; import {fromHexString, toHexString} from "@chainsafe/ssz"; -import {AttestationData, IndexedAttestation} from "@lodestar/types/phase0"; +import {itBench} from "@dapplion/benchmark"; import {ATTESTATION_SUBNET_COUNT} from "@lodestar/params"; -import {ssz} from "@lodestar/types"; import {computeEpochAtSlot} from "@lodestar/state-transition"; +import {ssz} from "@lodestar/types"; +import {AttestationData, IndexedAttestation} from "@lodestar/types/phase0"; import {initializeForkChoice} from "./util.js"; describe("ForkChoice onAttestation", () => { diff --git a/packages/fork-choice/test/perf/forkChoice/updateHead.test.ts b/packages/fork-choice/test/perf/forkChoice/updateHead.test.ts index 850215f5a844..892135b4eb34 100644 --- a/packages/fork-choice/test/perf/forkChoice/updateHead.test.ts +++ b/packages/fork-choice/test/perf/forkChoice/updateHead.test.ts @@ -1,7 +1,7 @@ import {itBench} from "@dapplion/benchmark"; import {computeEpochAtSlot} from "@lodestar/state-transition"; import {ForkChoice, ProtoBlock} from "../../../src/index.js"; -import {initializeForkChoice, Opts} from "./util.js"; +import {Opts, initializeForkChoice} from "./util.js"; describe("forkchoice updateHead", () => { for (const initialValidatorCount of [100_000, 600_000, 1_000_000]) { diff --git a/packages/fork-choice/test/perf/forkChoice/util.ts b/packages/fork-choice/test/perf/forkChoice/util.ts index 6c04ac817fb2..4376ce047727 100644 --- a/packages/fork-choice/test/perf/forkChoice/util.ts +++ b/packages/fork-choice/test/perf/forkChoice/util.ts @@ -1,14 +1,14 @@ import {fromHexString} from "@chainsafe/ssz"; import {config} from "@lodestar/config/default"; +import {computeTotalBalance} from "../../../src/forkChoice/store.js"; import { + DataAvailabilityStatus, ExecutionStatus, ForkChoice, IForkChoiceStore, - ProtoBlock, ProtoArray, - DataAvailabilityStatus, + ProtoBlock, } from "../../../src/index.js"; -import {computeTotalBalance} from "../../../src/forkChoice/store.js"; const genesisSlot = 0; const genesisEpoch = 0; diff --git a/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts b/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts index 9b51f640d949..cb99d8b566d4 100644 --- a/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts +++ b/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts @@ -1,7 +1,7 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsZeroed} from "@lodestar/state-transition"; -import {VoteTracker} from "../../../src/protoArray/interface.js"; import {computeDeltas} from "../../../src/protoArray/computeDeltas.js"; +import {VoteTracker} from "../../../src/protoArray/interface.js"; describe("computeDeltas", () => { let oldBalances: EffectiveBalanceIncrements; diff --git a/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts b/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts index f47849136bff..db7482f30cde 100644 --- a/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts @@ -1,18 +1,18 @@ -import {describe, it, expect, beforeEach, beforeAll} from "vitest"; import {fromHexString} from "@chainsafe/ssz"; import {config} from "@lodestar/config/default"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {computeEpochAtSlot} from "@lodestar/state-transition"; import {RootHex, Slot} from "@lodestar/types"; import {toHex} from "@lodestar/utils"; -import {computeEpochAtSlot} from "@lodestar/state-transition"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {beforeAll, beforeEach, describe, expect, it} from "vitest"; import { + DataAvailabilityStatus, + EpochDifference, + ExecutionStatus, ForkChoice, IForkChoiceStore, - ProtoBlock, ProtoArray, - ExecutionStatus, - EpochDifference, - DataAvailabilityStatus, + ProtoBlock, } from "../../../src/index.js"; import {getBlockRoot, getStateRoot} from "../../utils/index.js"; diff --git a/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts b/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts index 187834e6d63a..ba225756733d 100644 --- a/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/getProposerHead.test.ts @@ -1,18 +1,18 @@ -import {describe, it, expect, beforeEach} from "vitest"; import {fromHexString} from "@chainsafe/ssz"; import {config} from "@lodestar/config/default"; +import {INTERVALS_PER_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; import {Slot} from "@lodestar/types"; import {toHex} from "@lodestar/utils"; -import {INTERVALS_PER_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {beforeEach, describe, expect, it} from "vitest"; +import {NotReorgedReason} from "../../../src/forkChoice/interface.js"; import { + DataAvailabilityStatus, + ExecutionStatus, ForkChoice, IForkChoiceStore, ProtoArray, - ExecutionStatus, ProtoBlock, - DataAvailabilityStatus, } from "../../../src/index.js"; -import {NotReorgedReason} from "../../../src/forkChoice/interface.js"; import {getBlockRoot, getStateRoot} from "../../utils/index.js"; type ProtoBlockWithWeight = ProtoBlock & {weight: number}; // weight of the block itself diff --git a/packages/fork-choice/test/unit/forkChoice/utils.test.ts b/packages/fork-choice/test/unit/forkChoice/utils.test.ts index 44b0eb8b719b..b3bea1020544 100644 --- a/packages/fork-choice/test/unit/forkChoice/utils.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/utils.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; import {createChainForkConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; -import {assertValidTerminalPowBlock, ExecutionStatus} from "../../../src/index.js"; +import {describe, expect, it} from "vitest"; +import {ExecutionStatus, assertValidTerminalPowBlock} from "../../../src/index.js"; describe("assertValidTerminalPowBlock", () => { const config = createChainForkConfig({TERMINAL_TOTAL_DIFFICULTY: BigInt(10)}); diff --git a/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts b/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts index 4428807bd13d..af5d42f834b9 100644 --- a/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts +++ b/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {getEffectiveBalanceIncrementsZeroed} from "@lodestar/state-transition"; +import {describe, expect, it} from "vitest"; import {computeDeltas} from "../../../src/protoArray/computeDeltas.js"; diff --git a/packages/fork-choice/test/unit/protoArray/executionStatusUpdates.test.ts b/packages/fork-choice/test/unit/protoArray/executionStatusUpdates.test.ts index cefb2b07df02..4fcc6c79d190 100644 --- a/packages/fork-choice/test/unit/protoArray/executionStatusUpdates.test.ts +++ b/packages/fork-choice/test/unit/protoArray/executionStatusUpdates.test.ts @@ -1,10 +1,10 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import { - ProtoBlock, - ProtoArray, + BlockExtraMeta, ExecutionStatus, MaybeValidExecutionStatus, - BlockExtraMeta, + ProtoArray, + ProtoBlock, } from "../../../src/index.js"; import {LVHExecErrorCode} from "../../../src/protoArray/errors.js"; import {DataAvailabilityStatus} from "../../../src/protoArray/interface.js"; diff --git a/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts b/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts index b9b7f9c37b43..3bc322112332 100644 --- a/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts +++ b/packages/fork-choice/test/unit/protoArray/getCommonAncestor.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; -import {ProtoArray, ExecutionStatus, DataAvailabilityStatus} from "../../../src/index.js"; +import {describe, expect, it} from "vitest"; +import {DataAvailabilityStatus, ExecutionStatus, ProtoArray} from "../../../src/index.js"; describe("getCommonAncestor", () => { const blocks: {slot: number; root: string; parent: string}[] = [ diff --git a/packages/fork-choice/test/unit/protoArray/protoArray.test.ts b/packages/fork-choice/test/unit/protoArray/protoArray.test.ts index 92dfc61d61b2..5e87504dc455 100644 --- a/packages/fork-choice/test/unit/protoArray/protoArray.test.ts +++ b/packages/fork-choice/test/unit/protoArray/protoArray.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; import {RootHex} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; -import {ProtoArray, ExecutionStatus, DataAvailabilityStatus} from "../../../src/index.js"; +import {DataAvailabilityStatus, ExecutionStatus, ProtoArray} from "../../../src/index.js"; describe("ProtoArray", () => { it("finalized descendant", () => { diff --git a/packages/light-client/src/index.ts b/packages/light-client/src/index.ts index 098ea18adc31..7dd4601ab837 100644 --- a/packages/light-client/src/index.ts +++ b/packages/light-client/src/index.ts @@ -1,4 +1,4 @@ -import mitt from "mitt"; +import {BeaconConfig, ChainForkConfig, createBeaconConfig} from "@lodestar/config"; import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD} from "@lodestar/params"; import { LightClientBootstrap, @@ -6,22 +6,22 @@ import { LightClientHeader, LightClientOptimisticUpdate, LightClientUpdate, - phase0, RootHex, Slot, SyncPeriod, + phase0, } from "@lodestar/types"; -import {createBeaconConfig, BeaconConfig, ChainForkConfig} from "@lodestar/config"; import {fromHex, isErrorAborted, sleep, toRootHex} from "@lodestar/utils"; -import {getCurrentSlot, slotWithFutureTolerance, timeUntilNextEpoch} from "./utils/clock.js"; -import {chunkifyInclusiveRange} from "./utils/chunkify.js"; +import mitt from "mitt"; import {LightclientEmitter, LightclientEvent} from "./events.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"; import {ProcessUpdateOpts} from "./spec/processLightClientUpdate.js"; +import {validateLightClientBootstrap} from "./spec/validateLightClientBootstrap.js"; import {LightClientTransport} from "./transport/interface.js"; +import {chunkifyInclusiveRange} from "./utils/chunkify.js"; +import {getCurrentSlot, slotWithFutureTolerance, timeUntilNextEpoch} from "./utils/clock.js"; +import {computeEpochAtSlot, computeSyncPeriodAtEpoch, computeSyncPeriodAtSlot} from "./utils/clock.js"; +import {ILcLogger, getConsoleLogger} from "./utils/logger.js"; // Re-export types export {LightclientEvent} from "./events.js"; @@ -327,8 +327,8 @@ export class Lightclient { } } +import * as transport from "./transport.js"; // 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/spec/index.ts b/packages/light-client/src/spec/index.ts index 0934e15b1c17..ff4fe22b28b0 100644 --- a/packages/light-client/src/spec/index.ts +++ b/packages/light-client/src/spec/index.ts @@ -8,7 +8,7 @@ import { Slot, } from "@lodestar/types"; import {computeSyncPeriodAtSlot} from "../utils/index.js"; -import {getSyncCommitteeAtPeriod, processLightClientUpdate, ProcessUpdateOpts} from "./processLightClientUpdate.js"; +import {ProcessUpdateOpts, getSyncCommitteeAtPeriod, processLightClientUpdate} from "./processLightClientUpdate.js"; import {ILightClientStore, LightClientStore, LightClientStoreEvents} from "./store.js"; import {ZERO_FINALITY_BRANCH, ZERO_HEADER, ZERO_SYNC_COMMITTEE, getZeroSyncCommitteeBranch} from "./utils.js"; diff --git a/packages/light-client/src/spec/processLightClientUpdate.ts b/packages/light-client/src/spec/processLightClientUpdate.ts index 644a956ab4b0..1c5483b499ab 100644 --- a/packages/light-client/src/spec/processLightClientUpdate.ts +++ b/packages/light-client/src/spec/processLightClientUpdate.ts @@ -1,9 +1,9 @@ +import {ChainForkConfig} from "@lodestar/config"; import {SYNC_COMMITTEE_SIZE} from "@lodestar/params"; import {LightClientUpdate, Slot, SyncPeriod} from "@lodestar/types"; -import {ChainForkConfig} from "@lodestar/config"; import {pruneSetToMax} from "@lodestar/utils"; import {computeSyncPeriodAtSlot, deserializeSyncCommittee, sumBits} from "../utils/index.js"; -import {isBetterUpdate, LightClientUpdateSummary, toLightClientUpdateSummary} from "./isBetterUpdate.js"; +import {LightClientUpdateSummary, isBetterUpdate, toLightClientUpdateSummary} from "./isBetterUpdate.js"; import {ILightClientStore, MAX_SYNC_PERIODS_CACHE, SyncCommitteeFast} from "./store.js"; import {getSafetyThreshold, isSyncCommitteeUpdate} from "./utils.js"; import {validateLightClientUpdate} from "./validateLightClientUpdate.js"; diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 36bc7098fcc5..cd0c03fd5b0d 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -1,30 +1,30 @@ import {BitArray, byteArrayEquals} from "@chainsafe/ssz"; +import {ChainForkConfig} from "@lodestar/config"; import { - FINALIZED_ROOT_DEPTH, - NEXT_SYNC_COMMITTEE_DEPTH, - ForkSeq, - ForkName, BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, BLOCK_BODY_EXECUTION_PAYLOAD_INDEX as EXECUTION_PAYLOAD_INDEX, + FINALIZED_ROOT_DEPTH, + FINALIZED_ROOT_DEPTH_ELECTRA, + ForkName, + ForkSeq, + NEXT_SYNC_COMMITTEE_DEPTH, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, isForkPostElectra, - FINALIZED_ROOT_DEPTH_ELECTRA, } from "@lodestar/params"; import { - ssz, - Slot, + BeaconBlockHeader, LightClientFinalityUpdate, LightClientHeader, LightClientOptimisticUpdate, LightClientUpdate, - BeaconBlockHeader, + Slot, SyncCommittee, isElectraLightClientUpdate, + ssz, } from "@lodestar/types"; -import {ChainForkConfig} from "@lodestar/config"; -import {isValidMerkleBranch, computeEpochAtSlot, computeSyncPeriodAtSlot} from "../utils/index.js"; +import {computeEpochAtSlot, computeSyncPeriodAtSlot, isValidMerkleBranch} from "../utils/index.js"; import {normalizeMerkleBranch} from "../utils/normalizeMerkleBranch.js"; import {LightClientStore} from "./store.js"; diff --git a/packages/light-client/src/spec/validateLightClientBootstrap.ts b/packages/light-client/src/spec/validateLightClientBootstrap.ts index 2eafea0791f0..79c1f7a68fff 100644 --- a/packages/light-client/src/spec/validateLightClientBootstrap.ts +++ b/packages/light-client/src/spec/validateLightClientBootstrap.ts @@ -1,8 +1,8 @@ import {byteArrayEquals} from "@chainsafe/ssz"; -import {LightClientBootstrap, Root, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; -import {toHex} from "@lodestar/utils"; import {isForkPostElectra} from "@lodestar/params"; +import {LightClientBootstrap, Root, ssz} from "@lodestar/types"; +import {toHex} from "@lodestar/utils"; import {isValidMerkleBranch} from "../utils/verifyMerkleBranch.js"; import {isValidLightClientHeader} from "./utils.js"; diff --git a/packages/light-client/src/spec/validateLightClientUpdate.ts b/packages/light-client/src/spec/validateLightClientUpdate.ts index 9a5ea1985f16..ce2791f1a9da 100644 --- a/packages/light-client/src/spec/validateLightClientUpdate.ts +++ b/packages/light-client/src/spec/validateLightClientUpdate.ts @@ -1,32 +1,32 @@ import bls from "@chainsafe/bls"; import type {PublicKey, Signature} from "@chainsafe/bls/types"; -import {LightClientUpdate, Root, isElectraLightClientUpdate, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import { - FINALIZED_ROOT_INDEX, - FINALIZED_ROOT_DEPTH, - NEXT_SYNC_COMMITTEE_DEPTH, - MIN_SYNC_COMMITTEE_PARTICIPANTS, DOMAIN_SYNC_COMMITTEE, + FINALIZED_ROOT_DEPTH, + FINALIZED_ROOT_DEPTH_ELECTRA, + FINALIZED_ROOT_INDEX, + FINALIZED_ROOT_INDEX_ELECTRA, GENESIS_SLOT, + MIN_SYNC_COMMITTEE_PARTICIPANTS, + NEXT_SYNC_COMMITTEE_DEPTH, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, - NEXT_SYNC_COMMITTEE_INDEX_ELECTRA, NEXT_SYNC_COMMITTEE_INDEX, - FINALIZED_ROOT_DEPTH_ELECTRA, - FINALIZED_ROOT_INDEX_ELECTRA, + NEXT_SYNC_COMMITTEE_INDEX_ELECTRA, } from "@lodestar/params"; -import {getParticipantPubkeys, sumBits} from "../utils/utils.js"; -import {isValidMerkleBranch} from "../utils/index.js"; +import {LightClientUpdate, Root, isElectraLightClientUpdate, ssz} from "@lodestar/types"; import {SyncCommitteeFast} from "../types.js"; +import {isValidMerkleBranch} from "../utils/index.js"; +import {getParticipantPubkeys, sumBits} from "../utils/utils.js"; +import {ILightClientStore} from "./store.js"; import { + ZERO_HASH, isFinalityUpdate, isSyncCommitteeUpdate, + isValidLightClientHeader, isZeroedHeader, isZeroedSyncCommittee, - ZERO_HASH, - isValidLightClientHeader, } from "./utils.js"; -import {ILightClientStore} from "./store.js"; export function validateLightClientUpdate( config: ChainForkConfig, diff --git a/packages/light-client/src/transport/interface.ts b/packages/light-client/src/transport/interface.ts index dc9c697c00be..816336a6fa04 100644 --- a/packages/light-client/src/transport/interface.ts +++ b/packages/light-client/src/transport/interface.ts @@ -1,3 +1,4 @@ +import {ForkName} from "@lodestar/params"; import { LightClientBootstrap, LightClientFinalityUpdate, @@ -5,7 +6,6 @@ import { LightClientUpdate, SyncPeriod, } from "@lodestar/types"; -import {ForkName} from "@lodestar/params"; export interface LightClientTransport { getUpdates( diff --git a/packages/light-client/src/transport/rest.ts b/packages/light-client/src/transport/rest.ts index c260e1aaeee3..aaffa090ade0 100644 --- a/packages/light-client/src/transport/rest.ts +++ b/packages/light-client/src/transport/rest.ts @@ -1,4 +1,5 @@ -import mitt from "mitt"; +import {type ApiClient, routes} from "@lodestar/api"; +import {type ForkName} from "@lodestar/params"; import { LightClientBootstrap, LightClientFinalityUpdate, @@ -6,8 +7,7 @@ import { LightClientUpdate, type SyncPeriod, } from "@lodestar/types"; -import {type ApiClient, routes} from "@lodestar/api"; -import {type ForkName} from "@lodestar/params"; +import mitt from "mitt"; import {MittEmitter} from "../events.js"; import {type LightClientTransport} from "./interface.js"; diff --git a/packages/light-client/src/utils/api.ts b/packages/light-client/src/utils/api.ts index 6ccb187052e1..31846270ca40 100644 --- a/packages/light-client/src/utils/api.ts +++ b/packages/light-client/src/utils/api.ts @@ -1,4 +1,4 @@ -import {getClient, ApiClient, ApiRequestInit} from "@lodestar/api"; +import {ApiClient, ApiRequestInit, getClient} from "@lodestar/api"; import {ChainForkConfig, createChainForkConfig} from "@lodestar/config"; import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; diff --git a/packages/light-client/src/utils/domain.ts b/packages/light-client/src/utils/domain.ts index 90923ed8c9fc..d9bef6bb511c 100644 --- a/packages/light-client/src/utils/domain.ts +++ b/packages/light-client/src/utils/domain.ts @@ -1,7 +1,7 @@ // Only used by processDeposit + lightclient import {Type} from "@chainsafe/ssz"; -import {Epoch, Version, Root, DomainType, phase0, ssz, Domain} from "@lodestar/types"; +import {Domain, DomainType, Epoch, Root, Version, phase0, ssz} from "@lodestar/types"; /** * Return the domain for the [[domainType]] and [[forkVersion]]. diff --git a/packages/light-client/src/utils/utils.ts b/packages/light-client/src/utils/utils.ts index 5a298d81d37b..a4a697f0420d 100644 --- a/packages/light-client/src/utils/utils.ts +++ b/packages/light-client/src/utils/utils.ts @@ -2,7 +2,7 @@ import bls from "@chainsafe/bls"; import type {PublicKey} from "@chainsafe/bls/types"; import {BitArray} from "@chainsafe/ssz"; import {ApiClient} from "@lodestar/api"; -import {altair, Bytes32, Root, ssz} from "@lodestar/types"; +import {Bytes32, Root, altair, ssz} from "@lodestar/types"; import {BeaconBlockHeader} from "@lodestar/types/phase0"; import {GenesisData} from "../index.js"; import {SyncCommitteeFast} from "../types.js"; diff --git a/packages/light-client/src/utils/verifyMerkleBranch.ts b/packages/light-client/src/utils/verifyMerkleBranch.ts index 87b1d660eb32..a9a5b8643783 100644 --- a/packages/light-client/src/utils/verifyMerkleBranch.ts +++ b/packages/light-client/src/utils/verifyMerkleBranch.ts @@ -1,5 +1,5 @@ -import {byteArrayEquals} from "@chainsafe/ssz"; import {hasher} from "@chainsafe/persistent-merkle-tree"; +import {byteArrayEquals} from "@chainsafe/ssz"; export const SYNC_COMMITTEES_DEPTH = 4; export const SYNC_COMMITTEES_INDEX = 11; diff --git a/packages/light-client/src/validation.ts b/packages/light-client/src/validation.ts index c756d612f3e7..22cbf700ed16 100644 --- a/packages/light-client/src/validation.ts +++ b/packages/light-client/src/validation.ts @@ -1,30 +1,30 @@ import bls from "@chainsafe/bls"; import type {PublicKey, Signature} from "@chainsafe/bls/types"; +import {BeaconConfig} from "@lodestar/config"; +import { + DOMAIN_SYNC_COMMITTEE, + FINALIZED_ROOT_DEPTH, + FINALIZED_ROOT_DEPTH_ELECTRA, + FINALIZED_ROOT_INDEX, + MIN_SYNC_COMMITTEE_PARTICIPANTS, + NEXT_SYNC_COMMITTEE_DEPTH, + NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, + NEXT_SYNC_COMMITTEE_INDEX, + NEXT_SYNC_COMMITTEE_INDEX_ELECTRA, +} from "@lodestar/params"; import { - altair, - isElectraLightClientUpdate, LightClientFinalityUpdate, LightClientUpdate, Root, Slot, + altair, + isElectraLightClientUpdate, ssz, } from "@lodestar/types"; -import { - FINALIZED_ROOT_INDEX, - FINALIZED_ROOT_DEPTH, - NEXT_SYNC_COMMITTEE_INDEX, - NEXT_SYNC_COMMITTEE_DEPTH, - MIN_SYNC_COMMITTEE_PARTICIPANTS, - DOMAIN_SYNC_COMMITTEE, - NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, - FINALIZED_ROOT_DEPTH_ELECTRA, - NEXT_SYNC_COMMITTEE_INDEX_ELECTRA, -} from "@lodestar/params"; -import {BeaconConfig} from "@lodestar/config"; -import {isValidMerkleBranch} from "./utils/verifyMerkleBranch.js"; -import {assertZeroHashes, getParticipantPubkeys, isEmptyHeader} from "./utils/utils.js"; import {SyncCommitteeFast} from "./types.js"; import {computeSyncPeriodAtSlot} from "./utils/clock.js"; +import {assertZeroHashes, getParticipantPubkeys, isEmptyHeader} from "./utils/utils.js"; +import {isValidMerkleBranch} from "./utils/verifyMerkleBranch.js"; /** * diff --git a/packages/light-client/test/mocks/BeaconChainLcMock.ts b/packages/light-client/test/mocks/BeaconChainLcMock.ts index b6813662649e..f08cb55e808c 100644 --- a/packages/light-client/test/mocks/BeaconChainLcMock.ts +++ b/packages/light-client/test/mocks/BeaconChainLcMock.ts @@ -1,6 +1,6 @@ import {toHexString} from "@chainsafe/ssz"; import {BeaconStateAltair} from "@lodestar/state-transition"; -import {altair, Root, ssz} from "@lodestar/types"; +import {Root, altair, ssz} from "@lodestar/types"; import {IBeaconChainLc} from "../utils/prepareUpdateNaive.js"; /** diff --git a/packages/light-client/test/mocks/LightclientServerApiMock.ts b/packages/light-client/test/mocks/LightclientServerApiMock.ts index faf33ad260c8..ce23d785183a 100644 --- a/packages/light-client/test/mocks/LightclientServerApiMock.ts +++ b/packages/light-client/test/mocks/LightclientServerApiMock.ts @@ -1,11 +1,11 @@ -import {concat} from "uint8arrays/concat"; import {digest} from "@chainsafe/as-sha256"; -import {CompactMultiProof, createProof, ProofType} from "@chainsafe/persistent-merkle-tree"; +import {CompactMultiProof, ProofType, createProof} from "@chainsafe/persistent-merkle-tree"; import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; -import {altair, RootHex, SyncPeriod} from "@lodestar/types"; -import {notNullish} from "@lodestar/utils"; import {ForkName} from "@lodestar/params"; +import {RootHex, SyncPeriod, altair} from "@lodestar/types"; +import {notNullish} from "@lodestar/utils"; +import {concat} from "uint8arrays/concat"; import {BeaconStateAltair} from "../utils/types.js"; type ProofApi = ApplicationMethods; diff --git a/packages/light-client/test/unit/isValidLightClientHeader.test.ts b/packages/light-client/test/unit/isValidLightClientHeader.test.ts index 2bbbd1250961..1782f1853296 100644 --- a/packages/light-client/test/unit/isValidLightClientHeader.test.ts +++ b/packages/light-client/test/unit/isValidLightClientHeader.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; import {fromHexString} from "@chainsafe/ssz"; -import {LightClientHeader, ssz} from "@lodestar/types"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; +import {LightClientHeader, ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import {isValidLightClientHeader} from "../../src/spec/utils.js"; describe("isValidLightClientHeader", () => { diff --git a/packages/light-client/test/unit/sync.node.test.ts b/packages/light-client/test/unit/sync.node.test.ts index 52afd05760d7..f373b006584f 100644 --- a/packages/light-client/test/unit/sync.node.test.ts +++ b/packages/light-client/test/unit/sync.node.test.ts @@ -1,27 +1,27 @@ -import {describe, it, expect, afterEach, vi} from "vitest"; -import {JsonPath, toHexString} from "@chainsafe/ssz"; import {CompactMultiProof, computeDescriptor} from "@chainsafe/persistent-merkle-tree"; +import {JsonPath, toHexString} from "@chainsafe/ssz"; +import {ApiClient, getClient, routes} from "@lodestar/api"; +import {ChainConfig, createBeaconConfig} from "@lodestar/config"; +import {chainConfig as chainConfigDef} from "@lodestar/config/default"; import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params"; import {BeaconStateAllForks, BeaconStateAltair} from "@lodestar/state-transition"; import {altair, ssz} from "@lodestar/types"; -import {routes, getClient, ApiClient} from "@lodestar/api"; -import {chainConfig as chainConfigDef} from "@lodestar/config/default"; -import {createBeaconConfig, ChainConfig} from "@lodestar/config"; +import {afterEach, describe, expect, it, vi} from "vitest"; import {Lightclient, LightclientEvent} from "../../src/index.js"; -import {LightclientServerApiMock, ProofServerApiMock} from "../mocks/LightclientServerApiMock.js"; +import {LightClientRestTransport} from "../../src/transport/rest.js"; +import {computeSyncPeriodAtSlot} from "../../src/utils/clock.js"; import {EventsServerApiMock} from "../mocks/EventsServerApiMock.js"; +import {LightclientServerApiMock, ProofServerApiMock} from "../mocks/LightclientServerApiMock.js"; +import {ServerOpts, startServer} from "../utils/server.js"; import { - computeLightclientUpdate, + committeeUpdateToLatestFinalizedHeadUpdate, + committeeUpdateToLatestHeadUpdate, computeLightClientSnapshot, + computeLightclientUpdate, getInteropSyncCommittee, - testLogger, - committeeUpdateToLatestHeadUpdate, - committeeUpdateToLatestFinalizedHeadUpdate, lastInMap, + testLogger, } from "../utils/utils.js"; -import {startServer, ServerOpts} from "../utils/server.js"; -import {computeSyncPeriodAtSlot} from "../../src/utils/clock.js"; -import {LightClientRestTransport} from "../../src/transport/rest.js"; const SOME_HASH = Buffer.alloc(32, 0xff); diff --git a/packages/light-client/test/unit/syncInMemory.test.ts b/packages/light-client/test/unit/syncInMemory.test.ts index 6118a1b4e61a..3f3b04cc7baf 100644 --- a/packages/light-client/test/unit/syncInMemory.test.ts +++ b/packages/light-client/test/unit/syncInMemory.test.ts @@ -1,14 +1,14 @@ -import {describe, it, expect, beforeAll, vi} from "vitest"; import bls from "@chainsafe/bls"; import {createBeaconConfig} from "@lodestar/config"; import {chainConfig} from "@lodestar/config/default"; import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {altair, ssz, SyncPeriod} from "@lodestar/types"; +import {SyncPeriod, altair, ssz} from "@lodestar/types"; +import {beforeAll, describe, expect, it, vi} from "vitest"; import {LightClientStoreFast} from "../../src/types.js"; import {BeaconChainLcMock} from "../mocks/BeaconChainLcMock.js"; import {processLightClientUpdate} from "../utils/naive/update.js"; import {IBeaconChainLc, prepareUpdateNaive} from "../utils/prepareUpdateNaive.js"; -import {getInteropSyncCommittee, getSyncAggregateSigningRoot, SyncCommitteeKeys} from "../utils/utils.js"; +import {SyncCommitteeKeys, getInteropSyncCommittee, getSyncAggregateSigningRoot} from "../utils/utils.js"; function getSyncCommittee( syncCommitteesKeys: Map, diff --git a/packages/light-client/test/unit/utils.test.ts b/packages/light-client/test/unit/utils.test.ts index 9913c6c462a4..18df5aee076a 100644 --- a/packages/light-client/test/unit/utils.test.ts +++ b/packages/light-client/test/unit/utils.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; +import {ZERO_HASH} from "../../src/spec/utils.js"; +import {normalizeMerkleBranch} from "../../src/utils/normalizeMerkleBranch.js"; import {isValidMerkleBranch} from "../../src/utils/verifyMerkleBranch.js"; import {computeMerkleBranch} from "../utils/utils.js"; -import {normalizeMerkleBranch} from "../../src/utils/normalizeMerkleBranch.js"; -import {ZERO_HASH} from "../../src/spec/utils.js"; describe("utils", () => { it("constructMerkleBranch", () => { diff --git a/packages/light-client/test/unit/utils/chunkify.test.ts b/packages/light-client/test/unit/utils/chunkify.test.ts index 297637fd70b0..585dce5c670e 100644 --- a/packages/light-client/test/unit/utils/chunkify.test.ts +++ b/packages/light-client/test/unit/utils/chunkify.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {chunkifyInclusiveRange} from "../../../src/utils/chunkify.js"; describe("utils / chunkifyInclusiveRange", () => { diff --git a/packages/light-client/test/unit/validation.test.ts b/packages/light-client/test/unit/validation.test.ts index 6ed3b714a690..222277993216 100644 --- a/packages/light-client/test/unit/validation.test.ts +++ b/packages/light-client/test/unit/validation.test.ts @@ -1,9 +1,7 @@ -import {describe, it, expect, beforeAll, vi} from "vitest"; import bls from "@chainsafe/bls"; import {Tree} from "@chainsafe/persistent-merkle-tree"; -import {altair, ssz} from "@lodestar/types"; -import {chainConfig} from "@lodestar/config/default"; import {createBeaconConfig} from "@lodestar/config"; +import {chainConfig} from "@lodestar/config/default"; import { EPOCHS_PER_SYNC_COMMITTEE_PERIOD, FINALIZED_ROOT_GINDEX, @@ -11,8 +9,10 @@ import { SLOTS_PER_EPOCH, SYNC_COMMITTEE_SIZE, } from "@lodestar/params"; -import {assertValidLightClientUpdate} from "../../src/validation.js"; +import {altair, ssz} from "@lodestar/types"; +import {beforeAll, describe, expect, it, vi} from "vitest"; import {LightClientSnapshotFast, SyncCommitteeFast} from "../../src/types.js"; +import {assertValidLightClientUpdate} from "../../src/validation.js"; import {defaultBeaconBlockHeader, getSyncAggregateSigningRoot, signAndAggregate} from "../utils/utils.js"; describe("validation", () => { diff --git a/packages/light-client/test/unit/webEsmBundle.browser.test.ts b/packages/light-client/test/unit/webEsmBundle.browser.test.ts index defc421d7071..9940342e28b2 100644 --- a/packages/light-client/test/unit/webEsmBundle.browser.test.ts +++ b/packages/light-client/test/unit/webEsmBundle.browser.test.ts @@ -1,7 +1,7 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call */ -import {expect, describe, it, vi, beforeAll} from "vitest"; import {sleep} from "@lodestar/utils"; -import {Lightclient, LightclientEvent, utils, transport} from "../../dist/lightclient.min.mjs"; +/* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call */ +import {beforeAll, describe, expect, it, vi} from "vitest"; +import {Lightclient, LightclientEvent, transport, utils} from "../../dist/lightclient.min.mjs"; describe("web bundle for lightclient", () => { vi.setConfig({testTimeout: 20_000}); diff --git a/packages/light-client/test/utils/naive/update.ts b/packages/light-client/test/utils/naive/update.ts index b2e0ecf47a8a..01eaf35e1ad8 100644 --- a/packages/light-client/test/utils/naive/update.ts +++ b/packages/light-client/test/utils/naive/update.ts @@ -1,10 +1,10 @@ -import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {altair, Slot} from "@lodestar/types"; import {BeaconConfig} from "@lodestar/config"; +import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {Slot, altair} from "@lodestar/types"; import {LightClientSnapshotFast, LightClientStoreFast} from "../../../src/types.js"; -import {assertValidLightClientUpdate} from "../../../src/validation.js"; -import {deserializeSyncCommittee, isEmptyHeader, sumBits} from "../../../src/utils/utils.js"; import {computeSyncPeriodAtSlot} from "../../../src/utils/clock.js"; +import {deserializeSyncCommittee, isEmptyHeader, sumBits} from "../../../src/utils/utils.js"; +import {assertValidLightClientUpdate} from "../../../src/validation.js"; // // A lightclient has two types of syncing: diff --git a/packages/light-client/test/utils/prepareUpdateNaive.ts b/packages/light-client/test/utils/prepareUpdateNaive.ts index 3d0653c97263..17900ef7df56 100644 --- a/packages/light-client/test/utils/prepareUpdateNaive.ts +++ b/packages/light-client/test/utils/prepareUpdateNaive.ts @@ -1,7 +1,7 @@ -import {CompositeViewDU} from "@chainsafe/ssz"; import {Tree} from "@chainsafe/persistent-merkle-tree"; -import {altair, Root, ssz} from "@lodestar/types"; +import {CompositeViewDU} from "@chainsafe/ssz"; import {FINALIZED_ROOT_GINDEX, NEXT_SYNC_COMMITTEE_GINDEX, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; +import {Root, altair, ssz} from "@lodestar/types"; export interface IBeaconChainLc { getBlockHeaderByRoot(blockRoot: Root): Promise; diff --git a/packages/light-client/test/utils/server.ts b/packages/light-client/test/utils/server.ts index 6cc55e03cee4..4c6f22e06a31 100644 --- a/packages/light-client/test/utils/server.ts +++ b/packages/light-client/test/utils/server.ts @@ -1,10 +1,10 @@ -import {parse as parseQueryString} from "qs"; -import {FastifyInstance, fastify} from "fastify"; import {fastifyCors} from "@fastify/cors"; import {Endpoints} from "@lodestar/api"; -import {ApplicationMethods, addSszContentTypeParser} from "@lodestar/api/server"; import {BeaconApiMethods, registerRoutes} from "@lodestar/api/beacon/server"; +import {ApplicationMethods, addSszContentTypeParser} from "@lodestar/api/server"; import {ChainForkConfig} from "@lodestar/config"; +import {FastifyInstance, fastify} from "fastify"; +import {parse as parseQueryString} from "qs"; export type ServerOpts = { port: number; diff --git a/packages/light-client/test/utils/utils.ts b/packages/light-client/test/utils/utils.ts index 8364bcc7fc85..f497bac0541e 100644 --- a/packages/light-client/test/utils/utils.ts +++ b/packages/light-client/test/utils/utils.ts @@ -1,6 +1,6 @@ import bls from "@chainsafe/bls"; import {PointFormat, PublicKey, SecretKey} from "@chainsafe/bls/types"; -import {hasher, Tree} from "@chainsafe/persistent-merkle-tree"; +import {Tree, hasher} from "@chainsafe/persistent-merkle-tree"; import {BitArray, fromHexString} from "@chainsafe/ssz"; import {BeaconConfig} from "@lodestar/config"; import { @@ -11,7 +11,7 @@ import { SLOTS_PER_EPOCH, SYNC_COMMITTEE_SIZE, } from "@lodestar/params"; -import {altair, LightClientBootstrap, phase0, Slot, ssz, SyncPeriod} from "@lodestar/types"; +import {LightClientBootstrap, Slot, SyncPeriod, altair, phase0, ssz} from "@lodestar/types"; import {SyncCommitteeFast} from "../../src/types.js"; import {computeSigningRoot} from "../../src/utils/domain.js"; import {getConsoleLogger} from "../../src/utils/logger.js"; diff --git a/packages/logger/src/browser.ts b/packages/logger/src/browser.ts index 7f4972111459..60e756079377 100644 --- a/packages/logger/src/browser.ts +++ b/packages/logger/src/browser.ts @@ -1,8 +1,8 @@ +import {LogLevel, Logger} from "@lodestar/utils"; import winston from "winston"; import Transport from "winston-transport"; -import {LogLevel, Logger} from "@lodestar/utils"; -import {createWinstonLogger} from "./winston.js"; import {LEVEL, MESSAGE, TimestampFormat, WinstonLogInfo} from "./interface.js"; +import {createWinstonLogger} from "./winston.js"; export type BrowserLoggerOpts = { /** diff --git a/packages/logger/src/interface.ts b/packages/logger/src/interface.ts index e3ba8483a458..30b219874248 100644 --- a/packages/logger/src/interface.ts +++ b/packages/logger/src/interface.ts @@ -1,5 +1,5 @@ +import {LogData, LogHandler, LogLevel, Logger} from "@lodestar/utils"; import {LEVEL, MESSAGE} from "triple-beam"; -import {LogLevel, Logger, LogHandler, LogData} from "@lodestar/utils"; export {LogLevel, LEVEL, MESSAGE}; export type {Logger, LogHandler, LogData}; diff --git a/packages/logger/src/node.ts b/packages/logger/src/node.ts index fcd9c535dd9e..21786f21c27c 100644 --- a/packages/logger/src/node.ts +++ b/packages/logger/src/node.ts @@ -1,11 +1,11 @@ import path from "node:path"; -import DailyRotateFile from "winston-daily-rotate-file"; -import TransportStream from "winston-transport"; // We want to keep `winston` export as it's more readable and easier to understand /* eslint-disable import/no-named-as-default-member */ import winston from "winston"; import type {Logger as Winston} from "winston"; -import {Logger, LogLevel, TimestampFormat} from "./interface.js"; +import DailyRotateFile from "winston-daily-rotate-file"; +import TransportStream from "winston-transport"; +import {LogLevel, Logger, TimestampFormat} from "./interface.js"; import {ConsoleDynamicLevel} from "./utils/consoleTransport.js"; import {WinstonLogger} from "./winston.js"; diff --git a/packages/logger/src/utils/format.ts b/packages/logger/src/utils/format.ts index 4e657c0040af..8688016b63c9 100644 --- a/packages/logger/src/utils/format.ts +++ b/packages/logger/src/utils/format.ts @@ -1,7 +1,7 @@ -import winston, {format} from "winston"; import {LodestarError, isEmptyObject} from "@lodestar/utils"; +import winston, {format} from "winston"; import {LoggerOptions, TimestampFormatCode} from "../interface.js"; -import {logCtxToJson, logCtxToString, LogData} from "./json.js"; +import {LogData, logCtxToJson, logCtxToString} from "./json.js"; import {formatEpochSlotTime} from "./timeFormat.js"; type Format = ReturnType; diff --git a/packages/logger/src/winston.ts b/packages/logger/src/winston.ts index b886894e6aba..184f27e31335 100644 --- a/packages/logger/src/winston.ts +++ b/packages/logger/src/winston.ts @@ -2,7 +2,7 @@ /* eslint-disable import/no-named-as-default-member */ import winston from "winston"; import type {Logger as Winston} from "winston"; -import {Logger, LoggerOptions, LogLevel, logLevelNum} from "./interface.js"; +import {LogLevel, Logger, LoggerOptions, logLevelNum} from "./interface.js"; import {getFormat} from "./utils/format.js"; import {LogData} from "./utils/json.js"; diff --git a/packages/logger/test/e2e/logger/workerLoggerHandler.ts b/packages/logger/test/e2e/logger/workerLoggerHandler.ts index ab2097171af0..07a2dd6d2287 100644 --- a/packages/logger/test/e2e/logger/workerLoggerHandler.ts +++ b/packages/logger/test/e2e/logger/workerLoggerHandler.ts @@ -1,5 +1,5 @@ import workerThreads from "node:worker_threads"; -import {spawn, Worker} from "@chainsafe/threads"; +import {Worker, spawn} from "@chainsafe/threads"; export type LoggerWorker = { log(data: string): void; diff --git a/packages/logger/test/e2e/logger/workerLogs.test.ts b/packages/logger/test/e2e/logger/workerLogs.test.ts index 01ede8f6e4ec..13b8247e7dc1 100644 --- a/packages/logger/test/e2e/logger/workerLogs.test.ts +++ b/packages/logger/test/e2e/logger/workerLogs.test.ts @@ -1,8 +1,8 @@ -import path from "node:path"; import fs from "node:fs"; +import path from "node:path"; import {fileURLToPath} from "node:url"; -import {describe, it, expect, vi, beforeEach, afterEach} from "vitest"; import {sleep} from "@lodestar/utils"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {LoggerWorker, getLoggerWorker} from "./workerLoggerHandler.js"; // Global variable __dirname no longer available in ES6 modules. diff --git a/packages/logger/test/unit/browser.test.ts b/packages/logger/test/unit/browser.test.ts index 591437450c2d..e415ef79b3be 100644 --- a/packages/logger/test/unit/browser.test.ts +++ b/packages/logger/test/unit/browser.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect} from "vitest"; -import {LogLevel} from "@lodestar/utils"; import {stubLoggerForConsole} from "@lodestar/test-utils/doubles"; +import {LogLevel} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; +import {getBrowserLogger} from "../../src/browser.js"; import {TimestampFormatCode, logFormats} from "../../src/index.js"; import {formatsTestCases} from "../fixtures/loggerFormats.js"; -import {getBrowserLogger} from "../../src/browser.js"; describe("browser logger", () => { describe("format and options", () => { diff --git a/packages/logger/test/unit/env.node.test.ts b/packages/logger/test/unit/env.node.test.ts index 4bd4df689adf..c1f39424eb0a 100644 --- a/packages/logger/test/unit/env.node.test.ts +++ b/packages/logger/test/unit/env.node.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect} from "vitest"; -import {LogLevel} from "@lodestar/utils"; import {stubLoggerForConsole} from "@lodestar/test-utils/doubles"; +import {LogLevel} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; +import {getEnvLogger} from "../../src/env.js"; import {TimestampFormatCode, logFormats} from "../../src/index.js"; import {formatsTestCases} from "../fixtures/loggerFormats.js"; -import {getEnvLogger} from "../../src/env.js"; describe("env logger", () => { describe("format and options", () => { diff --git a/packages/logger/test/unit/node.node.test.ts b/packages/logger/test/unit/node.node.test.ts index b7c882a1e3bd..998c7e42e2fb 100644 --- a/packages/logger/test/unit/node.node.test.ts +++ b/packages/logger/test/unit/node.node.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect, vi, afterEach, Mock} from "vitest"; import {LogLevel} from "@lodestar/utils"; +import {Mock, afterEach, describe, expect, it, vi} from "vitest"; import {TimestampFormatCode, logFormats} from "../../src/index.js"; import {getNodeLogger} from "../../src/node.js"; import {formatsTestCases} from "../fixtures/loggerFormats.js"; diff --git a/packages/logger/test/unit/utils/json.test.ts b/packages/logger/test/unit/utils/json.test.ts index 7ca5604edf00..68e3f827e241 100644 --- a/packages/logger/test/unit/utils/json.test.ts +++ b/packages/logger/test/unit/utils/json.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; import {fromHexString, toHexString} from "@chainsafe/ssz"; import {LodestarError} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; import {logCtxToJson, logCtxToString} from "../../../src/utils/json.js"; describe("Json helper", () => { diff --git a/packages/logger/test/unit/utils/timeFormat.test.ts b/packages/logger/test/unit/utils/timeFormat.test.ts index fc374a0f6c7f..12c0ea97f167 100644 --- a/packages/logger/test/unit/utils/timeFormat.test.ts +++ b/packages/logger/test/unit/utils/timeFormat.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {formatEpochSlotTime} from "../../../src/utils/timeFormat.js"; describe("logger / util / formatEpochSlotTime", () => { diff --git a/packages/logger/test/unit/winston.node.test.ts b/packages/logger/test/unit/winston.node.test.ts index e4cfca2b041a..0db86a18fab9 100644 --- a/packages/logger/test/unit/winston.node.test.ts +++ b/packages/logger/test/unit/winston.node.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; -import {describe, it, expect, beforeAll, afterAll, afterEach, vi, Mock} from "vitest"; import {LogLevel} from "@lodestar/utils"; +import {Mock, afterAll, afterEach, beforeAll, describe, expect, it, vi} from "vitest"; import {TimestampFormatCode} from "../../src/index.js"; import {getNodeLogger} from "../../src/node.js"; import {readFileWhenExists} from "../utils/files.js"; diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 544113e3f8e1..82ffa491daa3 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -1,9 +1,9 @@ import {PresetName} from "./presetName.js"; +import {presetStatus} from "./presetStatus.js"; +import {gnosisPreset} from "./presets/gnosis.js"; import {mainnetPreset} from "./presets/mainnet.js"; import {minimalPreset} from "./presets/minimal.js"; -import {gnosisPreset} from "./presets/gnosis.js"; -import {presetStatus} from "./presetStatus.js"; -import {userSelectedPreset, userOverrides} from "./setPreset.js"; +import {userOverrides, userSelectedPreset} from "./setPreset.js"; export type {BeaconPreset} from "./types.js"; export * from "./forkName.js"; diff --git a/packages/params/src/setPreset.ts b/packages/params/src/setPreset.ts index 61836d86a241..1f2a962a868b 100644 --- a/packages/params/src/setPreset.ts +++ b/packages/params/src/setPreset.ts @@ -1,7 +1,7 @@ +import {presetFromJson} from "./json.js"; import {PresetName} from "./presetName.js"; import {presetStatus} from "./presetStatus.js"; import {BeaconPreset} from "./types.js"; -import {presetFromJson} from "./json.js"; export {PresetName, presetFromJson}; diff --git a/packages/params/test/e2e/ensure-config-is-synced.test.ts b/packages/params/test/e2e/ensure-config-is-synced.test.ts index c54b0d4d44f8..ab34c16201c8 100644 --- a/packages/params/test/e2e/ensure-config-is-synced.test.ts +++ b/packages/params/test/e2e/ensure-config-is-synced.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect, vi} from "vitest"; import axios from "axios"; +import {describe, expect, it, vi} from "vitest"; +import {BeaconPreset, ForkName} from "../../src/index.js"; import {mainnetPreset} from "../../src/presets/mainnet.js"; import {minimalPreset} from "../../src/presets/minimal.js"; -import {ForkName, BeaconPreset} from "../../src/index.js"; import {loadConfigYaml} from "../yaml.js"; // Not e2e, but slow. Run with e2e tests diff --git a/packages/params/test/e2e/overridePreset.test.ts b/packages/params/test/e2e/overridePreset.test.ts index df7afbbf84da..aa609b5e8f75 100644 --- a/packages/params/test/e2e/overridePreset.test.ts +++ b/packages/params/test/e2e/overridePreset.test.ts @@ -1,8 +1,8 @@ -import path from "node:path"; -import util from "node:util"; import child from "node:child_process"; +import path from "node:path"; import {fileURLToPath} from "node:url"; -import {describe, it, expect, vi} from "vitest"; +import util from "node:util"; +import {describe, expect, it, vi} from "vitest"; const scriptNames = { ok: "overridePresetOk.ts", diff --git a/packages/params/test/e2e/overridePresetError.ts b/packages/params/test/e2e/overridePresetError.ts index 869f521d33b5..aeb544115c61 100644 --- a/packages/params/test/e2e/overridePresetError.ts +++ b/packages/params/test/e2e/overridePresetError.ts @@ -3,6 +3,6 @@ // 1. Import from not only @lodestar/params/setPreset will trigger an error import "../../lib/index.js"; -import {setActivePreset, PresetName} from "../../lib/setPreset.js"; +import {PresetName, setActivePreset} from "../../lib/setPreset.js"; // This line should throw setActivePreset(PresetName.minimal, {SLOTS_PER_EPOCH: 2}); diff --git a/packages/params/test/e2e/overridePresetOk.ts b/packages/params/test/e2e/overridePresetOk.ts index 8887155b5400..f82d9eb42eb3 100644 --- a/packages/params/test/e2e/overridePresetOk.ts +++ b/packages/params/test/e2e/overridePresetOk.ts @@ -5,7 +5,7 @@ import assert from "node:assert"; // It demonstrates how to properly change the Lodestar preset safely // 1. Import from @lodestar/params/setPreset only -import {setActivePreset, PresetName} from "../../src/setPreset.js"; +import {PresetName, setActivePreset} from "../../src/setPreset.js"; setActivePreset(PresetName.minimal, {SLOTS_PER_EPOCH: 2}); // 2. Import from any other @lodestar/params paths diff --git a/packages/params/test/e2e/setPreset.test.ts b/packages/params/test/e2e/setPreset.test.ts index 2108a4f23342..d75cf9861869 100644 --- a/packages/params/test/e2e/setPreset.test.ts +++ b/packages/params/test/e2e/setPreset.test.ts @@ -1,8 +1,8 @@ -import path from "node:path"; -import util from "node:util"; import child from "node:child_process"; +import path from "node:path"; import {fileURLToPath} from "node:url"; -import {describe, it, expect, vi} from "vitest"; +import util from "node:util"; +import {describe, expect, it, vi} from "vitest"; const scriptNames = { ok: "setPresetOk.ts", diff --git a/packages/params/test/e2e/setPresetError.ts b/packages/params/test/e2e/setPresetError.ts index debbb47f013d..362e7da5ce46 100644 --- a/packages/params/test/e2e/setPresetError.ts +++ b/packages/params/test/e2e/setPresetError.ts @@ -3,6 +3,6 @@ // 1. Import from not only @lodestar/params/setPreset will trigger an error import "../../lib/index.js"; -import {setActivePreset, PresetName} from "../../lib/setPreset.js"; +import {PresetName, setActivePreset} from "../../lib/setPreset.js"; // This line should throw setActivePreset(PresetName.minimal); diff --git a/packages/params/test/e2e/setPresetOk.ts b/packages/params/test/e2e/setPresetOk.ts index 5e76149b293a..a5b291db0047 100644 --- a/packages/params/test/e2e/setPresetOk.ts +++ b/packages/params/test/e2e/setPresetOk.ts @@ -3,7 +3,7 @@ // It demostrates how to properly change the Lodestar preset safely // 1. Import from @lodestar/params/setPreset only -import {setActivePreset, PresetName} from "../../src/setPreset.js"; +import {PresetName, setActivePreset} from "../../src/setPreset.js"; setActivePreset(PresetName.minimal); // 2. Import from any other @lodestar/params paths diff --git a/packages/params/test/unit/activePreset.test.ts b/packages/params/test/unit/activePreset.test.ts index 3aeee69672a1..7035053a9efc 100644 --- a/packages/params/test/unit/activePreset.test.ts +++ b/packages/params/test/unit/activePreset.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect, beforeAll} from "vitest"; +import {beforeAll, describe, expect, it} from "vitest"; +import {ACTIVE_PRESET, PresetName} from "../../src/index.js"; +import {gnosisPreset as gnosisParams} from "../../src/presets/gnosis.js"; import {mainnetPreset} from "../../src/presets/mainnet.js"; import {minimalPreset} from "../../src/presets/minimal.js"; -import {gnosisPreset as gnosisParams} from "../../src/presets/gnosis.js"; -import {ACTIVE_PRESET, PresetName} from "../../src/index.js"; import {setActivePreset} from "../../src/setPreset.js"; import {setActivePreset as setActivePresetLib} from "../../src/setPreset.js"; diff --git a/packages/params/test/unit/applicationDomains.test.ts b/packages/params/test/unit/applicationDomains.test.ts index f78e9aa22f07..8192de56dc1a 100644 --- a/packages/params/test/unit/applicationDomains.test.ts +++ b/packages/params/test/unit/applicationDomains.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; -import {DOMAIN_APPLICATION_MASK, DOMAIN_APPLICATION_BUILDER} from "../../src/index.js"; +import {describe, expect, it} from "vitest"; +import {DOMAIN_APPLICATION_BUILDER, DOMAIN_APPLICATION_MASK} from "../../src/index.js"; describe("validate application domains", () => { [{name: "builder domain", domain: DOMAIN_APPLICATION_BUILDER}].map(({name, domain}) => { diff --git a/packages/params/test/unit/forkName.test.ts b/packages/params/test/unit/forkName.test.ts index 4385c1e10d8a..70e3b6d38411 100644 --- a/packages/params/test/unit/forkName.test.ts +++ b/packages/params/test/unit/forkName.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import { ForkName, forkAll, diff --git a/packages/params/test/yaml.ts b/packages/params/test/yaml.ts index f56016a4dbc0..a5eac0ed4320 100644 --- a/packages/params/test/yaml.ts +++ b/packages/params/test/yaml.ts @@ -1,4 +1,4 @@ -import {load, FAILSAFE_SCHEMA, Type} from "js-yaml"; +import {FAILSAFE_SCHEMA, Type, load} from "js-yaml"; export function loadConfigYaml(configYaml: string): Record { return load(configYaml, {schema}) as Record; diff --git a/packages/prover/src/cli/applyPreset.ts b/packages/prover/src/cli/applyPreset.ts index f0c3d83c7751..4c1cfbaf757c 100644 --- a/packages/prover/src/cli/applyPreset.ts +++ b/packages/prover/src/cli/applyPreset.ts @@ -21,7 +21,7 @@ setHasher(hasher); // set LODESTAR_PRESET manually every time. // IMPORTANT: only import Lodestar code here which does not import any other Lodestar libraries -import {setActivePreset, presetFromJson, PresetName} from "@lodestar/params/setPreset"; +import {PresetName, presetFromJson, setActivePreset} from "@lodestar/params/setPreset"; import {readFile} from "../utils/file.js"; const network = valueOfArg("network"); diff --git a/packages/prover/src/cli/cli.ts b/packages/prover/src/cli/cli.ts index 5e084a551536..fcd26b2c7b49 100644 --- a/packages/prover/src/cli/cli.ts +++ b/packages/prover/src/cli/cli.ts @@ -1,7 +1,7 @@ +import {registerCommandToYargs} from "@lodestar/utils"; // Must not use `* as yargs`, see https://github.com/yargs/yargs/issues/1131 import yargs from "yargs"; import {hideBin} from "yargs/helpers"; -import {registerCommandToYargs} from "@lodestar/utils"; import {getVersionData} from "../utils/version.js"; import {cmds, proverProxyStartCommand} from "./cmds/index.js"; import {globalOptions} from "./options.js"; diff --git a/packages/prover/src/cli/cmds/start/handler.ts b/packages/prover/src/cli/cmds/start/handler.ts index 92922f1a45a4..e5fa5d402dfd 100644 --- a/packages/prover/src/cli/cmds/start/handler.ts +++ b/packages/prover/src/cli/cmds/start/handler.ts @@ -1,8 +1,8 @@ import {ChainConfig, chainConfigFromJson} from "@lodestar/config"; import {readFile} from "../../../utils/file.js"; -import {createVerifiedExecutionProxy, VerifiedProxyOptions} from "../../../web3_proxy.js"; +import {VerifiedProxyOptions, createVerifiedExecutionProxy} from "../../../web3_proxy.js"; import {GlobalArgs, parseGlobalArgs} from "../../options.js"; -import {parseStartArgs, StartArgs} from "./options.js"; +import {StartArgs, parseStartArgs} from "./options.js"; /** * Runs a beacon node. diff --git a/packages/prover/src/cli/options.ts b/packages/prover/src/cli/options.ts index c37250070056..36ab331ceb78 100644 --- a/packages/prover/src/cli/options.ts +++ b/packages/prover/src/cli/options.ts @@ -1,6 +1,6 @@ import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; -import {CliCommandOptions, LogLevel, LogLevels} from "@lodestar/utils"; import {ACTIVE_PRESET} from "@lodestar/params"; +import {CliCommandOptions, LogLevel, LogLevels} from "@lodestar/utils"; import {YargsError} from "../utils/errors.js"; export type GlobalArgs = { diff --git a/packages/prover/src/interfaces.ts b/packages/prover/src/interfaces.ts index 9a67b47ea3b3..c62d17e7f0f5 100644 --- a/packages/prover/src/interfaces.ts +++ b/packages/prover/src/interfaces.ts @@ -1,6 +1,6 @@ import {ChainConfig} from "@lodestar/config"; import {NetworkName} from "@lodestar/config/networks"; -import {Logger, LogLevel} from "@lodestar/utils"; +import {LogLevel, Logger} from "@lodestar/utils"; import {ProofProvider} from "./proof_provider/proof_provider.js"; import {JsonRpcRequest, JsonRpcRequestOrBatch, JsonRpcResponse, JsonRpcResponseOrBatch} from "./types.js"; import {ELRpcProvider} from "./utils/rpc_provider.js"; diff --git a/packages/prover/src/proof_provider/payload_store.ts b/packages/prover/src/proof_provider/payload_store.ts index c891cb994da1..4cf5dff36ac6 100644 --- a/packages/prover/src/proof_provider/payload_store.ts +++ b/packages/prover/src/proof_provider/payload_store.ts @@ -1,7 +1,7 @@ import {ApiClient} from "@lodestar/api"; -import {Logger} from "@lodestar/utils"; -import {ExecutionPayload, LightClientHeader} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; +import {ExecutionPayload, LightClientHeader} from "@lodestar/types"; +import {Logger} from "@lodestar/utils"; import {MAX_PAYLOAD_HISTORY} from "../constants.js"; import {fetchBlock, getExecutionPayloadForBlockNumber} from "../utils/consensus.js"; import {bufferToHex, hexToNumber} from "../utils/conversion.js"; diff --git a/packages/prover/src/proof_provider/proof_provider.ts b/packages/prover/src/proof_provider/proof_provider.ts index 3a95b0e4e604..fbf025c377ad 100644 --- a/packages/prover/src/proof_provider/proof_provider.ts +++ b/packages/prover/src/proof_provider/proof_provider.ts @@ -4,8 +4,8 @@ import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; import {Lightclient, LightclientEvent, RunStatusCode} from "@lodestar/light-client"; import {LightClientRestTransport} from "@lodestar/light-client/transport"; import {ForkName, isForkWithdrawals} from "@lodestar/params"; -import {Logger} from "@lodestar/utils"; import {ExecutionPayload, LightClientHeader} from "@lodestar/types"; +import {Logger} from "@lodestar/utils"; import {LCTransport, RootProviderInitOptions} from "../interfaces.js"; import {assertLightClient} from "../utils/assertion.js"; import { diff --git a/packages/prover/src/utils/consensus.ts b/packages/prover/src/utils/consensus.ts index ac8fd24d139f..d157bf1cf15c 100644 --- a/packages/prover/src/utils/consensus.ts +++ b/packages/prover/src/utils/consensus.ts @@ -1,6 +1,6 @@ import {ApiClient} from "@lodestar/api/beacon"; -import {Bytes32, ExecutionPayload, capella} from "@lodestar/types"; import {GenesisData, Lightclient} from "@lodestar/light-client"; +import {Bytes32, ExecutionPayload, capella} from "@lodestar/types"; import {Logger} from "@lodestar/utils"; import {MAX_PAYLOAD_HISTORY} from "../constants.js"; import {hexToBuffer} from "./conversion.js"; diff --git a/packages/prover/src/utils/evm.ts b/packages/prover/src/utils/evm.ts index 40950647b8f3..391dd302c7ad 100644 --- a/packages/prover/src/utils/evm.ts +++ b/packages/prover/src/utils/evm.ts @@ -1,19 +1,19 @@ +import {Block, BlockHeader} from "@ethereumjs/block"; import {Blockchain} from "@ethereumjs/blockchain"; -import {Account, Address} from "@ethereumjs/util"; -import {VM, RunTxResult} from "@ethereumjs/vm"; import {TransactionFactory} from "@ethereumjs/tx"; -import {Block, BlockHeader} from "@ethereumjs/block"; +import {Account, Address} from "@ethereumjs/util"; +import {RunTxResult, VM} from "@ethereumjs/vm"; import {NetworkName} from "@lodestar/config/networks"; -import {Logger} from "@lodestar/utils"; import {ExecutionPayload} from "@lodestar/types"; +import {Logger} from "@lodestar/utils"; import {ZERO_ADDRESS} from "../constants.js"; import {ProofProvider} from "../proof_provider/proof_provider.js"; import {ELBlock, ELProof, ELTransaction, JsonRpcVersion} from "../types.js"; import {bufferToHex, chunkIntoN, cleanObject, hexToBigInt, hexToBuffer, numberToHex, padLeft} from "./conversion.js"; import {getChainCommon, getTxType} from "./execution.js"; import {isValidResponse} from "./json_rpc.js"; -import {isNullish, isValidAccount, isValidCodeHash, isValidStorageKeys} from "./validation.js"; import {ELRpcProvider} from "./rpc_provider.js"; +import {isNullish, isValidAccount, isValidCodeHash, isValidStorageKeys} from "./validation.js"; export async function createVM({proofProvider}: {proofProvider: ProofProvider}): Promise { const common = getChainCommon(proofProvider.config.PRESET_BASE as string); diff --git a/packages/prover/src/utils/execution.ts b/packages/prover/src/utils/execution.ts index 91d5f8d625ff..8ce9d71857f3 100644 --- a/packages/prover/src/utils/execution.ts +++ b/packages/prover/src/utils/execution.ts @@ -1,8 +1,8 @@ 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 {ELRpcProvider} from "./rpc_provider.js"; +import {isBlockNumber, isPresent} from "./validation.js"; export type Optional = Omit & {[P in keyof T]?: T[P] | undefined}; diff --git a/packages/prover/src/utils/gitData/gitDataPath.ts b/packages/prover/src/utils/gitData/gitDataPath.ts index 1ad3104aafc6..b4c7f8c7c62c 100644 --- a/packages/prover/src/utils/gitData/gitDataPath.ts +++ b/packages/prover/src/utils/gitData/gitDataPath.ts @@ -1,5 +1,5 @@ -import path from "node:path"; import fs from "node:fs"; +import path from "node:path"; import {fileURLToPath} from "node:url"; // Global variable __dirname no longer available in ES6 modules. diff --git a/packages/prover/src/utils/gitData/index.ts b/packages/prover/src/utils/gitData/index.ts index 0720d39d9e30..c5681660f8ce 100644 --- a/packages/prover/src/utils/gitData/index.ts +++ b/packages/prover/src/utils/gitData/index.ts @@ -2,7 +2,7 @@ import {execSync} from "node:child_process"; // This file is created in the build step and is distributed through NPM // MUST be in sync with `-/gitDataPath.ts` and `package.json` files. -import {readGitDataFile, GitData} from "./gitDataPath.js"; +import {GitData, readGitDataFile} from "./gitDataPath.js"; /** Reads git data from a persisted file or local git data at build time. */ export function readAndGetGitData(): GitData { diff --git a/packages/prover/src/utils/json_rpc.ts b/packages/prover/src/utils/json_rpc.ts index 74727c198122..d0d2bc850fd0 100644 --- a/packages/prover/src/utils/json_rpc.ts +++ b/packages/prover/src/utils/json_rpc.ts @@ -1,17 +1,17 @@ import {Logger} from "@lodestar/logger"; import {VERIFICATION_FAILED_RESPONSE_CODE} from "../constants.js"; import { + JsonRpcBatchRequest, + JsonRpcBatchResponse, JsonRpcErrorPayload, JsonRpcNotificationPayload, - JsonRpcRequestPayload, JsonRpcRequest, + JsonRpcRequestOrBatch, + JsonRpcRequestPayload, JsonRpcResponse, + JsonRpcResponseOrBatch, JsonRpcResponseWithErrorPayload, JsonRpcResponseWithResultPayload, - JsonRpcResponseOrBatch, - JsonRpcBatchResponse, - JsonRpcRequestOrBatch, - JsonRpcBatchRequest, } from "../types.js"; import {isNullish} from "./validation.js"; diff --git a/packages/prover/src/utils/process.ts b/packages/prover/src/utils/process.ts index 75bb79516609..b8464edd7ac8 100644 --- a/packages/prover/src/utils/process.ts +++ b/packages/prover/src/utils/process.ts @@ -1,17 +1,17 @@ import {Logger} from "@lodestar/logger"; import {ELVerifiedRequestHandler} from "../interfaces.js"; import {ProofProvider} from "../proof_provider/proof_provider.js"; -import {JsonRpcRequestOrBatch, JsonRpcBatchRequest, JsonRpcResponseOrBatch, JsonRpcBatchResponse} from "../types.js"; +import {JsonRpcBatchRequest, JsonRpcBatchResponse, JsonRpcRequestOrBatch, JsonRpcResponseOrBatch} from "../types.js"; +import {eth_call} from "../verified_requests/eth_call.js"; +import {eth_estimateGas} from "../verified_requests/eth_estimateGas.js"; import {eth_getBalance} from "../verified_requests/eth_getBalance.js"; -import {eth_getTransactionCount} from "../verified_requests/eth_getTransactionCount.js"; import {eth_getBlockByHash} from "../verified_requests/eth_getBlockByHash.js"; import {eth_getBlockByNumber} from "../verified_requests/eth_getBlockByNumber.js"; import {eth_getCode} from "../verified_requests/eth_getCode.js"; -import {eth_call} from "../verified_requests/eth_call.js"; -import {eth_estimateGas} from "../verified_requests/eth_estimateGas.js"; +import {eth_getTransactionCount} from "../verified_requests/eth_getTransactionCount.js"; import {getResponseForRequest, isBatchRequest, isRequest} from "./json_rpc.js"; -import {isNullish} from "./validation.js"; import {ELRpcProvider} from "./rpc_provider.js"; +import {isNullish} from "./validation.js"; // biome-ignore lint/suspicious/noExplicitAny: export const verifiableMethodHandlers: Record> = { diff --git a/packages/prover/src/utils/validation.ts b/packages/prover/src/utils/validation.ts index 3adc37571db5..085798c875bc 100644 --- a/packages/prover/src/utils/validation.ts +++ b/packages/prover/src/utils/validation.ts @@ -2,10 +2,10 @@ import {Block} from "@ethereumjs/block"; import {RLP} from "@ethereumjs/rlp"; import {Trie} from "@ethereumjs/trie"; import {Account, KECCAK256_NULL_S} from "@ethereumjs/util"; -import {keccak256} from "ethereum-cryptography/keccak.js"; +import {ChainForkConfig} from "@lodestar/config"; import {Bytes32, ExecutionPayload} from "@lodestar/types"; import {Logger} from "@lodestar/utils"; -import {ChainForkConfig} from "@lodestar/config"; +import {keccak256} from "ethereum-cryptography/keccak.js"; import {ELBlock, ELProof, ELStorageProof, HexString} from "../types.js"; import {blockDataFromELBlock, bufferToHex, hexToBuffer, padLeft} from "./conversion.js"; import {getChainCommon} from "./execution.js"; diff --git a/packages/prover/src/utils/verification.ts b/packages/prover/src/utils/verification.ts index a468bf277eba..fb304bf34936 100644 --- a/packages/prover/src/utils/verification.ts +++ b/packages/prover/src/utils/verification.ts @@ -3,8 +3,8 @@ import {ProofProvider} from "../proof_provider/proof_provider.js"; 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 {ELRpcProvider} from "./rpc_provider.js"; +import {isValidAccount, isValidBlock, isValidCodeHash, isValidStorageKeys} from "./validation.js"; type VerificationResult = {data: T; valid: true} | {valid: false; data?: undefined}; diff --git a/packages/prover/src/verified_requests/eth_call.ts b/packages/prover/src/verified_requests/eth_call.ts index eea7ba146c3f..2b28f699fb5b 100644 --- a/packages/prover/src/verified_requests/eth_call.ts +++ b/packages/prover/src/verified_requests/eth_call.ts @@ -3,8 +3,8 @@ import {ELApiParams, ELApiReturn} from "../types.js"; import {bufferToHex} from "../utils/conversion.js"; import {createVM, executeVMCall, getVMWithState} from "../utils/evm.js"; import { - getResponseForRequest, getErrorResponseForRequestWithFailedVerification, + getResponseForRequest, getVerificationFailedMessage, } from "../utils/json_rpc.js"; diff --git a/packages/prover/src/verified_requests/eth_getBalance.ts b/packages/prover/src/verified_requests/eth_getBalance.ts index 0c03b23be788..c1e1749bebf8 100644 --- a/packages/prover/src/verified_requests/eth_getBalance.ts +++ b/packages/prover/src/verified_requests/eth_getBalance.ts @@ -1,10 +1,10 @@ import {ELVerifiedRequestHandler} from "../interfaces.js"; -import {verifyAccount} from "../utils/verification.js"; import { getErrorResponseForRequestWithFailedVerification, getResponseForRequest, getVerificationFailedMessage, } from "../utils/json_rpc.js"; +import {verifyAccount} from "../utils/verification.js"; export const eth_getBalance: ELVerifiedRequestHandler<[address: string, block?: number | string], string> = async ({ rpc, diff --git a/packages/prover/src/verified_requests/eth_getBlockByHash.ts b/packages/prover/src/verified_requests/eth_getBlockByHash.ts index 00a110c01e9a..b1374865aa34 100644 --- a/packages/prover/src/verified_requests/eth_getBlockByHash.ts +++ b/packages/prover/src/verified_requests/eth_getBlockByHash.ts @@ -1,11 +1,11 @@ import {ELVerifiedRequestHandler} from "../interfaces.js"; import {ELBlock} from "../types.js"; -import {verifyBlock} from "../utils/verification.js"; import { getErrorResponseForRequestWithFailedVerification, getResponseForRequest, getVerificationFailedMessage, } from "../utils/json_rpc.js"; +import {verifyBlock} from "../utils/verification.js"; export const eth_getBlockByHash: ELVerifiedRequestHandler<[block: string, hydrated: boolean], ELBlock> = async ({ rpc, diff --git a/packages/prover/src/verified_requests/eth_getBlockByNumber.ts b/packages/prover/src/verified_requests/eth_getBlockByNumber.ts index 23e0fa2ca863..c54c219be91f 100644 --- a/packages/prover/src/verified_requests/eth_getBlockByNumber.ts +++ b/packages/prover/src/verified_requests/eth_getBlockByNumber.ts @@ -1,11 +1,11 @@ import {ELVerifiedRequestHandler} from "../interfaces.js"; import {ELBlock} from "../types.js"; -import {verifyBlock} from "../utils/verification.js"; import { getErrorResponseForRequestWithFailedVerification, getResponseForRequest, getVerificationFailedMessage, } from "../utils/json_rpc.js"; +import {verifyBlock} from "../utils/verification.js"; export const eth_getBlockByNumber: ELVerifiedRequestHandler< [block: string | number, hydrated: boolean], diff --git a/packages/prover/src/verified_requests/eth_getCode.ts b/packages/prover/src/verified_requests/eth_getCode.ts index f94ae8c1c8bd..1132ec089b24 100644 --- a/packages/prover/src/verified_requests/eth_getCode.ts +++ b/packages/prover/src/verified_requests/eth_getCode.ts @@ -1,10 +1,10 @@ import {ELVerifiedRequestHandler} from "../interfaces.js"; -import {verifyAccount, verifyCode} from "../utils/verification.js"; import { getErrorResponseForRequestWithFailedVerification, getResponseForRequest, getVerificationFailedMessage, } from "../utils/json_rpc.js"; +import {verifyAccount, verifyCode} from "../utils/verification.js"; export const eth_getCode: ELVerifiedRequestHandler<[address: string, block?: number | string], string> = async ({ rpc, diff --git a/packages/prover/src/verified_requests/eth_getTransactionCount.ts b/packages/prover/src/verified_requests/eth_getTransactionCount.ts index aeef67e96e74..ceb7c0797a81 100644 --- a/packages/prover/src/verified_requests/eth_getTransactionCount.ts +++ b/packages/prover/src/verified_requests/eth_getTransactionCount.ts @@ -1,10 +1,10 @@ import {ELVerifiedRequestHandler} from "../interfaces.js"; -import {verifyAccount} from "../utils/verification.js"; import { - getResponseForRequest, getErrorResponseForRequestWithFailedVerification, + getResponseForRequest, getVerificationFailedMessage, } from "../utils/json_rpc.js"; +import {verifyAccount} from "../utils/verification.js"; export const eth_getTransactionCount: ELVerifiedRequestHandler< [address: string, block?: number | string], diff --git a/packages/prover/src/web3_provider.ts b/packages/prover/src/web3_provider.ts index b42c349d1017..a28d43fa0b7b 100644 --- a/packages/prover/src/web3_provider.ts +++ b/packages/prover/src/web3_provider.ts @@ -3,9 +3,9 @@ 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 {processAndVerifyRequest} from "./utils/process.js"; import {ELRpcProvider} from "./utils/rpc_provider.js"; import {Web3ProviderInspector} from "./web3_provider_inspector.js"; -import {processAndVerifyRequest} from "./utils/process.js"; export type Web3ProviderTypeHandler = ( provider: T, diff --git a/packages/prover/src/web3_provider_inspector.ts b/packages/prover/src/web3_provider_inspector.ts index 154a860d0922..4cbcb221fc64 100644 --- a/packages/prover/src/web3_provider_inspector.ts +++ b/packages/prover/src/web3_provider_inspector.ts @@ -1,10 +1,10 @@ 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 ethersProviderType from "./provider_types/ethers_provider_type.js"; import legacyProviderType from "./provider_types/legacy_provider_type.js"; +import web3jsProviderType from "./provider_types/web3_js_provider_type.js"; export class Web3ProviderInspector { protected providerTypes: Web3ProviderType[] = []; diff --git a/packages/prover/src/web3_proxy.ts b/packages/prover/src/web3_proxy.ts index 273508852adf..d74eb1319e60 100644 --- a/packages/prover/src/web3_proxy.ts +++ b/packages/prover/src/web3_proxy.ts @@ -1,15 +1,15 @@ import http from "node:http"; import https from "node:https"; import url from "node:url"; -import httpProxy from "http-proxy"; -import {getNodeLogger} from "@lodestar/logger/node"; import {LogLevel} from "@lodestar/logger"; +import {getNodeLogger} from "@lodestar/logger/node"; +import httpProxy from "http-proxy"; import {ELRequestHandler, VerifiedExecutionInitOptions} from "./interfaces.js"; import {ProofProvider} from "./proof_provider/proof_provider.js"; import {JsonRpcRequestOrBatch, JsonRpcRequestPayload, JsonRpcResponseOrBatch} from "./types.js"; import {getResponseForRequest, isBatchRequest} from "./utils/json_rpc.js"; -import {fetchRequestPayload, fetchResponseBody} from "./utils/req_resp.js"; import {processAndVerifyRequest} from "./utils/process.js"; +import {fetchRequestPayload, fetchResponseBody} from "./utils/req_resp.js"; import {ELRpcProvider} from "./utils/rpc_provider.js"; export type VerifiedProxyOptions = Exclude, "mutateProvider" | "providerTypes"> & { diff --git a/packages/prover/test/e2e/cli/cmds/start.test.ts b/packages/prover/test/e2e/cli/cmds/start.test.ts index 75773ac02d36..ffdad63f1bd7 100644 --- a/packages/prover/test/e2e/cli/cmds/start.test.ts +++ b/packages/prover/test/e2e/cli/cmds/start.test.ts @@ -1,13 +1,13 @@ import childProcess from "node:child_process"; -import {writeFile, mkdir} from "node:fs/promises"; +import {mkdir, writeFile} from "node:fs/promises"; import path from "node:path"; -import {describe, it, expect, beforeAll, afterAll} from "vitest"; -import {Web3} from "web3"; +import {ChainConfig, chainConfigToJson} from "@lodestar/config"; import {runCliCommand, spawnCliCommand, stopChildProcess} from "@lodestar/test-utils"; import {sleep} from "@lodestar/utils"; -import {ChainConfig, chainConfigToJson} from "@lodestar/config"; +import {afterAll, beforeAll, describe, expect, it} from "vitest"; +import {Web3} from "web3"; import {getLodestarProverCli} from "../../../../src/cli/cli.js"; -import {rpcUrl, beaconUrl, proxyPort, proxyUrl, chainId, waitForCapellaFork, config} from "../../../utils/e2e_env.js"; +import {beaconUrl, chainId, config, proxyPort, proxyUrl, rpcUrl, waitForCapellaFork} from "../../../utils/e2e_env.js"; const cli = getLodestarProverCli(); diff --git a/packages/prover/test/e2e/web3_batch_request.test.ts b/packages/prover/test/e2e/web3_batch_request.test.ts index 6dae04a9c36d..ea265057ef8d 100644 --- a/packages/prover/test/e2e/web3_batch_request.test.ts +++ b/packages/prover/test/e2e/web3_batch_request.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect, beforeAll, vi} from "vitest"; +import {beforeAll, describe, expect, it, vi} from "vitest"; import {Web3} from "web3"; import {LCTransport} from "../../src/interfaces.js"; -import {createVerifiedExecutionProvider} from "../../src/web3_provider.js"; -import {rpcUrl, beaconUrl, config, waitForCapellaFork, minCapellaTimeMs} from "../utils/e2e_env.js"; import {getVerificationFailedMessage} from "../../src/utils/json_rpc.js"; +import {createVerifiedExecutionProvider} from "../../src/web3_provider.js"; +import {beaconUrl, config, minCapellaTimeMs, rpcUrl, waitForCapellaFork} from "../utils/e2e_env.js"; describe("web3_batch_requests", () => { vi.setConfig({hookTimeout: minCapellaTimeMs}); diff --git a/packages/prover/test/e2e/web3_provider.test.ts b/packages/prover/test/e2e/web3_provider.test.ts index edb3bb09e2fb..7f11a6ca1619 100644 --- a/packages/prover/test/e2e/web3_provider.test.ts +++ b/packages/prover/test/e2e/web3_provider.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect, beforeAll, vi} from "vitest"; -import {Web3} from "web3"; import {ethers} from "ethers"; +import {beforeAll, describe, expect, it, vi} from "vitest"; +import {Web3} from "web3"; import {LCTransport} from "../../src/interfaces.js"; import {createVerifiedExecutionProvider} from "../../src/web3_provider.js"; -import {waitForCapellaFork, minCapellaTimeMs, rpcUrl, beaconUrl, config} from "../utils/e2e_env.js"; +import {beaconUrl, config, minCapellaTimeMs, rpcUrl, waitForCapellaFork} from "../utils/e2e_env.js"; describe("web3_provider", () => { vi.setConfig({hookTimeout: minCapellaTimeMs}); diff --git a/packages/prover/test/mocks/request_handler.ts b/packages/prover/test/mocks/request_handler.ts index edde1e59a3fe..2b37cc134a36 100644 --- a/packages/prover/test/mocks/request_handler.ts +++ b/packages/prover/test/mocks/request_handler.ts @@ -1,10 +1,10 @@ -import {vi, expect} from "vitest"; -import {when} from "vitest-when"; -import deepmerge from "deepmerge"; -import {NetworkName} from "@lodestar/config/networks"; import {ForkConfig} from "@lodestar/config"; -import {PresetName} from "@lodestar/params"; +import {NetworkName} from "@lodestar/config/networks"; import {getEmptyLogger} from "@lodestar/logger/empty"; +import {PresetName} from "@lodestar/params"; +import deepmerge from "deepmerge"; +import {expect, vi} from "vitest"; +import {when} from "vitest-when"; import {ELVerifiedRequestHandlerOpts} from "../../src/interfaces.js"; import {ProofProvider} from "../../src/proof_provider/proof_provider.js"; import { @@ -18,8 +18,8 @@ import { JsonRpcResponseOrBatch, JsonRpcVersion, } from "../../src/types.js"; -import {isNullish} from "../../src/utils/validation.js"; import {isBatchRequest, mergeBatchReqResp} from "../../src/utils/json_rpc.js"; +import {isNullish} from "../../src/utils/validation.js"; type Writeable = { -readonly [K in keyof T]?: T[K] extends object ? Writeable : T[K]; diff --git a/packages/prover/test/unit/proof_provider/orderd_map.test.ts b/packages/prover/test/unit/proof_provider/orderd_map.test.ts index 309c4de71568..eadf76af8b59 100644 --- a/packages/prover/test/unit/proof_provider/orderd_map.test.ts +++ b/packages/prover/test/unit/proof_provider/orderd_map.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {OrderedMap} from "../../../src/proof_provider/ordered_map.js"; describe("proof_provider/ordered_map", () => { diff --git a/packages/prover/test/unit/proof_provider/payload_store.test.ts b/packages/prover/test/unit/proof_provider/payload_store.test.ts index 6bc1e4265205..76007f2a1e22 100644 --- a/packages/prover/test/unit/proof_provider/payload_store.test.ts +++ b/packages/prover/test/unit/proof_provider/payload_store.test.ts @@ -1,13 +1,13 @@ -import {describe, it, expect, beforeEach, vi, MockedObject} from "vitest"; -import {when} from "vitest-when"; import {ApiClient, ApiResponse, HttpStatusCode, routes} from "@lodestar/api"; -import {hash} from "@lodestar/utils"; import {Logger} from "@lodestar/logger"; +import {ForkName} from "@lodestar/params"; import {ExecutionPayload, SignedBeaconBlock, capella} from "@lodestar/types"; +import {hash} from "@lodestar/utils"; import {toHexString} from "@lodestar/utils"; -import {ForkName} from "@lodestar/params"; -import {PayloadStore} from "../../../src/proof_provider/payload_store.js"; +import {MockedObject, beforeEach, describe, expect, it, vi} from "vitest"; +import {when} from "vitest-when"; import {MAX_PAYLOAD_HISTORY} from "../../../src/constants.js"; +import {PayloadStore} from "../../../src/proof_provider/payload_store.js"; const slotNumber = 10; const createHash = (input: string): Uint8Array => hash(Buffer.from(input, "utf8")); 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 index c24252d9548f..b35106d493cb 100644 --- a/packages/prover/test/unit/provider_types/ethers_provider_type.test.ts +++ b/packages/prover/test/unit/provider_types/ethers_provider_type.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {ethers} from "ethers"; +import {describe, expect, it} from "vitest"; import {Web3} from "web3"; import ethersProviderType from "../../../src/provider_types/ethers_provider_type.js"; 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 index 37ffc18e58ab..bdb532788845 100644 --- a/packages/prover/test/unit/provider_types/legacy_provider_type.test.ts +++ b/packages/prover/test/unit/provider_types/legacy_provider_type.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {ethers} from "ethers"; +import {describe, expect, it} from "vitest"; import {Web3} from "web3"; import legacyProviderType from "../../../src/provider_types/legacy_provider_type.js"; 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 index 54da395bca25..badb066c0bc1 100644 --- a/packages/prover/test/unit/provider_types/web3js_provider_type.test.ts +++ b/packages/prover/test/unit/provider_types/web3js_provider_type.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {ethers} from "ethers"; +import {describe, expect, it} from "vitest"; import {Web3} from "web3"; import web3jsProviderType from "../../../src/provider_types/web3_js_provider_type.js"; diff --git a/packages/prover/test/unit/utils/conversion.test.ts b/packages/prover/test/unit/utils/conversion.test.ts index ee9c16b9cb94..8b0c1476b5ac 100644 --- a/packages/prover/test/unit/utils/conversion.test.ts +++ b/packages/prover/test/unit/utils/conversion.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {chunkIntoN} from "../../../src/utils/conversion.js"; describe("utils/conversion", () => { diff --git a/packages/prover/test/unit/utils/execution.test.ts b/packages/prover/test/unit/utils/execution.test.ts index 9219b5ec0c03..5b9443c95bb4 100644 --- a/packages/prover/test/unit/utils/execution.test.ts +++ b/packages/prover/test/unit/utils/execution.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect} from "vitest"; -import deepmerge from "deepmerge"; import {getEnvLogger} from "@lodestar/logger/env"; +import deepmerge from "deepmerge"; +import {describe, expect, it} from "vitest"; import {ELProof, ELStorageProof} from "../../../src/types.js"; +import {hexToBuffer} from "../../../src/utils/conversion.js"; import {isValidAccount, isValidStorageKeys} from "../../../src/utils/validation.js"; import {invalidStorageProof, validStorageProof} from "../../fixtures/index.js"; import eoaProof from "../../fixtures/sepolia/eth_getBalance_eoa.json" assert {type: "json"}; -import {hexToBuffer} from "../../../src/utils/conversion.js"; const address = eoaProof.request.params[0] as string; const validAccountProof = eoaProof.dependentRequests[0].response.result as unknown as ELProof; diff --git a/packages/prover/test/unit/verified_requests/eth_call.test.ts b/packages/prover/test/unit/verified_requests/eth_call.test.ts index e76b3fe4ed83..74e998910505 100644 --- a/packages/prover/test/unit/verified_requests/eth_call.test.ts +++ b/packages/prover/test/unit/verified_requests/eth_call.test.ts @@ -1,13 +1,13 @@ -import {describe, it, expect} from "vitest"; import {createForkConfig} from "@lodestar/config"; import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; +import {describe, expect, it} from "vitest"; import {ELTransaction} from "../../../lib/types.js"; import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js"; +import {JsonRpcRequest, JsonRpcResponseWithResultPayload} from "../../../src/types.js"; +import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; import {eth_call} from "../../../src/verified_requests/eth_call.js"; import ethCallCase1 from "../../fixtures/mainnet/eth_call.json" assert {type: "json"}; import {cloneTestFixture, generateReqHandlerOptionsMock} from "../../mocks/request_handler.js"; -import {JsonRpcRequest, JsonRpcResponseWithResultPayload} from "../../../src/types.js"; -import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; const testCases = [ethCallCase1]; diff --git a/packages/prover/test/unit/verified_requests/eth_estimateGas.test.ts b/packages/prover/test/unit/verified_requests/eth_estimateGas.test.ts index 27fbfb98a1b3..55ac3a74e581 100644 --- a/packages/prover/test/unit/verified_requests/eth_estimateGas.test.ts +++ b/packages/prover/test/unit/verified_requests/eth_estimateGas.test.ts @@ -1,14 +1,14 @@ -import {describe, it, expect} from "vitest"; import {createForkConfig} from "@lodestar/config"; import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; +import {describe, expect, it} from "vitest"; import {ELTransaction} from "../../../lib/types.js"; import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js"; +import {JsonRpcRequest, JsonRpcResponseWithResultPayload} from "../../../src/types.js"; +import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; import {eth_estimateGas} from "../../../src/verified_requests/eth_estimateGas.js"; -import ethEstimateGasCase1 from "../../fixtures/mainnet/eth_estimateGas_simple_transfer.json" assert {type: "json"}; import ethEstimateGasCase2 from "../../fixtures/mainnet/eth_estimateGas_contract_call.json" assert {type: "json"}; +import ethEstimateGasCase1 from "../../fixtures/mainnet/eth_estimateGas_simple_transfer.json" assert {type: "json"}; import {TestFixture, cloneTestFixture, generateReqHandlerOptionsMock} from "../../mocks/request_handler.js"; -import {JsonRpcRequest, JsonRpcResponseWithResultPayload} from "../../../src/types.js"; -import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; const testCases = [ethEstimateGasCase1, ethEstimateGasCase2] as TestFixture[]; diff --git a/packages/prover/test/unit/verified_requests/eth_getBalance.test.ts b/packages/prover/test/unit/verified_requests/eth_getBalance.test.ts index 4032f4c25f19..f5f5470e385f 100644 --- a/packages/prover/test/unit/verified_requests/eth_getBalance.test.ts +++ b/packages/prover/test/unit/verified_requests/eth_getBalance.test.ts @@ -1,12 +1,12 @@ -import {describe, it, expect} from "vitest"; import {createForkConfig} from "@lodestar/config"; import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; +import {describe, expect, it} from "vitest"; import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js"; +import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; import {eth_getBalance} from "../../../src/verified_requests/eth_getBalance.js"; -import ethGetBalanceEoa from "../../fixtures/sepolia/eth_getBalance_eoa.json" assert {type: "json"}; import ethGetBalanceContract from "../../fixtures/sepolia/eth_getBalance_contract.json" assert {type: "json"}; +import ethGetBalanceEoa from "../../fixtures/sepolia/eth_getBalance_eoa.json" assert {type: "json"}; import {cloneTestFixture, generateReqHandlerOptionsMock} from "../../mocks/request_handler.js"; -import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; const testCases = [ethGetBalanceEoa, ethGetBalanceContract]; diff --git a/packages/prover/test/unit/verified_requests/eth_getBlockByHash.test.ts b/packages/prover/test/unit/verified_requests/eth_getBlockByHash.test.ts index 3175bdd6d60c..265863680712 100644 --- a/packages/prover/test/unit/verified_requests/eth_getBlockByHash.test.ts +++ b/packages/prover/test/unit/verified_requests/eth_getBlockByHash.test.ts @@ -1,7 +1,9 @@ -import {describe, it, expect} from "vitest"; import {createForkConfig} from "@lodestar/config"; import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; +import {describe, expect, it} from "vitest"; import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js"; +import {ELBlock} from "../../../src/types.js"; +import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; import {eth_getBlockByHash} from "../../../src/verified_requests/eth_getBlockByHash.js"; import ethGetBlockWithContractCreation from "../../fixtures/sepolia/eth_getBlock_with_contractCreation.json" assert { type: "json", @@ -10,8 +12,6 @@ import ethGetBlockWithNoAccessList from "../../fixtures/sepolia/eth_getBlock_wit type: "json", }; import {TestFixture, cloneTestFixture, generateReqHandlerOptionsMock} from "../../mocks/request_handler.js"; -import {ELBlock} from "../../../src/types.js"; -import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; const testCases = [ethGetBlockWithNoAccessList, ethGetBlockWithContractCreation] as [ TestFixture, diff --git a/packages/prover/test/unit/verified_requests/eth_getBlockByNumber.test.ts b/packages/prover/test/unit/verified_requests/eth_getBlockByNumber.test.ts index cc1389128ec0..9b59d39db771 100644 --- a/packages/prover/test/unit/verified_requests/eth_getBlockByNumber.test.ts +++ b/packages/prover/test/unit/verified_requests/eth_getBlockByNumber.test.ts @@ -1,8 +1,9 @@ -import {describe, it, expect} from "vitest"; import {createForkConfig} from "@lodestar/config"; import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; +import {describe, expect, it} from "vitest"; import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js"; import {ELBlock} from "../../../src/types.js"; +import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; import {eth_getBlockByNumber} from "../../../src/verified_requests/eth_getBlockByNumber.js"; import ethGetBlockWithContractCreation from "../../fixtures/sepolia/eth_getBlock_with_contractCreation.json" assert { type: "json", @@ -11,7 +12,6 @@ import ethGetBlockWithNoAccessList from "../../fixtures/sepolia/eth_getBlock_wit type: "json", }; import {TestFixture, cloneTestFixture, generateReqHandlerOptionsMock} from "../../mocks/request_handler.js"; -import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; const testCases = [ethGetBlockWithNoAccessList, ethGetBlockWithContractCreation] as [ TestFixture, diff --git a/packages/prover/test/unit/verified_requests/eth_getCode.test.ts b/packages/prover/test/unit/verified_requests/eth_getCode.test.ts index 51cf0c153857..aeef17cb6ced 100644 --- a/packages/prover/test/unit/verified_requests/eth_getCode.test.ts +++ b/packages/prover/test/unit/verified_requests/eth_getCode.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect} from "vitest"; import {createForkConfig} from "@lodestar/config"; import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; +import {describe, expect, it} from "vitest"; import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js"; +import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; import {eth_getCode} from "../../../src/verified_requests/eth_getCode.js"; import ethGetCodeCase1 from "../../fixtures/sepolia/eth_getCode.json" assert {type: "json"}; -import {generateReqHandlerOptionsMock, cloneTestFixture} from "../../mocks/request_handler.js"; -import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; +import {cloneTestFixture, generateReqHandlerOptionsMock} from "../../mocks/request_handler.js"; const testCases = [ethGetCodeCase1]; diff --git a/packages/prover/test/unit/verified_requests/eth_getTransactionCount.test.ts b/packages/prover/test/unit/verified_requests/eth_getTransactionCount.test.ts index 8baf8fd7976b..e72bfd4dbf96 100644 --- a/packages/prover/test/unit/verified_requests/eth_getTransactionCount.test.ts +++ b/packages/prover/test/unit/verified_requests/eth_getTransactionCount.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect} from "vitest"; import {createForkConfig} from "@lodestar/config"; import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; +import {describe, expect, it} from "vitest"; import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js"; +import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; import {eth_getTransactionCount} from "../../../src/verified_requests/eth_getTransactionCount.js"; import getTransactionCountCase1 from "../../fixtures/sepolia/eth_getTransactionCount.json" assert {type: "json"}; -import {generateReqHandlerOptionsMock, cloneTestFixture} from "../../mocks/request_handler.js"; -import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js"; +import {cloneTestFixture, generateReqHandlerOptionsMock} from "../../mocks/request_handler.js"; const testCases = [getTransactionCountCase1]; diff --git a/packages/prover/test/unit/web3_provider.node.test.ts b/packages/prover/test/unit/web3_provider.node.test.ts index d1f281175b56..10f0fee3387d 100644 --- a/packages/prover/test/unit/web3_provider.node.test.ts +++ b/packages/prover/test/unit/web3_provider.node.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect, afterEach, vi} from "vitest"; -import {Web3} from "web3"; import {ethers} from "ethers"; -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 {afterEach, describe, expect, it, vi} from "vitest"; +import {Web3} from "web3"; import {LCTransport, Web3ProviderType} from "../../src/interfaces.js"; +import {ProofProvider} from "../../src/proof_provider/proof_provider.js"; import {JsonRpcRequest, JsonRpcRequestOrBatch, JsonRpcResponse} from "../../src/types.js"; +import {ELRpcProvider} from "../../src/utils/rpc_provider.js"; +import {createVerifiedExecutionProvider} from "../../src/web3_provider.js"; describe("web3_provider", () => { afterEach(() => { diff --git a/packages/prover/test/unit/web3_provider_inspector.test.ts b/packages/prover/test/unit/web3_provider_inspector.test.ts index 95df8a0d760e..53da2c7c8482 100644 --- a/packages/prover/test/unit/web3_provider_inspector.test.ts +++ b/packages/prover/test/unit/web3_provider_inspector.test.ts @@ -1,9 +1,9 @@ -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 {getEnvLogger} from "@lodestar/logger/env"; +import {beforeEach, describe, expect, it} from "vitest"; import {AnyWeb3Provider, Web3ProviderType} from "../../src/interfaces.js"; import web3JsProviderType from "../../src/provider_types/web3_js_provider_type.js"; +import {Web3ProviderInspector} from "../../src/web3_provider_inspector.js"; describe("Web3ProviderInspector", () => { let inspector: Web3ProviderInspector; diff --git a/packages/reqresp/src/ReqResp.ts b/packages/reqresp/src/ReqResp.ts index dc1459d87497..fadf99476156 100644 --- a/packages/reqresp/src/ReqResp.ts +++ b/packages/reqresp/src/ReqResp.ts @@ -1,21 +1,21 @@ import {setMaxListeners} from "node:events"; import {Connection, PeerId, Stream} from "@libp2p/interface"; -import type {Libp2p} from "libp2p"; import {Logger, MetricsRegister} from "@lodestar/utils"; -import {getMetrics, Metrics} from "./metrics.js"; -import {RequestError, RequestErrorCode, sendRequest, SendRequestOpts} from "./request/index.js"; +import type {Libp2p} from "libp2p"; +import {Metrics, getMetrics} from "./metrics.js"; +import {ReqRespRateLimiter} from "./rate_limiter/ReqRespRateLimiter.js"; +import {RequestError, RequestErrorCode, SendRequestOpts, sendRequest} from "./request/index.js"; import {handleRequest} from "./response/index.js"; import { DialOnlyProtocol, Encoding, MixedProtocol, - ReqRespRateLimiterOpts, Protocol, ProtocolDescriptor, + ReqRespRateLimiterOpts, ResponseIncoming, } from "./types.js"; import {formatProtocolID} from "./utils/protocolId.js"; -import {ReqRespRateLimiter} from "./rate_limiter/ReqRespRateLimiter.js"; type ProtocolID = string; diff --git a/packages/reqresp/src/encoders/requestDecode.ts b/packages/reqresp/src/encoders/requestDecode.ts index e91462ab7602..d50f1ee37b5b 100644 --- a/packages/reqresp/src/encoders/requestDecode.ts +++ b/packages/reqresp/src/encoders/requestDecode.ts @@ -1,8 +1,8 @@ import type {Sink} from "it-stream-types"; import {Uint8ArrayList} from "uint8arraylist"; +import {readEncodedPayload} from "../encodingStrategies/index.js"; import {MixedProtocol} from "../types.js"; import {BufferedSource} from "../utils/index.js"; -import {readEncodedPayload} from "../encodingStrategies/index.js"; const EMPTY_DATA = new Uint8Array(); diff --git a/packages/reqresp/src/encoders/requestEncode.ts b/packages/reqresp/src/encoders/requestEncode.ts index 7ea20664bc8b..752924c10118 100644 --- a/packages/reqresp/src/encoders/requestEncode.ts +++ b/packages/reqresp/src/encoders/requestEncode.ts @@ -1,5 +1,5 @@ -import {MixedProtocol} from "../types.js"; import {writeEncodedPayload} from "../encodingStrategies/index.js"; +import {MixedProtocol} from "../types.js"; /** * Yields byte chunks for a `` diff --git a/packages/reqresp/src/encoders/responseDecode.ts b/packages/reqresp/src/encoders/responseDecode.ts index 0dde5bcdc95e..23799037a3d2 100644 --- a/packages/reqresp/src/encoders/responseDecode.ts +++ b/packages/reqresp/src/encoders/responseDecode.ts @@ -1,16 +1,16 @@ -import {Uint8ArrayList} from "uint8arraylist"; import {ForkName} from "@lodestar/params"; -import {BufferedSource, decodeErrorMessage} from "../utils/index.js"; +import {Uint8ArrayList} from "uint8arraylist"; import {readEncodedPayload} from "../encodingStrategies/index.js"; +import {RespStatus} from "../interface.js"; import {ResponseError} from "../response/index.js"; import { - ContextBytesType, CONTEXT_BYTES_FORK_DIGEST_LENGTH, ContextBytesFactory, + ContextBytesType, MixedProtocol, ResponseIncoming, } from "../types.js"; -import {RespStatus} from "../interface.js"; +import {BufferedSource, decodeErrorMessage} from "../utils/index.js"; /** * Internal helper type to signal stream ended early diff --git a/packages/reqresp/src/encoders/responseEncode.ts b/packages/reqresp/src/encoders/responseEncode.ts index c5320ffc1ce9..9a1f9251c008 100644 --- a/packages/reqresp/src/encoders/responseEncode.ts +++ b/packages/reqresp/src/encoders/responseEncode.ts @@ -1,7 +1,7 @@ import {writeEncodedPayload} from "../encodingStrategies/index.js"; -import {encodeErrorMessage} from "../utils/index.js"; -import {ContextBytesType, ContextBytesFactory, MixedProtocol, Protocol, ResponseOutgoing} from "../types.js"; import {RespStatus, RpcResponseStatusError} from "../interface.js"; +import {ContextBytesFactory, ContextBytesType, MixedProtocol, Protocol, ResponseOutgoing} from "../types.js"; +import {encodeErrorMessage} from "../utils/index.js"; const SUCCESS_BUFFER = Buffer.from([RespStatus.SUCCESS]); diff --git a/packages/reqresp/src/encodingStrategies/sszSnappy/decode.ts b/packages/reqresp/src/encodingStrategies/sszSnappy/decode.ts index 9ebe52876cfe..9104104a0aa8 100644 --- a/packages/reqresp/src/encodingStrategies/sszSnappy/decode.ts +++ b/packages/reqresp/src/encodingStrategies/sszSnappy/decode.ts @@ -1,10 +1,10 @@ import {decode as varintDecode, encodingLength as varintEncodingLength} from "uint8-varint"; import {Uint8ArrayList} from "uint8arraylist"; -import {BufferedSource} from "../../utils/index.js"; import {TypeSizes} from "../../types.js"; +import {BufferedSource} from "../../utils/index.js"; +import {SszSnappyError, SszSnappyErrorCode} from "./errors.js"; import {SnappyFramesUncompress} from "./snappyFrames/uncompress.js"; import {maxEncodedLen} from "./utils.js"; -import {SszSnappyError, SszSnappyErrorCode} from "./errors.js"; export const MAX_VARINT_BYTES = 10; diff --git a/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/compress.ts b/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/compress.ts index e1c3887eaa70..98ae4053e90c 100644 --- a/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/compress.ts +++ b/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/compress.ts @@ -1,5 +1,5 @@ -import snappy from "snappy"; import crc32c from "@chainsafe/fast-crc32c"; +import snappy from "snappy"; import {ChunkType, IDENTIFIER_FRAME} from "./common.js"; // The logic in this file is largely copied (in simplified form) from https://github.com/ChainSafe/node-snappy-stream/ diff --git a/packages/reqresp/src/request/errors.ts b/packages/reqresp/src/request/errors.ts index ba3904e563ed..6795d9440a89 100644 --- a/packages/reqresp/src/request/errors.ts +++ b/packages/reqresp/src/request/errors.ts @@ -1,6 +1,6 @@ import {LodestarError, LodestarErrorObject} from "@lodestar/utils"; -import {ResponseError} from "../response/index.js"; import {RespStatus, RpcResponseStatusError} from "../interface.js"; +import {ResponseError} from "../response/index.js"; export enum RequestErrorCode { // Declaring specific values of RpcResponseStatusError for error clarity downstream diff --git a/packages/reqresp/src/request/index.ts b/packages/reqresp/src/request/index.ts index 9a374db3b8be..edd3b25eedbf 100644 --- a/packages/reqresp/src/request/index.ts +++ b/packages/reqresp/src/request/index.ts @@ -1,14 +1,14 @@ -import {pipe} from "it-pipe"; import {PeerId} from "@libp2p/interface"; +import {ErrorAborted, Logger, TimeoutError, withTimeout} from "@lodestar/utils"; +import {pipe} from "it-pipe"; import type {Libp2p} from "libp2p"; import {Uint8ArrayList} from "uint8arraylist"; -import {ErrorAborted, Logger, withTimeout, TimeoutError} from "@lodestar/utils"; -import {MixedProtocol, ResponseIncoming} from "../types.js"; -import {prettyPrintPeerId, abortableSource} from "../utils/index.js"; -import {Metrics} from "../metrics.js"; -import {ResponseError} from "../response/index.js"; import {requestEncode} from "../encoders/requestEncode.js"; import {responseDecode} from "../encoders/responseDecode.js"; +import {Metrics} from "../metrics.js"; +import {ResponseError} from "../response/index.js"; +import {MixedProtocol, ResponseIncoming} from "../types.js"; +import {abortableSource, prettyPrintPeerId} from "../utils/index.js"; import {RequestError, RequestErrorCode, responseStatusErrorToRequestError} from "./errors.js"; export {RequestError, RequestErrorCode}; diff --git a/packages/reqresp/src/response/index.ts b/packages/reqresp/src/response/index.ts index d9f0e1b1806a..265d5418d655 100644 --- a/packages/reqresp/src/response/index.ts +++ b/packages/reqresp/src/response/index.ts @@ -1,15 +1,15 @@ -import {pipe} from "it-pipe"; import {PeerId, Stream} from "@libp2p/interface"; -import {Uint8ArrayList} from "uint8arraylist"; import {Logger, TimeoutError, withTimeout} from "@lodestar/utils"; -import {prettyPrintPeerId} from "../utils/index.js"; -import {Protocol, ReqRespRequest} from "../types.js"; +import {pipe} from "it-pipe"; +import {Uint8ArrayList} from "uint8arraylist"; import {requestDecode} from "../encoders/requestDecode.js"; import {responseEncodeError, responseEncodeSuccess} from "../encoders/responseEncode.js"; import {RespStatus} from "../interface.js"; -import {RequestError, RequestErrorCode} from "../request/errors.js"; -import {ReqRespRateLimiter} from "../rate_limiter/ReqRespRateLimiter.js"; import {Metrics} from "../metrics.js"; +import {ReqRespRateLimiter} from "../rate_limiter/ReqRespRateLimiter.js"; +import {RequestError, RequestErrorCode} from "../request/errors.js"; +import {Protocol, ReqRespRequest} from "../types.js"; +import {prettyPrintPeerId} from "../utils/index.js"; import {ResponseError} from "./errors.js"; export {ResponseError}; diff --git a/packages/reqresp/src/utils/collectExactOne.ts b/packages/reqresp/src/utils/collectExactOne.ts index 962616135cdf..ab1edea6478a 100644 --- a/packages/reqresp/src/utils/collectExactOne.ts +++ b/packages/reqresp/src/utils/collectExactOne.ts @@ -1,4 +1,4 @@ -import {RequestErrorCode, RequestError} from "../request/errors.js"; +import {RequestError, RequestErrorCode} from "../request/errors.js"; /** * Sink for `*`, from diff --git a/packages/reqresp/test/fixtures/encodingStrategies.ts b/packages/reqresp/test/fixtures/encodingStrategies.ts index 7bf183d8714c..58652a4d6b92 100644 --- a/packages/reqresp/test/fixtures/encodingStrategies.ts +++ b/packages/reqresp/test/fixtures/encodingStrategies.ts @@ -1,9 +1,9 @@ import fs from "node:fs"; import path from "node:path"; import {fileURLToPath} from "node:url"; -import {encode as varintEncode} from "uint8-varint"; -import {ssz} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; +import {encode as varintEncode} from "uint8-varint"; import {SszSnappyErrorCode} from "../../src/encodingStrategies/sszSnappy/errors.js"; import {ResponseOutgoing, TypeSizes} from "../../src/types.js"; import { diff --git a/packages/reqresp/test/fixtures/messages.ts b/packages/reqresp/test/fixtures/messages.ts index a243a05b221b..4fa6c69e2865 100644 --- a/packages/reqresp/test/fixtures/messages.ts +++ b/packages/reqresp/test/fixtures/messages.ts @@ -1,8 +1,8 @@ import {fromHexString} from "@chainsafe/ssz"; import {createBeaconConfig} from "@lodestar/config"; import {chainConfig} from "@lodestar/config/default"; -import {ssz} from "@lodestar/types"; import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; import {ResponseIncoming, TypeSizes} from "../../src/types.js"; import {ZERO_HASH} from "../utils/index.js"; diff --git a/packages/reqresp/test/fixtures/protocols.ts b/packages/reqresp/test/fixtures/protocols.ts index 19e8936fc376..0afd6300fb1c 100644 --- a/packages/reqresp/test/fixtures/protocols.ts +++ b/packages/reqresp/test/fixtures/protocols.ts @@ -1,7 +1,7 @@ -import {ContainerType, UintNumberType, ListBasicType, ValueOf} from "@chainsafe/ssz"; -import {ssz} from "@lodestar/types"; +import {ContainerType, ListBasicType, UintNumberType, ValueOf} from "@chainsafe/ssz"; import {ForkName} from "@lodestar/params"; -import {ContextBytesType, DialOnlyProtocol, Encoding, ProtocolHandler, Protocol} from "../../src/types.js"; +import {ssz} from "@lodestar/types"; +import {ContextBytesType, DialOnlyProtocol, Encoding, Protocol, ProtocolHandler} from "../../src/types.js"; import {getEmptyHandler} from "./messages.js"; import {beaconConfig} from "./messages.js"; diff --git a/packages/reqresp/test/unit/ReqResp.test.ts b/packages/reqresp/test/unit/ReqResp.test.ts index 8d78a46f292f..b9e9fe3e9e60 100644 --- a/packages/reqresp/test/unit/ReqResp.test.ts +++ b/packages/reqresp/test/unit/ReqResp.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; -import {Libp2p} from "libp2p"; -import {Logger} from "@lodestar/utils"; import {getEmptyLogger} from "@lodestar/logger/empty"; -import {RespStatus} from "../../src/interface.js"; +import {Logger} from "@lodestar/utils"; +import {Libp2p} from "libp2p"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {ReqResp} from "../../src/ReqResp.js"; +import {RespStatus} from "../../src/interface.js"; import {getEmptyHandler, sszSnappyPing} from "../fixtures/messages.js"; import {numberToStringProtocol, numberToStringProtocolDialOnly, pingProtocol} from "../fixtures/protocols.js"; import {MockLibP2pStream} from "../utils/index.js"; diff --git a/packages/reqresp/test/unit/encoders/reqestEncode.test.ts b/packages/reqresp/test/unit/encoders/reqestEncode.test.ts index 221dc8237e19..8771e26913cd 100644 --- a/packages/reqresp/test/unit/encoders/reqestEncode.test.ts +++ b/packages/reqresp/test/unit/encoders/reqestEncode.test.ts @@ -1,6 +1,6 @@ -import {describe, it} from "vitest"; import all from "it-all"; import {pipe} from "it-pipe"; +import {describe, it} from "vitest"; import {requestEncode} from "../../../src/encoders/requestEncode.js"; import {requestEncodersCases} from "../../fixtures/encoders.js"; import {expectEqualByteChunks} from "../../utils/index.js"; diff --git a/packages/reqresp/test/unit/encoders/requestDecode.test.ts b/packages/reqresp/test/unit/encoders/requestDecode.test.ts index 462bc3bb7378..cd8c7bc303e6 100644 --- a/packages/reqresp/test/unit/encoders/requestDecode.test.ts +++ b/packages/reqresp/test/unit/encoders/requestDecode.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {pipe} from "it-pipe"; +import {describe, expect, it} from "vitest"; import {requestDecode} from "../../../src/encoders/requestDecode.js"; import {requestEncodersCases, requestEncodersErrorCases} from "../../fixtures/encoders.js"; import {expectRejectedWithLodestarError} from "../../utils/errors.js"; diff --git a/packages/reqresp/test/unit/encoders/responseDecode.test.ts b/packages/reqresp/test/unit/encoders/responseDecode.test.ts index 8fc919c46313..9c6cf9a32361 100644 --- a/packages/reqresp/test/unit/encoders/responseDecode.test.ts +++ b/packages/reqresp/test/unit/encoders/responseDecode.test.ts @@ -1,12 +1,12 @@ -import {describe, it, expect} from "vitest"; +import {LodestarError} from "@lodestar/utils"; import all from "it-all"; import {pipe} from "it-pipe"; -import {LodestarError} from "@lodestar/utils"; +import {describe, expect, it} from "vitest"; import {responseDecode} from "../../../src/encoders/responseDecode.js"; +import {ResponseIncoming} from "../../../src/types.js"; import {responseEncodersErrorTestCases, responseEncodersTestCases} from "../../fixtures/encoders.js"; import {expectRejectedWithLodestarError} from "../../utils/errors.js"; import {arrToSource, onlySuccessResp} from "../../utils/index.js"; -import {ResponseIncoming} from "../../../src/types.js"; describe("encoders / responseDecode", () => { describe("valid cases", () => { diff --git a/packages/reqresp/test/unit/encoders/responseEncode.test.ts b/packages/reqresp/test/unit/encoders/responseEncode.test.ts index b9b5f3f8ee11..9580d0b2fcd8 100644 --- a/packages/reqresp/test/unit/encoders/responseEncode.test.ts +++ b/packages/reqresp/test/unit/encoders/responseEncode.test.ts @@ -1,10 +1,10 @@ -import {describe, it} from "vitest"; import all from "it-all"; import {pipe} from "it-pipe"; +import {describe, it} from "vitest"; import {Protocol} from "../../../src/types.js"; import {responseEncodersTestCases} from "../../fixtures/encoders.js"; -import {responseEncode} from "../../utils/response.js"; import {expectEqualByteChunks} from "../../utils/index.js"; +import {responseEncode} from "../../utils/response.js"; describe("encoders / responseEncode", () => { describe("valid cases", () => { diff --git a/packages/reqresp/test/unit/encodingStrategies/sszSnappy/decode.test.ts b/packages/reqresp/test/unit/encodingStrategies/sszSnappy/decode.test.ts index bfa597e42519..f315cc26316b 100644 --- a/packages/reqresp/test/unit/encodingStrategies/sszSnappy/decode.test.ts +++ b/packages/reqresp/test/unit/encodingStrategies/sszSnappy/decode.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {Uint8ArrayList} from "uint8arraylist"; import {encode as varintEncode} from "uint8-varint"; +import {Uint8ArrayList} from "uint8arraylist"; +import {describe, expect, it} from "vitest"; import {readSszSnappyPayload} from "../../../../src/encodingStrategies/sszSnappy/index.js"; import {BufferedSource} from "../../../../src/utils/index.js"; import { diff --git a/packages/reqresp/test/unit/encodingStrategies/sszSnappy/encode.test.ts b/packages/reqresp/test/unit/encodingStrategies/sszSnappy/encode.test.ts index 6ec27d1e6b16..68f5c4e5299d 100644 --- a/packages/reqresp/test/unit/encodingStrategies/sszSnappy/encode.test.ts +++ b/packages/reqresp/test/unit/encodingStrategies/sszSnappy/encode.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; import all from "it-all"; import {pipe} from "it-pipe"; import {encode as varintEncode} from "uint8-varint"; +import {describe, expect, it} from "vitest"; import {writeSszSnappyPayload} from "../../../../src/encodingStrategies/sszSnappy/encode.js"; import {encodingStrategiesMainnetTestCases, encodingStrategiesTestCases} from "../../../fixtures/index.js"; import {expectEqualByteChunks} from "../../../utils/index.js"; diff --git a/packages/reqresp/test/unit/encodingStrategies/sszSnappy/snappyFrames/uncompress.test.ts b/packages/reqresp/test/unit/encodingStrategies/sszSnappy/snappyFrames/uncompress.test.ts index dc01a1952142..66d4f3548b9f 100644 --- a/packages/reqresp/test/unit/encodingStrategies/sszSnappy/snappyFrames/uncompress.test.ts +++ b/packages/reqresp/test/unit/encodingStrategies/sszSnappy/snappyFrames/uncompress.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect} from "vitest"; -import {Uint8ArrayList} from "uint8arraylist"; import {pipe} from "it-pipe"; -import {SnappyFramesUncompress} from "../../../../../src/encodingStrategies/sszSnappy/snappyFrames/uncompress.js"; +import {Uint8ArrayList} from "uint8arraylist"; +import {describe, expect, it} from "vitest"; import {encodeSnappy} from "../../../../../src/encodingStrategies/sszSnappy/snappyFrames/compress.js"; +import {SnappyFramesUncompress} from "../../../../../src/encodingStrategies/sszSnappy/snappyFrames/uncompress.js"; describe("encodingStrategies / sszSnappy / snappy frames / uncompress", () => { it("should work with short input", () => diff --git a/packages/reqresp/test/unit/encodingStrategies/sszSnappy/utils.test.ts b/packages/reqresp/test/unit/encodingStrategies/sszSnappy/utils.test.ts index a494b4acab9a..34e40967bf00 100644 --- a/packages/reqresp/test/unit/encodingStrategies/sszSnappy/utils.test.ts +++ b/packages/reqresp/test/unit/encodingStrategies/sszSnappy/utils.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {maxEncodedLen} from "../../../../src/encodingStrategies/sszSnappy/utils.js"; describe("encodingStrategies / sszSnappy / utils", () => { diff --git a/packages/reqresp/test/unit/rate_limiter/rateLimiterGRCA.test.ts b/packages/reqresp/test/unit/rate_limiter/rateLimiterGRCA.test.ts index a8cbb6e0d3a6..e74eb9a25e0b 100644 --- a/packages/reqresp/test/unit/rate_limiter/rateLimiterGRCA.test.ts +++ b/packages/reqresp/test/unit/rate_limiter/rateLimiterGRCA.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, vi, beforeEach, afterEach} from "vitest"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {RateLimiterGRCA} from "../../../src/rate_limiter/rateLimiterGRCA.js"; describe("rateLimiterGRCA", () => { diff --git a/packages/reqresp/test/unit/request/index.test.ts b/packages/reqresp/test/unit/request/index.test.ts index 888520457bb2..4d9a8bfabbd3 100644 --- a/packages/reqresp/test/unit/request/index.test.ts +++ b/packages/reqresp/test/unit/request/index.test.ts @@ -1,19 +1,19 @@ -import {describe, it, expect, vi, beforeEach, afterEach} from "vitest"; import {PeerId} from "@libp2p/interface"; +import {getEmptyLogger} from "@lodestar/logger/empty"; +import {LodestarError, sleep} from "@lodestar/utils"; import all from "it-all"; import {pipe} from "it-pipe"; import {Libp2p} from "libp2p"; -import {getEmptyLogger} from "@lodestar/logger/empty"; -import {LodestarError, sleep} from "@lodestar/utils"; -import {RequestError, RequestErrorCode, sendRequest, SendRequestOpts} from "../../../src/request/index.js"; -import {Protocol, MixedProtocol, ResponseIncoming} from "../../../src/types.js"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; +import {RespStatus} from "../../../src/interface.js"; +import {RequestError, RequestErrorCode, SendRequestOpts, sendRequest} from "../../../src/request/index.js"; +import {MixedProtocol, Protocol, ResponseIncoming} from "../../../src/types.js"; import {getEmptyHandler, sszSnappyPing} from "../../fixtures/messages.js"; -import {getValidPeerId} from "../../utils/peer.js"; +import {pingProtocol} from "../../fixtures/protocols.js"; +import {expectRejectedWithLodestarError} from "../../utils/errors.js"; import {MockLibP2pStream} from "../../utils/index.js"; +import {getValidPeerId} from "../../utils/peer.js"; import {responseEncode} from "../../utils/response.js"; -import {RespStatus} from "../../../src/interface.js"; -import {expectRejectedWithLodestarError} from "../../utils/errors.js"; -import {pingProtocol} from "../../fixtures/protocols.js"; describe("request / sendRequest", () => { const logger = getEmptyLogger(); diff --git a/packages/reqresp/test/unit/response/index.test.ts b/packages/reqresp/test/unit/response/index.test.ts index 62a8e63f3fe0..4433f44faeeb 100644 --- a/packages/reqresp/test/unit/response/index.test.ts +++ b/packages/reqresp/test/unit/response/index.test.ts @@ -1,15 +1,15 @@ -import {describe, it, expect, beforeEach, afterEach} from "vitest"; import {PeerId} from "@libp2p/interface"; -import {LodestarError, fromHex} from "@lodestar/utils"; import {getEmptyLogger} from "@lodestar/logger/empty"; +import {LodestarError, fromHex} from "@lodestar/utils"; +import {afterEach, beforeEach, describe, expect, it} from "vitest"; import {Protocol, RespStatus} from "../../../src/index.js"; import {ReqRespRateLimiter} from "../../../src/rate_limiter/ReqRespRateLimiter.js"; import {handleRequest} from "../../../src/response/index.js"; import {sszSnappyPing} from "../../fixtures/messages.js"; +import {pingProtocol} from "../../fixtures/protocols.js"; import {expectRejectedWithLodestarError} from "../../utils/errors.js"; import {MockLibP2pStream, expectEqualByteChunks} from "../../utils/index.js"; import {getValidPeerId} from "../../utils/peer.js"; -import {pingProtocol} from "../../fixtures/protocols.js"; const testCases: { id: string; diff --git a/packages/reqresp/test/unit/utils/protocolId.test.ts b/packages/reqresp/test/unit/utils/protocolId.test.ts index 04cd93222045..047c4a0272fa 100644 --- a/packages/reqresp/test/unit/utils/protocolId.test.ts +++ b/packages/reqresp/test/unit/utils/protocolId.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {Encoding, ProtocolAttributes} from "../../../src/index.js"; import {formatProtocolID, parseProtocolID as reqrespParseProtocolID} from "../../../src/utils/index.js"; diff --git a/packages/reqresp/test/utils/errors.ts b/packages/reqresp/test/utils/errors.ts index e4697a6d97d5..b882b1c63e71 100644 --- a/packages/reqresp/test/utils/errors.ts +++ b/packages/reqresp/test/utils/errors.ts @@ -1,5 +1,5 @@ -import {expect} from "vitest"; import {LodestarError, mapValues} from "@lodestar/utils"; +import {expect} from "vitest"; export function expectThrowsLodestarError(fn: () => void, expectedErr: LodestarError | string): void { try { diff --git a/packages/reqresp/test/utils/index.ts b/packages/reqresp/test/utils/index.ts index afddace8328d..77c05c1739a4 100644 --- a/packages/reqresp/test/utils/index.ts +++ b/packages/reqresp/test/utils/index.ts @@ -1,10 +1,10 @@ +import {toHexString} from "@chainsafe/ssz"; import {Direction, ReadStatus, Stream, StreamStatus, WriteStatus} from "@libp2p/interface"; import {logger} from "@libp2p/logger"; -import {expect} from "vitest"; -import {Uint8ArrayList} from "uint8arraylist"; -import {toHexString} from "@chainsafe/ssz"; import {fromHex} from "@lodestar/utils"; -import {ResponseIncoming, RespStatus} from "../../src/index.js"; +import {Uint8ArrayList} from "uint8arraylist"; +import {expect} from "vitest"; +import {RespStatus, ResponseIncoming} from "../../src/index.js"; import {ResponseChunk} from "../fixtures/index.js"; /** diff --git a/packages/spec-test-util/src/downloadTests.ts b/packages/spec-test-util/src/downloadTests.ts index bca6a8ac52c9..53113e716eea 100644 --- a/packages/spec-test-util/src/downloadTests.ts +++ b/packages/spec-test-util/src/downloadTests.ts @@ -3,10 +3,10 @@ import fs from "node:fs"; import path from "node:path"; import stream from "node:stream"; import {promisify} from "node:util"; -import {rimraf} from "rimraf"; +import {retry} from "@lodestar/utils"; import axios from "axios"; +import {rimraf} from "rimraf"; import {x as extractTar} from "tar"; -import {retry} from "@lodestar/utils"; export const defaultSpecTestsRepoUrl = "https://github.com/ethereum/consensus-spec-tests"; diff --git a/packages/spec-test-util/src/single.ts b/packages/spec-test-util/src/single.ts index 888c87e3ffa8..476ac8e1eebf 100644 --- a/packages/spec-test-util/src/single.ts +++ b/packages/spec-test-util/src/single.ts @@ -1,8 +1,8 @@ import fs from "node:fs"; import path from "node:path"; -import {describe, it, vi, expect} from "vitest"; -import {uncompress} from "snappyjs"; import {loadYaml} from "@lodestar/utils"; +import {uncompress} from "snappyjs"; +import {describe, expect, it, vi} from "vitest"; /* eslint-disable @typescript-eslint/no-unsafe-assignment, diff --git a/packages/spec-test-util/src/sszGeneric.ts b/packages/spec-test-util/src/sszGeneric.ts index e932b897a90c..590b97151f17 100644 --- a/packages/spec-test-util/src/sszGeneric.ts +++ b/packages/spec-test-util/src/sszGeneric.ts @@ -1,7 +1,7 @@ -import path from "node:path"; import fs from "node:fs"; -import {uncompress} from "snappyjs"; +import path from "node:path"; import {loadYaml} from "@lodestar/utils"; +import {uncompress} from "snappyjs"; /* eslint-disable @typescript-eslint/explicit-function-return-type */ diff --git a/packages/spec-test-util/test/e2e/single/index.test.ts b/packages/spec-test-util/test/e2e/single/index.test.ts index 2dbefbb9cd22..8e7c90182e7a 100644 --- a/packages/spec-test-util/test/e2e/single/index.test.ts +++ b/packages/spec-test-util/test/e2e/single/index.test.ts @@ -1,10 +1,10 @@ import fs from "node:fs"; import path from "node:path"; import {fileURLToPath} from "node:url"; -import {beforeAll, afterAll} from "vitest"; import {ContainerType, Type} from "@chainsafe/ssz"; import {ssz} from "@lodestar/types"; -import {describeDirectorySpecTest, InputType, loadYamlFile} from "../../../src/single.js"; +import {afterAll, beforeAll} from "vitest"; +import {InputType, describeDirectorySpecTest, loadYamlFile} from "../../../src/single.js"; // Global variable __dirname no longer available in ES6 modules. // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules diff --git a/packages/state-transition/src/block/index.ts b/packages/state-transition/src/block/index.ts index 3857511292c8..8004a2657556 100644 --- a/packages/state-transition/src/block/index.ts +++ b/packages/state-transition/src/block/index.ts @@ -1,15 +1,15 @@ import {ForkSeq} from "@lodestar/params"; import {BeaconBlock, BlindedBeaconBlock, altair, capella} from "@lodestar/types"; +import {CachedBeaconStateAllForks, CachedBeaconStateBellatrix, CachedBeaconStateCapella} from "../types.js"; import {getFullOrBlindedPayload, isExecutionEnabled} from "../util/execution.js"; -import {CachedBeaconStateAllForks, CachedBeaconStateCapella, CachedBeaconStateBellatrix} from "../types.js"; -import {processExecutionPayload} from "./processExecutionPayload.js"; -import {processSyncAggregate} from "./processSyncCommittee.js"; +import {BlockExternalData, DataAvailableStatus} from "./externalData.js"; +import {processBlobKzgCommitments} from "./processBlobKzgCommitments.js"; import {processBlockHeader} from "./processBlockHeader.js"; import {processEth1Data} from "./processEth1Data.js"; +import {processExecutionPayload} from "./processExecutionPayload.js"; import {processOperations} from "./processOperations.js"; import {processRandao} from "./processRandao.js"; -import {processBlobKzgCommitments} from "./processBlobKzgCommitments.js"; -import {BlockExternalData, DataAvailableStatus} from "./externalData.js"; +import {processSyncAggregate} from "./processSyncCommittee.js"; import {processWithdrawals} from "./processWithdrawals.js"; import {ProcessBlockOpts} from "./types.js"; diff --git a/packages/state-transition/src/block/isValidIndexedAttestation.ts b/packages/state-transition/src/block/isValidIndexedAttestation.ts index 8c7502ceedb5..fdb005484733 100644 --- a/packages/state-transition/src/block/isValidIndexedAttestation.ts +++ b/packages/state-transition/src/block/isValidIndexedAttestation.ts @@ -1,8 +1,8 @@ import {ForkSeq, MAX_COMMITTEES_PER_SLOT, MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; import {phase0} from "@lodestar/types"; +import {getIndexedAttestationBigintSignatureSet, getIndexedAttestationSignatureSet} from "../signatureSets/index.js"; import {CachedBeaconStateAllForks} from "../types.js"; import {verifySignatureSet} from "../util/index.js"; -import {getIndexedAttestationBigintSignatureSet, getIndexedAttestationSignatureSet} from "../signatureSets/index.js"; /** * Check if `indexedAttestation` has sorted and unique indices and a valid aggregate signature. diff --git a/packages/state-transition/src/block/processAttestationPhase0.ts b/packages/state-transition/src/block/processAttestationPhase0.ts index e2b32bbbbee8..ab57bd27c80d 100644 --- a/packages/state-transition/src/block/processAttestationPhase0.ts +++ b/packages/state-transition/src/block/processAttestationPhase0.ts @@ -1,9 +1,9 @@ +import {ForkSeq, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {Attestation, Slot, electra, phase0, ssz} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; -import {Slot, Attestation, electra, phase0, ssz} from "@lodestar/types"; -import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH, ForkSeq} from "@lodestar/params"; import {assert} from "@lodestar/utils"; +import {CachedBeaconStateAllForks, CachedBeaconStatePhase0} from "../types.js"; import {computeEpochAtSlot} from "../util/index.js"; -import {CachedBeaconStatePhase0, CachedBeaconStateAllForks} from "../types.js"; import {isValidIndexedAttestation} from "./index.js"; /** diff --git a/packages/state-transition/src/block/processAttestations.ts b/packages/state-transition/src/block/processAttestations.ts index 844bda768570..09b8cd7584f2 100644 --- a/packages/state-transition/src/block/processAttestations.ts +++ b/packages/state-transition/src/block/processAttestations.ts @@ -1,5 +1,5 @@ -import {Attestation} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; +import {Attestation} from "@lodestar/types"; import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../types.js"; import {processAttestationPhase0} from "./processAttestationPhase0.js"; import {processAttestationsAltair} from "./processAttestationsAltair.js"; diff --git a/packages/state-transition/src/block/processAttestationsAltair.ts b/packages/state-transition/src/block/processAttestationsAltair.ts index 046a23d7dc27..0157f4e997a1 100644 --- a/packages/state-transition/src/block/processAttestationsAltair.ts +++ b/packages/state-transition/src/block/processAttestationsAltair.ts @@ -1,8 +1,9 @@ import {byteArrayEquals} from "@chainsafe/ssz"; -import {Epoch, Attestation, phase0} from "@lodestar/types"; +import {Attestation, Epoch, phase0} from "@lodestar/types"; import {intSqrt} from "@lodestar/utils"; import { + ForkSeq, MIN_ATTESTATION_INCLUSION_DELAY, PROPOSER_WEIGHT, SLOTS_PER_EPOCH, @@ -13,12 +14,11 @@ import { TIMELY_TARGET_FLAG_INDEX, TIMELY_TARGET_WEIGHT, WEIGHT_DENOMINATOR, - ForkSeq, } from "@lodestar/params"; -import {increaseBalance, verifySignatureSet} from "../util/index.js"; +import {getAttestationWithIndicesSignatureSet} from "../signatureSets/indexedAttestation.js"; import {CachedBeaconStateAltair} from "../types.js"; +import {increaseBalance, verifySignatureSet} from "../util/index.js"; import {RootCache} from "../util/rootCache.js"; -import {getAttestationWithIndicesSignatureSet} from "../signatureSets/indexedAttestation.js"; import {checkpointToStr, isTimelyTarget, validateAttestation} from "./processAttestationPhase0.js"; const PROPOSER_REWARD_DOMINATOR = ((WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR) / PROPOSER_WEIGHT; diff --git a/packages/state-transition/src/block/processAttesterSlashing.ts b/packages/state-transition/src/block/processAttesterSlashing.ts index 0f635e33fce2..5470082a7c2b 100644 --- a/packages/state-transition/src/block/processAttesterSlashing.ts +++ b/packages/state-transition/src/block/processAttesterSlashing.ts @@ -1,10 +1,10 @@ -import {phase0} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; +import {phase0} from "@lodestar/types"; -import {isSlashableValidator, isSlashableAttestationData, getAttesterSlashableIndices} from "../util/index.js"; import {CachedBeaconStateAllForks} from "../types.js"; -import {slashValidator} from "./slashValidator.js"; +import {getAttesterSlashableIndices, isSlashableAttestationData, isSlashableValidator} from "../util/index.js"; import {isValidIndexedAttestationBigint} from "./isValidIndexedAttestation.js"; +import {slashValidator} from "./slashValidator.js"; /** * Process an AttesterSlashing operation. Initiates the exit of a validator, decreases the balance of the slashed diff --git a/packages/state-transition/src/block/processBlockHeader.ts b/packages/state-transition/src/block/processBlockHeader.ts index da3e389fb507..b4e07ffd5f73 100644 --- a/packages/state-transition/src/block/processBlockHeader.ts +++ b/packages/state-transition/src/block/processBlockHeader.ts @@ -1,8 +1,8 @@ import {byteArrayEquals} from "@chainsafe/ssz"; import {BeaconBlock, BlindedBeaconBlock, ssz} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; -import {CachedBeaconStateAllForks} from "../types.js"; import {ZERO_HASH} from "../constants/index.js"; +import {CachedBeaconStateAllForks} from "../types.js"; import {blindedOrFullBlockToHeader} from "../util/index.js"; /** * Converts a Deposit record (created by the eth-execution deposit contract) into a Validator object that goes into the eth-consensus state. diff --git a/packages/state-transition/src/block/processBlsToExecutionChange.ts b/packages/state-transition/src/block/processBlsToExecutionChange.ts index be79f06f3f21..04be6371fe6d 100644 --- a/packages/state-transition/src/block/processBlsToExecutionChange.ts +++ b/packages/state-transition/src/block/processBlsToExecutionChange.ts @@ -1,7 +1,7 @@ -import {byteArrayEquals} from "@chainsafe/ssz"; import {digest} from "@chainsafe/as-sha256"; -import {capella} from "@lodestar/types"; +import {byteArrayEquals} from "@chainsafe/ssz"; import {BLS_WITHDRAWAL_PREFIX, ETH1_ADDRESS_WITHDRAWAL_PREFIX} from "@lodestar/params"; +import {capella} from "@lodestar/types"; import {toHex} from "@lodestar/utils"; import {verifyBlsToExecutionChangeSignature} from "../signatureSets/index.js"; diff --git a/packages/state-transition/src/block/processConsolidationRequest.ts b/packages/state-transition/src/block/processConsolidationRequest.ts index c14612579c58..d0650135d0c6 100644 --- a/packages/state-transition/src/block/processConsolidationRequest.ts +++ b/packages/state-transition/src/block/processConsolidationRequest.ts @@ -1,11 +1,11 @@ -import {electra, ssz} from "@lodestar/types"; import {FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} from "@lodestar/params"; +import {electra, ssz} from "@lodestar/types"; import {CachedBeaconStateElectra} from "../types.js"; -import {getConsolidationChurnLimit, isActiveValidator} from "../util/validator.js"; +import {hasEth1WithdrawalCredential} from "../util/capella.js"; import {hasExecutionWithdrawalCredential, switchToCompoundingValidator} from "../util/electra.js"; import {computeConsolidationEpochAndUpdateChurn} from "../util/epoch.js"; -import {hasEth1WithdrawalCredential} from "../util/capella.js"; +import {getConsolidationChurnLimit, isActiveValidator} from "../util/validator.js"; // TODO Electra: Clean up necessary as there is a lot of overlap with isValidSwitchToCompoundRequest export function processConsolidationRequest( diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index b7e9827c4cd7..23c5e6c9b26d 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -12,12 +12,12 @@ import { MAX_EFFECTIVE_BALANCE, } from "@lodestar/params"; -import {DepositData} from "@lodestar/types/lib/phase0/types.js"; -import {DepositRequest} from "@lodestar/types/lib/electra/types.js"; import {BeaconConfig} from "@lodestar/config"; +import {DepositRequest} from "@lodestar/types/lib/electra/types.js"; +import {DepositData} from "@lodestar/types/lib/phase0/types.js"; import {ZERO_HASH} from "../constants/index.js"; -import {computeDomain, computeSigningRoot, getMaxEffectiveBalance, increaseBalance} from "../util/index.js"; import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStateElectra} from "../types.js"; +import {computeDomain, computeSigningRoot, getMaxEffectiveBalance, increaseBalance} from "../util/index.js"; /** * Process a Deposit operation. Potentially adds a new validator to the registry. Mutates the validators and balances diff --git a/packages/state-transition/src/block/processDepositRequest.ts b/packages/state-transition/src/block/processDepositRequest.ts index 7c6ea4928f54..8a8b6c08eed8 100644 --- a/packages/state-transition/src/block/processDepositRequest.ts +++ b/packages/state-transition/src/block/processDepositRequest.ts @@ -1,5 +1,5 @@ -import {electra, ssz} from "@lodestar/types"; import {ForkSeq, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; +import {electra, ssz} from "@lodestar/types"; import {CachedBeaconStateElectra} from "../types.js"; diff --git a/packages/state-transition/src/block/processExecutionPayload.ts b/packages/state-transition/src/block/processExecutionPayload.ts index 3d70e46d40fd..3900583956ba 100644 --- a/packages/state-transition/src/block/processExecutionPayload.ts +++ b/packages/state-transition/src/block/processExecutionPayload.ts @@ -1,14 +1,14 @@ import {byteArrayEquals} from "@chainsafe/ssz"; -import {BeaconBlockBody, BlindedBeaconBlockBody, deneb, isExecutionPayload} from "@lodestar/types"; import {ForkSeq, MAX_BLOBS_PER_BLOCK} from "@lodestar/params"; +import {BeaconBlockBody, BlindedBeaconBlockBody, deneb, isExecutionPayload} from "@lodestar/types"; import {toHex, toRootHex} from "@lodestar/utils"; import {CachedBeaconStateBellatrix, CachedBeaconStateCapella} from "../types.js"; -import {getRandaoMix} from "../util/index.js"; import { - isMergeTransitionComplete, - getFullOrBlindedPayloadFromBody, executionPayloadToPayloadHeader, + getFullOrBlindedPayloadFromBody, + isMergeTransitionComplete, } from "../util/execution.js"; +import {getRandaoMix} from "../util/index.js"; import {BlockExternalData, ExecutionPayloadStatus} from "./externalData.js"; export function processExecutionPayload( diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index d611581584c1..165dcd10d4e2 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -1,18 +1,18 @@ -import {BeaconBlockBody, capella, electra} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; +import {BeaconBlockBody, capella, electra} from "@lodestar/types"; import {CachedBeaconStateAllForks, CachedBeaconStateCapella, CachedBeaconStateElectra} from "../types.js"; import {getEth1DepositCount} from "../util/deposit.js"; import {processAttestations} from "./processAttestations.js"; -import {processProposerSlashing} from "./processProposerSlashing.js"; import {processAttesterSlashing} from "./processAttesterSlashing.js"; +import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js"; +import {processConsolidationRequest} from "./processConsolidationRequest.js"; import {processDeposit} from "./processDeposit.js"; +import {processDepositRequest} from "./processDepositRequest.js"; +import {processProposerSlashing} from "./processProposerSlashing.js"; import {processVoluntaryExit} from "./processVoluntaryExit.js"; -import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js"; import {processWithdrawalRequest} from "./processWithdrawalRequest.js"; -import {processDepositRequest} from "./processDepositRequest.js"; import {ProcessBlockOpts} from "./types.js"; -import {processConsolidationRequest} from "./processConsolidationRequest.js"; export { processProposerSlashing, diff --git a/packages/state-transition/src/block/processProposerSlashing.ts b/packages/state-transition/src/block/processProposerSlashing.ts index 70bd37092f98..c65fd567aa24 100644 --- a/packages/state-transition/src/block/processProposerSlashing.ts +++ b/packages/state-transition/src/block/processProposerSlashing.ts @@ -1,9 +1,9 @@ -import {phase0, ssz} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; +import {phase0, ssz} from "@lodestar/types"; +import {getProposerSlashingSignatureSets} from "../signatureSets/index.js"; +import {CachedBeaconStateAllForks} from "../types.js"; import {isSlashableValidator} from "../util/index.js"; import {verifySignatureSet} from "../util/signatureSets.js"; -import {CachedBeaconStateAllForks} from "../types.js"; -import {getProposerSlashingSignatureSets} from "../signatureSets/index.js"; import {slashValidator} from "./slashValidator.js"; /** diff --git a/packages/state-transition/src/block/processRandao.ts b/packages/state-transition/src/block/processRandao.ts index 65bcd60f52f6..b32ec43b6768 100644 --- a/packages/state-transition/src/block/processRandao.ts +++ b/packages/state-transition/src/block/processRandao.ts @@ -1,9 +1,9 @@ import {digest} from "@chainsafe/as-sha256"; -import {BeaconBlock} from "@lodestar/types"; import {EPOCHS_PER_HISTORICAL_VECTOR} from "@lodestar/params"; -import {getRandaoMix} from "../util/index.js"; +import {BeaconBlock} from "@lodestar/types"; import {verifyRandaoSignature} from "../signatureSets/index.js"; import {CachedBeaconStateAllForks} from "../types.js"; +import {getRandaoMix} from "../util/index.js"; /** * Commit a randao reveal to generate pseudorandomness seeds diff --git a/packages/state-transition/src/block/processSyncCommittee.ts b/packages/state-transition/src/block/processSyncCommittee.ts index 5f81a984b677..eaa98ac72a8d 100644 --- a/packages/state-transition/src/block/processSyncCommittee.ts +++ b/packages/state-transition/src/block/processSyncCommittee.ts @@ -1,9 +1,9 @@ import {byteArrayEquals} from "@chainsafe/ssz"; -import {altair, ssz} from "@lodestar/types"; import {DOMAIN_SYNC_COMMITTEE, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; -import {computeSigningRoot, ISignatureSet, SignatureSetType, verifySignatureSet} from "../util/index.js"; -import {CachedBeaconStateAllForks} from "../types.js"; +import {altair, ssz} from "@lodestar/types"; import {G2_POINT_AT_INFINITY} from "../constants/index.js"; +import {CachedBeaconStateAllForks} from "../types.js"; +import {ISignatureSet, SignatureSetType, computeSigningRoot, verifySignatureSet} from "../util/index.js"; import {decreaseBalance, increaseBalance} from "../util/index.js"; export function processSyncAggregate( diff --git a/packages/state-transition/src/block/processVoluntaryExit.ts b/packages/state-transition/src/block/processVoluntaryExit.ts index b08aa7800884..a0a0271a0d1e 100644 --- a/packages/state-transition/src/block/processVoluntaryExit.ts +++ b/packages/state-transition/src/block/processVoluntaryExit.ts @@ -1,8 +1,8 @@ import {FAR_FUTURE_EPOCH, ForkSeq} from "@lodestar/params"; import {phase0} from "@lodestar/types"; -import {getPendingBalanceToWithdraw, isActiveValidator} from "../util/index.js"; -import {CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; import {verifyVoluntaryExitSignature} from "../signatureSets/index.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; +import {getPendingBalanceToWithdraw, isActiveValidator} from "../util/index.js"; import {initiateValidatorExit} from "./index.js"; /** diff --git a/packages/state-transition/src/block/processWithdrawalRequest.ts b/packages/state-transition/src/block/processWithdrawalRequest.ts index e8a64ec63e41..573c0a49dfc8 100644 --- a/packages/state-transition/src/block/processWithdrawalRequest.ts +++ b/packages/state-transition/src/block/processWithdrawalRequest.ts @@ -1,17 +1,17 @@ -import {electra, phase0, ssz} from "@lodestar/types"; import { FAR_FUTURE_EPOCH, - MIN_ACTIVATION_BALANCE, - PENDING_PARTIAL_WITHDRAWALS_LIMIT, FULL_EXIT_REQUEST_AMOUNT, ForkSeq, + MIN_ACTIVATION_BALANCE, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, } from "@lodestar/params"; +import {electra, phase0, ssz} from "@lodestar/types"; import {toHex} from "@lodestar/utils"; import {CachedBeaconStateElectra} from "../types.js"; import {hasCompoundingWithdrawalCredential, hasExecutionWithdrawalCredential} from "../util/electra.js"; -import {getPendingBalanceToWithdraw, isActiveValidator} from "../util/validator.js"; import {computeExitEpochAndUpdateChurn} from "../util/epoch.js"; +import {getPendingBalanceToWithdraw, isActiveValidator} from "../util/validator.js"; import {initiateValidatorExit} from "./initiateValidatorExit.js"; export function processWithdrawalRequest( diff --git a/packages/state-transition/src/block/processWithdrawals.ts b/packages/state-transition/src/block/processWithdrawals.ts index 610a2ed62b41..ab1df570eb30 100644 --- a/packages/state-transition/src/block/processWithdrawals.ts +++ b/packages/state-transition/src/block/processWithdrawals.ts @@ -1,14 +1,14 @@ import {byteArrayEquals} from "@chainsafe/ssz"; -import {ssz, capella} from "@lodestar/types"; import { - MAX_WITHDRAWALS_PER_PAYLOAD, - MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP, + FAR_FUTURE_EPOCH, ForkSeq, + MAX_EFFECTIVE_BALANCE, MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP, - FAR_FUTURE_EPOCH, + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP, + MAX_WITHDRAWALS_PER_PAYLOAD, MIN_ACTIVATION_BALANCE, - MAX_EFFECTIVE_BALANCE, } from "@lodestar/params"; +import {capella, ssz} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {CachedBeaconStateCapella, CachedBeaconStateElectra} from "../types.js"; diff --git a/packages/state-transition/src/block/slashValidator.ts b/packages/state-transition/src/block/slashValidator.ts index c4b7d5f848ea..2e1decec1e99 100644 --- a/packages/state-transition/src/block/slashValidator.ts +++ b/packages/state-transition/src/block/slashValidator.ts @@ -1,4 +1,3 @@ -import {ValidatorIndex} from "@lodestar/types"; import { EFFECTIVE_BALANCE_INCREMENT, EPOCHS_PER_SLASHINGS_VECTOR, @@ -14,9 +13,10 @@ import { WHISTLEBLOWER_REWARD_QUOTIENT, WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA, } from "@lodestar/params"; +import {ValidatorIndex} from "@lodestar/types"; -import {decreaseBalance, increaseBalance} from "../util/index.js"; import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; +import {decreaseBalance, increaseBalance} from "../util/index.js"; import {initiateValidatorExit} from "./initiateValidatorExit.js"; /** Same to https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/beacon-chain.md#has_flag */ diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 66ce12b82d18..207267dff4f4 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -1,20 +1,6 @@ import {PublicKey} from "@chainsafe/blst"; -import * as immutable from "immutable"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; -import { - BLSSignature, - CommitteeIndex, - Epoch, - Slot, - ValidatorIndex, - phase0, - RootHex, - SyncPeriod, - Attestation, - IndexedAttestation, - electra, -} from "@lodestar/types"; -import {createBeaconConfig, BeaconConfig, ChainConfig} from "@lodestar/config"; +import {BeaconConfig, ChainConfig, createBeaconConfig} from "@lodestar/config"; import { ATTESTATION_SUBNET_COUNT, DOMAIN_BEACON_PROPOSER, @@ -26,47 +12,61 @@ import { SLOTS_PER_EPOCH, WEIGHT_DENOMINATOR, } from "@lodestar/params"; +import { + Attestation, + BLSSignature, + CommitteeIndex, + Epoch, + IndexedAttestation, + RootHex, + Slot, + SyncPeriod, + ValidatorIndex, + electra, + phase0, +} from "@lodestar/types"; import {LodestarError, fromHex} from "@lodestar/utils"; +import * as immutable from "immutable"; +import {getTotalSlashingsByIncrement} from "../epoch/processSlashings.js"; +import {EpochCacheMetrics} from "../metrics.js"; +import {AttesterDuty, calculateCommitteeAssignments} from "../util/calculateCommitteeAssignments.js"; +import { + EpochShuffling, + IShufflingCache, + calculateShufflingDecisionRoot, + computeEpochShuffling, +} from "../util/epochShuffling.js"; import { computeActivationExitEpoch, computeEpochAtSlot, + computeProposers, computeStartSlotAtEpoch, + computeSyncPeriodAtEpoch, + getActivationChurnLimit, getChurnLimit, + getSeed, isActiveValidator, isAggregatorFromCommitteeLength, - computeSyncPeriodAtEpoch, - getSeed, - computeProposers, - getActivationChurnLimit, } from "../util/index.js"; -import { - computeEpochShuffling, - EpochShuffling, - calculateShufflingDecisionRoot, - IShufflingCache, -} from "../util/epochShuffling.js"; import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; -import {getTotalSlashingsByIncrement} from "../epoch/processSlashings.js"; -import {AttesterDuty, calculateCommitteeAssignments} from "../util/calculateCommitteeAssignments.js"; -import {EpochCacheMetrics} from "../metrics.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; -import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; import { Index2PubkeyCache, + PubkeyHex, UnfinalizedPubkeyIndexMap, + newUnfinalizedPubkeyIndexMap, syncPubkeys, toMemoryEfficientHexStr, - PubkeyHex, - newUnfinalizedPubkeyIndexMap, } from "./pubkeyCache.js"; +import {CachedBeaconStateAllForks} from "./stateCache.js"; import { - computeSyncCommitteeCache, - getSyncCommitteeCache, SyncCommitteeCache, SyncCommitteeCacheEmpty, + computeSyncCommitteeCache, + getSyncCommitteeCache, } from "./syncCommitteeCache.js"; -import {CachedBeaconStateAllForks} from "./stateCache.js"; +import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; /** `= PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT)` */ export const PROPOSER_WEIGHT_FACTOR = PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT); diff --git a/packages/state-transition/src/cache/epochTransitionCache.ts b/packages/state-transition/src/cache/epochTransitionCache.ts index 2a35317fbc93..d86431c72eee 100644 --- a/packages/state-transition/src/cache/epochTransitionCache.ts +++ b/packages/state-transition/src/cache/epochTransitionCache.ts @@ -1,27 +1,27 @@ -import {phase0, Epoch, RootHex, ValidatorIndex} from "@lodestar/types"; -import {intDiv, toRootHex} from "@lodestar/utils"; import { EPOCHS_PER_SLASHINGS_VECTOR, FAR_FUTURE_EPOCH, ForkSeq, - SLOTS_PER_HISTORICAL_ROOT, MIN_ACTIVATION_BALANCE, + SLOTS_PER_HISTORICAL_ROOT, } from "@lodestar/params"; +import {Epoch, RootHex, ValidatorIndex, phase0} from "@lodestar/types"; +import {intDiv, toRootHex} from "@lodestar/utils"; +import {processPendingAttestations} from "../epoch/processPendingAttestations.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../index.js"; +import {computeBaseRewardPerIncrement} from "../util/altair.js"; import { - hasMarkers, - FLAG_UNSLASHED, + FLAG_CURR_HEAD_ATTESTER, + FLAG_CURR_SOURCE_ATTESTER, + FLAG_CURR_TARGET_ATTESTER, FLAG_ELIGIBLE_ATTESTER, + FLAG_PREV_HEAD_ATTESTER, FLAG_PREV_SOURCE_ATTESTER, FLAG_PREV_TARGET_ATTESTER, - FLAG_PREV_HEAD_ATTESTER, - FLAG_CURR_SOURCE_ATTESTER, - FLAG_CURR_TARGET_ATTESTER, - FLAG_CURR_HEAD_ATTESTER, + FLAG_UNSLASHED, + hasMarkers, } from "../util/attesterStatus.js"; -import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../index.js"; -import {computeBaseRewardPerIncrement} from "../util/altair.js"; -import {processPendingAttestations} from "../epoch/processPendingAttestations.js"; export type EpochTransitionCacheOpts = { /** diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index f96436ec14f4..16c8f3de6787 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -1,7 +1,7 @@ import {PublicKey} from "@chainsafe/blst"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; -import * as immutable from "immutable"; import {ValidatorIndex, phase0} from "@lodestar/types"; +import * as immutable from "immutable"; export type Index2PubkeyCache = PublicKey[]; /** diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 3eeeb285b660..6690f8f5c3db 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -2,17 +2,17 @@ import {PublicKey} from "@chainsafe/blst"; import {BeaconConfig} from "@lodestar/config"; import {loadState} from "../util/loadState/loadState.js"; import {EpochCache, EpochCacheImmutableData, EpochCacheOpts} from "./epochCache.js"; +import {RewardCache, createEmptyRewardCache} from "./rewardCache.js"; import { BeaconStateAllForks, - BeaconStateExecutions, - BeaconStatePhase0, BeaconStateAltair, BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, BeaconStateElectra, + BeaconStateExecutions, + BeaconStatePhase0, } from "./types.js"; -import {RewardCache, createEmptyRewardCache} from "./rewardCache.js"; export type BeaconStateCache = { config: BeaconConfig; diff --git a/packages/state-transition/src/cache/syncCommitteeCache.ts b/packages/state-transition/src/cache/syncCommitteeCache.ts index b9a65302c3e2..3f79a45f3573 100644 --- a/packages/state-transition/src/cache/syncCommitteeCache.ts +++ b/packages/state-transition/src/cache/syncCommitteeCache.ts @@ -1,6 +1,6 @@ -import {CompositeViewDU} from "@chainsafe/ssz"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; -import {ssz, ValidatorIndex} from "@lodestar/types"; +import {CompositeViewDU} from "@chainsafe/ssz"; +import {ValidatorIndex, ssz} from "@lodestar/types"; import {toPubkeyHex} from "@lodestar/utils"; type SyncComitteeValidatorIndexMap = Map; diff --git a/packages/state-transition/src/cache/types.ts b/packages/state-transition/src/cache/types.ts index b3fe6fc8ed5b..625e47270782 100644 --- a/packages/state-transition/src/cache/types.ts +++ b/packages/state-transition/src/cache/types.ts @@ -1,6 +1,6 @@ import {CompositeViewDU} from "@chainsafe/ssz"; -import {Epoch, RootHex, SSZTypesFor} from "@lodestar/types"; import {ForkAll, ForkExecution, ForkName} from "@lodestar/params"; +import {Epoch, RootHex, SSZTypesFor} from "@lodestar/types"; import {EpochShuffling} from "../util/epochShuffling.js"; export type BeaconStatePhase0 = CompositeViewDU>; diff --git a/packages/state-transition/src/epoch/computeUnrealizedCheckpoints.ts b/packages/state-transition/src/epoch/computeUnrealizedCheckpoints.ts index 3baed0f42cbe..d93b4e4f6d10 100644 --- a/packages/state-transition/src/epoch/computeUnrealizedCheckpoints.ts +++ b/packages/state-transition/src/epoch/computeUnrealizedCheckpoints.ts @@ -1,10 +1,10 @@ import {ForkSeq, GENESIS_EPOCH} from "@lodestar/params"; import {phase0} from "@lodestar/types"; -import {CachedBeaconStateAllForks} from "../types.js"; import {beforeProcessEpoch} from "../cache/epochTransitionCache.js"; +import {CachedBeaconStateAllForks} from "../types.js"; import { - weighJustificationAndFinalization, processJustificationAndFinalization, + weighJustificationAndFinalization, } from "./processJustificationAndFinalization.js"; /** diff --git a/packages/state-transition/src/epoch/getAttestationDeltas.ts b/packages/state-transition/src/epoch/getAttestationDeltas.ts index dd69738a55b5..d9172fd69702 100644 --- a/packages/state-transition/src/epoch/getAttestationDeltas.ts +++ b/packages/state-transition/src/epoch/getAttestationDeltas.ts @@ -1,4 +1,3 @@ -import {bigIntSqrt, bnToNum} from "@lodestar/utils"; import { BASE_REWARD_FACTOR, EFFECTIVE_BALANCE_INCREMENT, @@ -6,10 +5,11 @@ import { MIN_EPOCHS_TO_INACTIVITY_PENALTY, PROPOSER_REWARD_QUOTIENT, } from "@lodestar/params"; +import {bigIntSqrt, bnToNum} from "@lodestar/utils"; import {BASE_REWARDS_PER_EPOCH as BASE_REWARDS_PER_EPOCH_CONST} from "../constants/index.js"; -import {newZeroedArray} from "../util/index.js"; -import {EpochTransitionCache, CachedBeaconStatePhase0} from "../types.js"; +import {CachedBeaconStatePhase0, EpochTransitionCache} from "../types.js"; import {hasMarkers} from "../util/attesterStatus.js"; +import {newZeroedArray} from "../util/index.js"; /** * Redefine constants in attesterStatus to improve performance diff --git a/packages/state-transition/src/epoch/getRewardsAndPenalties.ts b/packages/state-transition/src/epoch/getRewardsAndPenalties.ts index bf766fe4666a..c7619873c202 100644 --- a/packages/state-transition/src/epoch/getRewardsAndPenalties.ts +++ b/packages/state-transition/src/epoch/getRewardsAndPenalties.ts @@ -1,5 +1,6 @@ import { EFFECTIVE_BALANCE_INCREMENT, + ForkSeq, INACTIVITY_PENALTY_QUOTIENT_ALTAIR, INACTIVITY_PENALTY_QUOTIENT_BELLATRIX, PARTICIPATION_FLAG_WEIGHTS, @@ -7,7 +8,6 @@ import { TIMELY_SOURCE_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX, WEIGHT_DENOMINATOR, - ForkSeq, } from "@lodestar/params"; import {CachedBeaconStateAltair, EpochTransitionCache} from "../types.js"; import { diff --git a/packages/state-transition/src/epoch/index.ts b/packages/state-transition/src/epoch/index.ts index b0b1651321d5..50118f5d4949 100644 --- a/packages/state-transition/src/epoch/index.ts +++ b/packages/state-transition/src/epoch/index.ts @@ -5,15 +5,15 @@ import { MAX_VALIDATORS_PER_COMMITTEE, SLOTS_PER_EPOCH, } from "@lodestar/params"; +import {BeaconStateTransitionMetrics} from "../metrics.js"; import { CachedBeaconStateAllForks, - CachedBeaconStateCapella, CachedBeaconStateAltair, + CachedBeaconStateCapella, + CachedBeaconStateElectra, CachedBeaconStatePhase0, EpochTransitionCache, - CachedBeaconStateElectra, } from "../types.js"; -import {BeaconStateTransitionMetrics} from "../metrics.js"; import {processEffectiveBalanceUpdates} from "./processEffectiveBalanceUpdates.js"; import {processEth1DataReset} from "./processEth1DataReset.js"; import {processHistoricalRootsUpdate} from "./processHistoricalRootsUpdate.js"; @@ -22,14 +22,14 @@ import {processInactivityUpdates} from "./processInactivityUpdates.js"; import {processJustificationAndFinalization} from "./processJustificationAndFinalization.js"; import {processParticipationFlagUpdates} from "./processParticipationFlagUpdates.js"; import {processParticipationRecordUpdates} from "./processParticipationRecordUpdates.js"; +import {processPendingConsolidations} from "./processPendingConsolidations.js"; +import {processPendingDeposits} from "./processPendingDeposits.js"; import {processRandaoMixesReset} from "./processRandaoMixesReset.js"; import {processRegistryUpdates} from "./processRegistryUpdates.js"; import {processRewardsAndPenalties} from "./processRewardsAndPenalties.js"; import {processSlashings} from "./processSlashings.js"; import {processSlashingsReset} from "./processSlashingsReset.js"; import {processSyncCommitteeUpdates} from "./processSyncCommitteeUpdates.js"; -import {processPendingDeposits} from "./processPendingDeposits.js"; -import {processPendingConsolidations} from "./processPendingConsolidations.js"; // For spec tests export {getRewardsAndPenalties} from "./processRewardsAndPenalties.js"; diff --git a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts index 1fe5c92eea1a..d55f37aba178 100644 --- a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts +++ b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts @@ -7,7 +7,7 @@ import { MAX_EFFECTIVE_BALANCE, TIMELY_TARGET_FLAG_INDEX, } from "@lodestar/params"; -import {EpochTransitionCache, CachedBeaconStateAllForks, BeaconStateAltair} from "../types.js"; +import {BeaconStateAltair, CachedBeaconStateAllForks, EpochTransitionCache} from "../types.js"; import {getMaxEffectiveBalance} from "../util/validator.js"; /** Same to https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/beacon-chain.md#has_flag */ diff --git a/packages/state-transition/src/epoch/processEth1DataReset.ts b/packages/state-transition/src/epoch/processEth1DataReset.ts index a16f865fdc07..d783389e2f24 100644 --- a/packages/state-transition/src/epoch/processEth1DataReset.ts +++ b/packages/state-transition/src/epoch/processEth1DataReset.ts @@ -1,6 +1,6 @@ import {EPOCHS_PER_ETH1_VOTING_PERIOD} from "@lodestar/params"; import {ssz} from "@lodestar/types"; -import {EpochTransitionCache, CachedBeaconStateAllForks} from "../types.js"; +import {CachedBeaconStateAllForks, EpochTransitionCache} from "../types.js"; /** * Reset eth1DataVotes tree every `EPOCHS_PER_ETH1_VOTING_PERIOD`. diff --git a/packages/state-transition/src/epoch/processHistoricalRootsUpdate.ts b/packages/state-transition/src/epoch/processHistoricalRootsUpdate.ts index e649e1c9678b..a396738fc840 100644 --- a/packages/state-transition/src/epoch/processHistoricalRootsUpdate.ts +++ b/packages/state-transition/src/epoch/processHistoricalRootsUpdate.ts @@ -1,7 +1,7 @@ import {SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; import {ssz} from "@lodestar/types"; import {intDiv} from "@lodestar/utils"; -import {EpochTransitionCache, CachedBeaconStateAllForks} from "../types.js"; +import {CachedBeaconStateAllForks, EpochTransitionCache} from "../types.js"; /** * Persist blockRoots and stateRoots to historicalRoots. diff --git a/packages/state-transition/src/epoch/processHistoricalSummariesUpdate.ts b/packages/state-transition/src/epoch/processHistoricalSummariesUpdate.ts index 17da010dfa91..38bdc591ef32 100644 --- a/packages/state-transition/src/epoch/processHistoricalSummariesUpdate.ts +++ b/packages/state-transition/src/epoch/processHistoricalSummariesUpdate.ts @@ -1,7 +1,7 @@ import {SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; import {ssz} from "@lodestar/types"; import {intDiv} from "@lodestar/utils"; -import {EpochTransitionCache, CachedBeaconStateCapella} from "../types.js"; +import {CachedBeaconStateCapella, EpochTransitionCache} from "../types.js"; /** * Persist blockRoots and stateRoots to historicalSummaries. diff --git a/packages/state-transition/src/epoch/processJustificationAndFinalization.ts b/packages/state-transition/src/epoch/processJustificationAndFinalization.ts index 8526b7f3a749..845a98337be7 100644 --- a/packages/state-transition/src/epoch/processJustificationAndFinalization.ts +++ b/packages/state-transition/src/epoch/processJustificationAndFinalization.ts @@ -1,8 +1,8 @@ import {BitArray} from "@chainsafe/ssz"; import {GENESIS_EPOCH} from "@lodestar/params"; import {ssz} from "@lodestar/types"; -import {computeEpochAtSlot, getBlockRoot} from "../util/index.js"; import {CachedBeaconStateAllForks, EpochTransitionCache} from "../types.js"; +import {computeEpochAtSlot, getBlockRoot} from "../util/index.js"; /** * Update justified and finalized checkpoints depending on network participation. diff --git a/packages/state-transition/src/epoch/processPendingDeposits.ts b/packages/state-transition/src/epoch/processPendingDeposits.ts index 53af3ab38763..866dcc2510ad 100644 --- a/packages/state-transition/src/epoch/processPendingDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingDeposits.ts @@ -1,10 +1,10 @@ import {FAR_FUTURE_EPOCH, ForkSeq, GENESIS_SLOT, MAX_PENDING_DEPOSITS_PER_EPOCH} from "@lodestar/params"; import {PendingDeposit} from "@lodestar/types/lib/electra/types.js"; +import {addValidatorToRegistry, isValidDepositSignature} from "../block/processDeposit.js"; import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; import {increaseBalance} from "../util/balance.js"; -import {getActivationExitChurnLimit} from "../util/validator.js"; import {computeStartSlotAtEpoch} from "../util/epoch.js"; -import {addValidatorToRegistry, isValidDepositSignature} from "../block/processDeposit.js"; +import {getActivationExitChurnLimit} from "../util/validator.js"; /** * Starting from Electra: diff --git a/packages/state-transition/src/epoch/processRandaoMixesReset.ts b/packages/state-transition/src/epoch/processRandaoMixesReset.ts index afb45ba39d19..d50ae1261778 100644 --- a/packages/state-transition/src/epoch/processRandaoMixesReset.ts +++ b/packages/state-transition/src/epoch/processRandaoMixesReset.ts @@ -1,5 +1,5 @@ import {EPOCHS_PER_HISTORICAL_VECTOR} from "@lodestar/params"; -import {EpochTransitionCache, CachedBeaconStateAllForks} from "../types.js"; +import {CachedBeaconStateAllForks, EpochTransitionCache} from "../types.js"; /** * Write next randaoMix diff --git a/packages/state-transition/src/epoch/processRegistryUpdates.ts b/packages/state-transition/src/epoch/processRegistryUpdates.ts index d2e93632dabe..05b3b2c8f9ed 100644 --- a/packages/state-transition/src/epoch/processRegistryUpdates.ts +++ b/packages/state-transition/src/epoch/processRegistryUpdates.ts @@ -1,7 +1,7 @@ import {ForkSeq} from "@lodestar/params"; -import {computeActivationExitEpoch} from "../util/index.js"; import {initiateValidatorExit} from "../block/index.js"; -import {EpochTransitionCache, CachedBeaconStateAllForks} from "../types.js"; +import {CachedBeaconStateAllForks, EpochTransitionCache} from "../types.js"; +import {computeActivationExitEpoch} from "../util/index.js"; /** * Update validator registry for validators that activate + exit diff --git a/packages/state-transition/src/epoch/processSlashings.ts b/packages/state-transition/src/epoch/processSlashings.ts index 23ee815cabb3..09b93b21042d 100644 --- a/packages/state-transition/src/epoch/processSlashings.ts +++ b/packages/state-transition/src/epoch/processSlashings.ts @@ -6,8 +6,8 @@ import { PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX, } from "@lodestar/params"; -import {decreaseBalance} from "../util/index.js"; import {BeaconStateAllForks, CachedBeaconStateAllForks, EpochTransitionCache} from "../types.js"; +import {decreaseBalance} from "../util/index.js"; /** * Update validator registry for validators that activate + exit diff --git a/packages/state-transition/src/epoch/processSlashingsReset.ts b/packages/state-transition/src/epoch/processSlashingsReset.ts index 6ab22d47526c..68857b266db7 100644 --- a/packages/state-transition/src/epoch/processSlashingsReset.ts +++ b/packages/state-transition/src/epoch/processSlashingsReset.ts @@ -1,5 +1,5 @@ import {EFFECTIVE_BALANCE_INCREMENT, EPOCHS_PER_SLASHINGS_VECTOR} from "@lodestar/params"; -import {EpochTransitionCache, CachedBeaconStateAllForks} from "../types.js"; +import {CachedBeaconStateAllForks, EpochTransitionCache} from "../types.js"; /** * Reset the next slashings balance accumulator diff --git a/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts b/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts index f01f2055420a..4d8106328958 100644 --- a/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts +++ b/packages/state-transition/src/epoch/processSyncCommitteeUpdates.ts @@ -1,8 +1,8 @@ import {aggregateSerializedPublicKeys} from "@chainsafe/blst"; import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, ForkSeq} from "@lodestar/params"; import {ssz} from "@lodestar/types"; -import {getNextSyncCommitteeIndices} from "../util/seed.js"; import {CachedBeaconStateAltair} from "../types.js"; +import {getNextSyncCommitteeIndices} from "../util/seed.js"; /** * Rotate nextSyncCommittee to currentSyncCommittee if sync committee period is over. diff --git a/packages/state-transition/src/metrics.ts b/packages/state-transition/src/metrics.ts index ac558a1be139..fee20de1d565 100644 --- a/packages/state-transition/src/metrics.ts +++ b/packages/state-transition/src/metrics.ts @@ -1,8 +1,8 @@ import {Epoch} from "@lodestar/types"; import {Gauge, Histogram} from "@lodestar/utils"; -import {CachedBeaconStateAllForks} from "./types.js"; -import {StateCloneSource, StateHashTreeRootSource} from "./stateTransition.js"; import {EpochTransitionStep} from "./epoch/index.js"; +import {StateCloneSource, StateHashTreeRootSource} from "./stateTransition.js"; +import {CachedBeaconStateAllForks} from "./types.js"; export type BeaconStateTransitionMetrics = { epochTransitionTime: Histogram; diff --git a/packages/state-transition/src/signatureSets/attesterSlashings.ts b/packages/state-transition/src/signatureSets/attesterSlashings.ts index 36f31d97e083..b053bb497805 100644 --- a/packages/state-transition/src/signatureSets/attesterSlashings.ts +++ b/packages/state-transition/src/signatureSets/attesterSlashings.ts @@ -1,7 +1,7 @@ -import {SignedBeaconBlock, ssz, AttesterSlashing, IndexedAttestationBigint} from "@lodestar/types"; import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; -import {computeSigningRoot, computeStartSlotAtEpoch, ISignatureSet, SignatureSetType} from "../util/index.js"; +import {AttesterSlashing, IndexedAttestationBigint, SignedBeaconBlock, ssz} from "@lodestar/types"; import {CachedBeaconStateAllForks} from "../types.js"; +import {ISignatureSet, SignatureSetType, computeSigningRoot, computeStartSlotAtEpoch} from "../util/index.js"; /** Get signature sets from all AttesterSlashing objects in a block */ export function getAttesterSlashingsSignatureSets( diff --git a/packages/state-transition/src/signatureSets/blsToExecutionChange.ts b/packages/state-transition/src/signatureSets/blsToExecutionChange.ts index 672ad546dfc8..22a5826c4a3a 100644 --- a/packages/state-transition/src/signatureSets/blsToExecutionChange.ts +++ b/packages/state-transition/src/signatureSets/blsToExecutionChange.ts @@ -1,10 +1,10 @@ import {PublicKey} from "@chainsafe/blst"; +import {BeaconConfig} from "@lodestar/config"; import {DOMAIN_BLS_TO_EXECUTION_CHANGE, ForkName} from "@lodestar/params"; import {capella, ssz} from "@lodestar/types"; -import {BeaconConfig} from "@lodestar/config"; -import {computeSigningRoot, ISignatureSet, SignatureSetType, verifySignatureSet} from "../util/index.js"; import {CachedBeaconStateAllForks} from "../types.js"; +import {ISignatureSet, SignatureSetType, computeSigningRoot, verifySignatureSet} from "../util/index.js"; export function verifyBlsToExecutionChangeSignature( state: CachedBeaconStateAllForks, diff --git a/packages/state-transition/src/signatureSets/index.ts b/packages/state-transition/src/signatureSets/index.ts index c883bb0587f8..ac10abef6b34 100644 --- a/packages/state-transition/src/signatureSets/index.ts +++ b/packages/state-transition/src/signatureSets/index.ts @@ -1,15 +1,15 @@ import {ForkSeq} from "@lodestar/params"; import {SignedBeaconBlock, altair, capella} from "@lodestar/types"; -import {ISignatureSet} from "../util/index.js"; -import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; import {getSyncCommitteeSignatureSet} from "../block/processSyncCommittee.js"; -import {getProposerSlashingsSignatureSets} from "./proposerSlashings.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; +import {ISignatureSet} from "../util/index.js"; import {getAttesterSlashingsSignatureSets} from "./attesterSlashings.js"; +import {getBlsToExecutionChangeSignatureSets} from "./blsToExecutionChange.js"; import {getAttestationsSignatureSets} from "./indexedAttestation.js"; import {getBlockProposerSignatureSet} from "./proposer.js"; +import {getProposerSlashingsSignatureSets} from "./proposerSlashings.js"; import {getRandaoRevealSignatureSet} from "./randao.js"; import {getVoluntaryExitsSignatureSets} from "./voluntaryExits.js"; -import {getBlsToExecutionChangeSignatureSets} from "./blsToExecutionChange.js"; export * from "./attesterSlashings.js"; export * from "./indexedAttestation.js"; diff --git a/packages/state-transition/src/signatureSets/indexedAttestation.ts b/packages/state-transition/src/signatureSets/indexedAttestation.ts index 86535fece8b8..2a0765ee60c1 100644 --- a/packages/state-transition/src/signatureSets/indexedAttestation.ts +++ b/packages/state-transition/src/signatureSets/indexedAttestation.ts @@ -1,12 +1,12 @@ import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; import {SignedBeaconBlock, phase0, ssz} from "@lodestar/types"; +import {CachedBeaconStateAllForks} from "../types.js"; import { + ISignatureSet, computeSigningRoot, computeStartSlotAtEpoch, createAggregateSignatureSetFromComponents, - ISignatureSet, } from "../util/index.js"; -import {CachedBeaconStateAllForks} from "../types.js"; export function getAttestationDataSigningRoot( state: CachedBeaconStateAllForks, diff --git a/packages/state-transition/src/signatureSets/proposer.ts b/packages/state-transition/src/signatureSets/proposer.ts index e5ae7fd1f6f1..dd662931815f 100644 --- a/packages/state-transition/src/signatureSets/proposer.ts +++ b/packages/state-transition/src/signatureSets/proposer.ts @@ -1,8 +1,8 @@ import {DOMAIN_BEACON_PROPOSER} from "@lodestar/params"; import {SignedBeaconBlock, SignedBlindedBeaconBlock, isBlindedBeaconBlock, phase0, ssz} from "@lodestar/types"; +import {CachedBeaconStateAllForks} from "../types.js"; import {computeSigningRoot} from "../util/index.js"; import {ISignatureSet, SignatureSetType, verifySignatureSet} from "../util/signatureSets.js"; -import {CachedBeaconStateAllForks} from "../types.js"; export function verifyProposerSignature( state: CachedBeaconStateAllForks, diff --git a/packages/state-transition/src/signatureSets/proposerSlashings.ts b/packages/state-transition/src/signatureSets/proposerSlashings.ts index b0c1aa465bd5..d21c0906c511 100644 --- a/packages/state-transition/src/signatureSets/proposerSlashings.ts +++ b/packages/state-transition/src/signatureSets/proposerSlashings.ts @@ -1,7 +1,7 @@ import {DOMAIN_BEACON_PROPOSER} from "@lodestar/params"; import {SignedBeaconBlock, phase0, ssz} from "@lodestar/types"; -import {computeSigningRoot, ISignatureSet, SignatureSetType} from "../util/index.js"; import {CachedBeaconStateAllForks} from "../types.js"; +import {ISignatureSet, SignatureSetType, computeSigningRoot} from "../util/index.js"; /** * Extract signatures to allow validating all block signatures at once diff --git a/packages/state-transition/src/signatureSets/randao.ts b/packages/state-transition/src/signatureSets/randao.ts index 41422a9c1d00..495212f6aa2f 100644 --- a/packages/state-transition/src/signatureSets/randao.ts +++ b/packages/state-transition/src/signatureSets/randao.ts @@ -1,13 +1,13 @@ import {DOMAIN_RANDAO} from "@lodestar/params"; import {BeaconBlock, ssz} from "@lodestar/types"; +import {CachedBeaconStateAllForks} from "../types.js"; import { - computeEpochAtSlot, - computeSigningRoot, ISignatureSet, SignatureSetType, + computeEpochAtSlot, + computeSigningRoot, verifySignatureSet, } from "../util/index.js"; -import {CachedBeaconStateAllForks} from "../types.js"; export function verifyRandaoSignature(state: CachedBeaconStateAllForks, block: BeaconBlock): boolean { return verifySignatureSet(getRandaoRevealSignatureSet(state, block)); diff --git a/packages/state-transition/src/signatureSets/voluntaryExits.ts b/packages/state-transition/src/signatureSets/voluntaryExits.ts index 51dd20d671b6..9fae3f920da0 100644 --- a/packages/state-transition/src/signatureSets/voluntaryExits.ts +++ b/packages/state-transition/src/signatureSets/voluntaryExits.ts @@ -1,12 +1,12 @@ import {SignedBeaconBlock, phase0, ssz} from "@lodestar/types"; +import {CachedBeaconStateAllForks} from "../types.js"; import { - computeSigningRoot, - computeStartSlotAtEpoch, ISignatureSet, SignatureSetType, + computeSigningRoot, + computeStartSlotAtEpoch, verifySignatureSet, } from "../util/index.js"; -import {CachedBeaconStateAllForks} from "../types.js"; export function verifyVoluntaryExitSignature( state: CachedBeaconStateAllForks, diff --git a/packages/state-transition/src/slot/index.ts b/packages/state-transition/src/slot/index.ts index b05bd7ac93f2..0f2fa471f2f0 100644 --- a/packages/state-transition/src/slot/index.ts +++ b/packages/state-transition/src/slot/index.ts @@ -1,7 +1,7 @@ import {byteArrayEquals} from "@chainsafe/ssz"; import {SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; -import {CachedBeaconStateAllForks} from "../types.js"; import {ZERO_HASH} from "../constants/index.js"; +import {CachedBeaconStateAllForks} from "../types.js"; export {upgradeStateToAltair} from "./upgradeStateToAltair.js"; export {upgradeStateToBellatrix} from "./upgradeStateToBellatrix.js"; diff --git a/packages/state-transition/src/slot/upgradeStateToAltair.ts b/packages/state-transition/src/slot/upgradeStateToAltair.ts index 22ab8b13882c..ec6661d0d7ad 100644 --- a/packages/state-transition/src/slot/upgradeStateToAltair.ts +++ b/packages/state-transition/src/slot/upgradeStateToAltair.ts @@ -1,12 +1,12 @@ import {CompositeViewDU} from "@chainsafe/ssz"; -import {ssz} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; -import {CachedBeaconStatePhase0, CachedBeaconStateAltair} from "../types.js"; -import {newZeroedArray, RootCache} from "../util/index.js"; +import {ssz} from "@lodestar/types"; +import {getAttestationParticipationStatus} from "../block/processAttestationsAltair.js"; +import {getCachedBeaconState} from "../cache/stateCache.js"; +import {CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../types.js"; +import {RootCache, newZeroedArray} from "../util/index.js"; import {getNextSyncCommittee} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; -import {getCachedBeaconState} from "../cache/stateCache.js"; -import {getAttestationParticipationStatus} from "../block/processAttestationsAltair.js"; /** * Upgrade a state from phase0 to altair. diff --git a/packages/state-transition/src/slot/upgradeStateToBellatrix.ts b/packages/state-transition/src/slot/upgradeStateToBellatrix.ts index abcaed50a749..969357279d4a 100644 --- a/packages/state-transition/src/slot/upgradeStateToBellatrix.ts +++ b/packages/state-transition/src/slot/upgradeStateToBellatrix.ts @@ -1,6 +1,6 @@ import {ssz} from "@lodestar/types"; -import {CachedBeaconStateAltair, CachedBeaconStateBellatrix} from "../types.js"; import {getCachedBeaconState} from "../cache/stateCache.js"; +import {CachedBeaconStateAltair, CachedBeaconStateBellatrix} from "../types.js"; /** * Upgrade a state from altair to bellatrix. diff --git a/packages/state-transition/src/slot/upgradeStateToCapella.ts b/packages/state-transition/src/slot/upgradeStateToCapella.ts index 30a0701e58e8..06f30ec0360a 100644 --- a/packages/state-transition/src/slot/upgradeStateToCapella.ts +++ b/packages/state-transition/src/slot/upgradeStateToCapella.ts @@ -1,6 +1,6 @@ import {ssz} from "@lodestar/types"; -import {CachedBeaconStateBellatrix, CachedBeaconStateCapella} from "../types.js"; import {getCachedBeaconState} from "../cache/stateCache.js"; +import {CachedBeaconStateBellatrix, CachedBeaconStateCapella} from "../types.js"; /** * Upgrade a state from bellatrix to capella. diff --git a/packages/state-transition/src/slot/upgradeStateToDeneb.ts b/packages/state-transition/src/slot/upgradeStateToDeneb.ts index 2344a8d4e08e..158b66db4e71 100644 --- a/packages/state-transition/src/slot/upgradeStateToDeneb.ts +++ b/packages/state-transition/src/slot/upgradeStateToDeneb.ts @@ -1,6 +1,6 @@ import {ssz} from "@lodestar/types"; -import {CachedBeaconStateDeneb} from "../types.js"; import {getCachedBeaconState} from "../cache/stateCache.js"; +import {CachedBeaconStateDeneb} from "../types.js"; import {CachedBeaconStateCapella} from "../types.js"; /** diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index a3c8981ab13f..f030f9d572fe 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -1,11 +1,11 @@ -import {Epoch, ValidatorIndex, ssz} from "@lodestar/types"; import {FAR_FUTURE_EPOCH, GENESIS_SLOT, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; -import {CachedBeaconStateDeneb} from "../types.js"; +import {Epoch, ValidatorIndex, ssz} from "@lodestar/types"; import {CachedBeaconStateElectra, getCachedBeaconState} from "../cache/stateCache.js"; +import {G2_POINT_AT_INFINITY} from "../constants/constants.js"; +import {CachedBeaconStateDeneb} from "../types.js"; import {hasCompoundingWithdrawalCredential, queueExcessActiveBalance} from "../util/electra.js"; import {computeActivationExitEpoch} from "../util/epoch.js"; import {getActivationExitChurnLimit, getConsolidationChurnLimit} from "../util/validator.js"; -import {G2_POINT_AT_INFINITY} from "../constants/constants.js"; /** * Upgrade a state from Deneb to Electra. diff --git a/packages/state-transition/src/stateTransition.ts b/packages/state-transition/src/stateTransition.ts index f025c685b1a6..929a37468c6e 100644 --- a/packages/state-transition/src/stateTransition.ts +++ b/packages/state-transition/src/stateTransition.ts @@ -1,17 +1,12 @@ -import {SignedBeaconBlock, SignedBlindedBeaconBlock, Slot, ssz} from "@lodestar/types"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {SignedBeaconBlock, SignedBlindedBeaconBlock, Slot, ssz} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; +import {BlockExternalData, DataAvailableStatus, ExecutionPayloadStatus} from "./block/externalData.js"; +import {processBlock} from "./block/index.js"; +import {ProcessBlockOpts} from "./block/types.js"; +import {EpochTransitionCache, EpochTransitionCacheOpts, beforeProcessEpoch} from "./cache/epochTransitionCache.js"; +import {EpochTransitionStep, processEpoch} from "./epoch/index.js"; import {BeaconStateTransitionMetrics, onPostStateMetrics, onStateCloneMetrics} from "./metrics.js"; -import {beforeProcessEpoch, EpochTransitionCache, EpochTransitionCacheOpts} from "./cache/epochTransitionCache.js"; -import { - CachedBeaconStateAllForks, - CachedBeaconStatePhase0, - CachedBeaconStateAltair, - CachedBeaconStateBellatrix, - CachedBeaconStateCapella, - CachedBeaconStateDeneb, -} from "./types.js"; -import {computeEpochAtSlot} from "./util/index.js"; import {verifyProposerSignature} from "./signatureSets/index.js"; import { processSlot, @@ -21,10 +16,15 @@ import { upgradeStateToDeneb, upgradeStateToElectra, } from "./slot/index.js"; -import {processBlock} from "./block/index.js"; -import {EpochTransitionStep, processEpoch} from "./epoch/index.js"; -import {BlockExternalData, DataAvailableStatus, ExecutionPayloadStatus} from "./block/externalData.js"; -import {ProcessBlockOpts} from "./block/types.js"; +import { + CachedBeaconStateAllForks, + CachedBeaconStateAltair, + CachedBeaconStateBellatrix, + CachedBeaconStateCapella, + CachedBeaconStateDeneb, + CachedBeaconStatePhase0, +} from "./types.js"; +import {computeEpochAtSlot} from "./util/index.js"; // Multifork capable state transition diff --git a/packages/state-transition/src/util/aggregator.ts b/packages/state-transition/src/util/aggregator.ts index 02afda67cc42..dc4e140bb4cd 100644 --- a/packages/state-transition/src/util/aggregator.ts +++ b/packages/state-transition/src/util/aggregator.ts @@ -1,12 +1,12 @@ import {digest} from "@chainsafe/as-sha256"; -import {BLSSignature} from "@lodestar/types"; -import {intDiv, bytesToBigInt} from "@lodestar/utils"; import { - TARGET_AGGREGATORS_PER_COMMITTEE, SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_COUNT, + TARGET_AGGREGATORS_PER_COMMITTEE, TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE, } from "@lodestar/params"; +import {BLSSignature} from "@lodestar/types"; +import {bytesToBigInt, intDiv} from "@lodestar/utils"; const ZERO_BIGINT = BigInt(0); diff --git a/packages/state-transition/src/util/attestation.ts b/packages/state-transition/src/util/attestation.ts index cfa8f512e7d5..f45011b1e838 100644 --- a/packages/state-transition/src/util/attestation.ts +++ b/packages/state-transition/src/util/attestation.ts @@ -1,5 +1,5 @@ import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {phase0, Slot, ssz, ValidatorIndex} from "@lodestar/types"; +import {Slot, ValidatorIndex, phase0, ssz} from "@lodestar/types"; /** * Check if [[data1]] and [[data2]] are slashable according to Casper FFG rules. diff --git a/packages/state-transition/src/util/blindedBlock.ts b/packages/state-transition/src/util/blindedBlock.ts index 1793ff37255e..7d25fb25e22c 100644 --- a/packages/state-transition/src/util/blindedBlock.ts +++ b/packages/state-transition/src/util/blindedBlock.ts @@ -1,20 +1,20 @@ import {ChainForkConfig} from "@lodestar/config"; import {ForkExecution, ForkSeq} from "@lodestar/params"; import { - Root, - isBlindedBeaconBlock, - isExecutionPayloadAndBlobsBundle, BeaconBlock, BeaconBlockHeader, - SignedBeaconBlock, + BlindedBeaconBlock, + BlobsBundle, + Contents, ExecutionPayload, ExecutionPayloadAndBlobsBundle, - BlobsBundle, + ExecutionPayloadHeader, + Root, + SignedBeaconBlock, SignedBeaconBlockOrContents, - Contents, SignedBlindedBeaconBlock, - BlindedBeaconBlock, - ExecutionPayloadHeader, + isBlindedBeaconBlock, + isExecutionPayloadAndBlobsBundle, } from "@lodestar/types"; import {executionPayloadToPayloadHeader} from "./execution.js"; diff --git a/packages/state-transition/src/util/blockRoot.ts b/packages/state-transition/src/util/blockRoot.ts index 54d96885e675..c446c9dec386 100644 --- a/packages/state-transition/src/util/blockRoot.ts +++ b/packages/state-transition/src/util/blockRoot.ts @@ -1,14 +1,14 @@ +import {ChainForkConfig} from "@lodestar/config"; +import {SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; import { + BeaconBlock, + BeaconBlockHeader, Epoch, - Slot, Root, - BeaconBlock, SignedBeaconBlock, - BeaconBlockHeader, SignedBeaconBlockHeader, + Slot, } from "@lodestar/types"; -import {ChainForkConfig} from "@lodestar/config"; -import {SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; import {ZERO_HASH} from "../constants/index.js"; import {BeaconStateAllForks} from "../types.js"; import {computeStartSlotAtEpoch} from "./epoch.js"; diff --git a/packages/state-transition/src/util/calculateCommitteeAssignments.ts b/packages/state-transition/src/util/calculateCommitteeAssignments.ts index 992c5efbdaaa..008161afa04b 100644 --- a/packages/state-transition/src/util/calculateCommitteeAssignments.ts +++ b/packages/state-transition/src/util/calculateCommitteeAssignments.ts @@ -1,5 +1,5 @@ -import {CommitteeIndex, Slot, ValidatorIndex} from "@lodestar/types"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {CommitteeIndex, Slot, ValidatorIndex} from "@lodestar/types"; import {EpochShuffling} from "./epochShuffling.js"; // Copied from lodestar-api package to avoid depending on the package diff --git a/packages/state-transition/src/util/computeAnchorCheckpoint.ts b/packages/state-transition/src/util/computeAnchorCheckpoint.ts index e37ffc2c632d..1edb2ac57ca2 100644 --- a/packages/state-transition/src/util/computeAnchorCheckpoint.ts +++ b/packages/state-transition/src/util/computeAnchorCheckpoint.ts @@ -1,6 +1,6 @@ import {ChainForkConfig} from "@lodestar/config"; -import {ssz, phase0} from "@lodestar/types"; import {GENESIS_SLOT, ZERO_HASH} from "@lodestar/params"; +import {phase0, ssz} from "@lodestar/types"; import {BeaconStateAllForks} from "../types.js"; import {blockToHeader} from "./blockRoot.js"; import {computeCheckpointEpochAtStateSlot} from "./epoch.js"; diff --git a/packages/state-transition/src/util/domain.ts b/packages/state-transition/src/util/domain.ts index b84e5bca44f4..1368834aaa2f 100644 --- a/packages/state-transition/src/util/domain.ts +++ b/packages/state-transition/src/util/domain.ts @@ -1,4 +1,4 @@ -import {Epoch, Version, Root, DomainType, phase0, ssz} from "@lodestar/types"; +import {DomainType, Epoch, Root, Version, phase0, ssz} from "@lodestar/types"; // Only used by processDeposit + lightclient /** diff --git a/packages/state-transition/src/util/electra.ts b/packages/state-transition/src/util/electra.ts index f1082c6d4603..f5b899eadcab 100644 --- a/packages/state-transition/src/util/electra.ts +++ b/packages/state-transition/src/util/electra.ts @@ -1,7 +1,7 @@ import {COMPOUNDING_WITHDRAWAL_PREFIX, GENESIS_SLOT, MIN_ACTIVATION_BALANCE} from "@lodestar/params"; import {ValidatorIndex, ssz} from "@lodestar/types"; -import {CachedBeaconStateElectra} from "../types.js"; import {G2_POINT_AT_INFINITY} from "../constants/constants.js"; +import {CachedBeaconStateElectra} from "../types.js"; import {hasEth1WithdrawalCredential} from "./capella.js"; export function hasCompoundingWithdrawalCredential(withdrawalCredentials: Uint8Array): boolean { diff --git a/packages/state-transition/src/util/epoch.ts b/packages/state-transition/src/util/epoch.ts index 7fed5e53f1f3..cc95d0d192f6 100644 --- a/packages/state-transition/src/util/epoch.ts +++ b/packages/state-transition/src/util/epoch.ts @@ -1,5 +1,5 @@ import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, GENESIS_EPOCH, MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {BeaconState, Epoch, Slot, SyncPeriod, Gwei} from "@lodestar/types"; +import {BeaconState, Epoch, Gwei, Slot, SyncPeriod} from "@lodestar/types"; import {CachedBeaconStateElectra} from "../types.js"; import {getActivationExitChurnLimit, getConsolidationChurnLimit} from "./validator.js"; diff --git a/packages/state-transition/src/util/epochShuffling.ts b/packages/state-transition/src/util/epochShuffling.ts index 6f63a2f4f5f8..6d0acbd32455 100644 --- a/packages/state-transition/src/util/epochShuffling.ts +++ b/packages/state-transition/src/util/epochShuffling.ts @@ -1,20 +1,20 @@ import {asyncUnshuffleList, unshuffleList} from "@chainsafe/swap-or-not-shuffle"; -import {Epoch, RootHex, ssz, ValidatorIndex} from "@lodestar/types"; -import {GaugeExtra, intDiv, Logger, NoLabels, toRootHex} from "@lodestar/utils"; +import {BeaconConfig} from "@lodestar/config"; import { DOMAIN_BEACON_ATTESTER, GENESIS_SLOT, MAX_COMMITTEES_PER_SLOT, + SHUFFLE_ROUND_COUNT, SLOTS_PER_EPOCH, TARGET_COMMITTEE_SIZE, - SHUFFLE_ROUND_COUNT, } from "@lodestar/params"; -import {BeaconConfig} from "@lodestar/config"; +import {Epoch, RootHex, ValidatorIndex, ssz} from "@lodestar/types"; +import {GaugeExtra, Logger, NoLabels, intDiv, toRootHex} from "@lodestar/utils"; import {BeaconStateAllForks} from "../types.js"; -import {getSeed} from "./seed.js"; -import {computeStartSlotAtEpoch} from "./epoch.js"; import {getBlockRootAtSlot} from "./blockRoot.js"; import {computeAnchorCheckpoint} from "./computeAnchorCheckpoint.js"; +import {computeStartSlotAtEpoch} from "./epoch.js"; +import {getSeed} from "./seed.js"; export interface ShufflingBuildProps { state: BeaconStateAllForks; diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index deed64bd6c51..9d70790f74a6 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -1,23 +1,23 @@ +import {ForkExecution, ForkName, ForkSeq} from "@lodestar/params"; import { + BeaconBlock, + BeaconBlockBody, + BlindedBeaconBlock, + BlindedBeaconBlockBody, + ExecutionPayload, + ExecutionPayloadHeader, bellatrix, capella, deneb, isBlindedBeaconBlockBody, - ssz, - BeaconBlock, - BeaconBlockBody, - ExecutionPayload, isExecutionPayload, - ExecutionPayloadHeader, - BlindedBeaconBlockBody, - BlindedBeaconBlock, + ssz, } from "@lodestar/types"; -import {ForkExecution, ForkName, ForkSeq} from "@lodestar/params"; import { + BeaconStateAllForks, BeaconStateBellatrix, BeaconStateCapella, - BeaconStateAllForks, BeaconStateExecutions, CachedBeaconStateAllForks, CachedBeaconStateExecutions, diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index aca81258a47a..27f7aee00460 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -10,18 +10,18 @@ import { MAX_EFFECTIVE_BALANCE, UNSET_DEPOSIT_REQUESTS_START_INDEX, } from "@lodestar/params"; -import {Bytes32, phase0, Root, ssz, TimeSeconds} from "@lodestar/types"; +import {Bytes32, Root, TimeSeconds, phase0, ssz} from "@lodestar/types"; -import {CachedBeaconStateAllForks, BeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; -import {createCachedBeaconState} from "../cache/stateCache.js"; -import {EpochCacheImmutableData} from "../cache/epochCache.js"; import {processDeposit} from "../block/processDeposit.js"; +import {EpochCacheImmutableData} from "../cache/epochCache.js"; +import {createCachedBeaconState} from "../cache/stateCache.js"; import {increaseBalance} from "../index.js"; -import {computeEpochAtSlot} from "./epoch.js"; -import {getActiveValidatorIndices, getMaxEffectiveBalance} from "./validator.js"; -import {getTemporaryBlockHeader} from "./blockRoot.js"; +import {BeaconStateAllForks, CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; import {newFilledArray} from "./array.js"; +import {getTemporaryBlockHeader} from "./blockRoot.js"; +import {computeEpochAtSlot} from "./epoch.js"; import {getNextSyncCommittee} from "./syncCommittee.js"; +import {getActiveValidatorIndices, getMaxEffectiveBalance} from "./validator.js"; type DepositDataRootListType = ListCompositeType; type DepositDataRootViewDU = CompositeViewDU; diff --git a/packages/state-transition/src/util/interop.ts b/packages/state-transition/src/util/interop.ts index e99799da127d..de7ba31d5a63 100644 --- a/packages/state-transition/src/util/interop.ts +++ b/packages/state-transition/src/util/interop.ts @@ -1,7 +1,7 @@ -import {toBufferBE} from "bigint-buffer"; import {digest} from "@chainsafe/as-sha256"; import {SecretKey} from "@chainsafe/blst"; import {bytesToBigInt, intToBytes} from "@lodestar/utils"; +import {toBufferBE} from "bigint-buffer"; let curveOrder: bigint; function getCurveOrder(): bigint { diff --git a/packages/state-transition/src/util/loadState/loadState.ts b/packages/state-transition/src/util/loadState/loadState.ts index 6e3e9c6719fa..b8254f8a5edc 100644 --- a/packages/state-transition/src/util/loadState/loadState.ts +++ b/packages/state-transition/src/util/loadState/loadState.ts @@ -1,10 +1,10 @@ -import {deserializeContainerIgnoreFields, ssz} from "@lodestar/types"; -import {ForkSeq} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; +import {ForkSeq} from "@lodestar/params"; +import {deserializeContainerIgnoreFields, ssz} from "@lodestar/types"; import {BeaconStateAllForks, BeaconStateAltair} from "../../types.js"; import {VALIDATOR_BYTES_SIZE, getForkFromStateBytes, getStateTypeFromBytes} from "../sszBytes.js"; -import {findModifiedValidators} from "./findModifiedValidators.js"; import {findModifiedInactivityScores} from "./findModifiedInactivityScores.js"; +import {findModifiedValidators} from "./findModifiedValidators.js"; import {loadValidator} from "./loadValidator.js"; type MigrateStateOutput = {state: BeaconStateAllForks; modifiedValidators: number[]}; diff --git a/packages/state-transition/src/util/rootCache.ts b/packages/state-transition/src/util/rootCache.ts index f3fc5b52ff52..ada841dbbb9f 100644 --- a/packages/state-transition/src/util/rootCache.ts +++ b/packages/state-transition/src/util/rootCache.ts @@ -1,4 +1,4 @@ -import {Epoch, phase0, Root, Slot} from "@lodestar/types"; +import {Epoch, Root, Slot, phase0} from "@lodestar/types"; import {CachedBeaconStateAllForks} from "../types.js"; import {getBlockRoot, getBlockRootAtSlot} from "./blockRoot.js"; diff --git a/packages/state-transition/src/util/seed.ts b/packages/state-transition/src/util/seed.ts index 4131d4d9481f..129cf6bfaf72 100644 --- a/packages/state-transition/src/util/seed.ts +++ b/packages/state-transition/src/util/seed.ts @@ -1,6 +1,4 @@ import {digest} from "@chainsafe/as-sha256"; -import {Epoch, Bytes32, DomainType, ValidatorIndex} from "@lodestar/types"; -import {assert, bytesToBigInt, intToBytes} from "@lodestar/utils"; import { DOMAIN_SYNC_COMMITTEE, EFFECTIVE_BALANCE_INCREMENT, @@ -13,8 +11,10 @@ import { SLOTS_PER_EPOCH, SYNC_COMMITTEE_SIZE, } from "@lodestar/params"; -import {BeaconStateAllForks} from "../types.js"; +import {Bytes32, DomainType, Epoch, ValidatorIndex} from "@lodestar/types"; +import {assert, bytesToBigInt, intToBytes} from "@lodestar/utils"; import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js"; +import {BeaconStateAllForks} from "../types.js"; import {computeStartSlotAtEpoch} from "./epoch.js"; import {computeEpochAtSlot} from "./epoch.js"; diff --git a/packages/state-transition/src/util/slot.ts b/packages/state-transition/src/util/slot.ts index 495a350ca11f..3cf145367a1d 100644 --- a/packages/state-transition/src/util/slot.ts +++ b/packages/state-transition/src/util/slot.ts @@ -1,7 +1,7 @@ import {ChainConfig} from "@lodestar/config"; import {GENESIS_SLOT, INTERVALS_PER_SLOT} from "@lodestar/params"; -import {Slot, Epoch, TimeSeconds} from "@lodestar/types"; -import {computeStartSlotAtEpoch, computeEpochAtSlot} from "./epoch.js"; +import {Epoch, Slot, TimeSeconds} from "@lodestar/types"; +import {computeEpochAtSlot, computeStartSlotAtEpoch} from "./epoch.js"; export function getSlotsSinceGenesis(config: ChainConfig, genesisTime: TimeSeconds): Slot { const diffInSeconds = Date.now() / 1000 - genesisTime; diff --git a/packages/state-transition/src/util/syncCommittee.ts b/packages/state-transition/src/util/syncCommittee.ts index c1f53632e521..a0731cf8d6ac 100644 --- a/packages/state-transition/src/util/syncCommittee.ts +++ b/packages/state-transition/src/util/syncCommittee.ts @@ -8,10 +8,10 @@ import { SYNC_REWARD_WEIGHT, WEIGHT_DENOMINATOR, } from "@lodestar/params"; -import {altair, ValidatorIndex} from "@lodestar/types"; +import {ValidatorIndex, altair} from "@lodestar/types"; import {bigIntSqrt} from "@lodestar/utils"; -import {BeaconStateAllForks} from "../types.js"; import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js"; +import {BeaconStateAllForks} from "../types.js"; import {getNextSyncCommitteeIndices} from "./seed.js"; /** diff --git a/packages/state-transition/src/util/validator.ts b/packages/state-transition/src/util/validator.ts index 4906a9349402..555b8a09b614 100644 --- a/packages/state-transition/src/util/validator.ts +++ b/packages/state-transition/src/util/validator.ts @@ -1,5 +1,3 @@ -import {Epoch, phase0, ValidatorIndex} from "@lodestar/types"; -import {intDiv} from "@lodestar/utils"; import {ChainForkConfig} from "@lodestar/config"; import { EFFECTIVE_BALANCE_INCREMENT, @@ -7,6 +5,8 @@ import { MAX_EFFECTIVE_BALANCE_ELECTRA, MIN_ACTIVATION_BALANCE, } from "@lodestar/params"; +import {Epoch, ValidatorIndex, phase0} from "@lodestar/types"; +import {intDiv} from "@lodestar/utils"; import {BeaconStateAllForks, CachedBeaconStateElectra, EpochCache} from "../types.js"; import {hasCompoundingWithdrawalCredential} from "./electra.js"; diff --git a/packages/state-transition/src/util/weakSubjectivity.ts b/packages/state-transition/src/util/weakSubjectivity.ts index 8d7c82842496..fc2b485aea9f 100644 --- a/packages/state-transition/src/util/weakSubjectivity.ts +++ b/packages/state-transition/src/util/weakSubjectivity.ts @@ -6,7 +6,7 @@ import {Checkpoint} from "@lodestar/types/phase0"; import {toRootHex} from "@lodestar/utils"; import {ZERO_HASH} from "../constants/constants.js"; import {BeaconStateAllForks, CachedBeaconStateAllForks} from "../types.js"; -import {computeEpochAtSlot, getCurrentEpoch, computeCheckpointEpochAtStateSlot} from "./epoch.js"; +import {computeCheckpointEpochAtStateSlot, computeEpochAtSlot, getCurrentEpoch} from "./epoch.js"; import {getCurrentSlot} from "./slot.js"; import {getActiveValidatorIndices, getChurnLimit} from "./validator.js"; diff --git a/packages/state-transition/test/perf/analyzeEpochs.ts b/packages/state-transition/test/perf/analyzeEpochs.ts index ebad63ccf0ad..1141f488dba1 100644 --- a/packages/state-transition/test/perf/analyzeEpochs.ts +++ b/packages/state-transition/test/perf/analyzeEpochs.ts @@ -4,10 +4,10 @@ import {config} from "@lodestar/config/default"; import {NetworkName} from "@lodestar/config/networks.js"; import {phase0, ssz} from "@lodestar/types"; import { - computeEpochAtSlot, - computeStartSlotAtEpoch, AttesterFlags, beforeProcessEpoch, + computeEpochAtSlot, + computeStartSlotAtEpoch, parseAttesterFlags, processSlots, } from "../../src/index.js"; diff --git a/packages/state-transition/test/perf/block/processAttestation.test.ts b/packages/state-transition/test/perf/block/processAttestation.test.ts index 673b0e17430f..25528b2458e4 100644 --- a/packages/state-transition/test/perf/block/processAttestation.test.ts +++ b/packages/state-transition/test/perf/block/processAttestation.test.ts @@ -11,8 +11,8 @@ import { SYNC_COMMITTEE_SIZE, } from "@lodestar/params"; import {phase0} from "@lodestar/types"; -import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../../../src/index.js"; import {processAttestationsAltair} from "../../../src/block/processAttestationsAltair.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../../../src/index.js"; import {generatePerfTestCachedStateAltair, perfStateId} from "../util.js"; import {BlockAltairOpts, getBlockAltair} from "./util.js"; diff --git a/packages/state-transition/test/perf/block/processBlockAltair.test.ts b/packages/state-transition/test/perf/block/processBlockAltair.test.ts index cf0898946ab6..60ad8b50afa6 100644 --- a/packages/state-transition/test/perf/block/processBlockAltair.test.ts +++ b/packages/state-transition/test/perf/block/processBlockAltair.test.ts @@ -1,5 +1,4 @@ import {itBench} from "@dapplion/benchmark"; -import {ssz} from "@lodestar/types"; import { ACTIVE_PRESET, MAX_ATTESTATIONS, @@ -10,14 +9,15 @@ import { PresetName, SYNC_COMMITTEE_SIZE, } from "@lodestar/params"; +import {ssz} from "@lodestar/types"; import { CachedBeaconStateAltair, DataAvailableStatus, ExecutionPayloadStatus, stateTransition, } from "../../../src/index.js"; -import {cachedStateAltairPopulateCaches, generatePerfTestCachedStateAltair, perfStateId} from "../util.js"; import {StateBlock} from "../types.js"; +import {cachedStateAltairPopulateCaches, generatePerfTestCachedStateAltair, perfStateId} from "../util.js"; import {BlockAltairOpts, getBlockAltair} from "./util.js"; // As of Jun 12 2021 diff --git a/packages/state-transition/test/perf/block/processBlockPhase0.test.ts b/packages/state-transition/test/perf/block/processBlockPhase0.test.ts index 92d8630a58ac..980586f6326b 100644 --- a/packages/state-transition/test/perf/block/processBlockPhase0.test.ts +++ b/packages/state-transition/test/perf/block/processBlockPhase0.test.ts @@ -9,8 +9,8 @@ import { PresetName, } from "@lodestar/params"; import {DataAvailableStatus, ExecutionPayloadStatus, stateTransition} from "../../../src/index.js"; -import {generatePerfTestCachedStatePhase0, perfStateId} from "../util.js"; import {StateBlock} from "../types.js"; +import {generatePerfTestCachedStatePhase0, perfStateId} from "../util.js"; import {BlockOpts, getBlockPhase0} from "./util.js"; // As of Jun 12 2021 diff --git a/packages/state-transition/test/perf/block/processEth1Data.test.ts b/packages/state-transition/test/perf/block/processEth1Data.test.ts index 45dc8aa631d7..ba7cb0b5ba1d 100644 --- a/packages/state-transition/test/perf/block/processEth1Data.test.ts +++ b/packages/state-transition/test/perf/block/processEth1Data.test.ts @@ -1,8 +1,8 @@ import {itBench} from "@dapplion/benchmark"; import {ACTIVE_PRESET, PresetName, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; import {phase0} from "@lodestar/types"; -import {CachedBeaconStateAllForks} from "../../../src/index.js"; import {processEth1Data} from "../../../src/block/processEth1Data.js"; +import {CachedBeaconStateAllForks} from "../../../src/index.js"; import {generatePerfTestCachedStateAltair, perfStateId} from "../util.js"; import {getBlockAltair} from "./util.js"; diff --git a/packages/state-transition/test/perf/block/processWithdrawals.test.ts b/packages/state-transition/test/perf/block/processWithdrawals.test.ts index 66d624b39bfd..23f76825225d 100644 --- a/packages/state-transition/test/perf/block/processWithdrawals.test.ts +++ b/packages/state-transition/test/perf/block/processWithdrawals.test.ts @@ -1,9 +1,9 @@ import {itBench} from "@dapplion/benchmark"; import {ForkSeq} from "@lodestar/params"; -import {CachedBeaconStateCapella} from "../../../src/index.js"; import {getExpectedWithdrawals} from "../../../src/block/processWithdrawals.js"; +import {CachedBeaconStateCapella} from "../../../src/index.js"; +import {WithdrawalOpts, getExpectedWithdrawalsTestData} from "../../utils/capella.js"; import {numValidators} from "../util.js"; -import {getExpectedWithdrawalsTestData, WithdrawalOpts} from "../../utils/capella.js"; // PERF: Fixed cost for MAX_WITHDRAWALS_PER_PAYLOAD probes // + cost 'proportional' to $VALIDATOR_COUNT with balances under MAX_EFFECTIVE_BALANCE or diff --git a/packages/state-transition/test/perf/block/util.ts b/packages/state-transition/test/perf/block/util.ts index baa86dcac6a5..7b95d1621f5a 100644 --- a/packages/state-transition/test/perf/block/util.ts +++ b/packages/state-transition/test/perf/block/util.ts @@ -1,16 +1,16 @@ -import {toGindex, Tree} from "@chainsafe/persistent-merkle-tree"; -import {BitArray} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; -import {altair, phase0, ssz} from "@lodestar/types"; -import {DOMAIN_DEPOSIT, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; +import {Tree, toGindex} from "@chainsafe/persistent-merkle-tree"; +import {BitArray} from "@chainsafe/ssz"; import {config} from "@lodestar/config/default"; +import {DOMAIN_DEPOSIT, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; +import {altair, phase0, ssz} from "@lodestar/types"; import { + CachedBeaconStateAllForks, + CachedBeaconStateAltair, + ZERO_HASH, computeDomain, computeEpochAtSlot, computeSigningRoot, - ZERO_HASH, - CachedBeaconStateAllForks, - CachedBeaconStateAltair, } from "../../../src/index.js"; import {getBlockRoot, getBlockRootAtSlot} from "../../../src/index.js"; diff --git a/packages/state-transition/test/perf/dataStructures/arrayish.test.ts b/packages/state-transition/test/perf/dataStructures/arrayish.test.ts index 353f81951aa7..ebeefacbd27e 100644 --- a/packages/state-transition/test/perf/dataStructures/arrayish.test.ts +++ b/packages/state-transition/test/perf/dataStructures/arrayish.test.ts @@ -1,5 +1,5 @@ +import {LeafNode, Tree, toGindex, zeroNode} from "@chainsafe/persistent-merkle-tree"; import {itBench, setBenchOpts} from "@dapplion/benchmark"; -import {LeafNode, toGindex, Tree, zeroNode} from "@chainsafe/persistent-merkle-tree"; // Understand the cost of each array-ish data structure to: // - Get one element diff --git a/packages/state-transition/test/perf/epoch/epochAltair.test.ts b/packages/state-transition/test/perf/epoch/epochAltair.test.ts index 5a10fd4d8bbd..aa08619250dd 100644 --- a/packages/state-transition/test/perf/epoch/epochAltair.test.ts +++ b/packages/state-transition/test/perf/epoch/epochAltair.test.ts @@ -1,28 +1,28 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {ForkSeq} from "@lodestar/params"; +import {processEpoch} from "../../../src/epoch/index.js"; +import {processEffectiveBalanceUpdates} from "../../../src/epoch/processEffectiveBalanceUpdates.js"; +import {processEth1DataReset} from "../../../src/epoch/processEth1DataReset.js"; +import {processHistoricalRootsUpdate} from "../../../src/epoch/processHistoricalRootsUpdate.js"; +import {processInactivityUpdates} from "../../../src/epoch/processInactivityUpdates.js"; +import {processJustificationAndFinalization} from "../../../src/epoch/processJustificationAndFinalization.js"; +import {processParticipationFlagUpdates} from "../../../src/epoch/processParticipationFlagUpdates.js"; +import {processRandaoMixesReset} from "../../../src/epoch/processRandaoMixesReset.js"; +import {processRegistryUpdates} from "../../../src/epoch/processRegistryUpdates.js"; +import {processRewardsAndPenalties} from "../../../src/epoch/processRewardsAndPenalties.js"; +import {processSlashings} from "../../../src/epoch/processSlashings.js"; +import {processSlashingsReset} from "../../../src/epoch/processSlashingsReset.js"; +import {processSyncCommitteeUpdates} from "../../../src/epoch/processSyncCommitteeUpdates.js"; import { - computeStartSlotAtEpoch, CachedBeaconStateAllForks, CachedBeaconStateAltair, beforeProcessEpoch, + computeStartSlotAtEpoch, } from "../../../src/index.js"; -import {beforeValue, LazyValue} from "../../utils/beforeValueMocha.js"; +import {LazyValue, beforeValue} from "../../utils/beforeValueMocha.js"; import {getNetworkCachedState} from "../../utils/testFileCache.js"; -import {StateEpoch} from "../types.js"; import {altairState} from "../params.js"; -import {processJustificationAndFinalization} from "../../../src/epoch/processJustificationAndFinalization.js"; -import {processInactivityUpdates} from "../../../src/epoch/processInactivityUpdates.js"; -import {processRewardsAndPenalties} from "../../../src/epoch/processRewardsAndPenalties.js"; -import {processRegistryUpdates} from "../../../src/epoch/processRegistryUpdates.js"; -import {processSlashings} from "../../../src/epoch/processSlashings.js"; -import {processEth1DataReset} from "../../../src/epoch/processEth1DataReset.js"; -import {processEffectiveBalanceUpdates} from "../../../src/epoch/processEffectiveBalanceUpdates.js"; -import {processSlashingsReset} from "../../../src/epoch/processSlashingsReset.js"; -import {processRandaoMixesReset} from "../../../src/epoch/processRandaoMixesReset.js"; -import {processHistoricalRootsUpdate} from "../../../src/epoch/processHistoricalRootsUpdate.js"; -import {processParticipationFlagUpdates} from "../../../src/epoch/processParticipationFlagUpdates.js"; -import {processSyncCommitteeUpdates} from "../../../src/epoch/processSyncCommitteeUpdates.js"; -import {processEpoch} from "../../../src/epoch/index.js"; +import {StateEpoch} from "../types.js"; const slot = computeStartSlotAtEpoch(altairState.epoch) - 1; const stateId = `${altairState.network}_e${altairState.epoch}`; diff --git a/packages/state-transition/test/perf/epoch/epochCapella.test.ts b/packages/state-transition/test/perf/epoch/epochCapella.test.ts index a4daf308aaa0..1376fd61d965 100644 --- a/packages/state-transition/test/perf/epoch/epochCapella.test.ts +++ b/packages/state-transition/test/perf/epoch/epochCapella.test.ts @@ -1,28 +1,28 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {ForkSeq} from "@lodestar/params"; +import {processEpoch} from "../../../src/epoch/index.js"; +import {processEffectiveBalanceUpdates} from "../../../src/epoch/processEffectiveBalanceUpdates.js"; +import {processEth1DataReset} from "../../../src/epoch/processEth1DataReset.js"; +import {processHistoricalRootsUpdate} from "../../../src/epoch/processHistoricalRootsUpdate.js"; +import {processInactivityUpdates} from "../../../src/epoch/processInactivityUpdates.js"; +import {processJustificationAndFinalization} from "../../../src/epoch/processJustificationAndFinalization.js"; +import {processParticipationFlagUpdates} from "../../../src/epoch/processParticipationFlagUpdates.js"; +import {processRandaoMixesReset} from "../../../src/epoch/processRandaoMixesReset.js"; +import {processRegistryUpdates} from "../../../src/epoch/processRegistryUpdates.js"; +import {processRewardsAndPenalties} from "../../../src/epoch/processRewardsAndPenalties.js"; +import {processSlashings} from "../../../src/epoch/processSlashings.js"; +import {processSlashingsReset} from "../../../src/epoch/processSlashingsReset.js"; import { - computeStartSlotAtEpoch, CachedBeaconStateAllForks, - CachedBeaconStateCapella, CachedBeaconStateAltair, + CachedBeaconStateCapella, beforeProcessEpoch, + computeStartSlotAtEpoch, } from "../../../src/index.js"; -import {beforeValue, LazyValue} from "../../utils/beforeValueMocha.js"; +import {LazyValue, beforeValue} from "../../utils/beforeValueMocha.js"; import {getNetworkCachedState} from "../../utils/testFileCache.js"; -import {StateEpoch} from "../types.js"; import {capellaState} from "../params.js"; -import {processJustificationAndFinalization} from "../../../src/epoch/processJustificationAndFinalization.js"; -import {processInactivityUpdates} from "../../../src/epoch/processInactivityUpdates.js"; -import {processRewardsAndPenalties} from "../../../src/epoch/processRewardsAndPenalties.js"; -import {processRegistryUpdates} from "../../../src/epoch/processRegistryUpdates.js"; -import {processSlashings} from "../../../src/epoch/processSlashings.js"; -import {processEth1DataReset} from "../../../src/epoch/processEth1DataReset.js"; -import {processEffectiveBalanceUpdates} from "../../../src/epoch/processEffectiveBalanceUpdates.js"; -import {processSlashingsReset} from "../../../src/epoch/processSlashingsReset.js"; -import {processRandaoMixesReset} from "../../../src/epoch/processRandaoMixesReset.js"; -import {processHistoricalRootsUpdate} from "../../../src/epoch/processHistoricalRootsUpdate.js"; -import {processParticipationFlagUpdates} from "../../../src/epoch/processParticipationFlagUpdates.js"; -import {processEpoch} from "../../../src/epoch/index.js"; +import {StateEpoch} from "../types.js"; const slot = computeStartSlotAtEpoch(capellaState.epoch) - 1; const stateId = `${capellaState.network}_e${capellaState.epoch}`; diff --git a/packages/state-transition/test/perf/epoch/epochPhase0.test.ts b/packages/state-transition/test/perf/epoch/epochPhase0.test.ts index 5c19b347af62..cca93b045cae 100644 --- a/packages/state-transition/test/perf/epoch/epochPhase0.test.ts +++ b/packages/state-transition/test/perf/epoch/epochPhase0.test.ts @@ -1,26 +1,26 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {ForkSeq} from "@lodestar/params"; +import {processEpoch} from "../../../src/epoch/index.js"; +import {processEffectiveBalanceUpdates} from "../../../src/epoch/processEffectiveBalanceUpdates.js"; +import {processEth1DataReset} from "../../../src/epoch/processEth1DataReset.js"; +import {processHistoricalRootsUpdate} from "../../../src/epoch/processHistoricalRootsUpdate.js"; +import {processJustificationAndFinalization} from "../../../src/epoch/processJustificationAndFinalization.js"; +import {processParticipationRecordUpdates} from "../../../src/epoch/processParticipationRecordUpdates.js"; +import {processRandaoMixesReset} from "../../../src/epoch/processRandaoMixesReset.js"; +import {processRegistryUpdates} from "../../../src/epoch/processRegistryUpdates.js"; +import {processRewardsAndPenalties} from "../../../src/epoch/processRewardsAndPenalties.js"; +import {processSlashings} from "../../../src/epoch/processSlashings.js"; +import {processSlashingsReset} from "../../../src/epoch/processSlashingsReset.js"; import { - computeStartSlotAtEpoch, CachedBeaconStateAllForks, CachedBeaconStatePhase0, beforeProcessEpoch, + computeStartSlotAtEpoch, } from "../../../src/index.js"; -import {beforeValue, LazyValue} from "../../utils/beforeValueMocha.js"; +import {LazyValue, beforeValue} from "../../utils/beforeValueMocha.js"; import {getNetworkCachedState} from "../../utils/testFileCache.js"; -import {StateEpoch} from "../types.js"; import {phase0State} from "../params.js"; -import {processEpoch} from "../../../src/epoch/index.js"; -import {processParticipationRecordUpdates} from "../../../src/epoch/processParticipationRecordUpdates.js"; -import {processJustificationAndFinalization} from "../../../src/epoch/processJustificationAndFinalization.js"; -import {processRewardsAndPenalties} from "../../../src/epoch/processRewardsAndPenalties.js"; -import {processRegistryUpdates} from "../../../src/epoch/processRegistryUpdates.js"; -import {processSlashings} from "../../../src/epoch/processSlashings.js"; -import {processEth1DataReset} from "../../../src/epoch/processEth1DataReset.js"; -import {processEffectiveBalanceUpdates} from "../../../src/epoch/processEffectiveBalanceUpdates.js"; -import {processSlashingsReset} from "../../../src/epoch/processSlashingsReset.js"; -import {processRandaoMixesReset} from "../../../src/epoch/processRandaoMixesReset.js"; -import {processHistoricalRootsUpdate} from "../../../src/epoch/processHistoricalRootsUpdate.js"; +import {StateEpoch} from "../types.js"; const slot = computeStartSlotAtEpoch(phase0State.epoch) - 1; const stateId = `${phase0State.network}_e${phase0State.epoch}`; diff --git a/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts b/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts index 19f18df86c2e..fe2fabd2dd4d 100644 --- a/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts +++ b/packages/state-transition/test/perf/epoch/processEffectiveBalanceUpdates.test.ts @@ -1,12 +1,12 @@ import {itBench} from "@dapplion/benchmark"; -import {ssz} from "@lodestar/types"; import {config} from "@lodestar/config/default"; import {ForkSeq} from "@lodestar/params"; -import {beforeProcessEpoch, CachedBeaconStateAllForks, EpochTransitionCache} from "../../../src/index.js"; +import {ssz} from "@lodestar/types"; import {processEffectiveBalanceUpdates} from "../../../src/epoch/processEffectiveBalanceUpdates.js"; -import {numValidators} from "../util.js"; -import {StateEpoch} from "../types.js"; +import {CachedBeaconStateAllForks, EpochTransitionCache, beforeProcessEpoch} from "../../../src/index.js"; import {createCachedBeaconStateTest} from "../../utils/state.js"; +import {StateEpoch} from "../types.js"; +import {numValidators} from "../util.js"; // PERF: Cost 'proportional' to $VALIDATOR_COUNT, to iterate over all balances. Then cost is proportional to the amount // of validators whose effectiveBalance changed. Worst case is a massive network leak or a big slashing event which diff --git a/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts b/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts index 588fe9ec0213..b02c2aa3c9a2 100644 --- a/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts +++ b/packages/state-transition/test/perf/epoch/processRegistryUpdates.test.ts @@ -1,9 +1,9 @@ import {itBench} from "@dapplion/benchmark"; import {ForkSeq} from "@lodestar/params"; -import {beforeProcessEpoch, CachedBeaconStateAllForks, EpochTransitionCache} from "../../../src/index.js"; import {processRegistryUpdates} from "../../../src/epoch/processRegistryUpdates.js"; -import {generatePerfTestCachedStatePhase0, numValidators} from "../util.js"; +import {CachedBeaconStateAllForks, EpochTransitionCache, beforeProcessEpoch} from "../../../src/index.js"; import {StateEpoch} from "../types.js"; +import {generatePerfTestCachedStatePhase0, numValidators} from "../util.js"; // PERF: Cost 'proportional' to only validators that active + exit. For mainnet conditions: // - indicesEligibleForActivationQueue: Maxing deposits triggers 512 validator mutations diff --git a/packages/state-transition/test/perf/epoch/processRewardsAndPenalties.test.ts b/packages/state-transition/test/perf/epoch/processRewardsAndPenalties.test.ts index 03644ebca0f3..b4c157942584 100644 --- a/packages/state-transition/test/perf/epoch/processRewardsAndPenalties.test.ts +++ b/packages/state-transition/test/perf/epoch/processRewardsAndPenalties.test.ts @@ -1,9 +1,9 @@ import {itBench} from "@dapplion/benchmark"; import {processRewardsAndPenalties} from "../../../src/epoch/processRewardsAndPenalties.js"; -import {generatePerfTestCachedStateAltair, numValidators} from "../util.js"; import {StateAltairEpoch} from "../types.js"; -import {FlagFactors, generateBalanceDeltasEpochTransitionCache} from "./utilPhase0.js"; +import {generatePerfTestCachedStateAltair, numValidators} from "../util.js"; import {mutateInactivityScores} from "./util.js"; +import {FlagFactors, generateBalanceDeltasEpochTransitionCache} from "./utilPhase0.js"; // PERF: Cost = 'proportional' to $VALIDATOR_COUNT. Extra work is done per validator the more status flags are set diff --git a/packages/state-transition/test/perf/epoch/processRewardsAndPenaltiesPhase0.test.ts b/packages/state-transition/test/perf/epoch/processRewardsAndPenaltiesPhase0.test.ts index e39b5962ea18..c5e747502e76 100644 --- a/packages/state-transition/test/perf/epoch/processRewardsAndPenaltiesPhase0.test.ts +++ b/packages/state-transition/test/perf/epoch/processRewardsAndPenaltiesPhase0.test.ts @@ -1,7 +1,7 @@ import {itBench} from "@dapplion/benchmark"; import {getAttestationDeltas} from "../../../src/epoch/getAttestationDeltas.js"; -import {generatePerfTestCachedStatePhase0, numValidators} from "../util.js"; import {StatePhase0Epoch} from "../types.js"; +import {generatePerfTestCachedStatePhase0, numValidators} from "../util.js"; import {FlagFactors, generateBalanceDeltasEpochTransitionCache} from "./utilPhase0.js"; // - On normal mainnet conditions diff --git a/packages/state-transition/test/perf/epoch/processSlashingsAllForks.test.ts b/packages/state-transition/test/perf/epoch/processSlashingsAllForks.test.ts index 3b0bfa623fb2..6a590e3c632f 100644 --- a/packages/state-transition/test/perf/epoch/processSlashingsAllForks.test.ts +++ b/packages/state-transition/test/perf/epoch/processSlashingsAllForks.test.ts @@ -1,14 +1,14 @@ import {itBench} from "@dapplion/benchmark"; import {MAX_EFFECTIVE_BALANCE} from "@lodestar/params"; +import {processSlashings} from "../../../src/epoch/processSlashings.js"; import { - beforeProcessEpoch, - CachedBeaconStatePhase0, CachedBeaconStateAllForks, + CachedBeaconStatePhase0, EpochTransitionCache, + beforeProcessEpoch, } from "../../../src/index.js"; -import {processSlashings} from "../../../src/epoch/processSlashings.js"; -import {generatePerfTestCachedStatePhase0, numValidators} from "../util.js"; import {StateEpoch} from "../types.js"; +import {generatePerfTestCachedStatePhase0, numValidators} from "../util.js"; // PERF: Cost 'proportional' to only validators that are slashed. For mainnet conditions: // - indicesToSlash: max len is 8704. But it's very unlikely since it would require all validators on the same diff --git a/packages/state-transition/test/perf/epoch/utilPhase0.ts b/packages/state-transition/test/perf/epoch/utilPhase0.ts index 41c7d9780e01..78e27563835b 100644 --- a/packages/state-transition/test/perf/epoch/utilPhase0.ts +++ b/packages/state-transition/test/perf/epoch/utilPhase0.ts @@ -1,5 +1,5 @@ import {AttesterFlags, toAttesterFlags} from "../../../src/index.js"; -import {CachedBeaconStatePhase0, CachedBeaconStateAltair, EpochTransitionCache} from "../../../src/types.js"; +import {CachedBeaconStateAltair, CachedBeaconStatePhase0, EpochTransitionCache} from "../../../src/types.js"; /** * Generate an incomplete EpochTransitionCache to simulate any network condition relevant to getAttestationDeltas diff --git a/packages/state-transition/test/perf/hashing.test.ts b/packages/state-transition/test/perf/hashing.test.ts index 26bfd935c08a..d0a651cc8824 100644 --- a/packages/state-transition/test/perf/hashing.test.ts +++ b/packages/state-transition/test/perf/hashing.test.ts @@ -1,7 +1,7 @@ -import {itBench} from "@dapplion/benchmark"; import {unshuffleList} from "@chainsafe/swap-or-not-shuffle"; -import {ssz} from "@lodestar/types"; +import {itBench} from "@dapplion/benchmark"; import {SHUFFLE_ROUND_COUNT} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; import {generatePerfTestCachedStatePhase0, numValidators} from "./util.js"; // Test cost of hashing state after some modifications diff --git a/packages/state-transition/test/perf/misc/aggregationBits.test.ts b/packages/state-transition/test/perf/misc/aggregationBits.test.ts index a0578970dfe9..6beade2d11f4 100644 --- a/packages/state-transition/test/perf/misc/aggregationBits.test.ts +++ b/packages/state-transition/test/perf/misc/aggregationBits.test.ts @@ -1,5 +1,5 @@ -import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {BitArray} from "@chainsafe/ssz"; +import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; import {ssz} from "@lodestar/types"; diff --git a/packages/state-transition/test/perf/misc/byteArrayEquals.test.ts b/packages/state-transition/test/perf/misc/byteArrayEquals.test.ts index 64057a26d103..b8b34eda6721 100644 --- a/packages/state-transition/test/perf/misc/byteArrayEquals.test.ts +++ b/packages/state-transition/test/perf/misc/byteArrayEquals.test.ts @@ -1,6 +1,6 @@ import crypto from "node:crypto"; -import {itBench} from "@dapplion/benchmark"; import {byteArrayEquals} from "@chainsafe/ssz"; +import {itBench} from "@dapplion/benchmark"; import {generateState} from "../../utils/state.js"; import {generateValidators} from "../../utils/validator.js"; diff --git a/packages/state-transition/test/perf/misc/rootEquals.test.ts b/packages/state-transition/test/perf/misc/rootEquals.test.ts index f941e764c26b..39ec15c8de9f 100644 --- a/packages/state-transition/test/perf/misc/rootEquals.test.ts +++ b/packages/state-transition/test/perf/misc/rootEquals.test.ts @@ -1,5 +1,5 @@ -import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {byteArrayEquals, fromHexString} from "@chainsafe/ssz"; +import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {ssz} from "@lodestar/types"; // As of Sep 2023 diff --git a/packages/state-transition/test/perf/sanityCheck.test.ts b/packages/state-transition/test/perf/sanityCheck.test.ts index 834e118d0f76..26902622f6e4 100644 --- a/packages/state-transition/test/perf/sanityCheck.test.ts +++ b/packages/state-transition/test/perf/sanityCheck.test.ts @@ -1,5 +1,5 @@ -import {expect} from "chai"; import {ACTIVE_PRESET, EFFECTIVE_BALANCE_INCREMENT, PresetName} from "@lodestar/params"; +import {expect} from "chai"; import {beforeProcessEpoch} from "../../src/index.js"; import {generatePerfTestCachedStateAltair, generatePerfTestCachedStatePhase0, perfStateId} from "./util.js"; diff --git a/packages/state-transition/test/perf/slot/slots.test.ts b/packages/state-transition/test/perf/slot/slots.test.ts index 4f436876d9b0..8a1e9836ae22 100644 --- a/packages/state-transition/test/perf/slot/slots.test.ts +++ b/packages/state-transition/test/perf/slot/slots.test.ts @@ -1,7 +1,7 @@ import {itBench} from "@dapplion/benchmark"; import {processSlot} from "../../../src/slot/index.js"; -import {generatePerfTestCachedStatePhase0} from "../util.js"; import {State} from "../types.js"; +import {generatePerfTestCachedStatePhase0} from "../util.js"; // Test advancing through an empty slot, without any epoch transition diff --git a/packages/state-transition/test/perf/types.ts b/packages/state-transition/test/perf/types.ts index 8f4914238dba..2e494e263214 100644 --- a/packages/state-transition/test/perf/types.ts +++ b/packages/state-transition/test/perf/types.ts @@ -1,5 +1,5 @@ import {SignedBeaconBlock} from "@lodestar/types"; -import {CachedBeaconStateAllForks, CachedBeaconStatePhase0, CachedBeaconStateAltair} from "../../src/index.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../../src/index.js"; import {EpochTransitionCache} from "../../src/types.js"; // Type aliases to typesafe itBench() calls diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index 0f47c241f8f9..7dc5daeff754 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -1,9 +1,8 @@ -import {BitArray, fromHexString} from "@chainsafe/ssz"; import {PublicKey, SecretKey} from "@chainsafe/blst"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; -import {phase0, ssz, Slot, BeaconState} from "@lodestar/types"; -import {config} from "@lodestar/config/default"; +import {BitArray, fromHexString} from "@chainsafe/ssz"; import {createBeaconConfig, createChainForkConfig} from "@lodestar/config"; +import {config} from "@lodestar/config/default"; import { EPOCHS_PER_ETH1_VOTING_PERIOD, EPOCHS_PER_HISTORICAL_VECTOR, @@ -14,25 +13,26 @@ import { SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT, } from "@lodestar/params"; +import {BeaconState, Slot, phase0, ssz} from "@lodestar/types"; +import {getEffectiveBalanceIncrements} from "../../src/cache/effectiveBalanceIncrements.js"; import { - interopSecretKey, + computeCommitteeCount, computeEpochAtSlot, + createCachedBeaconState, getActiveValidatorIndices, + interopSecretKey, newFilledArray, - createCachedBeaconState, - computeCommitteeCount, } from "../../src/index.js"; +import {processSlots} from "../../src/index.js"; import { + BeaconStateAltair, + BeaconStatePhase0, CachedBeaconStateAllForks, - CachedBeaconStatePhase0, CachedBeaconStateAltair, - BeaconStatePhase0, - BeaconStateAltair, + CachedBeaconStatePhase0, } from "../../src/types.js"; -import {interopPubkeysCached} from "../utils/interop.js"; import {getNextSyncCommittee} from "../../src/util/syncCommittee.js"; -import {getEffectiveBalanceIncrements} from "../../src/cache/effectiveBalanceIncrements.js"; -import {processSlots} from "../../src/index.js"; +import {interopPubkeysCached} from "../utils/interop.js"; let phase0State: BeaconStatePhase0 | null = null; let phase0CachedState23637: CachedBeaconStatePhase0 | null = null; diff --git a/packages/state-transition/test/perf/util/balance.test.ts b/packages/state-transition/test/perf/util/balance.test.ts index 4103b3b5517f..a8d4f5157a6e 100644 --- a/packages/state-transition/test/perf/util/balance.test.ts +++ b/packages/state-transition/test/perf/util/balance.test.ts @@ -1,7 +1,7 @@ import {itBench} from "@dapplion/benchmark"; -import {generatePerfTestCachedStatePhase0, perfStateId} from "../util.js"; -import {State} from "../types.js"; import {getEffectiveBalanceIncrementsZeroInactive} from "../../../src/util/index.js"; +import {State} from "../types.js"; +import {generatePerfTestCachedStatePhase0, perfStateId} from "../util.js"; describe("getEffectiveBalanceIncrementsZeroInactive", () => { itBench({ diff --git a/packages/state-transition/test/perf/util/epochContext.test.ts b/packages/state-transition/test/perf/util/epochContext.test.ts index 9ae478d4161b..2f49d8bfa09b 100644 --- a/packages/state-transition/test/perf/util/epochContext.test.ts +++ b/packages/state-transition/test/perf/util/epochContext.test.ts @@ -1,6 +1,6 @@ import {itBench} from "@dapplion/benchmark"; import {Epoch} from "@lodestar/types"; -import {computeEpochAtSlot, CachedBeaconStateAllForks} from "../../../src/index.js"; +import {CachedBeaconStateAllForks, computeEpochAtSlot} from "../../../src/index.js"; import {generatePerfTestCachedStatePhase0, numValidators} from "../util.js"; // Current implementation scales very well with number of requested validators diff --git a/packages/state-transition/test/perf/util/loadState/findModifiedValidators.test.ts b/packages/state-transition/test/perf/util/loadState/findModifiedValidators.test.ts index 4028104f0bdc..6cd8650f3afc 100644 --- a/packages/state-transition/test/perf/util/loadState/findModifiedValidators.test.ts +++ b/packages/state-transition/test/perf/util/loadState/findModifiedValidators.test.ts @@ -1,12 +1,12 @@ -import {expect} from "chai"; -import {itBench} from "@dapplion/benchmark"; import {CompositeViewDU} from "@chainsafe/ssz"; +import {itBench} from "@dapplion/benchmark"; import {ssz} from "@lodestar/types"; import {bytesToInt} from "@lodestar/utils"; +import {expect} from "chai"; import {findModifiedValidators} from "../../../../src/util/loadState/findModifiedValidators.js"; import {VALIDATOR_BYTES_SIZE} from "../../../../src/util/sszBytes.js"; -import {generateValidators} from "../../../utils/validator.js"; import {generateState} from "../../../utils/state.js"; +import {generateValidators} from "../../../utils/validator.js"; /** * find modified validators by different ways. This proves that findModifiedValidators() leveraging Buffer.compare() is the fastest way. diff --git a/packages/state-transition/test/perf/util/loadState/loadState.test.ts b/packages/state-transition/test/perf/util/loadState/loadState.test.ts index 9f6175e95684..e41e4f6be7af 100644 --- a/packages/state-transition/test/perf/util/loadState/loadState.test.ts +++ b/packages/state-transition/test/perf/util/loadState/loadState.test.ts @@ -1,9 +1,9 @@ -import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {PublicKey} from "@chainsafe/blst"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; -import {loadState} from "../../../../src/util/loadState/loadState.js"; -import {createCachedBeaconState} from "../../../../src/cache/stateCache.js"; +import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {Index2PubkeyCache} from "../../../../src/cache/pubkeyCache.js"; +import {createCachedBeaconState} from "../../../../src/cache/stateCache.js"; +import {loadState} from "../../../../src/util/loadState/loadState.js"; import {generatePerfTestCachedStateAltair} from "../../util.js"; /** diff --git a/packages/state-transition/test/perf/util/rootCache.test.ts b/packages/state-transition/test/perf/util/rootCache.test.ts index 59edd2ebcb4e..2d0ba33004f5 100644 --- a/packages/state-transition/test/perf/util/rootCache.test.ts +++ b/packages/state-transition/test/perf/util/rootCache.test.ts @@ -1,7 +1,7 @@ import {itBench} from "@dapplion/benchmark"; -import {generatePerfTestCachedStatePhase0, perfStateId, perfStateEpoch} from "../util.js"; +import {RootCache, computeStartSlotAtEpoch, getBlockRootAtSlot} from "../../../src/util/index.js"; import {State} from "../types.js"; -import {computeStartSlotAtEpoch, getBlockRootAtSlot, RootCache} from "../../../src/util/index.js"; +import {generatePerfTestCachedStatePhase0, perfStateEpoch, perfStateId} from "../util.js"; const slot = computeStartSlotAtEpoch(perfStateEpoch) - 1; diff --git a/packages/state-transition/test/perf/util/shufflings.test.ts b/packages/state-transition/test/perf/util/shufflings.test.ts index 41767c184349..95afa1ca9849 100644 --- a/packages/state-transition/test/perf/util/shufflings.test.ts +++ b/packages/state-transition/test/perf/util/shufflings.test.ts @@ -1,12 +1,12 @@ import {itBench} from "@dapplion/benchmark"; -import {Epoch} from "@lodestar/types"; import {DOMAIN_BEACON_PROPOSER} from "@lodestar/params"; +import {Epoch} from "@lodestar/types"; import { - computeEpochAtSlot, CachedBeaconStateAllForks, + computeEpochAtSlot, computeEpochShuffling, - getNextSyncCommittee, computeProposers, + getNextSyncCommittee, getSeed, } from "../../../src/index.js"; import {generatePerfTestCachedStatePhase0, numValidators} from "../util.js"; diff --git a/packages/state-transition/test/perf/util/signingRoot.test.ts b/packages/state-transition/test/perf/util/signingRoot.test.ts index 1d308c2e3e43..b39ef44a15e7 100644 --- a/packages/state-transition/test/perf/util/signingRoot.test.ts +++ b/packages/state-transition/test/perf/util/signingRoot.test.ts @@ -1,6 +1,6 @@ -import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {digest} from "@chainsafe/as-sha256"; import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {phase0, ssz} from "@lodestar/types"; import {computeSigningRoot} from "../../../src/util/signingRoot.js"; diff --git a/packages/state-transition/test/unit/block/isValidIndexedAttestation.test.ts b/packages/state-transition/test/unit/block/isValidIndexedAttestation.test.ts index c219943b940f..c54457c0ad09 100644 --- a/packages/state-transition/test/unit/block/isValidIndexedAttestation.test.ts +++ b/packages/state-transition/test/unit/block/isValidIndexedAttestation.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect} from "vitest"; import {config} from "@lodestar/config/default"; import {FAR_FUTURE_EPOCH, MAX_EFFECTIVE_BALANCE} from "@lodestar/params"; import {phase0, ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; +import {isValidIndexedAttestation} from "../../../src/block/isValidIndexedAttestation.js"; import {EMPTY_SIGNATURE} from "../../../src/index.js"; import {generateCachedState} from "../../utils/state.js"; import {generateValidators} from "../../utils/validator.js"; -import {isValidIndexedAttestation} from "../../../src/block/isValidIndexedAttestation.js"; describe("validate indexed attestation", () => { const state = generateCachedState(config, { diff --git a/packages/state-transition/test/unit/block/processWithdrawals.test.ts b/packages/state-transition/test/unit/block/processWithdrawals.test.ts index 7b708d108a7b..7cfdfc6d58bb 100644 --- a/packages/state-transition/test/unit/block/processWithdrawals.test.ts +++ b/packages/state-transition/test/unit/block/processWithdrawals.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect} from "vitest"; import {ForkSeq} from "@lodestar/params"; +import {describe, expect, it} from "vitest"; import {getExpectedWithdrawals} from "../../../src/block/processWithdrawals.js"; import {numValidators} from "../../perf/util.js"; -import {getExpectedWithdrawalsTestData, WithdrawalOpts} from "../../utils/capella.js"; import {beforeValue} from "../../utils/beforeValue.js"; +import {WithdrawalOpts, getExpectedWithdrawalsTestData} from "../../utils/capella.js"; describe("getExpectedWithdrawals", () => { const vc = numValidators; diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index 668f22e13a1e..de2ba5893b02 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -1,14 +1,14 @@ -import {fromHexString} from "@chainsafe/ssz"; -import {describe, it, expect} from "vitest"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; +import {fromHexString} from "@chainsafe/ssz"; +import {createBeaconConfig, createChainForkConfig} from "@lodestar/config"; +import {config as defaultConfig} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; import {toHexString} from "@lodestar/utils"; -import {config as defaultConfig} from "@lodestar/config/default"; -import {createBeaconConfig, createChainForkConfig} from "@lodestar/config"; -import {createCachedBeaconStateTest} from "../utils/state.js"; +import {describe, expect, it} from "vitest"; import {createCachedBeaconState, loadCachedBeaconState} from "../../src/cache/stateCache.js"; -import {interopPubkeysCached} from "../utils/interop.js"; import {modifyStateSameValidator, newStateWithValidators} from "../utils/capella.js"; +import {interopPubkeysCached} from "../utils/interop.js"; +import {createCachedBeaconStateTest} from "../utils/state.js"; describe("CachedBeaconState", () => { it("Clone and mutate", () => { diff --git a/packages/state-transition/test/unit/constants.test.ts b/packages/state-transition/test/unit/constants.test.ts index 1cb17472218b..29b50fcb9c04 100644 --- a/packages/state-transition/test/unit/constants.test.ts +++ b/packages/state-transition/test/unit/constants.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import * as blst from "@chainsafe/blst"; +import {describe, expect, it} from "vitest"; import {G2_POINT_AT_INFINITY} from "../../src/index.js"; describe("constants", () => { diff --git a/packages/state-transition/test/unit/signatureSets/signatureSets.test.ts b/packages/state-transition/test/unit/signatureSets/signatureSets.test.ts index 353b68195636..ca9096ea8009 100644 --- a/packages/state-transition/test/unit/signatureSets/signatureSets.test.ts +++ b/packages/state-transition/test/unit/signatureSets/signatureSets.test.ts @@ -1,10 +1,10 @@ import crypto from "node:crypto"; -import {describe, it, expect} from "vitest"; -import {BitArray} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; +import {BitArray} from "@chainsafe/ssz"; import {config} from "@lodestar/config/default"; -import {phase0, capella, ValidatorIndex, BLSSignature, ssz} from "@lodestar/types"; import {FAR_FUTURE_EPOCH, MAX_EFFECTIVE_BALANCE} from "@lodestar/params"; +import {BLSSignature, ValidatorIndex, capella, phase0, ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import {ZERO_HASH} from "../../../src/constants/index.js"; import {getBlockSignatureSets} from "../../../src/signatureSets/index.js"; import {generateCachedState} from "../../utils/state.js"; diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 19a7d5c186f8..9923463b46be 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -1,13 +1,13 @@ -import {expect, describe, it} from "vitest"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; -import {ssz} from "@lodestar/types"; -import {ForkName} from "@lodestar/params"; -import {createBeaconConfig, ChainForkConfig, createChainForkConfig} from "@lodestar/config"; +import {ChainForkConfig, createBeaconConfig, createChainForkConfig} from "@lodestar/config"; import {config as chainConfig} from "@lodestar/config/default"; +import {ForkName} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; +import {createCachedBeaconState} from "../../src/cache/stateCache.js"; import {upgradeStateToDeneb} from "../../src/slot/upgradeStateToDeneb.js"; import {upgradeStateToElectra} from "../../src/slot/upgradeStateToElectra.js"; -import {createCachedBeaconState} from "../../src/cache/stateCache.js"; describe("upgradeState", () => { it("upgradeStateToDeneb", () => { diff --git a/packages/state-transition/test/unit/util/aggregator.test.ts b/packages/state-transition/test/unit/util/aggregator.test.ts index 58c2b0afbf58..ae4f1d0408f8 100644 --- a/packages/state-transition/test/unit/util/aggregator.test.ts +++ b/packages/state-transition/test/unit/util/aggregator.test.ts @@ -1,11 +1,11 @@ -import {describe, it, expect, beforeAll} from "vitest"; import {fromHexString} from "@chainsafe/ssz"; import { SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_COUNT, - TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE, TARGET_AGGREGATORS_PER_COMMITTEE, + TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE, } from "@lodestar/params"; +import {beforeAll, describe, expect, it} from "vitest"; import {isAggregatorFromCommitteeLength, isSyncCommitteeAggregator} from "../../../src/util/aggregator.js"; describe("isAttestationAggregator", () => { diff --git a/packages/state-transition/test/unit/util/balance.test.ts b/packages/state-transition/test/unit/util/balance.test.ts index 5b666cb0524e..2436c74a4e3c 100644 --- a/packages/state-transition/test/unit/util/balance.test.ts +++ b/packages/state-transition/test/unit/util/balance.test.ts @@ -1,14 +1,14 @@ -import {describe, it, expect} from "vitest"; import {config as minimalConfig} from "@lodestar/config/default"; +import {describe, expect, it} from "vitest"; import {EFFECTIVE_BALANCE_INCREMENT} from "@lodestar/params"; import {ValidatorIndex} from "@lodestar/types"; -import {increaseBalance, decreaseBalance, getTotalBalance, isActiveValidator} from "../../../src/util/index.js"; -import {getEffectiveBalanceIncrementsZeroed, getEffectiveBalanceIncrementsZeroInactive} from "../../../src/index.js"; +import {getEffectiveBalanceIncrementsZeroInactive, getEffectiveBalanceIncrementsZeroed} from "../../../src/index.js"; +import {decreaseBalance, getTotalBalance, increaseBalance, isActiveValidator} from "../../../src/util/index.js"; -import {generateValidators} from "../../utils/validator.js"; import {generateCachedState, generateState} from "../../utils/state.js"; +import {generateValidators} from "../../utils/validator.js"; describe("getTotalBalance", () => { it("should return correct balances - 500 validators", () => { diff --git a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts index c85a8c7a2ffd..cd7a161d5355 100644 --- a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts @@ -1,8 +1,8 @@ -import {describe, it} from "vitest"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; +import {describe, it} from "vitest"; import {createCachedBeaconState} from "../../../src/index.js"; describe("CachedBeaconState", () => { diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts index a682b4e993ed..de73015c1f71 100644 --- a/packages/state-transition/test/unit/util/deposit.test.ts +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; -import {ssz} from "@lodestar/types"; import {createChainForkConfig} from "@lodestar/config"; import {MAX_DEPOSITS} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import {getEth1DepositCount} from "../../../src/index.js"; import {createCachedBeaconStateTest} from "../../utils/state.js"; diff --git a/packages/state-transition/test/unit/util/epoch.test.ts b/packages/state-transition/test/unit/util/epoch.test.ts index e86a41875e1d..cc11688ef080 100644 --- a/packages/state-transition/test/unit/util/epoch.test.ts +++ b/packages/state-transition/test/unit/util/epoch.test.ts @@ -1,12 +1,12 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {GENESIS_SLOT, MAX_SEED_LOOKAHEAD} from "@lodestar/params"; import {Epoch, Slot} from "@lodestar/types"; import { - computeStartSlotAtEpoch, - getPreviousEpoch, computeActivationExitEpoch, computeEpochAtSlot, + computeStartSlotAtEpoch, + getPreviousEpoch, } from "../../../src/util/index.js"; import {generateState} from "../../utils/state.js"; diff --git a/packages/state-transition/test/unit/util/flags.test.ts b/packages/state-transition/test/unit/util/flags.test.ts index 07a8ce3fe097..58e40ff38586 100644 --- a/packages/state-transition/test/unit/util/flags.test.ts +++ b/packages/state-transition/test/unit/util/flags.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; describe("Altair status flags", () => { for (let prev = 0b000; prev <= 0b111; prev++) { diff --git a/packages/state-transition/test/unit/util/loadState.test.ts b/packages/state-transition/test/unit/util/loadState.test.ts index 97a792a28adb..4955c707e8ff 100644 --- a/packages/state-transition/test/unit/util/loadState.test.ts +++ b/packages/state-transition/test/unit/util/loadState.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect} from "vitest"; -import {ssz} from "@lodestar/types"; -import {mainnetChainConfig} from "@lodestar/config/networks"; import {createChainForkConfig} from "@lodestar/config"; +import {mainnetChainConfig} from "@lodestar/config/networks"; import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import {loadStateAndValidators} from "../../../src/util/loadState/loadState.js"; describe("loadStateAndValidators", () => { diff --git a/packages/state-transition/test/unit/util/loadState/findModifiedInactivityScores.test.ts b/packages/state-transition/test/unit/util/loadState/findModifiedInactivityScores.test.ts index 85697af2b7c1..77301b3aef58 100644 --- a/packages/state-transition/test/unit/util/loadState/findModifiedInactivityScores.test.ts +++ b/packages/state-transition/test/unit/util/loadState/findModifiedInactivityScores.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import { INACTIVITY_SCORE_SIZE, findModifiedInactivityScores, diff --git a/packages/state-transition/test/unit/util/loadState/findModifiedValidators.test.ts b/packages/state-transition/test/unit/util/loadState/findModifiedValidators.test.ts index 25c6233d2738..29c2b974a7a9 100644 --- a/packages/state-transition/test/unit/util/loadState/findModifiedValidators.test.ts +++ b/packages/state-transition/test/unit/util/loadState/findModifiedValidators.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {fromHexString} from "@chainsafe/ssz"; +import {describe, expect, it} from "vitest"; import {findModifiedValidators} from "../../../../src/util/loadState/findModifiedValidators.js"; import {generateState} from "../../../utils/state.js"; import {generateValidators} from "../../../utils/validator.js"; diff --git a/packages/state-transition/test/unit/util/loadState/loadValidator.test.ts b/packages/state-transition/test/unit/util/loadState/loadValidator.test.ts index 9a2094531813..9295df4f9797 100644 --- a/packages/state-transition/test/unit/util/loadState/loadValidator.test.ts +++ b/packages/state-transition/test/unit/util/loadState/loadValidator.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; import {CompositeViewDU} from "@chainsafe/ssz"; import {phase0, ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import {loadValidator} from "../../../../src/util/loadState/loadValidator.js"; describe("loadValidator", () => { diff --git a/packages/state-transition/test/unit/util/misc.test.ts b/packages/state-transition/test/unit/util/misc.test.ts index 5651da5ac5d1..ae6387137a3f 100644 --- a/packages/state-transition/test/unit/util/misc.test.ts +++ b/packages/state-transition/test/unit/util/misc.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; -import {toBigIntLE} from "bigint-buffer"; import {GENESIS_SLOT, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params"; +import {toBigIntLE} from "bigint-buffer"; import {getBlockRoot} from "../../../src/util/index.js"; import {generateState} from "../../utils/state.js"; diff --git a/packages/state-transition/test/unit/util/seed.test.ts b/packages/state-transition/test/unit/util/seed.test.ts index 7f7c0e1f8bc7..e0f9e5d8ae67 100644 --- a/packages/state-transition/test/unit/util/seed.test.ts +++ b/packages/state-transition/test/unit/util/seed.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {toHexString} from "@chainsafe/ssz"; import {GENESIS_EPOCH, GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; diff --git a/packages/state-transition/test/unit/util/shuffling.test.ts b/packages/state-transition/test/unit/util/shuffling.test.ts index f4039b472f5c..ed8eb1775db6 100644 --- a/packages/state-transition/test/unit/util/shuffling.test.ts +++ b/packages/state-transition/test/unit/util/shuffling.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect} from "vitest"; import {ssz} from "@lodestar/types"; -import {generateState} from "../../utils/state.js"; -import {computeEpochShuffling, computeEpochShufflingAsync} from "../../../src/util/epochShuffling.js"; +import {describe, expect, it} from "vitest"; import {computeEpochAtSlot} from "../../../src/index.js"; +import {computeEpochShuffling, computeEpochShufflingAsync} from "../../../src/util/epochShuffling.js"; +import {generateState} from "../../utils/state.js"; describe("EpochShuffling", () => { it("async and sync versions should be identical", async () => { diff --git a/packages/state-transition/test/unit/util/slashing.test.ts b/packages/state-transition/test/unit/util/slashing.test.ts index 49a7b6454c25..fbae1abbce84 100644 --- a/packages/state-transition/test/unit/util/slashing.test.ts +++ b/packages/state-transition/test/unit/util/slashing.test.ts @@ -1,4 +1,4 @@ -import {expect, it, describe} from "vitest"; +import {describe, expect, it} from "vitest"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {Epoch, phase0, ssz} from "@lodestar/types"; diff --git a/packages/state-transition/test/unit/util/slot.test.ts b/packages/state-transition/test/unit/util/slot.test.ts index c9546ad60043..aa76498b366f 100644 --- a/packages/state-transition/test/unit/util/slot.test.ts +++ b/packages/state-transition/test/unit/util/slot.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {Slot} from "@lodestar/types"; import {computeSlotsSinceEpochStart} from "../../../src/util/index.js"; diff --git a/packages/state-transition/test/unit/util/validator.test.ts b/packages/state-transition/test/unit/util/validator.test.ts index 203adf9d8ba3..9c571f87c029 100644 --- a/packages/state-transition/test/unit/util/validator.test.ts +++ b/packages/state-transition/test/unit/util/validator.test.ts @@ -1,12 +1,12 @@ -import {describe, it, expect, beforeEach} from "vitest"; +import {beforeEach, describe, expect, it} from "vitest"; import {phase0, ssz} from "@lodestar/types"; import {getActiveValidatorIndices, isActiveValidator, isSlashableValidator} from "../../../src/util/index.js"; import {randBetween} from "../../utils/misc.js"; -import {generateValidator} from "../../utils/validator.js"; import {generateState} from "../../utils/state.js"; +import {generateValidator} from "../../utils/validator.js"; describe("getActiveValidatorIndices", () => { it("empty list of validators should return no indices (empty list)", () => { diff --git a/packages/state-transition/test/unit/util/weakSubjectivity.test.ts b/packages/state-transition/test/unit/util/weakSubjectivity.test.ts index ce9f02b5ed2f..3db06f86a191 100644 --- a/packages/state-transition/test/unit/util/weakSubjectivity.test.ts +++ b/packages/state-transition/test/unit/util/weakSubjectivity.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; import {config} from "@lodestar/config/default"; -import {computeWeakSubjectivityPeriodFromConstituents} from "../../../src/util/weakSubjectivity.js"; +import {describe, expect, it} from "vitest"; import {getChurnLimit} from "../../../src/util/validator.js"; +import {computeWeakSubjectivityPeriodFromConstituents} from "../../../src/util/weakSubjectivity.js"; describe("weak subjectivity tests", () => { describe("computeWeakSubjectivityPeriodFromConstituents", () => { diff --git a/packages/state-transition/test/utils/capella.ts b/packages/state-transition/test/utils/capella.ts index 7ef9248a5675..249053e2a22a 100644 --- a/packages/state-transition/test/utils/capella.ts +++ b/packages/state-transition/test/utils/capella.ts @@ -1,5 +1,4 @@ import crypto from "node:crypto"; -import {ssz} from "@lodestar/types"; import {config} from "@lodestar/config/default"; import { BLS_WITHDRAWAL_PREFIX, @@ -7,10 +6,11 @@ import { SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT, } from "@lodestar/params"; +import {ssz} from "@lodestar/types"; import {BeaconStateCapella, CachedBeaconStateCapella} from "../../src/index.js"; -import {createCachedBeaconStateTest} from "./state.js"; -import {mulberry32} from "./rand.js"; import {interopPubkeysCached} from "./interop.js"; +import {mulberry32} from "./rand.js"; +import {createCachedBeaconStateTest} from "./state.js"; export interface WithdrawalOpts { excessBalance: number; diff --git a/packages/state-transition/test/utils/state.ts b/packages/state-transition/test/utils/state.ts index 9a79faf74480..23cd90e05469 100644 --- a/packages/state-transition/test/utils/state.ts +++ b/packages/state-transition/test/utils/state.ts @@ -1,5 +1,6 @@ import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {config as minimalConfig} from "@lodestar/config/default"; +import {config} from "@lodestar/config/default"; import { EPOCHS_PER_HISTORICAL_VECTOR, EPOCHS_PER_SLASHINGS_VECTOR, @@ -8,20 +9,19 @@ import { SLOTS_PER_HISTORICAL_ROOT, } from "@lodestar/params"; import {phase0, ssz} from "@lodestar/types"; -import {config} from "@lodestar/config/default"; -import {createBeaconConfig, ChainForkConfig} from "@lodestar/config"; +import {ChainForkConfig, createBeaconConfig} from "@lodestar/config"; import {ZERO_HASH} from "../../src/constants/index.js"; import {newZeroedArray} from "../../src/util/index.js"; +import {EpochCacheOpts} from "../../src/cache/epochCache.js"; +import {BeaconStateCache} from "../../src/cache/stateCache.js"; import { + BeaconStateAllForks, BeaconStatePhase0, CachedBeaconStateAllForks, - BeaconStateAllForks, createCachedBeaconState, } from "../../src/index.js"; -import {BeaconStateCache} from "../../src/cache/stateCache.js"; -import {EpochCacheOpts} from "../../src/cache/epochCache.js"; /** * Copy of BeaconState, but all fields are marked optional to allow for swapping out variables as needed. diff --git a/packages/state-transition/test/utils/testFileCache.ts b/packages/state-transition/test/utils/testFileCache.ts index 5283a6f87fa1..dff164bcec44 100644 --- a/packages/state-transition/test/utils/testFileCache.ts +++ b/packages/state-transition/test/utils/testFileCache.ts @@ -1,10 +1,10 @@ import fs from "node:fs"; import path from "node:path"; -import got from "got"; import {getClient} from "@lodestar/api"; +import {ChainForkConfig, createChainForkConfig} from "@lodestar/config"; import {NetworkName, networksChainConfig} from "@lodestar/config/networks"; -import {createChainForkConfig, ChainForkConfig} from "@lodestar/config"; import {SignedBeaconBlock} from "@lodestar/types"; +import got from "got"; import {CachedBeaconStateAllForks} from "../../src/index.js"; import {testCachePath} from "../cache.js"; import {createCachedBeaconStateTest} from "../utils/state.js"; diff --git a/packages/test-utils/src/childProcess.ts b/packages/test-utils/src/childProcess.ts index d8b86b83ee48..62262c1c7756 100644 --- a/packages/test-utils/src/childProcess.ts +++ b/packages/test-utils/src/childProcess.ts @@ -1,9 +1,9 @@ /* eslint-disable no-console */ import childProcess, {ChildProcess, ChildProcessWithoutNullStreams} from "node:child_process"; -import stream from "node:stream"; import fs from "node:fs"; import path from "node:path"; -import {prettyMsToTime, retry, sleep, Logger} from "@lodestar/utils"; +import stream from "node:stream"; +import {Logger, prettyMsToTime, retry, sleep} from "@lodestar/utils"; export type ChildProcessLogOptions = { /** diff --git a/packages/test-utils/src/cli.ts b/packages/test-utils/src/cli.ts index a7b2a248bc7e..bdc87df96ac2 100644 --- a/packages/test-utils/src/cli.ts +++ b/packages/test-utils/src/cli.ts @@ -1,13 +1,13 @@ import childProcess from "node:child_process"; import type {Argv} from "yargs"; -import {wrapTimeout} from "./timeout.js"; -import {nodeJsBinaryPath, repoRootPath} from "./path.js"; import { ExecChildProcessOptions, SpawnChildProcessOptions, execChildProcess, spawnChildProcess, } from "./childProcess.js"; +import {nodeJsBinaryPath, repoRootPath} from "./path.js"; +import {wrapTimeout} from "./timeout.js"; // We need to make it easy for the user to pass the args for the CLI // yargs treat `["--preset minimal"] as a single arg, so we need to split it ["--preset", "minimal"] diff --git a/packages/test-utils/src/doubles.ts b/packages/test-utils/src/doubles.ts index 171c55824996..0e2b4aeb1e7f 100644 --- a/packages/test-utils/src/doubles.ts +++ b/packages/test-utils/src/doubles.ts @@ -1,5 +1,5 @@ -import {vi, MockInstance} from "vitest"; import {Logger} from "@lodestar/utils"; +import {MockInstance, vi} from "vitest"; type Callback = () => void; type Handler = (cb: Callback) => void; diff --git a/packages/test-utils/src/externalSigner.ts b/packages/test-utils/src/externalSigner.ts index 1e48e6af8d40..cdfbe484e72e 100644 --- a/packages/test-utils/src/externalSigner.ts +++ b/packages/test-utils/src/externalSigner.ts @@ -1,8 +1,8 @@ import fs from "node:fs"; import path from "node:path"; -import {dirSync as tmpDirSync} from "tmp"; -import {GenericContainer, Wait, StartedTestContainer} from "testcontainers"; import {ForkSeq} from "@lodestar/params"; +import {GenericContainer, StartedTestContainer, Wait} from "testcontainers"; +import {dirSync as tmpDirSync} from "tmp"; const web3signerVersion = "24.2.0"; diff --git a/packages/test-utils/src/http.ts b/packages/test-utils/src/http.ts index 85b64c110cab..1821cebd4112 100644 --- a/packages/test-utils/src/http.ts +++ b/packages/test-utils/src/http.ts @@ -1,5 +1,5 @@ -import axios from "axios"; import {sleep} from "@lodestar/utils"; +import axios from "axios"; type Method = "GET" | "POST" | "PUT"; diff --git a/packages/types/src/altair/index.ts b/packages/types/src/altair/index.ts index 981b2015e02a..31c28a0d3690 100644 --- a/packages/types/src/altair/index.ts +++ b/packages/types/src/altair/index.ts @@ -1,4 +1,4 @@ export * from "./types.js"; -import * as ts from "./types.js"; import * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; export {ts, ssz}; diff --git a/packages/types/src/altair/sszTypes.ts b/packages/types/src/altair/sszTypes.ts index 8998571a9f0d..61671825c840 100644 --- a/packages/types/src/altair/sszTypes.ts +++ b/packages/types/src/altair/sszTypes.ts @@ -1,13 +1,13 @@ import {BitVectorType, ContainerType, ListBasicType, ListCompositeType, VectorCompositeType} from "@chainsafe/ssz"; import { + EPOCHS_PER_SYNC_COMMITTEE_PERIOD, FINALIZED_ROOT_DEPTH, + HISTORICAL_ROOTS_LIMIT, NEXT_SYNC_COMMITTEE_DEPTH, - SYNC_COMMITTEE_SUBNET_COUNT, + SLOTS_PER_EPOCH, SYNC_COMMITTEE_SIZE, - HISTORICAL_ROOTS_LIMIT, + SYNC_COMMITTEE_SUBNET_COUNT, VALIDATOR_REGISTRY_LIMIT, - EPOCHS_PER_SYNC_COMMITTEE_PERIOD, - SLOTS_PER_EPOCH, } from "@lodestar/params"; import * as phase0Ssz from "../phase0/sszTypes.js"; import * as primitiveSsz from "../primitive/sszTypes.js"; diff --git a/packages/types/src/bellatrix/index.ts b/packages/types/src/bellatrix/index.ts index 981b2015e02a..31c28a0d3690 100644 --- a/packages/types/src/bellatrix/index.ts +++ b/packages/types/src/bellatrix/index.ts @@ -1,4 +1,4 @@ export * from "./types.js"; -import * as ts from "./types.js"; import * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; export {ts, ssz}; diff --git a/packages/types/src/bellatrix/sszTypes.ts b/packages/types/src/bellatrix/sszTypes.ts index 53e6d436c012..08560552d112 100644 --- a/packages/types/src/bellatrix/sszTypes.ts +++ b/packages/types/src/bellatrix/sszTypes.ts @@ -2,13 +2,13 @@ import {ByteListType, ByteVectorType, ContainerType, ListCompositeType} from "@c import { BYTES_PER_LOGS_BLOOM, HISTORICAL_ROOTS_LIMIT, - MAX_TRANSACTIONS_PER_PAYLOAD, MAX_BYTES_PER_TRANSACTION, MAX_EXTRA_DATA_BYTES, + MAX_TRANSACTIONS_PER_PAYLOAD, } from "@lodestar/params"; -import {ssz as primitiveSsz} from "../primitive/index.js"; -import {ssz as phase0Ssz} from "../phase0/index.js"; import {ssz as altairSsz} from "../altair/index.js"; +import {ssz as phase0Ssz} from "../phase0/index.js"; +import {ssz as primitiveSsz} from "../primitive/index.js"; import {stringType} from "../utils/stringType.js"; const { diff --git a/packages/types/src/capella/index.ts b/packages/types/src/capella/index.ts index 981b2015e02a..31c28a0d3690 100644 --- a/packages/types/src/capella/index.ts +++ b/packages/types/src/capella/index.ts @@ -1,4 +1,4 @@ export * from "./types.js"; -import * as ts from "./types.js"; import * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; export {ts, ssz}; diff --git a/packages/types/src/capella/sszTypes.ts b/packages/types/src/capella/sszTypes.ts index d7cc444e77af..3110e59111d9 100644 --- a/packages/types/src/capella/sszTypes.ts +++ b/packages/types/src/capella/sszTypes.ts @@ -1,16 +1,16 @@ import {ContainerType, ListCompositeType, VectorCompositeType} from "@chainsafe/ssz"; import { + EPOCHS_PER_SYNC_COMMITTEE_PERIOD, + BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, HISTORICAL_ROOTS_LIMIT, - MAX_WITHDRAWALS_PER_PAYLOAD, MAX_BLS_TO_EXECUTION_CHANGES, - BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, - EPOCHS_PER_SYNC_COMMITTEE_PERIOD, + MAX_WITHDRAWALS_PER_PAYLOAD, SLOTS_PER_EPOCH, } from "@lodestar/params"; -import {ssz as primitiveSsz} from "../primitive/index.js"; -import {ssz as phase0Ssz} from "../phase0/index.js"; import {ssz as altairSsz} from "../altair/index.js"; import {ssz as bellatrixSsz} from "../bellatrix/index.js"; +import {ssz as phase0Ssz} from "../phase0/index.js"; +import {ssz as primitiveSsz} from "../primitive/index.js"; const { UintNum64, diff --git a/packages/types/src/deneb/index.ts b/packages/types/src/deneb/index.ts index 981b2015e02a..31c28a0d3690 100644 --- a/packages/types/src/deneb/index.ts +++ b/packages/types/src/deneb/index.ts @@ -1,4 +1,4 @@ export * from "./types.js"; -import * as ts from "./types.js"; import * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; export {ts, ssz}; diff --git a/packages/types/src/deneb/sszTypes.ts b/packages/types/src/deneb/sszTypes.ts index 076973bba579..6dc18c8f8b02 100644 --- a/packages/types/src/deneb/sszTypes.ts +++ b/packages/types/src/deneb/sszTypes.ts @@ -1,19 +1,19 @@ -import {ContainerType, ListCompositeType, ByteVectorType, VectorCompositeType} from "@chainsafe/ssz"; +import {ByteVectorType, ContainerType, ListCompositeType, VectorCompositeType} from "@chainsafe/ssz"; import { + BYTES_PER_FIELD_ELEMENT, + EPOCHS_PER_SYNC_COMMITTEE_PERIOD, + FIELD_ELEMENTS_PER_BLOB, HISTORICAL_ROOTS_LIMIT, + KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, MAX_BLOB_COMMITMENTS_PER_BLOCK, - FIELD_ELEMENTS_PER_BLOB, MAX_REQUEST_BLOB_SIDECARS, - BYTES_PER_FIELD_ELEMENT, - EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, - KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, } from "@lodestar/params"; -import {ssz as primitiveSsz} from "../primitive/index.js"; -import {ssz as phase0Ssz} from "../phase0/index.js"; import {ssz as altairSsz} from "../altair/index.js"; import {ssz as bellatrixSsz} from "../bellatrix/index.js"; import {ssz as capellaSsz} from "../capella/index.js"; +import {ssz as phase0Ssz} from "../phase0/index.js"; +import {ssz as primitiveSsz} from "../primitive/index.js"; const {UintNum64, Slot, Root, BLSSignature, UintBn64, UintBn256, Bytes32, Bytes48, Bytes96, BLSPubkey, BlobIndex} = primitiveSsz; diff --git a/packages/types/src/electra/index.ts b/packages/types/src/electra/index.ts index 981b2015e02a..31c28a0d3690 100644 --- a/packages/types/src/electra/index.ts +++ b/packages/types/src/electra/index.ts @@ -1,4 +1,4 @@ export * from "./types.js"; -import * as ts from "./types.js"; import * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; export {ts, ssz}; diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 079af08352ec..f6b6c745803e 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -7,28 +7,28 @@ import { VectorCompositeType, } from "@chainsafe/ssz"; import { - HISTORICAL_ROOTS_LIMIT, EPOCHS_PER_SYNC_COMMITTEE_PERIOD, - SLOTS_PER_EPOCH, - MAX_DEPOSIT_REQUESTS_PER_PAYLOAD, - MAX_VALIDATORS_PER_COMMITTEE, - MAX_COMMITTEES_PER_SLOT, + FINALIZED_ROOT_DEPTH_ELECTRA, + HISTORICAL_ROOTS_LIMIT, MAX_ATTESTATIONS_ELECTRA, MAX_ATTESTER_SLASHINGS_ELECTRA, - MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_COMMITTEES_PER_SLOT, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, + MAX_DEPOSIT_REQUESTS_PER_PAYLOAD, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, + PENDING_CONSOLIDATIONS_LIMIT, PENDING_DEPOSITS_LIMIT, PENDING_PARTIAL_WITHDRAWALS_LIMIT, - PENDING_CONSOLIDATIONS_LIMIT, - FINALIZED_ROOT_DEPTH_ELECTRA, - NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, + SLOTS_PER_EPOCH, } from "@lodestar/params"; -import {ssz as primitiveSsz} from "../primitive/index.js"; -import {ssz as phase0Ssz} from "../phase0/index.js"; import {ssz as altairSsz} from "../altair/index.js"; import {ssz as bellatrixSsz} from "../bellatrix/index.js"; import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; +import {ssz as phase0Ssz} from "../phase0/index.js"; +import {ssz as primitiveSsz} from "../primitive/index.js"; const { Epoch, diff --git a/packages/types/src/phase0/index.ts b/packages/types/src/phase0/index.ts index 981b2015e02a..31c28a0d3690 100644 --- a/packages/types/src/phase0/index.ts +++ b/packages/types/src/phase0/index.ts @@ -1,4 +1,4 @@ export * from "./types.js"; -import * as ts from "./types.js"; import * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; export {ts, ssz}; diff --git a/packages/types/src/phase0/sszTypes.ts b/packages/types/src/phase0/sszTypes.ts index 4a04701b789d..2f9eead77608 100644 --- a/packages/types/src/phase0/sszTypes.ts +++ b/packages/types/src/phase0/sszTypes.ts @@ -4,8 +4,8 @@ import { ContainerType, ListBasicType, ListCompositeType, - VectorBasicType, ListUintNum64Type, + VectorBasicType, VectorCompositeType, } from "@chainsafe/ssz"; import { diff --git a/packages/types/src/primitive/index.ts b/packages/types/src/primitive/index.ts index b68df6795375..2e5e6adc9753 100644 --- a/packages/types/src/primitive/index.ts +++ b/packages/types/src/primitive/index.ts @@ -1,3 +1,3 @@ -import * as ts from "./types.js"; import * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; export {ts, ssz}; diff --git a/packages/types/src/primitive/sszTypes.ts b/packages/types/src/primitive/sszTypes.ts index 0b5156eaf24d..40806aa40f4a 100644 --- a/packages/types/src/primitive/sszTypes.ts +++ b/packages/types/src/primitive/sszTypes.ts @@ -1,4 +1,4 @@ -import {ByteVectorType, UintNumberType, UintBigintType, BooleanType} from "@chainsafe/ssz"; +import {BooleanType, ByteVectorType, UintBigintType, UintNumberType} from "@chainsafe/ssz"; import {ExecutionAddressType} from "../utils/executionAddress.js"; // biome-ignore lint/suspicious/noShadowRestrictedNames: We explicitly want this name for variable diff --git a/packages/types/src/sszTypes.ts b/packages/types/src/sszTypes.ts index 55218574be76..2a8666f3e243 100644 --- a/packages/types/src/sszTypes.ts +++ b/packages/types/src/sszTypes.ts @@ -1,11 +1,11 @@ import {CompositeType, CompositeView, CompositeViewDU, ContainerType, ValueOf} from "@chainsafe/ssz"; import {ForkName} from "@lodestar/params"; -import {ssz as phase0} from "./phase0/index.js"; import {ssz as altair} from "./altair/index.js"; import {ssz as bellatrix} from "./bellatrix/index.js"; import {ssz as capella} from "./capella/index.js"; import {ssz as deneb} from "./deneb/index.js"; import {ssz as electra} from "./electra/index.js"; +import {ssz as phase0} from "./phase0/index.js"; export * from "./primitive/sszTypes.js"; export {phase0, altair, bellatrix, capella, deneb, electra}; diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index b1919c2f0842..badb1f1f2333 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -7,12 +7,12 @@ import { ForkPostElectra, ForkPreBlobs, } from "@lodestar/params"; -import {ts as phase0} from "./phase0/index.js"; import {ts as altair} from "./altair/index.js"; import {ts as bellatrix} from "./bellatrix/index.js"; import {ts as capella} from "./capella/index.js"; import {ts as deneb} from "./deneb/index.js"; import {ts as electra} from "./electra/index.js"; +import {ts as phase0} from "./phase0/index.js"; import {Slot} from "./primitive/types.js"; export * from "./primitive/types.js"; diff --git a/packages/types/src/utils/executionAddress.ts b/packages/types/src/utils/executionAddress.ts index 9d555c016f04..ea1856405443 100644 --- a/packages/types/src/utils/executionAddress.ts +++ b/packages/types/src/utils/executionAddress.ts @@ -1,5 +1,5 @@ -import {keccak256} from "ethereum-cryptography/keccak.js"; import {ByteVectorType} from "@chainsafe/ssz"; +import {keccak256} from "ethereum-cryptography/keccak.js"; export type ByteVector = Uint8Array; diff --git a/packages/types/src/utils/typeguards.ts b/packages/types/src/utils/typeguards.ts index a892c3a0c9c0..d4a27e23d1d6 100644 --- a/packages/types/src/utils/typeguards.ts +++ b/packages/types/src/utils/typeguards.ts @@ -1,20 +1,20 @@ import {FINALIZED_ROOT_DEPTH_ELECTRA, ForkBlobs, ForkExecution, ForkPostElectra} from "@lodestar/params"; import { + Attestation, + BeaconBlock, + BeaconBlockBody, + BeaconBlockOrContents, + BlindedBeaconBlock, + BlindedBeaconBlockBody, BlockContents, - SignedBeaconBlock, ExecutionPayload, ExecutionPayloadAndBlobsBundle, - BeaconBlockBody, - BeaconBlockOrContents, - SignedBeaconBlockOrContents, ExecutionPayloadHeader, - BlindedBeaconBlock, + LightClientUpdate, + SignedBeaconBlock, + SignedBeaconBlockOrContents, SignedBlindedBeaconBlock, - BlindedBeaconBlockBody, SignedBlockContents, - BeaconBlock, - Attestation, - LightClientUpdate, } from "../types.js"; export function isExecutionPayload( diff --git a/packages/types/test/constants/blobs.test.ts b/packages/types/test/constants/blobs.test.ts index 4b145161d292..66927d4b6040 100644 --- a/packages/types/test/constants/blobs.test.ts +++ b/packages/types/test/constants/blobs.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import * as constants from "@lodestar/params"; +import {describe, expect, it} from "vitest"; import {ssz} from "../../src/index.js"; // NOTE: This test is here and not in lodestar-params, to prevent lodestar-params depending on SSZ diff --git a/packages/types/test/constants/lightclient.test.ts b/packages/types/test/constants/lightclient.test.ts index 567cc7c3bd17..9e87fcadca42 100644 --- a/packages/types/test/constants/lightclient.test.ts +++ b/packages/types/test/constants/lightclient.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import * as constants from "@lodestar/params"; +import {describe, expect, it} from "vitest"; import {ssz} from "../../src/index.js"; // NOTE: This test is here and not in lodestar-params, to prevent lodestar-params depending on SSZ diff --git a/packages/types/test/unit/blinded.test.ts b/packages/types/test/unit/blinded.test.ts index 3d087b610b2d..1024707705fe 100644 --- a/packages/types/test/unit/blinded.test.ts +++ b/packages/types/test/unit/blinded.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; import {ForkName, isForkExecution} from "@lodestar/params"; +import {describe, expect, it} from "vitest"; import {ssz} from "../../src/index.js"; describe("blinded data structures", () => { diff --git a/packages/types/test/unit/executionAddress.test.ts b/packages/types/test/unit/executionAddress.test.ts index 841cd52468f5..00f47fefba0c 100644 --- a/packages/types/test/unit/executionAddress.test.ts +++ b/packages/types/test/unit/executionAddress.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {toChecksumAddress} from "../../src/utils/executionAddress.js"; describe("toChecksumAddress", () => { diff --git a/packages/types/test/unit/phase0/sszTypes.test.ts b/packages/types/test/unit/phase0/sszTypes.test.ts index 4bdb2031e5ea..473adae31aea 100644 --- a/packages/types/test/unit/phase0/sszTypes.test.ts +++ b/packages/types/test/unit/phase0/sszTypes.test.ts @@ -1,5 +1,5 @@ import {ContainerType} from "@chainsafe/ssz"; -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {ssz} from "../../../src/index.js"; import {ValidatorType} from "../../../src/phase0/validator.js"; diff --git a/packages/types/test/unit/ssz.test.ts b/packages/types/test/unit/ssz.test.ts index 41e4e0bbd23b..1cc249a17a3e 100644 --- a/packages/types/test/unit/ssz.test.ts +++ b/packages/types/test/unit/ssz.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {ssz} from "../../src/index.js"; describe("size", () => { diff --git a/packages/types/test/unit/validatorStatus.test.ts b/packages/types/test/unit/validatorStatus.test.ts index b5bd34004bdc..70189a29ee11 100644 --- a/packages/types/test/unit/validatorStatus.test.ts +++ b/packages/types/test/unit/validatorStatus.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {getValidatorStatus} from "../../src/utils/validatorStatus.js"; +import {describe, expect, it} from "vitest"; import {phase0} from "../../src/types.js"; +import {getValidatorStatus} from "../../src/utils/validatorStatus.js"; describe("getValidatorStatus", () => { it("should return PENDING_INITIALIZED", () => { diff --git a/packages/utils/src/bytes.ts b/packages/utils/src/bytes.ts index c290232ce8db..195157d7c132 100644 --- a/packages/utils/src/bytes.ts +++ b/packages/utils/src/bytes.ts @@ -1,4 +1,4 @@ -import {toBufferLE, toBigIntLE, toBufferBE, toBigIntBE} from "bigint-buffer"; +import {toBigIntBE, toBigIntLE, toBufferBE, toBufferLE} from "bigint-buffer"; type Endianness = "le" | "be"; diff --git a/packages/utils/src/bytes/index.ts b/packages/utils/src/bytes/index.ts index a079764738b7..762a33bf5237 100644 --- a/packages/utils/src/bytes/index.ts +++ b/packages/utils/src/bytes/index.ts @@ -1,14 +1,14 @@ import { - toHex as browserToHex, - toRootHex as browserToRootHex, fromHex as browserFromHex, + toHex as browserToHex, toPubkeyHex as browserToPubkeyHex, + toRootHex as browserToRootHex, } from "./browser.js"; import { - toHex as nodeToHex, - toRootHex as nodeToRootHex, fromHex as nodeFromHex, + toHex as nodeToHex, toPubkeyHex as nodeToPubkeyHex, + toRootHex as nodeToRootHex, } from "./nodejs.js"; let toHex = browserToHex; diff --git a/packages/utils/src/command.ts b/packages/utils/src/command.ts index 2e62ba5a9648..13bf5850c8de 100644 --- a/packages/utils/src/command.ts +++ b/packages/utils/src/command.ts @@ -1,4 +1,4 @@ -import type {Options, Argv} from "yargs"; +import type {Argv, Options} from "yargs"; export interface CliExample { command: string; diff --git a/packages/utils/test/perf/bytes.test.ts b/packages/utils/test/perf/bytes.test.ts index 6a1e96ab1579..9c67745ed9a3 100644 --- a/packages/utils/test/perf/bytes.test.ts +++ b/packages/utils/test/perf/bytes.test.ts @@ -1,7 +1,7 @@ import {itBench} from "@dapplion/benchmark"; -import {toHex, toRootHex} from "../../src/bytes/nodejs.js"; -import {toHex as browserToHex, toRootHex as browserToRootHex} from "../../src/bytes/browser.js"; import {toHexString} from "../../src/bytes.js"; +import {toHex as browserToHex, toRootHex as browserToRootHex} from "../../src/bytes/browser.js"; +import {toHex, toRootHex} from "../../src/bytes/nodejs.js"; describe("bytes utils", () => { const runsFactor = 1000; diff --git a/packages/utils/test/types/metrics.test-d.ts b/packages/utils/test/types/metrics.test-d.ts index 2f008618e648..c6ad53e976c8 100644 --- a/packages/utils/test/types/metrics.test-d.ts +++ b/packages/utils/test/types/metrics.test-d.ts @@ -1,5 +1,5 @@ -import {describe, it, expectTypeOf} from "vitest"; import {Counter as PromCounter, Gauge as PromGauge, Histogram as PromHistogram} from "prom-client"; +import {describe, expectTypeOf, it} from "vitest"; import {Counter, Gauge, Histogram, MetricsRegister} from "../../src/metrics.js"; describe("Metric types", () => { diff --git a/packages/utils/test/unit/assert.test.ts b/packages/utils/test/unit/assert.test.ts index 3b413efa11be..536c84effd97 100644 --- a/packages/utils/test/unit/assert.test.ts +++ b/packages/utils/test/unit/assert.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {assert} from "../../src/index.js"; describe("assert", () => { diff --git a/packages/utils/test/unit/base64.test.ts b/packages/utils/test/unit/base64.test.ts index 7c68e84f4c3e..97a1a4d6c9b5 100644 --- a/packages/utils/test/unit/base64.test.ts +++ b/packages/utils/test/unit/base64.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; -import {toBase64, fromBase64} from "../../src/index.js"; +import {describe, expect, it} from "vitest"; +import {fromBase64, toBase64} from "../../src/index.js"; describe("toBase64", () => { it("should encode UTF-8 string as base64 string", () => { diff --git a/packages/utils/test/unit/bytes.test.ts b/packages/utils/test/unit/bytes.test.ts index af4df6652f13..3877ad81e120 100644 --- a/packages/utils/test/unit/bytes.test.ts +++ b/packages/utils/test/unit/bytes.test.ts @@ -1,13 +1,13 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import { - intToBytes, bytesToInt, - toHex, + formatBytes, fromHex, + intToBytes, + toHex, toHexString, - toRootHex, toPubkeyHex, - formatBytes, + toRootHex, } from "../../src/index.js"; describe("intToBytes", () => { diff --git a/packages/utils/test/unit/err.test.ts b/packages/utils/test/unit/err.test.ts index 7a08ebbc4319..e344e2fb88c7 100644 --- a/packages/utils/test/unit/err.test.ts +++ b/packages/utils/test/unit/err.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; -import {Err, isErr, mapOkResults, mapOkResultsAsync, Result} from "../../src/err.js"; +import {describe, expect, it} from "vitest"; +import {Err, Result, isErr, mapOkResults, mapOkResultsAsync} from "../../src/err.js"; describe("Result Err", () => { describe("isErr works with any type", () => { diff --git a/packages/utils/test/unit/format.test.ts b/packages/utils/test/unit/format.test.ts index 11e8b89cb7a1..2ca679f32a79 100644 --- a/packages/utils/test/unit/format.test.ts +++ b/packages/utils/test/unit/format.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {formatBigDecimal} from "../../src/format.js"; describe("format", () => { diff --git a/packages/utils/test/unit/math.test.ts b/packages/utils/test/unit/math.test.ts index e324714600b1..98a995b24ed8 100644 --- a/packages/utils/test/unit/math.test.ts +++ b/packages/utils/test/unit/math.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; -import {bigIntMin, bigIntMax, intDiv, intSqrt, bigIntSqrt} from "../../src/index.js"; +import {describe, expect, it} from "vitest"; +import {bigIntMax, bigIntMin, bigIntSqrt, intDiv, intSqrt} from "../../src/index.js"; describe("util/maths", () => { describe("bigIntMin", () => { diff --git a/packages/utils/test/unit/objects.test.ts b/packages/utils/test/unit/objects.test.ts index a94ed9213390..59f2024e09d6 100644 --- a/packages/utils/test/unit/objects.test.ts +++ b/packages/utils/test/unit/objects.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {isPlainObject, objectToExpectedCase} from "../../src/index.js"; describe("Objects helper", () => { diff --git a/packages/utils/test/unit/promise.node.test.ts b/packages/utils/test/unit/promise.node.test.ts index 55cbad36b211..d2e7a6e4cc22 100644 --- a/packages/utils/test/unit/promise.node.test.ts +++ b/packages/utils/test/unit/promise.node.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect, vi, beforeEach, afterEach} from "vitest"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {callFnWhenAwait} from "../../src/promise.js"; // TODO: Need to debug why vi.useFakeTimers() is not working for the browsers diff --git a/packages/utils/test/unit/promise.test.ts b/packages/utils/test/unit/promise.test.ts index c76e72f70a22..56df4d88ecf1 100644 --- a/packages/utils/test/unit/promise.test.ts +++ b/packages/utils/test/unit/promise.test.ts @@ -1,7 +1,7 @@ /* Causing this error on usage of expect.any(Number) */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import {describe, it, expect} from "vitest"; -import {wrapPromise, PromiseRejectedResult, PromiseFulfilledResult} from "../../src/promise.js"; +import {describe, expect, it} from "vitest"; +import {PromiseFulfilledResult, PromiseRejectedResult, wrapPromise} from "../../src/promise.js"; describe("promise", () => { describe("wrapPromise", () => { diff --git a/packages/utils/test/unit/promiserace.test.ts b/packages/utils/test/unit/promiserace.test.ts index 4b20f19f9fba..5aa5886c9848 100644 --- a/packages/utils/test/unit/promiserace.test.ts +++ b/packages/utils/test/unit/promiserace.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; -import {resolveOrRacePromises, PromiseResult} from "../../src/promise.js"; +import {describe, expect, it} from "vitest"; +import {PromiseResult, resolveOrRacePromises} from "../../src/promise.js"; import {NonEmptyArray} from "../../src/types.js"; describe("resolveOrRacePromises", () => { diff --git a/packages/utils/test/unit/retry.test.ts b/packages/utils/test/unit/retry.test.ts index bd77c499a364..5e5793664e3b 100644 --- a/packages/utils/test/unit/retry.test.ts +++ b/packages/utils/test/unit/retry.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect} from "vitest"; -import {retry, RetryOptions} from "../../src/retry.js"; +import {describe, expect, it} from "vitest"; +import {RetryOptions, retry} from "../../src/retry.js"; describe("retry", () => { type TestCase = { diff --git a/packages/utils/test/unit/sleep.test.ts b/packages/utils/test/unit/sleep.test.ts index ef632fd34f64..40dd699a5a06 100644 --- a/packages/utils/test/unit/sleep.test.ts +++ b/packages/utils/test/unit/sleep.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {sleep} from "../../src/sleep.js"; +import {describe, expect, it} from "vitest"; import {ErrorAborted} from "../../src/errors.js"; +import {sleep} from "../../src/sleep.js"; describe("sleep", () => { it("Should resolve timeout", async () => { diff --git a/packages/utils/test/unit/timeout.test.ts b/packages/utils/test/unit/timeout.test.ts index 7b4b1eb883be..7568983daa8d 100644 --- a/packages/utils/test/unit/timeout.test.ts +++ b/packages/utils/test/unit/timeout.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect, afterEach} from "vitest"; -import {withTimeout} from "../../src/timeout.js"; +import {afterEach, describe, expect, it} from "vitest"; import {ErrorAborted, TimeoutError} from "../../src/errors.js"; +import {withTimeout} from "../../src/timeout.js"; describe("withTimeout", () => { const data = "DATA"; diff --git a/packages/utils/test/unit/waitFor.test.ts b/packages/utils/test/unit/waitFor.test.ts index 412c06f888ed..844b0d157c61 100644 --- a/packages/utils/test/unit/waitFor.test.ts +++ b/packages/utils/test/unit/waitFor.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect} from "vitest"; -import {waitFor, createElapsedTimeTracker} from "../../src/waitFor.js"; +import {describe, expect, it} from "vitest"; import {ErrorAborted, TimeoutError} from "../../src/errors.js"; import {sleep} from "../../src/sleep.js"; +import {createElapsedTimeTracker, waitFor} from "../../src/waitFor.js"; describe("waitFor", () => { const interval = 10; diff --git a/packages/validator/src/genesis.ts b/packages/validator/src/genesis.ts index 7fc3e20673bc..9e947f89c949 100644 --- a/packages/validator/src/genesis.ts +++ b/packages/validator/src/genesis.ts @@ -1,6 +1,6 @@ +import {ApiClient} from "@lodestar/api"; import {Genesis} from "@lodestar/types/phase0"; import {Logger, sleep} from "@lodestar/utils"; -import {ApiClient} from "@lodestar/api"; /** The time between polls when waiting for genesis */ const WAITING_FOR_GENESIS_POLL_MS = 12 * 1000; diff --git a/packages/validator/src/repositories/metaDataRepository.ts b/packages/validator/src/repositories/metaDataRepository.ts index 0ba1565a6651..263ad9f8c6f3 100644 --- a/packages/validator/src/repositories/metaDataRepository.ts +++ b/packages/validator/src/repositories/metaDataRepository.ts @@ -1,8 +1,8 @@ -import {encodeKey, DbReqOpts} from "@lodestar/db"; +import {DbReqOpts, encodeKey} from "@lodestar/db"; import {Root, UintNum64} from "@lodestar/types"; import {ssz} from "@lodestar/types"; -import {LodestarValidatorDatabaseController} from "../types.js"; import {Bucket, getBucketNameByValue} from "../buckets.js"; +import {LodestarValidatorDatabaseController} from "../types.js"; const GENESIS_VALIDATORS_ROOT = Buffer.from("GENESIS_VALIDATORS_ROOT"); const GENESIS_TIME = Buffer.from("GENESIS_TIME"); diff --git a/packages/validator/src/services/attestation.ts b/packages/validator/src/services/attestation.ts index 7f0dffa3e970..514ecbbd613d 100644 --- a/packages/validator/src/services/attestation.ts +++ b/packages/validator/src/services/attestation.ts @@ -1,18 +1,18 @@ -import {BLSSignature, phase0, Slot, ssz, Attestation, SignedAggregateAndProof} from "@lodestar/types"; +import {ApiClient, routes} from "@lodestar/api"; +import {ChainForkConfig} from "@lodestar/config"; import {ForkSeq} from "@lodestar/params"; import {computeEpochAtSlot, isAggregatorFromCommitteeLength} from "@lodestar/state-transition"; +import {Attestation, BLSSignature, SignedAggregateAndProof, Slot, phase0, ssz} from "@lodestar/types"; import {prettyBytes, sleep, toRootHex} from "@lodestar/utils"; -import {ApiClient, routes} from "@lodestar/api"; -import {ChainForkConfig} from "@lodestar/config"; -import {IClock, LoggerVc} from "../util/index.js"; -import {PubkeyHex} from "../types.js"; import {Metrics} from "../metrics.js"; -import {ValidatorStore} from "./validatorStore.js"; -import {AttestationDutiesService, AttDutyAndProof} from "./attestationDuties.js"; -import {groupAttDutiesByCommitteeIndex} from "./utils.js"; +import {PubkeyHex} from "../types.js"; +import {IClock, LoggerVc} from "../util/index.js"; +import {AttDutyAndProof, AttestationDutiesService} from "./attestationDuties.js"; import {ChainHeaderTracker} from "./chainHeaderTracker.js"; -import {SyncingStatusTracker} from "./syncingStatusTracker.js"; import {ValidatorEventEmitter} from "./emitter.js"; +import {SyncingStatusTracker} from "./syncingStatusTracker.js"; +import {groupAttDutiesByCommitteeIndex} from "./utils.js"; +import {ValidatorStore} from "./validatorStore.js"; export type AttestationServiceOpts = { afterBlockDelaySlotFraction?: number; diff --git a/packages/validator/src/services/attestationDuties.ts b/packages/validator/src/services/attestationDuties.ts index 83838afe1492..b57b163b78b8 100644 --- a/packages/validator/src/services/attestationDuties.ts +++ b/packages/validator/src/services/attestationDuties.ts @@ -1,14 +1,14 @@ +import {ApiClient, routes} from "@lodestar/api"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {sleep, toPubkeyHex} from "@lodestar/utils"; import {computeEpochAtSlot, isAggregatorFromCommitteeLength, isStartSlotOfEpoch} from "@lodestar/state-transition"; -import {BLSSignature, Epoch, Slot, ValidatorIndex, RootHex} from "@lodestar/types"; -import {ApiClient, routes} from "@lodestar/api"; -import {batchItems, IClock, LoggerVc} from "../util/index.js"; -import {PubkeyHex} from "../types.js"; +import {BLSSignature, Epoch, RootHex, Slot, ValidatorIndex} from "@lodestar/types"; +import {sleep, toPubkeyHex} from "@lodestar/utils"; import {Metrics} from "../metrics.js"; -import {ValidatorStore} from "./validatorStore.js"; +import {PubkeyHex} from "../types.js"; +import {IClock, LoggerVc, batchItems} from "../util/index.js"; import {ChainHeaderTracker, HeadEventData} from "./chainHeaderTracker.js"; import {SyncingStatusTracker} from "./syncingStatusTracker.js"; +import {ValidatorStore} from "./validatorStore.js"; /** Only retain `HISTORICAL_DUTIES_EPOCHS` duties prior to the current epoch. */ const HISTORICAL_DUTIES_EPOCHS = 2; diff --git a/packages/validator/src/services/block.ts b/packages/validator/src/services/block.ts index cb295450e96b..a27b5abe4b79 100644 --- a/packages/validator/src/services/block.ts +++ b/packages/validator/src/services/block.ts @@ -1,26 +1,26 @@ +import {ApiClient, routes} from "@lodestar/api"; +import {ChainForkConfig} from "@lodestar/config"; +import {ForkBlobs, ForkExecution, ForkName, ForkPreBlobs, ForkSeq} from "@lodestar/params"; import { BLSPubkey, - Slot, BLSSignature, - ProducedBlockSource, - deneb, - isBlockContents, BeaconBlock, BeaconBlockOrContents, - isBlindedSignedBeaconBlock, BlindedBeaconBlock, + ProducedBlockSource, SignedBeaconBlock, SignedBlindedBeaconBlock, + Slot, + deneb, + isBlindedSignedBeaconBlock, + isBlockContents, } from "@lodestar/types"; -import {ChainForkConfig} from "@lodestar/config"; -import {ForkPreBlobs, ForkBlobs, ForkSeq, ForkExecution, ForkName} from "@lodestar/params"; import {extendError, prettyBytes, prettyWeiToEth, toPubkeyHex} from "@lodestar/utils"; -import {ApiClient, routes} from "@lodestar/api"; -import {IClock, LoggerVc} from "../util/index.js"; -import {PubkeyHex} from "../types.js"; import {Metrics} from "../metrics.js"; -import {ValidatorStore} from "./validatorStore.js"; +import {PubkeyHex} from "../types.js"; +import {IClock, LoggerVc} from "../util/index.js"; import {BlockDutiesService, GENESIS_SLOT} from "./blockDuties.js"; +import {ValidatorStore} from "./validatorStore.js"; // The following combination of blocks and blobs can be produced // i) a full block pre deneb diff --git a/packages/validator/src/services/blockDuties.ts b/packages/validator/src/services/blockDuties.ts index d0e16f60e816..c9fc1712513d 100644 --- a/packages/validator/src/services/blockDuties.ts +++ b/packages/validator/src/services/blockDuties.ts @@ -1,11 +1,11 @@ +import {ApiClient, routes} from "@lodestar/api"; +import {ChainConfig} from "@lodestar/config"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {BLSPubkey, Epoch, RootHex, Slot} from "@lodestar/types"; -import {ApiClient, routes} from "@lodestar/api"; import {sleep, toPubkeyHex} from "@lodestar/utils"; -import {ChainConfig} from "@lodestar/config"; -import {IClock, differenceHex, LoggerVc} from "../util/index.js"; -import {PubkeyHex} from "../types.js"; import {Metrics} from "../metrics.js"; +import {PubkeyHex} from "../types.js"; +import {IClock, LoggerVc, differenceHex} from "../util/index.js"; import {ValidatorStore} from "./validatorStore.js"; /** This polls block duties 1s before the next epoch */ diff --git a/packages/validator/src/services/chainHeaderTracker.ts b/packages/validator/src/services/chainHeaderTracker.ts index 1c0b0d9a56d8..730d5b201ed3 100644 --- a/packages/validator/src/services/chainHeaderTracker.ts +++ b/packages/validator/src/services/chainHeaderTracker.ts @@ -1,7 +1,7 @@ import {ApiClient, routes} from "@lodestar/api"; -import {Logger, fromHex} from "@lodestar/utils"; -import {Slot, Root, RootHex} from "@lodestar/types"; import {GENESIS_SLOT} from "@lodestar/params"; +import {Root, RootHex, Slot} from "@lodestar/types"; +import {Logger, fromHex} from "@lodestar/utils"; import {ValidatorEvent, ValidatorEventEmitter} from "./emitter.js"; const {EventType} = routes.events; diff --git a/packages/validator/src/services/doppelgangerService.ts b/packages/validator/src/services/doppelgangerService.ts index aa43d7bba55b..33001970ee61 100644 --- a/packages/validator/src/services/doppelgangerService.ts +++ b/packages/validator/src/services/doppelgangerService.ts @@ -1,11 +1,11 @@ -import {Epoch, ValidatorIndex} from "@lodestar/types"; import {ApiClient, routes} from "@lodestar/api"; -import {Logger, fromHex, sleep, truncBytes} from "@lodestar/utils"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; +import {Epoch, ValidatorIndex} from "@lodestar/types"; +import {Logger, fromHex, sleep, truncBytes} from "@lodestar/utils"; +import {Metrics} from "../metrics.js"; import {ISlashingProtection} from "../slashingProtection/index.js"; import {ProcessShutdownCallback, PubkeyHex} from "../types.js"; import {IClock} from "../util/index.js"; -import {Metrics} from "../metrics.js"; import {IndicesService} from "./indices.js"; // The number of epochs that must be checked before we assume that there are diff --git a/packages/validator/src/services/emitter.ts b/packages/validator/src/services/emitter.ts index 2072acba6219..5c27189d02cb 100644 --- a/packages/validator/src/services/emitter.ts +++ b/packages/validator/src/services/emitter.ts @@ -1,6 +1,6 @@ import {EventEmitter} from "node:events"; -import {StrictEventEmitter} from "strict-event-emitter-types"; import {Slot} from "@lodestar/types"; +import {StrictEventEmitter} from "strict-event-emitter-types"; import {HeadEventData} from "./chainHeaderTracker.js"; export enum ValidatorEvent { diff --git a/packages/validator/src/services/externalSignerSync.ts b/packages/validator/src/services/externalSignerSync.ts index 2f6828d9e09b..dfccfa942ee6 100644 --- a/packages/validator/src/services/externalSignerSync.ts +++ b/packages/validator/src/services/externalSignerSync.ts @@ -3,8 +3,8 @@ import {ChainForkConfig} from "@lodestar/config"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {fromHex, toPrintableUrl} from "@lodestar/utils"; -import {LoggerVc} from "../util/index.js"; import {externalSignerGetKeys} from "../util/externalSignerClient.js"; +import {LoggerVc} from "../util/index.js"; import {SignerType, ValidatorStore} from "./validatorStore.js"; export type ExternalSignerOptions = { diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index ff8d1d46ab26..0a409fe3315d 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -1,8 +1,8 @@ +import {ApiClient, routes} from "@lodestar/api"; import {ValidatorIndex} from "@lodestar/types"; import {Logger, MapDef, toPubkeyHex} from "@lodestar/utils"; -import {ApiClient, routes} from "@lodestar/api"; -import {batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; +import {batchItems} from "../util/index.js"; /** * This is to prevent the "Request body is too large" issue for http post. diff --git a/packages/validator/src/services/prepareBeaconProposer.ts b/packages/validator/src/services/prepareBeaconProposer.ts index 6ae4b0a83870..51057f7f72da 100644 --- a/packages/validator/src/services/prepareBeaconProposer.ts +++ b/packages/validator/src/services/prepareBeaconProposer.ts @@ -1,10 +1,10 @@ -import {Epoch, bellatrix} from "@lodestar/types"; import {ApiClient, routes} from "@lodestar/api"; import {BeaconConfig} from "@lodestar/config"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {Epoch, bellatrix} from "@lodestar/types"; -import {IClock, LoggerVc, batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; +import {IClock, LoggerVc, batchItems} from "../util/index.js"; import {ValidatorStore} from "./validatorStore.js"; const REGISTRATION_CHUNK_SIZE = 512; diff --git a/packages/validator/src/services/syncCommittee.ts b/packages/validator/src/services/syncCommittee.ts index c960adc6986b..fb0aa74238d2 100644 --- a/packages/validator/src/services/syncCommittee.ts +++ b/packages/validator/src/services/syncCommittee.ts @@ -1,17 +1,17 @@ +import {ApiClient, routes} from "@lodestar/api"; import {ChainForkConfig} from "@lodestar/config"; -import {Slot, CommitteeIndex, altair, Root, BLSSignature} from "@lodestar/types"; -import {sleep} from "@lodestar/utils"; import {computeEpochAtSlot, isSyncCommitteeAggregator} from "@lodestar/state-transition"; -import {ApiClient, routes} from "@lodestar/api"; -import {IClock, LoggerVc} from "../util/index.js"; -import {PubkeyHex} from "../types.js"; +import {BLSSignature, CommitteeIndex, Root, Slot, altair} from "@lodestar/types"; +import {sleep} from "@lodestar/utils"; import {Metrics} from "../metrics.js"; -import {ValidatorStore} from "./validatorStore.js"; -import {SyncCommitteeDutiesService, SyncDutyAndProofs} from "./syncCommitteeDuties.js"; -import {groupSyncDutiesBySubcommitteeIndex, SubcommitteeDuty} from "./utils.js"; +import {PubkeyHex} from "../types.js"; +import {IClock, LoggerVc} from "../util/index.js"; import {ChainHeaderTracker} from "./chainHeaderTracker.js"; import {ValidatorEventEmitter} from "./emitter.js"; +import {SyncCommitteeDutiesService, SyncDutyAndProofs} from "./syncCommitteeDuties.js"; import {SyncingStatusTracker} from "./syncingStatusTracker.js"; +import {SubcommitteeDuty, groupSyncDutiesBySubcommitteeIndex} from "./utils.js"; +import {ValidatorStore} from "./validatorStore.js"; export type SyncCommitteeServiceOpts = { scAfterBlockDelaySlotFraction?: number; diff --git a/packages/validator/src/services/syncCommitteeDuties.ts b/packages/validator/src/services/syncCommitteeDuties.ts index ea448add15ec..218169e1dcea 100644 --- a/packages/validator/src/services/syncCommitteeDuties.ts +++ b/packages/validator/src/services/syncCommitteeDuties.ts @@ -1,3 +1,5 @@ +import {ApiClient, routes} from "@lodestar/api"; +import {ChainForkConfig} from "@lodestar/config"; import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; import { computeEpochAtSlot, @@ -6,16 +8,14 @@ import { isStartSlotOfEpoch, isSyncCommitteeAggregator, } from "@lodestar/state-transition"; -import {ChainForkConfig} from "@lodestar/config"; import {BLSSignature, Epoch, Slot, SyncPeriod, ValidatorIndex} from "@lodestar/types"; -import {ApiClient, routes} from "@lodestar/api"; import {toPubkeyHex} from "@lodestar/utils"; -import {IClock, LoggerVc} from "../util/index.js"; -import {PubkeyHex} from "../types.js"; import {Metrics} from "../metrics.js"; -import {ValidatorStore} from "./validatorStore.js"; -import {syncCommitteeIndicesToSubnets} from "./utils.js"; +import {PubkeyHex} from "../types.js"; +import {IClock, LoggerVc} from "../util/index.js"; import {SyncingStatusTracker} from "./syncingStatusTracker.js"; +import {syncCommitteeIndicesToSubnets} from "./utils.js"; +import {ValidatorStore} from "./validatorStore.js"; /** Only retain `HISTORICAL_DUTIES_PERIODS` duties prior to the current periods. */ const HISTORICAL_DUTIES_PERIODS = 2; diff --git a/packages/validator/src/services/syncingStatusTracker.ts b/packages/validator/src/services/syncingStatusTracker.ts index 4c38e670092d..bd8a8b78fc7c 100644 --- a/packages/validator/src/services/syncingStatusTracker.ts +++ b/packages/validator/src/services/syncingStatusTracker.ts @@ -1,8 +1,8 @@ import {ApiClient, routes} from "@lodestar/api"; -import {Logger} from "@lodestar/utils"; import {Slot} from "@lodestar/types"; -import {IClock} from "../util/clock.js"; +import {Logger} from "@lodestar/utils"; import {BeaconHealth, Metrics} from "../metrics.js"; +import {IClock} from "../util/clock.js"; export type SyncingStatus = routes.node.SyncingStatus; diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index f959b4e74ff5..0c66f576ffa0 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -1,16 +1,10 @@ -import {BitArray} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; -import { - computeEpochAtSlot, - computeSigningRoot, - computeStartSlotAtEpoch, - computeDomain, - ZERO_HASH, - blindedOrFullBlockHashTreeRoot, -} from "@lodestar/state-transition"; +import {BitArray} from "@chainsafe/ssz"; +import {routes} from "@lodestar/api"; import {BeaconConfig} from "@lodestar/config"; import { DOMAIN_AGGREGATE_AND_PROOF, + DOMAIN_APPLICATION_BUILDER, DOMAIN_BEACON_ATTESTER, DOMAIN_BEACON_PROPOSER, DOMAIN_CONTRIBUTION_AND_PROOF, @@ -18,39 +12,45 @@ import { DOMAIN_SELECTION_PROOF, DOMAIN_SYNC_COMMITTEE, DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF, - DOMAIN_APPLICATION_BUILDER, ForkSeq, MAX_COMMITTEES_PER_SLOT, } from "@lodestar/params"; import { - altair, - BeaconBlock, - bellatrix, - BlindedBeaconBlock, + ZERO_HASH, + blindedOrFullBlockHashTreeRoot, + computeDomain, + computeEpochAtSlot, + computeSigningRoot, + computeStartSlotAtEpoch, +} from "@lodestar/state-transition"; +import { + AggregateAndProof, + Attestation, BLSPubkey, BLSSignature, + BeaconBlock, + BlindedBeaconBlock, Epoch, - phase0, Root, + SignedAggregateAndProof, SignedBeaconBlock, SignedBlindedBeaconBlock, Slot, - ssz, ValidatorIndex, - Attestation, - AggregateAndProof, - SignedAggregateAndProof, + altair, + bellatrix, + phase0, + ssz, } from "@lodestar/types"; -import {routes} from "@lodestar/api"; import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; +import {Metrics} from "../metrics.js"; import {ISlashingProtection} from "../slashingProtection/index.js"; import {PubkeyHex} from "../types.js"; -import {externalSignerPostSignature, SignableMessageType, SignableMessage} from "../util/externalSignerClient.js"; -import {Metrics} from "../metrics.js"; +import {SignableMessage, SignableMessageType, externalSignerPostSignature} from "../util/externalSignerClient.js"; import {isValidatePubkeyHex} from "../util/format.js"; import {LoggerVc} from "../util/logger.js"; -import {IndicesService} from "./indices.js"; import {DoppelgangerService} from "./doppelgangerService.js"; +import {IndicesService} from "./indices.js"; type BLSPubkeyMaybeHex = BLSPubkey | PubkeyHex; type Eth1Address = string; diff --git a/packages/validator/src/slashingProtection/attestation/attestationByTargetRepository.ts b/packages/validator/src/slashingProtection/attestation/attestationByTargetRepository.ts index 61c13bb17ce2..e97ff5f96fad 100644 --- a/packages/validator/src/slashingProtection/attestation/attestationByTargetRepository.ts +++ b/packages/validator/src/slashingProtection/attestation/attestationByTargetRepository.ts @@ -1,11 +1,11 @@ import {ContainerType, Type} from "@chainsafe/ssz"; -import {BLSPubkey, Epoch, ssz} from "@lodestar/types"; -import {intToBytes, bytesToInt} from "@lodestar/utils"; import {DB_PREFIX_LENGTH, DbReqOpts, encodeKey, uintLen} from "@lodestar/db"; +import {BLSPubkey, Epoch, ssz} from "@lodestar/types"; +import {bytesToInt, intToBytes} from "@lodestar/utils"; +import {Bucket, getBucketNameByValue} from "../../buckets.js"; import {LodestarValidatorDatabaseController} from "../../types.js"; import {SlashingProtectionAttestation} from "../types.js"; import {blsPubkeyLen, uniqueVectorArr} from "../utils.js"; -import {Bucket, getBucketNameByValue} from "../../buckets.js"; /** * Manages validator db storage of attestations. diff --git a/packages/validator/src/slashingProtection/attestation/attestationLowerBoundRepository.ts b/packages/validator/src/slashingProtection/attestation/attestationLowerBoundRepository.ts index 84a4e7032a70..3cd6deab8881 100644 --- a/packages/validator/src/slashingProtection/attestation/attestationLowerBoundRepository.ts +++ b/packages/validator/src/slashingProtection/attestation/attestationLowerBoundRepository.ts @@ -1,8 +1,8 @@ import {ContainerType, Type} from "@chainsafe/ssz"; +import {DbReqOpts, encodeKey} from "@lodestar/db"; import {BLSPubkey, Epoch, ssz} from "@lodestar/types"; -import {encodeKey, DbReqOpts} from "@lodestar/db"; -import {LodestarValidatorDatabaseController} from "../../types.js"; import {Bucket, getBucketNameByValue} from "../../buckets.js"; +import {LodestarValidatorDatabaseController} from "../../types.js"; // Only used locally here export interface SlashingProtectionLowerBound { diff --git a/packages/validator/src/slashingProtection/attestation/index.ts b/packages/validator/src/slashingProtection/attestation/index.ts index f0d3a0bca172..8b2fec1bccab 100644 --- a/packages/validator/src/slashingProtection/attestation/index.ts +++ b/packages/validator/src/slashingProtection/attestation/index.ts @@ -1,10 +1,10 @@ import {BLSPubkey, Epoch} from "@lodestar/types"; -import {isEqualNonZeroRoot, minEpoch} from "../utils.js"; import {MinMaxSurround, SurroundAttestationError, SurroundAttestationErrorCode} from "../minMaxSurround/index.js"; import {SlashingProtectionAttestation} from "../types.js"; -import {InvalidAttestationError, InvalidAttestationErrorCode} from "./errors.js"; +import {isEqualNonZeroRoot, minEpoch} from "../utils.js"; import {AttestationByTargetRepository} from "./attestationByTargetRepository.js"; import {AttestationLowerBoundRepository} from "./attestationLowerBoundRepository.js"; +import {InvalidAttestationError, InvalidAttestationErrorCode} from "./errors.js"; export { AttestationByTargetRepository, AttestationLowerBoundRepository, diff --git a/packages/validator/src/slashingProtection/block/blockBySlotRepository.ts b/packages/validator/src/slashingProtection/block/blockBySlotRepository.ts index eb1ae092cf3f..2a1e86fcce23 100644 --- a/packages/validator/src/slashingProtection/block/blockBySlotRepository.ts +++ b/packages/validator/src/slashingProtection/block/blockBySlotRepository.ts @@ -1,9 +1,9 @@ import {ContainerType, Type} from "@chainsafe/ssz"; -import {BLSPubkey, Slot, ssz} from "@lodestar/types"; -import {intToBytes, bytesToInt} from "@lodestar/utils"; import {DB_PREFIX_LENGTH, DbReqOpts, encodeKey, uintLen} from "@lodestar/db"; -import {LodestarValidatorDatabaseController} from "../../types.js"; +import {BLSPubkey, Slot, ssz} from "@lodestar/types"; +import {bytesToInt, intToBytes} from "@lodestar/utils"; import {Bucket, getBucketNameByValue} from "../../buckets.js"; +import {LodestarValidatorDatabaseController} from "../../types.js"; import {SlashingProtectionBlock} from "../types.js"; import {blsPubkeyLen, uniqueVectorArr} from "../utils.js"; diff --git a/packages/validator/src/slashingProtection/block/index.ts b/packages/validator/src/slashingProtection/block/index.ts index 385575e82a0a..44a06d3ef01d 100644 --- a/packages/validator/src/slashingProtection/block/index.ts +++ b/packages/validator/src/slashingProtection/block/index.ts @@ -1,8 +1,8 @@ import {BLSPubkey} from "@lodestar/types"; -import {isEqualNonZeroRoot} from "../utils.js"; import {SlashingProtectionBlock} from "../types.js"; -import {InvalidBlockError, InvalidBlockErrorCode} from "./errors.js"; +import {isEqualNonZeroRoot} from "../utils.js"; import {BlockBySlotRepository} from "./blockBySlotRepository.js"; +import {InvalidBlockError, InvalidBlockErrorCode} from "./errors.js"; export {BlockBySlotRepository, InvalidBlockError, InvalidBlockErrorCode}; enum SafeStatus { diff --git a/packages/validator/src/slashingProtection/index.ts b/packages/validator/src/slashingProtection/index.ts index bc57b0e51c13..388744f95449 100644 --- a/packages/validator/src/slashingProtection/index.ts +++ b/packages/validator/src/slashingProtection/index.ts @@ -1,23 +1,23 @@ import {BLSPubkey, Epoch, Root} from "@lodestar/types"; import {Logger, toPubkeyHex} from "@lodestar/utils"; -import {LodestarValidatorDatabaseController} from "../types.js"; import {uniqueVectorArr} from "../slashingProtection/utils.js"; -import {BlockBySlotRepository, SlashingProtectionBlockService} from "./block/index.js"; +import {LodestarValidatorDatabaseController} from "../types.js"; import { AttestationByTargetRepository, AttestationLowerBoundRepository, SlashingProtectionAttestationService, } from "./attestation/index.js"; -import {ISlashingProtection} from "./interface.js"; +import {BlockBySlotRepository, SlashingProtectionBlockService} from "./block/index.js"; import { - InterchangeLodestar, Interchange, InterchangeFormatVersion, + InterchangeLodestar, parseInterchange, serializeInterchange, } from "./interchange/index.js"; -import {MinMaxSurround, DistanceStoreRepository} from "./minMaxSurround/index.js"; -import {SlashingProtectionBlock, SlashingProtectionAttestation} from "./types.js"; +import {ISlashingProtection} from "./interface.js"; +import {DistanceStoreRepository, MinMaxSurround} from "./minMaxSurround/index.js"; +import {SlashingProtectionAttestation, SlashingProtectionBlock} from "./types.js"; export {InvalidAttestationError, InvalidAttestationErrorCode} from "./attestation/index.js"; export {InvalidBlockError, InvalidBlockErrorCode} from "./block/index.js"; diff --git a/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts b/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts index 26210390a272..9cc514acd854 100644 --- a/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts +++ b/packages/validator/src/slashingProtection/interchange/formats/completeV4.ts @@ -1,6 +1,6 @@ import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; -import {InterchangeLodestar} from "../types.js"; import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js"; +import {InterchangeLodestar} from "../types.js"; /** * A complete record of all blocks and attestations signed by a set of validators diff --git a/packages/validator/src/slashingProtection/interchange/formats/v5.ts b/packages/validator/src/slashingProtection/interchange/formats/v5.ts index 88e2ce70fe07..5059fa1917bf 100644 --- a/packages/validator/src/slashingProtection/interchange/formats/v5.ts +++ b/packages/validator/src/slashingProtection/interchange/formats/v5.ts @@ -1,6 +1,6 @@ import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; -import {InterchangeLodestar} from "../types.js"; import {fromOptionalHexString, numToString, toOptionalHexString} from "../../utils.js"; +import {InterchangeLodestar} from "../types.js"; /** * A complete record of all blocks and attestations signed by a set of validators diff --git a/packages/validator/src/slashingProtection/interchange/parseInterchange.ts b/packages/validator/src/slashingProtection/interchange/parseInterchange.ts index 117cd11b5f2b..ec6b3c1ee6d6 100644 --- a/packages/validator/src/slashingProtection/interchange/parseInterchange.ts +++ b/packages/validator/src/slashingProtection/interchange/parseInterchange.ts @@ -1,9 +1,9 @@ import {Root} from "@lodestar/types"; import {isEqualRoot} from "../utils.js"; import {InterchangeError, InterchangeErrorErrorCode} from "./errors.js"; -import {Interchange, InterchangeLodestar} from "./types.js"; import {InterchangeCompleteV4, parseInterchangeCompleteV4} from "./formats/completeV4.js"; import {InterchangeV5, parseInterchangeV5} from "./formats/v5.js"; +import {Interchange, InterchangeLodestar} from "./types.js"; export function parseInterchange(interchange: Interchange, expectedGenesisValidatorsRoot: Root): InterchangeLodestar { const format = (interchange as InterchangeCompleteV4)?.metadata?.interchange_format; diff --git a/packages/validator/src/slashingProtection/interchange/serializeInterchange.ts b/packages/validator/src/slashingProtection/interchange/serializeInterchange.ts index a99fb3f3d172..4abb03b23d23 100644 --- a/packages/validator/src/slashingProtection/interchange/serializeInterchange.ts +++ b/packages/validator/src/slashingProtection/interchange/serializeInterchange.ts @@ -1,7 +1,7 @@ import {InterchangeError, InterchangeErrorErrorCode} from "./errors.js"; -import {Interchange, InterchangeFormatVersion, InterchangeLodestar} from "./types.js"; import {serializeInterchangeCompleteV4} from "./formats/completeV4.js"; import {serializeInterchangeV5} from "./formats/v5.js"; +import {Interchange, InterchangeFormatVersion, InterchangeLodestar} from "./types.js"; export function serializeInterchange( interchangeLodestar: InterchangeLodestar, diff --git a/packages/validator/src/slashingProtection/interface.ts b/packages/validator/src/slashingProtection/interface.ts index c2a790c98a65..11efa98d20f9 100644 --- a/packages/validator/src/slashingProtection/interface.ts +++ b/packages/validator/src/slashingProtection/interface.ts @@ -1,7 +1,7 @@ import {BLSPubkey, Epoch, Root} from "@lodestar/types"; import {Logger} from "@lodestar/utils"; import {Interchange, InterchangeFormatVersion} from "./interchange/types.js"; -import {SlashingProtectionBlock, SlashingProtectionAttestation} from "./types.js"; +import {SlashingProtectionAttestation, SlashingProtectionBlock} from "./types.js"; export interface ISlashingProtection { /** diff --git a/packages/validator/src/slashingProtection/minMaxSurround/distanceStoreRepository.ts b/packages/validator/src/slashingProtection/minMaxSurround/distanceStoreRepository.ts index 45315bf95b03..556eaf5374ba 100644 --- a/packages/validator/src/slashingProtection/minMaxSurround/distanceStoreRepository.ts +++ b/packages/validator/src/slashingProtection/minMaxSurround/distanceStoreRepository.ts @@ -1,5 +1,5 @@ import {Type} from "@chainsafe/ssz"; -import {encodeKey, DbReqOpts} from "@lodestar/db"; +import {DbReqOpts, encodeKey} from "@lodestar/db"; import {BLSPubkey, Epoch, ssz} from "@lodestar/types"; import {intToBytes} from "@lodestar/utils"; import {Bucket, getBucketNameByValue} from "../../buckets.js"; diff --git a/packages/validator/src/slashingProtection/minMaxSurround/minMaxSurround.ts b/packages/validator/src/slashingProtection/minMaxSurround/minMaxSurround.ts index 446c3cd763e7..87976f734ba6 100644 --- a/packages/validator/src/slashingProtection/minMaxSurround/minMaxSurround.ts +++ b/packages/validator/src/slashingProtection/minMaxSurround/minMaxSurround.ts @@ -1,6 +1,6 @@ import {BLSPubkey} from "@lodestar/types"; -import {IMinMaxSurround, DistanceEntry, IDistanceStore, MinMaxSurroundAttestation} from "./interface.js"; import {SurroundAttestationError, SurroundAttestationErrorCode} from "./errors.js"; +import {DistanceEntry, IDistanceStore, IMinMaxSurround, MinMaxSurroundAttestation} from "./interface.js"; // surround vote checking with min-max surround // https://github.com/protolambda/eth2-surround#min-max-surround diff --git a/packages/validator/src/types.ts b/packages/validator/src/types.ts index dd44fd49c61e..a765a7960b3f 100644 --- a/packages/validator/src/types.ts +++ b/packages/validator/src/types.ts @@ -1,6 +1,6 @@ import {SecretKey} from "@chainsafe/blst"; -import {BLSPubkey} from "@lodestar/types"; import {DatabaseController} from "@lodestar/db"; +import {BLSPubkey} from "@lodestar/types"; export type GenesisInfo = { startTime: number; diff --git a/packages/validator/src/util/clock.ts b/packages/validator/src/util/clock.ts index 4b3fc45cd803..6b7e0868233a 100644 --- a/packages/validator/src/util/clock.ts +++ b/packages/validator/src/util/clock.ts @@ -1,8 +1,8 @@ -import {ErrorAborted, Logger, isErrorAborted, sleep} from "@lodestar/utils"; -import {GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; -import {Epoch, Slot, TimeSeconds} from "@lodestar/types"; +import {GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params"; import {computeEpochAtSlot, getCurrentSlot} from "@lodestar/state-transition"; +import {Epoch, Slot, TimeSeconds} from "@lodestar/types"; +import {ErrorAborted, Logger, isErrorAborted, sleep} from "@lodestar/utils"; type RunEveryFn = (slot: Slot, signal: AbortSignal) => Promise; diff --git a/packages/validator/src/util/externalSignerClient.ts b/packages/validator/src/util/externalSignerClient.ts index 54c0c16946ad..ab5849cf1a6b 100644 --- a/packages/validator/src/util/externalSignerClient.ts +++ b/packages/validator/src/util/externalSignerClient.ts @@ -1,23 +1,23 @@ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {fetch} from "@lodestar/api"; +import {BeaconConfig} from "@lodestar/config"; +import {ForkPreExecution, ForkSeq} from "@lodestar/params"; +import {blindedOrFullBlockToHeader, computeEpochAtSlot} from "@lodestar/state-transition"; import { - phase0, - altair, - capella, + AggregateAndProof, BeaconBlock, BlindedBeaconBlock, - AggregateAndProof, - sszTypesFor, - ssz, - Slot, Epoch, - RootHex, Root, + RootHex, + Slot, + altair, + capella, + phase0, + ssz, + sszTypesFor, } from "@lodestar/types"; -import {ForkPreExecution, ForkSeq} from "@lodestar/params"; import {ValidatorRegistrationV1} from "@lodestar/types/bellatrix"; -import {BeaconConfig} from "@lodestar/config"; -import {computeEpochAtSlot, blindedOrFullBlockToHeader} from "@lodestar/state-transition"; import {toHex, toRootHex} from "@lodestar/utils"; import {PubkeyHex} from "../types.js"; diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 16374af2b837..53ccd759a5c1 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -1,5 +1,5 @@ import {ChainConfig, chainConfigToJson} from "@lodestar/config"; -import {activePreset, BeaconPreset, presetToJson} from "@lodestar/params"; +import {BeaconPreset, activePreset, presetToJson} from "@lodestar/params"; export class NotEqualParamsError extends Error {} diff --git a/packages/validator/src/validator.ts b/packages/validator/src/validator.ts index 09a3a80062da..ecb8bb4a161e 100644 --- a/packages/validator/src/validator.ts +++ b/packages/validator/src/validator.ts @@ -1,27 +1,27 @@ +import {ApiClient, ApiRequestInit, defaultInit, getClient, routes} from "@lodestar/api"; +import {BeaconConfig, ChainForkConfig, createBeaconConfig} from "@lodestar/config"; +import {computeEpochAtSlot, getCurrentSlot} from "@lodestar/state-transition"; import {BLSPubkey, phase0, ssz} from "@lodestar/types"; -import {createBeaconConfig, BeaconConfig, ChainForkConfig} from "@lodestar/config"; import {Genesis} from "@lodestar/types/phase0"; import {Logger, toPrintableUrl, toRootHex} from "@lodestar/utils"; -import {getClient, ApiClient, routes, ApiRequestInit, defaultInit} from "@lodestar/api"; -import {computeEpochAtSlot, getCurrentSlot} from "@lodestar/state-transition"; -import {Clock, IClock} from "./util/clock.js"; import {waitForGenesis} from "./genesis.js"; -import {BlockProposingService} from "./services/block.js"; +import {Metrics} from "./metrics.js"; +import {MetaDataRepository} from "./repositories/metaDataRepository.js"; import {AttestationService} from "./services/attestation.js"; +import {BlockProposingService} from "./services/block.js"; +import {ChainHeaderTracker} from "./services/chainHeaderTracker.js"; +import {DoppelgangerService} from "./services/doppelgangerService.js"; +import {ValidatorEventEmitter} from "./services/emitter.js"; +import {ExternalSignerOptions, pollExternalSignerPubkeys} from "./services/externalSignerSync.js"; import {IndicesService} from "./services/indices.js"; +import {pollBuilderValidatorRegistration, pollPrepareBeaconProposer} from "./services/prepareBeaconProposer.js"; import {SyncCommitteeService} from "./services/syncCommittee.js"; -import {pollPrepareBeaconProposer, pollBuilderValidatorRegistration} from "./services/prepareBeaconProposer.js"; -import {ExternalSignerOptions, pollExternalSignerPubkeys} from "./services/externalSignerSync.js"; -import {Interchange, InterchangeFormatVersion, ISlashingProtection} from "./slashingProtection/index.js"; -import {assertEqualParams, getLoggerVc, NotEqualParamsError} from "./util/index.js"; -import {ChainHeaderTracker} from "./services/chainHeaderTracker.js"; import {SyncingStatusTracker} from "./services/syncingStatusTracker.js"; -import {ValidatorEventEmitter} from "./services/emitter.js"; -import {ValidatorStore, Signer, ValidatorProposerConfig, defaultOptions} from "./services/validatorStore.js"; +import {Signer, ValidatorProposerConfig, ValidatorStore, defaultOptions} from "./services/validatorStore.js"; +import {ISlashingProtection, Interchange, InterchangeFormatVersion} from "./slashingProtection/index.js"; import {LodestarValidatorDatabaseController, ProcessShutdownCallback, PubkeyHex} from "./types.js"; -import {Metrics} from "./metrics.js"; -import {MetaDataRepository} from "./repositories/metaDataRepository.js"; -import {DoppelgangerService} from "./services/doppelgangerService.js"; +import {Clock, IClock} from "./util/clock.js"; +import {NotEqualParamsError, assertEqualParams, getLoggerVc} from "./util/index.js"; export type ValidatorModules = { opts: ValidatorOptions; diff --git a/packages/validator/test/e2e/web3signer.test.ts b/packages/validator/test/e2e/web3signer.test.ts index 855b3dd9f754..32a95276a102 100644 --- a/packages/validator/test/e2e/web3signer.test.ts +++ b/packages/validator/test/e2e/web3signer.test.ts @@ -1,14 +1,14 @@ -import {expect, describe, it, vi, beforeAll, afterAll} from "vitest"; -import {fromHex, toHex} from "@lodestar/utils"; -import {config} from "@lodestar/config/default"; -import {computeStartSlotAtEpoch, interopSecretKey, interopSecretKeys} from "@lodestar/state-transition"; +import {getClient, routes} from "@lodestar/api"; import {createBeaconConfig} from "@lodestar/config"; +import {config} from "@lodestar/config/default"; import {genesisData} from "@lodestar/config/networks"; -import {getClient, routes} from "@lodestar/api"; -import {ssz, sszTypesFor} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; -import {getKeystoresStr, StartedExternalSigner, startExternalSigner} from "@lodestar/test-utils"; -import {Interchange, ISlashingProtection, Signer, SignerType, ValidatorStore} from "../../src/index.js"; +import {computeStartSlotAtEpoch, interopSecretKey, interopSecretKeys} from "@lodestar/state-transition"; +import {StartedExternalSigner, getKeystoresStr, startExternalSigner} from "@lodestar/test-utils"; +import {ssz, sszTypesFor} from "@lodestar/types"; +import {fromHex, toHex} from "@lodestar/utils"; +import {afterAll, beforeAll, describe, expect, it, vi} from "vitest"; +import {ISlashingProtection, Interchange, Signer, SignerType, ValidatorStore} from "../../src/index.js"; import {IndicesService} from "../../src/services/indices.js"; import {testLogger} from "../utils/logger.js"; diff --git a/packages/validator/test/spec/downloadTests.ts b/packages/validator/test/spec/downloadTests.ts index 7aede8425b19..aa360df38a0c 100644 --- a/packages/validator/test/spec/downloadTests.ts +++ b/packages/validator/test/spec/downloadTests.ts @@ -1,5 +1,5 @@ import {downloadGenericSpecTests} from "@lodestar/spec-test-util/downloadTests"; -import {SPEC_TEST_LOCATION, SPEC_TEST_VERSION, SPEC_TEST_REPO_URL, TESTS_TO_DOWNLOAD} from "./params.js"; +import {SPEC_TEST_LOCATION, SPEC_TEST_REPO_URL, SPEC_TEST_VERSION, TESTS_TO_DOWNLOAD} from "./params.js"; /* eslint-disable no-console */ diff --git a/packages/validator/test/spec/index.test.ts b/packages/validator/test/spec/index.test.ts index bd6ff947ca41..457b8589a0eb 100644 --- a/packages/validator/test/spec/index.test.ts +++ b/packages/validator/test/spec/index.test.ts @@ -1,12 +1,12 @@ -import {expect, describe, it, beforeAll, afterAll} from "vitest"; -import {rimraf} from "rimraf"; import {LevelDbController} from "@lodestar/db"; +import {rimraf} from "rimraf"; +import {afterAll, beforeAll, describe, expect, it} from "vitest"; import { + InvalidAttestationError, + InvalidBlockError, SlashingProtection, - SlashingProtectionBlock, SlashingProtectionAttestation, - InvalidBlockError, - InvalidAttestationError, + SlashingProtectionBlock, } from "../../src/slashingProtection/index.js"; import {testLogger} from "../utils/logger.js"; diff --git a/packages/validator/test/spec/spec.test.ts b/packages/validator/test/spec/spec.test.ts index 41b094473c66..18c58bd84fa7 100644 --- a/packages/validator/test/spec/spec.test.ts +++ b/packages/validator/test/spec/spec.test.ts @@ -1,16 +1,16 @@ import path from "node:path"; -import {describe, it, beforeAll, beforeEach, afterAll, expect} from "vitest"; -import {rimraf} from "rimraf"; import {fromHexString} from "@chainsafe/ssz"; import {LevelDbController} from "@lodestar/db"; import {ZERO_HASH} from "@lodestar/state-transition"; +import {rimraf} from "rimraf"; +import {afterAll, beforeAll, beforeEach, describe, expect, it} from "vitest"; import { - SlashingProtection, InterchangeError, InvalidAttestationError, InvalidBlockError, - SlashingProtectionBlock, + SlashingProtection, SlashingProtectionAttestation, + SlashingProtectionBlock, } from "../../src/slashingProtection/index.js"; import {testLogger} from "../utils/logger.js"; import {loadTestCases} from "../utils/spec.js"; diff --git a/packages/validator/test/unit/services/attestation.test.ts b/packages/validator/test/unit/services/attestation.test.ts index 1652af83c5d1..e3a6f0771d62 100644 --- a/packages/validator/test/unit/services/attestation.test.ts +++ b/packages/validator/test/unit/services/attestation.test.ts @@ -1,20 +1,20 @@ -import {describe, it, expect, beforeAll, beforeEach, afterEach, vi} from "vitest"; -import {toHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; -import {ssz} from "@lodestar/types"; +import {toHexString} from "@chainsafe/ssz"; import {routes} from "@lodestar/api"; import {ChainConfig, createChainForkConfig} from "@lodestar/config"; import {config as defaultConfig} from "@lodestar/config/default"; import {ForkName} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; +import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; import {AttestationService, AttestationServiceOpts} from "../../../src/services/attestation.js"; import {AttDutyAndProof} from "../../../src/services/attestationDuties.js"; +import {ChainHeaderTracker} from "../../../src/services/chainHeaderTracker.js"; +import {ValidatorEventEmitter} from "../../../src/services/emitter.js"; +import {SyncingStatusTracker} from "../../../src/services/syncingStatusTracker.js"; import {ValidatorStore} from "../../../src/services/validatorStore.js"; import {getApiClientStub, mockApiResponse} from "../../utils/apiStub.js"; -import {loggerVc} from "../../utils/logger.js"; import {ClockMock} from "../../utils/clock.js"; -import {ChainHeaderTracker} from "../../../src/services/chainHeaderTracker.js"; -import {SyncingStatusTracker} from "../../../src/services/syncingStatusTracker.js"; -import {ValidatorEventEmitter} from "../../../src/services/emitter.js"; +import {loggerVc} from "../../utils/logger.js"; import {ZERO_HASH, ZERO_HASH_HEX} from "../../utils/types.js"; vi.mock("../../../src/services/validatorStore.js"); diff --git a/packages/validator/test/unit/services/attestationDuties.test.ts b/packages/validator/test/unit/services/attestationDuties.test.ts index fafccf209777..93a7aa0a83f7 100644 --- a/packages/validator/test/unit/services/attestationDuties.test.ts +++ b/packages/validator/test/unit/services/attestationDuties.test.ts @@ -1,20 +1,20 @@ -import {describe, it, expect, beforeAll, vi, Mocked, beforeEach, afterEach} from "vitest"; -import {toBufferBE} from "bigint-buffer"; -import {toHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; -import {chainConfig} from "@lodestar/config/default"; +import {toHexString} from "@chainsafe/ssz"; import {routes} from "@lodestar/api"; -import {ssz} from "@lodestar/types"; +import {chainConfig} from "@lodestar/config/default"; import {computeEpochAtSlot} from "@lodestar/state-transition"; +import {ssz} from "@lodestar/types"; +import {toBufferBE} from "bigint-buffer"; +import {Mocked, afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; import {AttestationDutiesService} from "../../../src/services/attestationDuties.js"; +import {ChainHeaderTracker} from "../../../src/services/chainHeaderTracker.js"; +import {SyncingStatusTracker} from "../../../src/services/syncingStatusTracker.js"; import {ValidatorStore} from "../../../src/services/validatorStore.js"; import {getApiClientStub, mockApiResponse} from "../../utils/apiStub.js"; -import {loggerVc} from "../../utils/logger.js"; import {ClockMock} from "../../utils/clock.js"; -import {initValidatorStore} from "../../utils/validatorStore.js"; -import {ChainHeaderTracker} from "../../../src/services/chainHeaderTracker.js"; -import {SyncingStatusTracker} from "../../../src/services/syncingStatusTracker.js"; +import {loggerVc} from "../../utils/logger.js"; import {ZERO_HASH_HEX} from "../../utils/types.js"; +import {initValidatorStore} from "../../utils/validatorStore.js"; vi.mock("../../../src/services/chainHeaderTracker.js"); diff --git a/packages/validator/test/unit/services/block.test.ts b/packages/validator/test/unit/services/block.test.ts index dc89f1169d92..6c80bea4ffd2 100644 --- a/packages/validator/test/unit/services/block.test.ts +++ b/packages/validator/test/unit/services/block.test.ts @@ -1,17 +1,17 @@ -import {describe, it, expect, beforeAll, beforeEach, afterEach, vi} from "vitest"; -import {toHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; +import {toHexString} from "@chainsafe/ssz"; +import {routes} from "@lodestar/api"; import {createChainForkConfig} from "@lodestar/config"; import {config as mainnetConfig} from "@lodestar/config/default"; -import {sleep} from "@lodestar/utils"; -import {ssz, ProducedBlockSource} from "@lodestar/types"; -import {routes} from "@lodestar/api"; import {ForkName} from "@lodestar/params"; +import {ProducedBlockSource, ssz} from "@lodestar/types"; +import {sleep} from "@lodestar/utils"; +import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; import {BlockProposingService} from "../../../src/services/block.js"; import {ValidatorStore} from "../../../src/services/validatorStore.js"; import {getApiClientStub, mockApiResponse} from "../../utils/apiStub.js"; -import {loggerVc} from "../../utils/logger.js"; import {ClockMock} from "../../utils/clock.js"; +import {loggerVc} from "../../utils/logger.js"; import {ZERO_HASH_HEX} from "../../utils/types.js"; vi.mock("../../../src/services/validatorStore.js"); diff --git a/packages/validator/test/unit/services/blockDuties.test.ts b/packages/validator/test/unit/services/blockDuties.test.ts index 51ced2cd70de..3150155d030a 100644 --- a/packages/validator/test/unit/services/blockDuties.test.ts +++ b/packages/validator/test/unit/services/blockDuties.test.ts @@ -1,17 +1,17 @@ -import {describe, it, expect, beforeAll, beforeEach, afterEach, vi} from "vitest"; -import {toBufferBE} from "bigint-buffer"; -import {toHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; +import {toHexString} from "@chainsafe/ssz"; import {routes} from "@lodestar/api"; import {chainConfig} from "@lodestar/config/default"; import {toHex} from "@lodestar/utils"; +import {toBufferBE} from "bigint-buffer"; +import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; import {BlockDutiesService} from "../../../src/services/blockDuties.js"; import {ValidatorStore} from "../../../src/services/validatorStore.js"; import {getApiClientStub, mockApiResponse} from "../../utils/apiStub.js"; -import {loggerVc} from "../../utils/logger.js"; import {ClockMock} from "../../utils/clock.js"; -import {initValidatorStore} from "../../utils/validatorStore.js"; +import {loggerVc} from "../../utils/logger.js"; import {ZERO_HASH_HEX} from "../../utils/types.js"; +import {initValidatorStore} from "../../utils/validatorStore.js"; describe("BlockDutiesService", () => { const api = getApiClientStub(); diff --git a/packages/validator/test/unit/services/doppelganger.test.ts b/packages/validator/test/unit/services/doppelganger.test.ts index 943f0c08a9d3..ba112245b0d2 100644 --- a/packages/validator/test/unit/services/doppelganger.test.ts +++ b/packages/validator/test/unit/services/doppelganger.test.ts @@ -1,14 +1,14 @@ -import {describe, it, expect} from "vitest"; +import {ApiClient} from "@lodestar/api"; +import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {Epoch, Slot, ValidatorIndex} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; -import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {ApiClient} from "@lodestar/api"; +import {describe, expect, it} from "vitest"; import {DoppelgangerService, DoppelgangerStatus} from "../../../src/services/doppelgangerService.js"; import {IndicesService} from "../../../src/services/indices.js"; -import {SlashingProtectionMock} from "../../utils/slashingProtectionMock.js"; import {mockApiResponse} from "../../utils/apiStub.js"; -import {testLogger} from "../../utils/logger.js"; import {ClockMock} from "../../utils/clock.js"; +import {testLogger} from "../../utils/logger.js"; +import {SlashingProtectionMock} from "../../utils/slashingProtectionMock.js"; // At genesis start validating immediately diff --git a/packages/validator/test/unit/services/externalSignerSync.test.ts b/packages/validator/test/unit/services/externalSignerSync.test.ts index 8dc7bff7e469..4a0ca5338bcb 100644 --- a/packages/validator/test/unit/services/externalSignerSync.test.ts +++ b/packages/validator/test/unit/services/externalSignerSync.test.ts @@ -1,14 +1,14 @@ -import {MockedFunction, afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; -import {toBufferBE} from "bigint-buffer"; import {SecretKey} from "@chainsafe/blst"; import {createChainForkConfig} from "@lodestar/config"; import {chainConfig} from "@lodestar/config/default"; +import {toBufferBE} from "bigint-buffer"; +import {MockedFunction, afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; import {ExternalSignerOptions, pollExternalSignerPubkeys} from "../../../src/services/externalSignerSync.js"; import {SignerRemote, SignerType, ValidatorStore} from "../../../src/services/validatorStore.js"; import {externalSignerGetKeys} from "../../../src/util/externalSignerClient.js"; -import {initValidatorStore} from "../../utils/validatorStore.js"; import {getApiClientStub} from "../../utils/apiStub.js"; import {loggerVc} from "../../utils/logger.js"; +import {initValidatorStore} from "../../utils/validatorStore.js"; vi.mock("../../../src/util/externalSignerClient.js"); diff --git a/packages/validator/test/unit/services/indicesService.test.ts b/packages/validator/test/unit/services/indicesService.test.ts index d4619aa65b94..91624ca36415 100644 --- a/packages/validator/test/unit/services/indicesService.test.ts +++ b/packages/validator/test/unit/services/indicesService.test.ts @@ -1,10 +1,10 @@ -import {describe, it, expect, beforeAll} from "vitest"; -import {toBufferBE} from "bigint-buffer"; -import {toHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; +import {toHexString} from "@chainsafe/ssz"; +import {toBufferBE} from "bigint-buffer"; +import {beforeAll, describe, expect, it} from "vitest"; +import {IndicesService} from "../../../src/services/indices.js"; import {getApiClientStub} from "../../utils/apiStub.js"; import {testLogger} from "../../utils/logger.js"; -import {IndicesService} from "../../../src/services/indices.js"; describe("IndicesService", () => { const logger = testLogger(); diff --git a/packages/validator/test/unit/services/syncCommitteDuties.test.ts b/packages/validator/test/unit/services/syncCommitteDuties.test.ts index 27a86d31f901..e7f0c46932ad 100644 --- a/packages/validator/test/unit/services/syncCommitteDuties.test.ts +++ b/packages/validator/test/unit/services/syncCommitteDuties.test.ts @@ -1,24 +1,24 @@ -import {describe, it, expect, beforeAll, beforeEach, afterEach, vi} from "vitest"; -import {when} from "vitest-when"; -import {toBufferBE} from "bigint-buffer"; -import {toHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; +import {toHexString} from "@chainsafe/ssz"; +import {routes} from "@lodestar/api"; import {createChainForkConfig} from "@lodestar/config"; import {config as mainnetConfig} from "@lodestar/config/default"; -import {routes} from "@lodestar/api"; import {ssz} from "@lodestar/types"; +import {toBufferBE} from "bigint-buffer"; +import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; +import {when} from "vitest-when"; import { SyncCommitteeDutiesService, SyncDutyAndProofs, SyncDutySubnet, } from "../../../src/services/syncCommitteeDuties.js"; -import {ValidatorStore} from "../../../src/services/validatorStore.js"; import {SyncingStatusTracker} from "../../../src/services/syncingStatusTracker.js"; +import {syncCommitteeIndicesToSubnets} from "../../../src/services/utils.js"; +import {ValidatorStore} from "../../../src/services/validatorStore.js"; import {getApiClientStub, mockApiResponse} from "../../utils/apiStub.js"; -import {loggerVc} from "../../utils/logger.js"; import {ClockMock} from "../../utils/clock.js"; +import {loggerVc} from "../../utils/logger.js"; import {initValidatorStore} from "../../utils/validatorStore.js"; -import {syncCommitteeIndicesToSubnets} from "../../../src/services/utils.js"; describe("SyncCommitteeDutiesService", () => { const api = getApiClientStub(); diff --git a/packages/validator/test/unit/services/syncCommittee.test.ts b/packages/validator/test/unit/services/syncCommittee.test.ts index 84c7f14d73b1..10ce3af44a20 100644 --- a/packages/validator/test/unit/services/syncCommittee.test.ts +++ b/packages/validator/test/unit/services/syncCommittee.test.ts @@ -1,20 +1,20 @@ -import {describe, it, expect, beforeAll, beforeEach, afterEach, vi} from "vitest"; -import {toHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; +import {toHexString} from "@chainsafe/ssz"; +import {routes} from "@lodestar/api"; import {createChainForkConfig} from "@lodestar/config"; import {config as mainnetConfig} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; -import {routes} from "@lodestar/api"; +import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; +import {ChainHeaderTracker} from "../../../src/services/chainHeaderTracker.js"; +import {ValidatorEventEmitter} from "../../../src/services/emitter.js"; import {SyncCommitteeService, SyncCommitteeServiceOpts} from "../../../src/services/syncCommittee.js"; import {SyncDutyAndProofs} from "../../../src/services/syncCommitteeDuties.js"; +import {SyncingStatusTracker} from "../../../src/services/syncingStatusTracker.js"; import {ValidatorStore} from "../../../src/services/validatorStore.js"; import {getApiClientStub, mockApiResponse} from "../../utils/apiStub.js"; -import {loggerVc} from "../../utils/logger.js"; import {ClockMock} from "../../utils/clock.js"; -import {ChainHeaderTracker} from "../../../src/services/chainHeaderTracker.js"; -import {SyncingStatusTracker} from "../../../src/services/syncingStatusTracker.js"; +import {loggerVc} from "../../utils/logger.js"; import {ZERO_HASH} from "../../utils/types.js"; -import {ValidatorEventEmitter} from "../../../src/services/emitter.js"; vi.mock("../../../src/services/validatorStore.js"); vi.mock("../../../src/services/emitter.js"); diff --git a/packages/validator/test/unit/services/syncingStatusTracker.test.ts b/packages/validator/test/unit/services/syncingStatusTracker.test.ts index 07364847e345..eccb00bc51ab 100644 --- a/packages/validator/test/unit/services/syncingStatusTracker.test.ts +++ b/packages/validator/test/unit/services/syncingStatusTracker.test.ts @@ -1,8 +1,8 @@ -import {describe, it, expect, vi, beforeEach, afterEach, MockedFunction} from "vitest"; +import {MockedFunction, afterEach, beforeEach, describe, expect, it, vi} from "vitest"; +import {SyncingStatus, SyncingStatusTracker} from "../../../src/services/syncingStatusTracker.js"; import {getApiClientStub, mockApiResponse} from "../../utils/apiStub.js"; -import {getMockedLogger} from "../../utils/logger.js"; import {ClockMock} from "../../utils/clock.js"; -import {SyncingStatus, SyncingStatusTracker} from "../../../src/services/syncingStatusTracker.js"; +import {getMockedLogger} from "../../utils/logger.js"; describe("SyncingStatusTracker", () => { const api = getApiClientStub(); diff --git a/packages/validator/test/unit/services/utils.test.ts b/packages/validator/test/unit/services/utils.test.ts index f4bb9e57cd04..bd78f36543c5 100644 --- a/packages/validator/test/unit/services/utils.test.ts +++ b/packages/validator/test/unit/services/utils.test.ts @@ -1,5 +1,5 @@ -import {describe, it, expect, beforeAll} from "vitest"; import {SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; +import {beforeAll, describe, expect, it} from "vitest"; import {syncCommitteeIndicesToSubnets} from "../../../src/services/utils.js"; describe("services / utils / syncCommitteeIndicesToSubnets", () => { diff --git a/packages/validator/test/unit/slashingProtection/interchange/index.test.ts b/packages/validator/test/unit/slashingProtection/interchange/index.test.ts index 4038c6d1d4c5..92b994605df3 100644 --- a/packages/validator/test/unit/slashingProtection/interchange/index.test.ts +++ b/packages/validator/test/unit/slashingProtection/interchange/index.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; import {toHexString} from "@chainsafe/ssz"; import {Root, ssz} from "@lodestar/types"; +import {describe, expect, it} from "vitest"; import { Interchange, parseInterchange, diff --git a/packages/validator/test/unit/slashingProtection/minMaxSurround/surroundTests.test.ts b/packages/validator/test/unit/slashingProtection/minMaxSurround/surroundTests.test.ts index 6bdc49fb7f0c..7e0d31fbfe7e 100644 --- a/packages/validator/test/unit/slashingProtection/minMaxSurround/surroundTests.test.ts +++ b/packages/validator/test/unit/slashingProtection/minMaxSurround/surroundTests.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import { MinMaxSurround, MinMaxSurroundAttestation, diff --git a/packages/validator/test/unit/slashingProtection/minMaxSurround/updateSpans.test.ts b/packages/validator/test/unit/slashingProtection/minMaxSurround/updateSpans.test.ts index 62f1ea5e1b4f..3471a81f49db 100644 --- a/packages/validator/test/unit/slashingProtection/minMaxSurround/updateSpans.test.ts +++ b/packages/validator/test/unit/slashingProtection/minMaxSurround/updateSpans.test.ts @@ -1,6 +1,6 @@ -import {describe, it, expect} from "vitest"; -import {MinMaxSurroundAttestation, MinMaxSurround} from "../../../../src/slashingProtection/minMaxSurround/index.js"; -import {DistanceStoreMemory, storeToSpansPerEpoch, emptyPubkey} from "./utils.js"; +import {describe, expect, it} from "vitest"; +import {MinMaxSurround, MinMaxSurroundAttestation} from "../../../../src/slashingProtection/minMaxSurround/index.js"; +import {DistanceStoreMemory, emptyPubkey, storeToSpansPerEpoch} from "./utils.js"; const updateSpansTests: { name: string; diff --git a/packages/validator/test/unit/slashingProtection/minMaxSurround/utils.ts b/packages/validator/test/unit/slashingProtection/minMaxSurround/utils.ts index 6d9e4e0f559d..96dc470a00f7 100644 --- a/packages/validator/test/unit/slashingProtection/minMaxSurround/utils.ts +++ b/packages/validator/test/unit/slashingProtection/minMaxSurround/utils.ts @@ -1,5 +1,5 @@ import {BLSPubkey, ssz} from "@lodestar/types"; -import {IDistanceStore, DistanceEntry} from "../../../../src/slashingProtection/minMaxSurround/index.js"; +import {DistanceEntry, IDistanceStore} from "../../../../src/slashingProtection/minMaxSurround/index.js"; export const emptyPubkey = ssz.BLSPubkey.defaultValue(); export class DistanceMapStore { diff --git a/packages/validator/test/unit/slashingProtection/utils.test.ts b/packages/validator/test/unit/slashingProtection/utils.test.ts index 2e0e4859436d..178b1ac4df63 100644 --- a/packages/validator/test/unit/slashingProtection/utils.test.ts +++ b/packages/validator/test/unit/slashingProtection/utils.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {minEpoch} from "../../../src/slashingProtection/utils.js"; describe("slashingProtection / utils / minEpoch", () => { diff --git a/packages/validator/test/unit/utils/batch.test.ts b/packages/validator/test/unit/utils/batch.test.ts index 455d31e19577..78c814505859 100644 --- a/packages/validator/test/unit/utils/batch.test.ts +++ b/packages/validator/test/unit/utils/batch.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {batchItems} from "../../../src/util/index.js"; describe("util / batch", () => { diff --git a/packages/validator/test/unit/utils/clock.test.ts b/packages/validator/test/unit/utils/clock.test.ts index 056260d9e515..430251d25a6e 100644 --- a/packages/validator/test/unit/utils/clock.test.ts +++ b/packages/validator/test/unit/utils/clock.test.ts @@ -1,7 +1,7 @@ -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; +import {BeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {BeaconConfig} from "@lodestar/config"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {Clock, getCurrentSlotAround} from "../../../src/util/clock.js"; import {testLogger} from "../../utils/logger.js"; diff --git a/packages/validator/test/unit/utils/difference.test.ts b/packages/validator/test/unit/utils/difference.test.ts index 023a6144877a..3d249d1999d9 100644 --- a/packages/validator/test/unit/utils/difference.test.ts +++ b/packages/validator/test/unit/utils/difference.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {differenceHex} from "../../../src/util/difference.js"; describe("utils / differenceHex", () => { diff --git a/packages/validator/test/unit/utils/metrics.test.ts b/packages/validator/test/unit/utils/metrics.test.ts index de4010761001..6876c3705ae9 100644 --- a/packages/validator/test/unit/utils/metrics.test.ts +++ b/packages/validator/test/unit/utils/metrics.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, expect, it} from "vitest"; import {BeaconHealth, renderEnumNumeric} from "../../../src/metrics.js"; describe("renderEnumNumeric", () => { diff --git a/packages/validator/test/unit/utils/params.test.ts b/packages/validator/test/unit/utils/params.test.ts index 13bab507cf13..b483c9a067c3 100644 --- a/packages/validator/test/unit/utils/params.test.ts +++ b/packages/validator/test/unit/utils/params.test.ts @@ -1,9 +1,9 @@ -import {describe, it, expect} from "vitest"; -import {chainConfigToJson, ChainConfig} from "@lodestar/config"; +import {ChainConfig, chainConfigToJson} from "@lodestar/config"; import {chainConfig} from "@lodestar/config/default"; import {networksChainConfig} from "@lodestar/config/networks"; -import {assertEqualParams, NotEqualParamsError} from "../../../src/util/params.js"; -import {lighthouseHoleskyConfig, prysmHoleskyConfig, tekuHoleskyConfig, nimbusHoleskyConfig} from "./interopConfigs.js"; +import {describe, expect, it} from "vitest"; +import {NotEqualParamsError, assertEqualParams} from "../../../src/util/params.js"; +import {lighthouseHoleskyConfig, nimbusHoleskyConfig, prysmHoleskyConfig, tekuHoleskyConfig} from "./interopConfigs.js"; const testCases: {name: string; items: [ChainConfig, Record]}[] = [ {name: "lighthouse", items: [networksChainConfig.holesky, lighthouseHoleskyConfig]}, diff --git a/packages/validator/test/unit/validatorStore.test.ts b/packages/validator/test/unit/validatorStore.test.ts index b029a33e163a..d32acf41647a 100644 --- a/packages/validator/test/unit/validatorStore.test.ts +++ b/packages/validator/test/unit/validatorStore.test.ts @@ -1,15 +1,15 @@ -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; -import {toBufferBE} from "bigint-buffer"; -import {toHexString, fromHexString} from "@chainsafe/ssz"; import {SecretKey} from "@chainsafe/blst"; +import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {routes} from "@lodestar/api"; import {chainConfig} from "@lodestar/config/default"; import {bellatrix} from "@lodestar/types"; -import {routes} from "@lodestar/api"; +import {toBufferBE} from "bigint-buffer"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {ValidatorStore} from "../../src/services/validatorStore.js"; +import {ValidatorProposerConfig} from "../../src/services/validatorStore.js"; import {getApiClientStub} from "../utils/apiStub.js"; import {initValidatorStore} from "../utils/validatorStore.js"; -import {ValidatorProposerConfig} from "../../src/services/validatorStore.js"; describe("ValidatorStore", () => { const api = getApiClientStub(); diff --git a/packages/validator/test/utils/apiStub.ts b/packages/validator/test/utils/apiStub.ts index 4443dab5c4ac..e26a18a1c216 100644 --- a/packages/validator/test/utils/apiStub.ts +++ b/packages/validator/test/utils/apiStub.ts @@ -1,5 +1,5 @@ -import {vi, Mocked} from "vitest"; import {ApiClientMethods, ApiResponse, Endpoint, Endpoints, HttpStatusCode, IHttpClient} from "@lodestar/api"; +import {Mocked, vi} from "vitest"; type ApiClientStub = {[K in keyof Endpoints]: Mocked>} & { httpClient: Mocked; diff --git a/packages/validator/test/utils/logger.ts b/packages/validator/test/utils/logger.ts index 44f5190dfe79..7f32ddba0381 100644 --- a/packages/validator/test/utils/logger.ts +++ b/packages/validator/test/utils/logger.ts @@ -1,6 +1,6 @@ -import {vi, Mocked} from "vitest"; import {Logger} from "@lodestar/logger"; import {getEnvLogger} from "@lodestar/logger/env"; +import {Mocked, vi} from "vitest"; import {getLoggerVc} from "../../src/util/index.js"; import {ClockMock} from "./clock.js"; diff --git a/packages/validator/test/utils/validatorStore.ts b/packages/validator/test/utils/validatorStore.ts index d3037ce522b9..e8eaa485cada 100644 --- a/packages/validator/test/utils/validatorStore.ts +++ b/packages/validator/test/utils/validatorStore.ts @@ -1,7 +1,7 @@ import {SecretKey} from "@chainsafe/blst"; import {ApiClient} from "@lodestar/api"; +import {ChainConfig, createBeaconConfig} from "@lodestar/config"; import {chainConfig} from "@lodestar/config/default"; -import {createBeaconConfig, ChainConfig} from "@lodestar/config"; import {Signer, SignerType, ValidatorStore} from "../../src/index.js"; import {IndicesService} from "../../src/services/indices.js"; import {ValidatorProposerConfig} from "../../src/services/validatorStore.js"; From 07d1145194a629baf0f7c93a2fc776e8afd83aea Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sun, 3 Nov 2024 07:21:41 +0000 Subject: [PATCH 189/259] fix: consistently validate pubkey and throw 404 if not found (#7214) * Throw error if pubkey is unknown when getting graffiti * Consistently validate pubkey and throw 404 if not found --- .../cli/src/cmds/validator/keymanager/impl.ts | 23 ++++++++++++++++++- .../validator/src/services/validatorStore.ts | 6 ++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/cmds/validator/keymanager/impl.ts b/packages/cli/src/cmds/validator/keymanager/impl.ts index 8816f964a8ce..24bf653250eb 100644 --- a/packages/cli/src/cmds/validator/keymanager/impl.ts +++ b/packages/cli/src/cmds/validator/keymanager/impl.ts @@ -42,11 +42,13 @@ export class KeymanagerApi implements Api { } async listFeeRecipient({pubkey}: {pubkey: PubkeyHex}): ReturnType { + this.assertValidKnownPubkey(pubkey); return {data: {pubkey, ethaddress: this.validator.validatorStore.getFeeRecipient(pubkey)}}; } async setFeeRecipient({pubkey, ethaddress}: FeeRecipientData): ReturnType { this.checkIfProposerWriteEnabled(); + this.assertValidKnownPubkey(pubkey); this.validator.validatorStore.setFeeRecipient(pubkey, parseFeeRecipient(ethaddress)); this.persistedKeysBackend.writeProposerConfig(pubkey, this.validator.validatorStore.getProposerConfig(pubkey)); return {status: 202}; @@ -54,12 +56,14 @@ export class KeymanagerApi implements Api { async deleteFeeRecipient({pubkey}: {pubkey: PubkeyHex}): ReturnType { this.checkIfProposerWriteEnabled(); + this.assertValidKnownPubkey(pubkey); this.validator.validatorStore.deleteFeeRecipient(pubkey); this.persistedKeysBackend.writeProposerConfig(pubkey, this.validator.validatorStore.getProposerConfig(pubkey)); return {status: 204}; } async getGraffiti({pubkey}: {pubkey: PubkeyHex}): ReturnType { + this.assertValidKnownPubkey(pubkey); const graffiti = this.validator.validatorStore.getGraffiti(pubkey); if (graffiti === undefined) { throw new ApiError(404, `No graffiti for pubkey ${pubkey}`); @@ -69,6 +73,7 @@ export class KeymanagerApi implements Api { async setGraffiti({pubkey, graffiti}: GraffitiData): ReturnType { this.checkIfProposerWriteEnabled(); + this.assertValidKnownPubkey(pubkey); this.validator.validatorStore.setGraffiti(pubkey, graffiti); this.persistedKeysBackend.writeProposerConfig(pubkey, this.validator.validatorStore.getProposerConfig(pubkey)); return {status: 202}; @@ -76,18 +81,21 @@ export class KeymanagerApi implements Api { async deleteGraffiti({pubkey}: {pubkey: PubkeyHex}): ReturnType { this.checkIfProposerWriteEnabled(); + this.assertValidKnownPubkey(pubkey); this.validator.validatorStore.deleteGraffiti(pubkey); this.persistedKeysBackend.writeProposerConfig(pubkey, this.validator.validatorStore.getProposerConfig(pubkey)); return {status: 204}; } async getGasLimit({pubkey}: {pubkey: PubkeyHex}): ReturnType { + this.assertValidKnownPubkey(pubkey); const gasLimit = this.validator.validatorStore.getGasLimit(pubkey); return {data: {pubkey, gasLimit}}; } async setGasLimit({pubkey, gasLimit}: GasLimitData): ReturnType { this.checkIfProposerWriteEnabled(); + this.assertValidKnownPubkey(pubkey); this.validator.validatorStore.setGasLimit(pubkey, gasLimit); this.persistedKeysBackend.writeProposerConfig(pubkey, this.validator.validatorStore.getProposerConfig(pubkey)); return {status: 202}; @@ -95,6 +103,7 @@ export class KeymanagerApi implements Api { async deleteGasLimit({pubkey}: {pubkey: PubkeyHex}): ReturnType { this.checkIfProposerWriteEnabled(); + this.assertValidKnownPubkey(pubkey); this.validator.validatorStore.deleteGasLimit(pubkey); this.persistedKeysBackend.writeProposerConfig(pubkey, this.validator.validatorStore.getProposerConfig(pubkey)); return {status: 204}; @@ -344,6 +353,7 @@ export class KeymanagerApi implements Api { } async getBuilderBoostFactor({pubkey}: {pubkey: PubkeyHex}): ReturnType { + this.assertValidKnownPubkey(pubkey); const builderBoostFactor = this.validator.validatorStore.getBuilderBoostFactor(pubkey); return {data: {pubkey, builderBoostFactor}}; } @@ -353,6 +363,7 @@ export class KeymanagerApi implements Api { builderBoostFactor, }: BuilderBoostFactorData): ReturnType { this.checkIfProposerWriteEnabled(); + this.assertValidKnownPubkey(pubkey); this.validator.validatorStore.setBuilderBoostFactor(pubkey, builderBoostFactor); this.persistedKeysBackend.writeProposerConfig(pubkey, this.validator.validatorStore.getProposerConfig(pubkey)); return {status: 202}; @@ -366,6 +377,8 @@ export class KeymanagerApi implements Api { } async getProposerConfig({pubkey}: {pubkey: PubkeyHex}): ReturnType { + this.assertValidKnownPubkey(pubkey); + const config = this.validator.validatorStore.getProposerConfig(pubkey); const data: ProposerConfigResponse = { @@ -383,10 +396,18 @@ export class KeymanagerApi implements Api { } async signVoluntaryExit({pubkey, epoch}: {pubkey: PubkeyHex; epoch?: Epoch}): ReturnType { + this.assertValidKnownPubkey(pubkey); + return {data: await this.validator.signVoluntaryExit(pubkey, epoch)}; + } + + private assertValidKnownPubkey(pubkey: PubkeyHex): void { if (!isValidatePubkeyHex(pubkey)) { throw new ApiError(400, `Invalid pubkey ${pubkey}`); } - return {data: await this.validator.signVoluntaryExit(pubkey, epoch)}; + + if (!this.validator.validatorStore.hasVotingPubkey(pubkey)) { + throw new ApiError(404, `Validator pubkey ${pubkey} not known`); + } } } diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index 0c66f576ffa0..e80c0b291ef5 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -251,7 +251,11 @@ export class ValidatorStore { } getGraffiti(pubkeyHex: PubkeyHex): string | undefined { - return this.validators.get(pubkeyHex)?.graffiti ?? this.defaultProposerConfig.graffiti; + const validatorData = this.validators.get(pubkeyHex); + if (validatorData === undefined) { + throw Error(`Validator pubkey ${pubkeyHex} not known`); + } + return validatorData.graffiti ?? this.defaultProposerConfig.graffiti; } setGraffiti(pubkeyHex: PubkeyHex, graffiti: string): void { From abe6751566d948df5c55f7d90b7742bfd8973f68 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sun, 3 Nov 2024 07:25:02 +0000 Subject: [PATCH 190/259] fix: only return local keys from /eth/v1/keystores (#7215) * fix: only return local keys from /eth/v1/keystores * Fix fetching remote keys in node assertion --- packages/cli/src/cmds/validator/keymanager/impl.ts | 9 ++++++--- .../cli/test/utils/crucible/assertions/nodeAssertion.ts | 9 +++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/cmds/validator/keymanager/impl.ts b/packages/cli/src/cmds/validator/keymanager/impl.ts index 24bf653250eb..9a5a8bd72743 100644 --- a/packages/cli/src/cmds/validator/keymanager/impl.ts +++ b/packages/cli/src/cmds/validator/keymanager/impl.ts @@ -110,12 +110,15 @@ export class KeymanagerApi implements Api { } async listKeys(): ReturnType { - const pubkeys = this.validator.validatorStore.votingPubkeys(); + const localKeys = this.validator.validatorStore + .votingPubkeys() + .filter((pubkey) => this.validator.validatorStore.getSigner(pubkey)?.type === SignerType.Local); + return { - data: pubkeys.map((pubkey) => ({ + data: localKeys.map((pubkey) => ({ validatingPubkey: pubkey, derivationPath: "", - readonly: this.validator.validatorStore.getSigner(pubkey)?.type !== SignerType.Local, + readonly: false, })), }; } diff --git a/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts b/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts index 6b94f2e701a9..5a951ced89ce 100644 --- a/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts +++ b/packages/cli/test/utils/crucible/assertions/nodeAssertion.ts @@ -20,8 +20,13 @@ export const nodeAssertion: Assertion<"node", {health: number; keyManagerKeys: s if (node.validator.client === ValidatorClient.Lighthouse || getAllKeys(node.validator.keys).length === 0) { keyManagerKeys = []; } else { - const keys = (await node.validator.keyManager.listKeys()).value(); - keyManagerKeys = keys.map((k) => k.validatingPubkey); + if (node.validator.keys.type === "local") { + const keys = (await node.validator.keyManager.listKeys()).value(); + keyManagerKeys = keys.map((k) => k.validatingPubkey); + } else { + const keys = (await node.validator.keyManager.listRemoteKeys()).value(); + keyManagerKeys = keys.map((k) => k.pubkey); + } } return {health, keyManagerKeys}; From 2e5265bf6fd12bc4ae824328fad9d2915beac29e Mon Sep 17 00:00:00 2001 From: g11tech Date: Sun, 3 Nov 2024 15:05:27 +0530 Subject: [PATCH 191/259] feat: add and use getBlobsV1 to expedite gossip import (#7134) * hookup the getblobs api to get bob and proof data from el remove unused fix import metrics overhault, test, debugging testing, some feeback fix add nethermind bug dicussion link fix resolve conflicts * deblobs timeout * fix metric --- .../src/api/impl/beacon/blocks/index.ts | 10 +- .../src/chain/blocks/verifyBlock.ts | 2 +- .../blocks/verifyBlocksDataAvailability.ts | 28 +- .../src/eth1/provider/jsonRpcHttpClient.ts | 2 +- .../src/execution/engine/disabled.ts | 4 + .../beacon-node/src/execution/engine/http.ts | 57 +++- .../src/execution/engine/interface.ts | 4 +- .../beacon-node/src/execution/engine/mock.ts | 7 + .../beacon-node/src/execution/engine/types.ts | 19 ++ .../beacon-node/src/metrics/metrics/beacon.ts | 115 ++++++++ .../src/network/processor/gossipHandlers.ts | 3 + .../reqresp/beaconBlocksMaybeBlobsByRoot.ts | 169 +++++++++++- packages/beacon-node/src/sync/unknownBlock.ts | 17 +- .../unavailableBeaconBlobsByRoot.test.ts | 257 ++++++++++++++++++ packages/types/src/deneb/types.ts | 4 + 15 files changed, 663 insertions(+), 35 deletions(-) create mode 100644 packages/beacon-node/test/unit/network/unavailableBeaconBlobsByRoot.test.ts 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 bda72bc3b997..66935df25b2b 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -215,12 +215,12 @@ export function getBeaconBlockApi({ // specification is very clear that this is the desired behaviour. // // i) Publish blobs and block before importing so that network can see them asap - // ii) publish blobs first because - // a) by the times nodes see block, they might decide to pull blobs - // b) they might require more hops to reach recipients in peerDAS kind of setup where - // blobs might need to hop between nodes because of partial subnet subscription - ...blobSidecars.map((blobSidecar) => () => network.publishBlobSidecar(blobSidecar)), + // ii) publish block first because + // a) as soon as node sees block they can start processing it while blobs arrive + // b) getting block first allows nodes to use getBlobs from local ELs and save + // import latency and hopefully bandwidth () => network.publishBeaconBlock(signedBlock) as Promise, + ...blobSidecars.map((blobSidecar) => () => network.publishBlobSidecar(blobSidecar)), () => // there is no rush to persist block since we published it to gossip anyway chain diff --git a/packages/beacon-node/src/chain/blocks/verifyBlock.ts b/packages/beacon-node/src/chain/blocks/verifyBlock.ts index 47a9a9060572..5ead67a720f7 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlock.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlock.ts @@ -106,7 +106,7 @@ export async function verifyBlocksInEpoch( } as SegmentExecStatus), // data availability for the blobs - verifyBlocksDataAvailability(this, blocksInput, opts), + verifyBlocksDataAvailability(this, blocksInput, abortController.signal, opts), // Run state transition only // TODO: Ensure it yields to allow flushing to workers and engine API diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts index 1d8c72a46873..11e1d8f94567 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksDataAvailability.ts @@ -2,7 +2,7 @@ import {ChainForkConfig} from "@lodestar/config"; import {DataAvailabilityStatus} from "@lodestar/fork-choice"; import {computeTimeAtSlot} from "@lodestar/state-transition"; import {UintNum64, deneb} from "@lodestar/types"; -import {Logger} from "@lodestar/utils"; +import {ErrorAborted, Logger} from "@lodestar/utils"; import {Metrics} from "../../metrics/metrics.js"; import {BlockError, BlockErrorCode} from "../errors/index.js"; import {validateBlobSidecars} from "../validation/blobSidecar.js"; @@ -27,6 +27,7 @@ const BLOB_AVAILABILITY_TIMEOUT = 12_000; export async function verifyBlocksDataAvailability( chain: {config: ChainForkConfig; genesisTime: UintNum64; logger: Logger; metrics: Metrics | null}, blocks: BlockInput[], + signal: AbortSignal, opts: ImportBlockOpts ): Promise<{ dataAvailabilityStatuses: DataAvailabilityStatus[]; @@ -43,9 +44,12 @@ export async function verifyBlocksDataAvailability( const availableBlockInputs: BlockInput[] = []; for (const blockInput of blocks) { + if (signal.aborted) { + throw new ErrorAborted("verifyBlocksDataAvailability"); + } // 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, availableBlockInput} = await maybeValidateBlobs(chain, blockInput, opts); + const {dataAvailabilityStatus, availableBlockInput} = await maybeValidateBlobs(chain, blockInput, signal, opts); dataAvailabilityStatuses.push(dataAvailabilityStatus); availableBlockInputs.push(availableBlockInput); } @@ -69,6 +73,7 @@ export async function verifyBlocksDataAvailability( async function maybeValidateBlobs( chain: {config: ChainForkConfig; genesisTime: UintNum64; logger: Logger}, blockInput: BlockInput, + signal: AbortSignal, opts: ImportBlockOpts ): Promise<{dataAvailabilityStatus: DataAvailabilityStatus; availableBlockInput: BlockInput}> { switch (blockInput.type) { @@ -92,7 +97,7 @@ async function maybeValidateBlobs( const blobsData = blockInput.type === BlockInputType.availableData ? blockInput.blockData - : await raceWithCutoff(chain, blockInput, blockInput.cachedData.availabilityPromise); + : await raceWithCutoff(chain, blockInput, blockInput.cachedData.availabilityPromise, signal); const {blobs} = blobsData; const {blobKzgCommitments} = (block as deneb.SignedBeaconBlock).message.body; @@ -122,16 +127,21 @@ async function maybeValidateBlobs( async function raceWithCutoff( chain: {config: ChainForkConfig; genesisTime: UintNum64; logger: Logger}, blockInput: BlockInput, - availabilityPromise: Promise + availabilityPromise: Promise, + signal: AbortSignal ): Promise { const {block} = blockInput; const blockSlot = block.message.slot; - const cutoffTime = Math.max( - computeTimeAtSlot(chain.config, blockSlot, chain.genesisTime) * 1000 + BLOB_AVAILABILITY_TIMEOUT - Date.now(), - 0 - ); - const cutoffTimeout = new Promise((_resolve, reject) => setTimeout(reject, cutoffTime)); + const cutoffTime = + computeTimeAtSlot(chain.config, blockSlot, chain.genesisTime) * 1000 + BLOB_AVAILABILITY_TIMEOUT - Date.now(); + const cutoffTimeout = + cutoffTime > 0 + ? new Promise((_resolve, reject) => { + setTimeout(() => reject(new Error("Timeout exceeded")), cutoffTime); + signal.addEventListener("abort", () => reject(signal.reason)); + }) + : Promise.reject(new Error("Cutoff time must be greater than 0")); chain.logger.debug("Racing for blob availabilityPromise", {blockSlot, cutoffTime}); try { diff --git a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts index da72d5183d30..906c9cd883c7 100644 --- a/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts +++ b/packages/beacon-node/src/eth1/provider/jsonRpcHttpClient.ts @@ -372,7 +372,7 @@ export class HttpRpcError extends Error { /** * JSON RPC spec errors https://www.jsonrpc.org/specification#response_object */ -function parseJsonRpcErrorCode(code: number): string { +export function parseJsonRpcErrorCode(code: number): string { if (code === -32700) return "Parse request error"; if (code === -32600) return "Invalid request object"; if (code === -32601) return "Method not found"; diff --git a/packages/beacon-node/src/execution/engine/disabled.ts b/packages/beacon-node/src/execution/engine/disabled.ts index 68c72dc02ac6..dce9244ef7ab 100644 --- a/packages/beacon-node/src/execution/engine/disabled.ts +++ b/packages/beacon-node/src/execution/engine/disabled.ts @@ -28,4 +28,8 @@ export class ExecutionEngineDisabled implements IExecutionEngine { getPayloadBodiesByRange(): Promise { throw Error("Execution engine disabled"); } + + getBlobs(): Promise { + throw Error("Execution engine disabled"); + } } diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index c5cf61481b67..ea064d2fe816 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -1,14 +1,16 @@ import {Logger} from "@lodestar/logger"; import {ForkName, ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ExecutionPayload, ExecutionRequests, Root, RootHex, Wei} from "@lodestar/types"; +import {BlobAndProof} from "@lodestar/types/deneb"; import { ErrorJsonRpcResponse, HttpRpcError, IJsonRpcHttpClient, JsonRpcHttpClientEvent, ReqOpts, + parseJsonRpcErrorCode, } from "../../eth1/provider/jsonRpcHttpClient.js"; -import {numToQuantity} from "../../eth1/provider/utils.js"; +import {bytesToData, numToQuantity} from "../../eth1/provider/utils.js"; import {Metrics} from "../../metrics/index.js"; import {EPOCHS_PER_BATCH} from "../../sync/constants.js"; import {getLodestarClientVersion} from "../../util/metadata.js"; @@ -31,6 +33,7 @@ import { EngineApiRpcReturnTypes, ExecutionPayloadBody, assertReqSizeLimit, + deserializeBlobAndProofs, deserializeExecutionPayloadBody, parseExecutionPayload, serializeBeaconBlockRoot, @@ -111,6 +114,7 @@ const getPayloadOpts: ReqOpts = {routeId: "getPayload"}; */ export class ExecutionEngineHttp implements IExecutionEngine { private logger: Logger; + private lastGetBlobsErrorTime = 0; // The default state is ONLINE, it will be updated to SYNCING once we receive the first payload // This assumption is better than the OFFLINE state, since we can't be sure if the EL is offline and being offline may trigger some notifications @@ -461,6 +465,57 @@ export class ExecutionEngineHttp implements IExecutionEngine { return response.map(deserializeExecutionPayloadBody); } + async getBlobs(_fork: ForkName, versionedHashes: VersionedHashes): Promise<(BlobAndProof | null)[]> { + // retry only after a day may be + const GETBLOBS_RETRY_TIMEOUT = 256 * 32 * 12; + const timeNow = Date.now() / 1000; + const timeSinceLastFail = timeNow - this.lastGetBlobsErrorTime; + if (timeSinceLastFail < GETBLOBS_RETRY_TIMEOUT) { + // do not try getblobs since it might not be available + this.logger.debug( + `disabled engine_getBlobsV1 api call since last failed < GETBLOBS_RETRY_TIMEOUT=${GETBLOBS_RETRY_TIMEOUT}`, + timeSinceLastFail + ); + throw Error( + `engine_getBlobsV1 call recently failed timeSinceLastFail=${timeSinceLastFail} < GETBLOBS_RETRY_TIMEOUT=${GETBLOBS_RETRY_TIMEOUT}` + ); + } + + const method = "engine_getBlobsV1"; + assertReqSizeLimit(versionedHashes.length, 128); + const versionedHashesHex = versionedHashes.map(bytesToData); + let response = await this.rpc + .fetchWithRetries({ + method, + params: [versionedHashesHex], + }) + .catch((e) => { + if (e instanceof ErrorJsonRpcResponse && parseJsonRpcErrorCode(e.response.error.code) === "Method not found") { + this.lastGetBlobsErrorTime = timeNow; + this.logger.debug("disabling engine_getBlobsV1 api call since engine responded with method not availeble", { + retryTimeout: GETBLOBS_RETRY_TIMEOUT, + }); + } + throw e; + }); + + // handle nethermind buggy response + // see: https://discord.com/channels/595666850260713488/1293605631785304088/1298956894274060301 + if ( + (response as unknown as {blobsAndProofs: EngineApiRpcReturnTypes[typeof method]}).blobsAndProofs !== undefined + ) { + response = (response as unknown as {blobsAndProofs: EngineApiRpcReturnTypes[typeof method]}).blobsAndProofs; + } + + if (response.length !== versionedHashes.length) { + const error = `Invalid engine_getBlobsV1 response length=${response.length} versionedHashes=${versionedHashes.length}`; + this.logger.error(error); + throw Error(error); + } + + return response.map(deserializeBlobAndProofs); + } + private async getClientVersion(clientVersion: ClientVersion): Promise { const method = "engine_getClientVersionV1"; diff --git a/packages/beacon-node/src/execution/engine/interface.ts b/packages/beacon-node/src/execution/engine/interface.ts index 7bbf1bb27c1d..c32cc1bc7215 100644 --- a/packages/beacon-node/src/execution/engine/interface.ts +++ b/packages/beacon-node/src/execution/engine/interface.ts @@ -1,6 +1,6 @@ import {ForkName} from "@lodestar/params"; import {ExecutionPayload, ExecutionRequests, Root, RootHex, Wei, capella} from "@lodestar/types"; -import {Blob, KZGCommitment, KZGProof} from "@lodestar/types/deneb"; +import {Blob, BlobAndProof, KZGCommitment, KZGProof} from "@lodestar/types/deneb"; import {DATA} from "../../eth1/provider/utils.js"; import {PayloadId, PayloadIdCache, WithdrawalV1} from "./payloadIdCache.js"; @@ -179,4 +179,6 @@ export interface IExecutionEngine { getPayloadBodiesByHash(fork: ForkName, blockHash: DATA[]): Promise<(ExecutionPayloadBody | null)[]>; getPayloadBodiesByRange(fork: ForkName, start: number, count: number): Promise<(ExecutionPayloadBody | null)[]>; + + getBlobs(fork: ForkName, versionedHashes: VersionedHashes): Promise<(BlobAndProof | null)[]>; } diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index 2331500624eb..8a84d2b0148e 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -99,6 +99,7 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { engine_getPayloadBodiesByHashV1: this.getPayloadBodiesByHash.bind(this), engine_getPayloadBodiesByRangeV1: this.getPayloadBodiesByRange.bind(this), engine_getClientVersionV1: this.getClientVersionV1.bind(this), + engine_getBlobsV1: this.getBlobs.bind(this), }; } @@ -397,6 +398,12 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { return [{code: ClientCode.XX, name: "mock", version: "", commit: ""}]; } + private getBlobs( + versionedHashes: EngineApiRpcParamTypes["engine_getBlobsV1"][0] + ): EngineApiRpcReturnTypes["engine_getBlobsV1"] { + return versionedHashes.map((_vh) => null); + } + private timestampToFork(timestamp: number): ForkExecution { if (timestamp > (this.opts.electraForkTimestamp ?? Infinity)) return ForkName.electra; if (timestamp > (this.opts.denebForkTimestamp ?? Infinity)) return ForkName.deneb; diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 9af2d8d1ce10..f35a63aa3d96 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -6,6 +6,7 @@ import { ForkSeq, } from "@lodestar/params"; import {ExecutionPayload, ExecutionRequests, Root, Wei, bellatrix, capella, deneb, electra, ssz} from "@lodestar/types"; +import {BlobAndProof} from "@lodestar/types/deneb"; import { DATA, @@ -67,6 +68,8 @@ export type EngineApiRpcParamTypes = { * Object - Instance of ClientVersion */ engine_getClientVersionV1: [ClientVersionRpc]; + + engine_getBlobsV1: [DATA[]]; }; export type PayloadStatus = { @@ -109,6 +112,8 @@ export type EngineApiRpcReturnTypes = { engine_getPayloadBodiesByRangeV1: (ExecutionPayloadBodyRpc | null)[]; engine_getClientVersionV1: ClientVersionRpc[]; + + engine_getBlobsV1: (BlobAndProofRpc | null)[]; }; type ExecutionPayloadRpcWithValue = { @@ -171,6 +176,11 @@ export type DepositRequestsRpc = DATA; export type WithdrawalRequestsRpc = DATA; export type ConsolidationRequestsRpc = DATA; +export type BlobAndProofRpc = { + blob: DATA; + proof: DATA; +}; + export type VersionedHashesRpc = DATA[]; export type PayloadAttributesRpc = { @@ -462,6 +472,15 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null) : null; } +export function deserializeBlobAndProofs(data: BlobAndProofRpc | null): BlobAndProof | null { + return data + ? { + blob: dataToBytes(data.blob, BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB), + proof: dataToBytes(data.proof, 48), + } + : null; +} + export function assertReqSizeLimit(blockHashesReqCount: number, count: number): void { if (blockHashesReqCount > count) { throw new Error(`Requested blocks must not be > ${count}`); diff --git a/packages/beacon-node/src/metrics/metrics/beacon.ts b/packages/beacon-node/src/metrics/metrics/beacon.ts index 0347aef8957b..f572ec0d3c1f 100644 --- a/packages/beacon-node/src/metrics/metrics/beacon.ts +++ b/packages/beacon-node/src/metrics/metrics/beacon.ts @@ -220,6 +220,121 @@ export function createBeaconMetrics(register: RegistryMetricCreator) { }), }, + blockInputFetchStats: { + // of already available blocks which didn't have to go through blobs pull + totalDataAvailableBlockInputs: register.gauge({ + name: "beacon_blockinputs_already_available_total", + help: "Total number of block inputs whose blobs were already available", + }), + totalDataAvailableBlockInputBlobs: register.gauge({ + name: "beacon_blockinput_blobs_already_available_total", + help: "Total number of block input blobs that of already available blocks", + }), + + // of those which need to be fetched + dataPromiseBlobsAlreadyAvailable: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_already_available_total", + help: "Count of blocks that were already available in blockinput cache via gossip", + }), + dataPromiseBlobsDelayedGossipAvailable: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_delayed_gossip_available_total", + help: "Count of blobs that became available delayed via gossip post block arrival", + }), + dataPromiseBlobsDeplayedGossipAvailableSavedGetBlobsCompute: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_delayed_gossip_saved_computation_total", + help: "Count of late available blobs that saved blob sidecar computation from getblobs", + }), + dataPromiseBlobsFoundInGetBlobsCacheNotNull: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_found_nonnull_in_getblobs_cache_total", + help: "Count of blobs that were found not null in getblobs cache", + }), + dataPromiseBlobsFoundInGetBlobsCacheNull: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_found_null_in_getblobs_cache_total", + help: "Count of blobs that were found null in the getblobs cache", + }), + dataPromiseBlobsNotAvailableInGetBlobsCache: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_notfound_in_getblobs_cache_total", + help: "Count of blobs that were newly seen and hence in not getblobs cache", + }), + dataPromiseBlobsEngineGetBlobsApiRequests: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_queried_in_getblobs_api_total", + help: "Total number of blobs requested to the getblobs api", + }), + dataPromiseBlobsEngineGetBlobsApiNotNull: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_responded_nonnull_in_getblobs_api_total", + help: "Count of successful engine API responses that were not null", + }), + dataPromiseBlobsEngineGetBlobsApiNull: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_responded_null_in_getblobs_api_total", + help: "Count of engine API responses that were null", + }), + dataPromiseBlobsEngineApiGetBlobsErroredNull: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_errored_as_null_in_getblobs_api_total", + help: "Number of responses marked null due to errors in getblobs api", + }), + dataPromiseBlobsEngineApiGetBlobsUseful: register.gauge({ + name: "beacon_datapromise_blockinput_getblobs_api_nonnull_responses_used_total", + help: "Count of successful non null engine API responses that were found useful", + }), + dataPromiseBlobsFinallyQueriedFromNetwork: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_finally_queried_from_network_total", + help: "Number of blob requests finally sent to the network", + }), + dataPromiseBlobsFinallyAvailableFromNetwork: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_finally_resolved_from_network_total", + help: "Number of blobs successfully fetched from the network", + }), + + totalDataPromiseBlockInputsAvailableUsingGetBlobs: register.gauge({ + name: "beacon_datapromise_blockinputs_available_using_getblobs_total", + help: "Count of block inputs that became available using non-null get blobs requests", + }), + totalDataPromiseBlockInputsTried: register.gauge({ + name: "beacon_datapromise_blockinputs_tried_for_blobs_pull_total", + help: "Total number of block inputs that were tried to resolve", + }), + totalDataPromiseBlockInputsResolvedAvailable: register.gauge({ + name: "beacon_datapromise_blockinputs_available_post_blobs_pull_total", + help: "Total number of block inputs that were successfully resolved as available on blobs pull", + }), + + // retry counts + totalDataPromiseBlockInputsReTried: register.gauge({ + name: "beacon_datapromise_blockinputs_retried_for_blobs_pull_total", + help: "Total number of block inputs that were retried for blobs pull from network", + }), + dataPromiseBlobsRetriedFromNetwork: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_retried_from_network_total", + help: "Number of blob requests required from the network on retries", + }), + dataPromiseBlobsRetriedAvailableFromNetwork: register.gauge({ + name: "beacon_datapromise_blockinput_blobs_retried_and_resolved_from_network_total", + help: "Number of blobs successfully fetched from the network on retries", + }), + totalDataPromiseBlockInputsRetriedAvailableFromNetwork: register.gauge({ + name: "beacon_datapromise_blockinputs_retried_and_resolved_from_network_total", + help: "Number of blockinputs successfully resolved from the network on retries", + }), + + // some caches stats + getBlobsCacheSize: register.gauge({ + name: "getblob_cache_size", + help: "getBlobs cache size", + }), + getBlobsCachePruned: register.gauge({ + name: "getblob_cache_pruned_total", + help: "getblobs cache pruned count", + }), + dataPromiseBlockInputRetryTrackerCacheSize: register.gauge({ + name: "beacon_datapromise_blockinput_retry_tracker_cache_size", + help: "datapromise retry tracker cache size", + }), + dataPromiseBlockInputRetryTrackerCachePruned: register.gauge({ + name: "beacon_datapromise_blockinput_retry_tracker_cache_pruned", + help: "datapromise retry tracker cache pruned count", + }), + }, + // Non-spec'ed clockSlot: register.gauge({ name: "beacon_clock_slot", diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index 5bec263a45c8..029e7ae4db42 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -253,6 +253,9 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand // if blobs are not yet fully available start an aggressive blob pull if (blockInput.type === BlockInputType.dataPromise) { events.emit(NetworkEvent.unknownBlockInput, {blockInput, peer: peerIdStr}); + } else if (blockInput.type === BlockInputType.availableData) { + metrics?.blockInputFetchStats.totalDataAvailableBlockInputs.inc(); + metrics?.blockInputFetchStats.totalDataAvailableBlockInputBlobs.inc(blockInput.blockData.blobs.length); } chain diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts index a6919318999d..3bbe00bfc56b 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRoot.ts @@ -1,6 +1,9 @@ +import {toHexString} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; -import {ForkSeq} from "@lodestar/params"; -import {SignedBeaconBlock, deneb, phase0} from "@lodestar/types"; +import {ForkName, ForkSeq} from "@lodestar/params"; +import {signedBlockToSignedHeader} from "@lodestar/state-transition"; +import {RootHex, SignedBeaconBlock, deneb, phase0} from "@lodestar/types"; +import {BlobAndProof} from "@lodestar/types/deneb"; import {fromHex} from "@lodestar/utils"; import { BlobsSource, @@ -13,11 +16,17 @@ import { getBlockInputBlobs, } from "../../chain/blocks/types.js"; import {BlockInputAvailabilitySource} from "../../chain/seenCache/seenGossipBlockInput.js"; +import {IExecutionEngine} from "../../execution/index.js"; import {Metrics} from "../../metrics/index.js"; +import {computeInclusionProof, kzgCommitmentToVersionedHash} from "../../util/blobs.js"; import {PeerIdStr} from "../../util/peerId.js"; import {INetwork} from "../interface.js"; import {matchBlockWithBlobs} from "./beaconBlocksMaybeBlobsByRange.js"; +// keep 1 epoch of stuff, assmume 16 blobs +const MAX_ENGINE_GETBLOBS_CACHE = 32 * 16; +const MAX_UNAVAILABLE_RETRY_CACHE = 32; + export async function beaconBlocksMaybeBlobsByRoot( config: ChainForkConfig, network: INetwork, @@ -35,6 +44,7 @@ export async function beaconBlocksMaybeBlobsByRoot( if (ForkSeq[fork] >= ForkSeq.deneb) { const blobKzgCommitmentsLen = (block.data.message.body as deneb.BeaconBlockBody).blobKzgCommitments.length; for (let index = 0; index < blobKzgCommitmentsLen; index++) { + // try see if the blob is available locally blobIdentifiers.push({blockRoot, index}); } } @@ -57,8 +67,14 @@ export async function unavailableBeaconBlobsByRoot( network: INetwork, peerId: PeerIdStr, unavailableBlockInput: BlockInput | NullBlockInput, - metrics: Metrics | null + opts: { + metrics: Metrics | null; + executionEngine: IExecutionEngine; + engineGetBlobsCache?: Map; + blockInputsRetryTrackerCache?: Set; + } ): Promise { + const {executionEngine, metrics, engineGetBlobsCache, blockInputsRetryTrackerCache} = opts; if (unavailableBlockInput.block !== null && unavailableBlockInput.type !== BlockInputType.dataPromise) { return unavailableBlockInput; } @@ -81,26 +97,150 @@ export async function unavailableBeaconBlobsByRoot( } // resolve missing blobs - const blobIdentifiers: deneb.BlobIdentifier[] = []; const slot = block.message.slot; + const fork = config.getForkName(slot); const blockRoot = config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block.message); + const blockRootHex = toHexString(blockRoot); + + const blockTriedBefore = blockInputsRetryTrackerCache?.has(blockRootHex) === true; + if (blockTriedBefore) { + metrics?.blockInputFetchStats.totalDataPromiseBlockInputsReTried.inc(); + } else { + metrics?.blockInputFetchStats.totalDataPromiseBlockInputsTried.inc(); + blockInputsRetryTrackerCache?.add(blockRootHex); + } const blobKzgCommitmentsLen = (block.message.body as deneb.BeaconBlockBody).blobKzgCommitments.length; + const signedBlockHeader = signedBlockToSignedHeader(config, block); + + const engineReqIdentifiers: (deneb.BlobIdentifier & { + kzgCommitment: deneb.KZGCommitment; + versionedHash: Uint8Array; + })[] = []; + const networkReqIdentifiers: deneb.BlobIdentifier[] = []; + + let getBlobsUseful = false; for (let index = 0; index < blobKzgCommitmentsLen; index++) { - if (blobsCache.has(index) === false) blobIdentifiers.push({blockRoot, index}); + if (blobsCache.has(index) === false) { + const kzgCommitment = (block.message.body as deneb.BeaconBlockBody).blobKzgCommitments[index]; + const versionedHash = kzgCommitmentToVersionedHash(kzgCommitment); + + // check if the getblobs cache has the data if block not been queried before + if (engineGetBlobsCache?.has(toHexString(versionedHash)) === true && !blockTriedBefore) { + const catchedBlobAndProof = engineGetBlobsCache.get(toHexString(versionedHash)) ?? null; + if (catchedBlobAndProof === null) { + metrics?.blockInputFetchStats.dataPromiseBlobsFoundInGetBlobsCacheNull.inc(); + networkReqIdentifiers.push({blockRoot, index}); + } else { + metrics?.blockInputFetchStats.dataPromiseBlobsFoundInGetBlobsCacheNotNull.inc(); + // compute TODO: also add inclusion proof cache + const {blob, proof: kzgProof} = catchedBlobAndProof; + const kzgCommitmentInclusionProof = computeInclusionProof(fork, block.message.body, index); + const blobSidecar = {index, blob, kzgCommitment, kzgProof, signedBlockHeader, kzgCommitmentInclusionProof}; + blobsCache.set(blobSidecar.index, {blobSidecar, blobBytes: null}); + } + } else if (blockTriedBefore) { + // only retry it from network + networkReqIdentifiers.push({blockRoot, index}); + } else { + // see if we can pull from EL + metrics?.blockInputFetchStats.dataPromiseBlobsNotAvailableInGetBlobsCache.inc(); + engineReqIdentifiers.push({blockRoot, index, versionedHash, kzgCommitment}); + } + } else { + metrics?.blockInputFetchStats.dataPromiseBlobsAlreadyAvailable.inc(); + } } - let allBlobSidecars: deneb.BlobSidecar[]; - if (blobIdentifiers.length > 0) { - allBlobSidecars = await network.sendBlobSidecarsByRoot(peerId, blobIdentifiers); + const versionedHashes = engineReqIdentifiers.map((bi) => bi.versionedHash); + metrics?.blockInputFetchStats.dataPromiseBlobsEngineGetBlobsApiRequests.inc(versionedHashes.length); + + const blobAndProofs = await executionEngine.getBlobs(ForkName.deneb, versionedHashes).catch((_e) => { + metrics?.blockInputFetchStats.dataPromiseBlobsEngineApiGetBlobsErroredNull.inc(versionedHashes.length); + return versionedHashes.map((_vh) => null); + }); + + for (let j = 0; j < versionedHashes.length; j++) { + const blobAndProof = blobAndProofs[j] ?? null; + // save to cache for future reference + engineGetBlobsCache?.set(toHexString(versionedHashes[j]), blobAndProof); + if (blobAndProof !== null) { + metrics?.blockInputFetchStats.dataPromiseBlobsEngineGetBlobsApiNotNull.inc(); + + // if we already got it by now, save the compute + if (blobsCache.has(engineReqIdentifiers[j].index) === false) { + metrics?.blockInputFetchStats.dataPromiseBlobsEngineApiGetBlobsUseful.inc(); + getBlobsUseful = true; + const {blob, proof: kzgProof} = blobAndProof; + const {kzgCommitment, index} = engineReqIdentifiers[j]; + const kzgCommitmentInclusionProof = computeInclusionProof(fork, block.message.body, index); + const blobSidecar = {index, blob, kzgCommitment, kzgProof, signedBlockHeader, kzgCommitmentInclusionProof}; + // add them in cache so that its reflected in all the blockInputs that carry this + // for e.g. a blockInput that might be awaiting blobs promise fullfillment in + // verifyBlocksDataAvailability + blobsCache.set(blobSidecar.index, {blobSidecar, blobBytes: null}); + } else { + metrics?.blockInputFetchStats.dataPromiseBlobsDelayedGossipAvailable.inc(); + metrics?.blockInputFetchStats.dataPromiseBlobsDeplayedGossipAvailableSavedGetBlobsCompute.inc(); + } + } + // may be blobsidecar arrived in the timespan of making the request + else { + metrics?.blockInputFetchStats.dataPromiseBlobsEngineGetBlobsApiNull.inc(); + if (blobsCache.has(engineReqIdentifiers[j].index) === false) { + const {blockRoot, index} = engineReqIdentifiers[j]; + networkReqIdentifiers.push({blockRoot, index}); + } else { + metrics?.blockInputFetchStats.dataPromiseBlobsDelayedGossipAvailable.inc(); + } + } + } + + if (engineGetBlobsCache !== undefined) { + // prune out engineGetBlobsCache + let pruneLength = Math.max(0, engineGetBlobsCache?.size - MAX_ENGINE_GETBLOBS_CACHE); + for (const key of engineGetBlobsCache.keys()) { + if (pruneLength <= 0) break; + engineGetBlobsCache.delete(key); + pruneLength--; + metrics?.blockInputFetchStats.getBlobsCachePruned.inc(); + } + metrics?.blockInputFetchStats.getBlobsCacheSize.set(engineGetBlobsCache.size); + } + if (blockInputsRetryTrackerCache !== undefined) { + // prune out engineGetBlobsCache + let pruneLength = Math.max(0, blockInputsRetryTrackerCache?.size - MAX_UNAVAILABLE_RETRY_CACHE); + for (const key of blockInputsRetryTrackerCache.keys()) { + if (pruneLength <= 0) break; + blockInputsRetryTrackerCache.delete(key); + pruneLength--; + metrics?.blockInputFetchStats.dataPromiseBlockInputRetryTrackerCachePruned.inc(); + } + metrics?.blockInputFetchStats.dataPromiseBlockInputRetryTrackerCacheSize.set(blockInputsRetryTrackerCache.size); + } + + // if clients expect sorted identifiers + networkReqIdentifiers.sort((a, b) => a.index - b.index); + let networkResBlobSidecars: deneb.BlobSidecar[]; + metrics?.blockInputFetchStats.dataPromiseBlobsFinallyQueriedFromNetwork.inc(networkReqIdentifiers.length); + if (blockTriedBefore) { + metrics?.blockInputFetchStats.dataPromiseBlobsRetriedFromNetwork.inc(networkReqIdentifiers.length); + } + + if (networkReqIdentifiers.length > 0) { + networkResBlobSidecars = await network.sendBlobSidecarsByRoot(peerId, networkReqIdentifiers); + metrics?.blockInputFetchStats.dataPromiseBlobsFinallyAvailableFromNetwork.inc(networkResBlobSidecars.length); + if (blockTriedBefore) { + metrics?.blockInputFetchStats.dataPromiseBlobsRetriedAvailableFromNetwork.inc(networkResBlobSidecars.length); + } } else { - allBlobSidecars = []; + networkResBlobSidecars = []; } // add them in cache so that its reflected in all the blockInputs that carry this // for e.g. a blockInput that might be awaiting blobs promise fullfillment in // verifyBlocksDataAvailability - for (const blobSidecar of allBlobSidecars) { + for (const blobSidecar of networkResBlobSidecars) { blobsCache.set(blobSidecar.index, {blobSidecar, blobBytes: null}); } @@ -114,5 +254,14 @@ export async function unavailableBeaconBlobsByRoot( const blockData = {fork: cachedData.fork, ...allBlobs, blobsSource: BlobsSource.byRoot} as BlockInputDataBlobs; resolveAvailability(blockData); metrics?.syncUnknownBlock.resolveAvailabilitySource.inc({source: BlockInputAvailabilitySource.UNKNOWN_SYNC}); + + metrics?.blockInputFetchStats.totalDataAvailableBlockInputs.inc(); + if (getBlobsUseful) { + metrics?.blockInputFetchStats.totalDataPromiseBlockInputsAvailableUsingGetBlobs.inc(); + } + if (blockTriedBefore) { + metrics?.blockInputFetchStats.totalDataPromiseBlockInputsRetriedAvailableFromNetwork.inc(); + } + return getBlockInput.availableData(config, block, BlockSource.byRoot, blockBytes, blockData); } diff --git a/packages/beacon-node/src/sync/unknownBlock.ts b/packages/beacon-node/src/sync/unknownBlock.ts index c9652dc6ecd2..f1fa44750f4b 100644 --- a/packages/beacon-node/src/sync/unknownBlock.ts +++ b/packages/beacon-node/src/sync/unknownBlock.ts @@ -1,6 +1,7 @@ import {ChainForkConfig} from "@lodestar/config"; import {INTERVALS_PER_SLOT} from "@lodestar/params"; import {Root, RootHex, deneb} from "@lodestar/types"; +import {BlobAndProof} from "@lodestar/types/deneb"; import {Logger, fromHex, pruneSetToMax, toRootHex} from "@lodestar/utils"; import {sleep} from "@lodestar/utils"; import {BlockInput, BlockInputType, NullBlockInput} from "../chain/blocks/types.js"; @@ -34,6 +35,9 @@ export class UnknownBlockSync { private readonly maxPendingBlocks; private subscribedToNetworkEvents = false; + private engineGetBlobsCache = new Map(); + private blockInputsRetryTrackerCache = new Set(); + constructor( private readonly config: ChainForkConfig, private readonly network: INetwork, @@ -532,13 +536,12 @@ export class UnknownBlockSync { for (let i = 0; i < MAX_ATTEMPTS_PER_BLOCK; i++) { const peer = shuffledPeers[i % shuffledPeers.length]; try { - const blockInput = await unavailableBeaconBlobsByRoot( - this.config, - this.network, - peer, - unavailableBlockInput, - this.metrics - ); + const blockInput = await unavailableBeaconBlobsByRoot(this.config, this.network, peer, unavailableBlockInput, { + metrics: this.metrics, + executionEngine: this.chain.executionEngine, + engineGetBlobsCache: this.engineGetBlobsCache, + blockInputsRetryTrackerCache: this.blockInputsRetryTrackerCache, + }); // Peer does not have the block, try with next peer if (blockInput === undefined) { diff --git a/packages/beacon-node/test/unit/network/unavailableBeaconBlobsByRoot.test.ts b/packages/beacon-node/test/unit/network/unavailableBeaconBlobsByRoot.test.ts new file mode 100644 index 000000000000..b222b2ac38d8 --- /dev/null +++ b/packages/beacon-node/test/unit/network/unavailableBeaconBlobsByRoot.test.ts @@ -0,0 +1,257 @@ +import {toHexString} from "@chainsafe/ssz"; +import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; +import {BYTES_PER_FIELD_ELEMENT, FIELD_ELEMENTS_PER_BLOB, ForkBlobs, ForkName, isForkBlobs} from "@lodestar/params"; +import {signedBlockToSignedHeader} from "@lodestar/state-transition"; +import {SignedBeaconBlock, deneb, ssz} from "@lodestar/types"; +import {beforeAll, describe, expect, it, vi} from "vitest"; +import { + BlobsSource, + BlockInput, + BlockInputDataBlobs, + BlockInputType, + BlockSource, + CachedData, + getBlockInput, +} from "../../../src/chain/blocks/types.js"; +import {IExecutionEngine} from "../../../src/execution/index.js"; +import {INetwork} from "../../../src/network/interface.js"; +import {unavailableBeaconBlobsByRoot} from "../../../src/network/reqresp/index.js"; +import {computeInclusionProof, kzgCommitmentToVersionedHash} from "../../../src/util/blobs.js"; +import {ckzg} from "../../../src/util/kzg.js"; +import {initCKZG, loadEthereumTrustedSetup} from "../../../src/util/kzg.js"; + +describe("unavailableBeaconBlobsByRoot", () => { + beforeAll(async () => { + await initCKZG(); + loadEthereumTrustedSetup(); + }); + + /* eslint-disable @typescript-eslint/naming-convention */ + const chainConfig = createChainForkConfig({ + ...defaultChainConfig, + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + }); + const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); + const config = createBeaconConfig(chainConfig, genesisValidatorsRoot); + + const executionEngine = { + getBlobs: vi.fn(), + }; + + const network = { + sendBeaconBlocksByRoot: vi.fn(), + sendBlobSidecarsByRoot: vi.fn(), + }; + + const peerId = "mockPeerId"; + const engineGetBlobsCache = new Map(); + + it("should successfully resolve all blobs from engine and network", async () => { + // Simulate a block 1 with 5 blobs + const signedBlock = ssz.deneb.SignedBeaconBlock.defaultValue(); + signedBlock.message.slot = 1; + const blobscommitmentsandproofs = generateBlobs(5); + signedBlock.message.body.blobKzgCommitments.push(...blobscommitmentsandproofs.kzgCommitments); + const blockheader = signedBlockToSignedHeader(config, signedBlock); + + const unavailableBlockInput = { + block: signedBlock, + source: BlockSource.gossip, + blockBytes: null, + type: BlockInputType.dataPromise, + cachedData: getEmptyBlockInputCacheEntry(ForkName.deneb).cachedData, + } as BlockInput; + + // total of 5 blobs + // blob 0. not in cache & to resolved by getBlobs + // blob 1. not in cache & to resolved by getBlobs + // blob 2. to be found in engineGetBlobsCache + // blob 3. null cached earlier so should directly go to network query and skip engine query + // blob 4. to hit getBlobs first with null response and then go to the network query + // + // engineGetBlobsCache caches 2 fully, and null for 3 + // getBlobs should see 0,1,4 and return first two non null and last null + // network should see 3,4 + + engineGetBlobsCache.set(toHexString(blobscommitmentsandproofs.blobVersionedHashes[2]), { + blob: blobscommitmentsandproofs.blobs[2], + proof: blobscommitmentsandproofs.kzgProofs[2], + }); + engineGetBlobsCache.set(toHexString(blobscommitmentsandproofs.blobVersionedHashes[3]), null); + + // Mock execution engine to return 2 blobs + executionEngine.getBlobs.mockResolvedValueOnce([ + { + blob: blobscommitmentsandproofs.blobs[0], + proof: blobscommitmentsandproofs.kzgProofs[0], + }, + { + blob: blobscommitmentsandproofs.blobs[1], + proof: blobscommitmentsandproofs.kzgProofs[1], + }, + null, + ]); + + // Mock network to return 2 blobs + network.sendBlobSidecarsByRoot.mockResolvedValueOnce([ + { + index: 3, + blob: blobscommitmentsandproofs.blobs[3], + kzgCommitment: blobscommitmentsandproofs.kzgCommitments[3], + kzgProof: blobscommitmentsandproofs.kzgProofs[3], + signedBlockHeader: blockheader, + kzgCommitmentInclusionProof: computeInclusionProof(ForkName.deneb, signedBlock.message.body, 3), + }, + { + index: 4, + blob: blobscommitmentsandproofs.blobs[4], + kzgCommitment: blobscommitmentsandproofs.kzgCommitments[4], + kzgProof: blobscommitmentsandproofs.kzgProofs[4], + signedBlockHeader: blockheader, + kzgCommitmentInclusionProof: computeInclusionProof(ForkName.deneb, signedBlock.message.body, 4), + }, + ]); + + const result = await unavailableBeaconBlobsByRoot( + config, + network as unknown as INetwork, + peerId, + unavailableBlockInput, + { + executionEngine: executionEngine as unknown as IExecutionEngine, + metrics: null, + engineGetBlobsCache, + } + ); + + // Check if all blobs are aggregated + const allBlobs = [ + { + index: 0, + blob: blobscommitmentsandproofs.blobs[0], + kzgCommitment: blobscommitmentsandproofs.kzgCommitments[0], + kzgProof: blobscommitmentsandproofs.kzgProofs[0], + signedBlockHeader: blockheader, + kzgCommitmentInclusionProof: computeInclusionProof(ForkName.deneb, signedBlock.message.body, 0), + }, + { + index: 1, + blob: blobscommitmentsandproofs.blobs[1], + kzgCommitment: blobscommitmentsandproofs.kzgCommitments[1], + kzgProof: blobscommitmentsandproofs.kzgProofs[1], + signedBlockHeader: blockheader, + kzgCommitmentInclusionProof: computeInclusionProof(ForkName.deneb, signedBlock.message.body, 1), + }, + { + index: 2, + blob: blobscommitmentsandproofs.blobs[2], + kzgCommitment: blobscommitmentsandproofs.kzgCommitments[2], + kzgProof: blobscommitmentsandproofs.kzgProofs[2], + signedBlockHeader: blockheader, + kzgCommitmentInclusionProof: computeInclusionProof(ForkName.deneb, signedBlock.message.body, 2), + }, + { + index: 3, + blob: blobscommitmentsandproofs.blobs[3], + kzgCommitment: blobscommitmentsandproofs.kzgCommitments[3], + kzgProof: blobscommitmentsandproofs.kzgProofs[3], + signedBlockHeader: blockheader, + kzgCommitmentInclusionProof: computeInclusionProof(ForkName.deneb, signedBlock.message.body, 3), + }, + { + index: 4, + blob: blobscommitmentsandproofs.blobs[4], + kzgCommitment: blobscommitmentsandproofs.kzgCommitments[4], + kzgProof: blobscommitmentsandproofs.kzgProofs[4], + signedBlockHeader: blockheader, + kzgCommitmentInclusionProof: computeInclusionProof(ForkName.deneb, signedBlock.message.body, 4), + }, + ]; + + const blockData = { + fork: ForkName.deneb as ForkBlobs, + blobs: allBlobs, + blobsBytes: [null, null, null, null, null], + blobsSource: BlobsSource.byRoot, + }; + const resolvedBlobs = getBlockInput.availableData(config, signedBlock, BlockSource.byRoot, null, blockData); + + const engineReqIdentifiers = [...blobscommitmentsandproofs.blobVersionedHashes]; + // versionedHashes: 1,2,4 + engineReqIdentifiers.splice(2, 2); + expect(result).toBeDefined(); + expect(executionEngine.getBlobs).toHaveBeenCalledWith("deneb", engineReqIdentifiers); + expect(result).toEqual(resolvedBlobs); + }); +}); + +type BlockInputCacheType = { + fork: ForkName; + block?: SignedBeaconBlock; + blockBytes?: Uint8Array | null; + cachedData?: CachedData; + // block promise and its callback cached for delayed resolution + blockInputPromise: Promise; + resolveBlockInput: (blockInput: BlockInput) => void; +}; + +function getEmptyBlockInputCacheEntry(fork: ForkName): BlockInputCacheType { + // Capture both the promise and its callbacks for blockInput and final availability + // It is not spec'ed but in tests in Firefox and NodeJS the promise constructor is run immediately + let resolveBlockInput: ((block: BlockInput) => void) | null = null; + const blockInputPromise = new Promise((resolveCB) => { + resolveBlockInput = resolveCB; + }); + if (resolveBlockInput === null) { + throw Error("Promise Constructor was not executed immediately"); + } + if (!isForkBlobs(fork)) { + return {fork, blockInputPromise, resolveBlockInput}; + } + + let resolveAvailability: ((blobs: BlockInputDataBlobs) => void) | null = null; + const availabilityPromise = new Promise((resolveCB) => { + resolveAvailability = resolveCB; + }); + + if (resolveAvailability === null) { + throw Error("Promise Constructor was not executed immediately"); + } + + const blobsCache = new Map(); + const cachedData: CachedData = {fork, blobsCache, availabilityPromise, resolveAvailability}; + return {fork, blockInputPromise, resolveBlockInput, cachedData}; +} + +function generateBlobs(count: number): { + blobs: Uint8Array[]; + kzgCommitments: Uint8Array[]; + blobVersionedHashes: Uint8Array[]; + kzgProofs: Uint8Array[]; +} { + const blobs = Array.from({length: count}, (_, index) => generateRandomBlob(index)); + const kzgCommitments = blobs.map((blob) => ckzg.blobToKzgCommitment(blob)); + const versionedHash = kzgCommitments.map((kzgCommitment) => kzgCommitmentToVersionedHash(kzgCommitment)); + const kzgProofs = blobs.map((blob, index) => ckzg.computeBlobKzgProof(blob, kzgCommitments[index])); + + return { + blobs, + kzgCommitments, + blobVersionedHashes: versionedHash.map((hash) => hash), + kzgProofs, + }; +} + +function generateRandomBlob(index: number): deneb.Blob { + const blob = new Uint8Array(FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT); + const dv = new DataView(blob.buffer, blob.byteOffset, blob.byteLength); + + for (let i = 0; i < FIELD_ELEMENTS_PER_BLOB; i++) { + // Generate a unique value based on the index + dv.setUint32(i * BYTES_PER_FIELD_ELEMENT, index + i); + } + return blob; +} diff --git a/packages/types/src/deneb/types.ts b/packages/types/src/deneb/types.ts index 7ee6648aeaf2..1bbabd0e4285 100644 --- a/packages/types/src/deneb/types.ts +++ b/packages/types/src/deneb/types.ts @@ -51,3 +51,7 @@ export type ProducedBlobSidecars = Omit; export type SignedBlockContents = ValueOf; export type Contents = Omit; +export type BlobAndProof = { + blob: Blob; + proof: KZGProof; +}; From e2c45b9ca597fa1d2d8101a0c7da725b810acf97 Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Thu, 7 Nov 2024 12:25:24 +0800 Subject: [PATCH 192/259] chore: revert async aggregate with randomness (#7218) Revert "feat: asyncAggregateWithRandomness (#7204)" This reverts commit e31d535bb59d209827cbab61cb4381dccac90171. --- packages/beacon-node/package.json | 2 +- .../src/chain/bls/multithread/index.ts | 2 +- .../src/chain/bls/multithread/jobItem.ts | 18 +++-- .../src/metrics/metrics/lodestar.ts | 5 ++ packages/cli/package.json | 2 +- packages/flare/package.json | 2 +- packages/state-transition/package.json | 2 +- packages/test-utils/package.json | 2 +- packages/validator/package.json | 2 +- yarn.lock | 78 +++++++++---------- 10 files changed, 64 insertions(+), 51 deletions(-) diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 450c6e119023..fcaf5b715216 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -95,7 +95,7 @@ }, "dependencies": { "@chainsafe/as-sha256": "^0.5.0", - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@chainsafe/discv5": "^9.0.0", "@chainsafe/enr": "^3.0.0", "@chainsafe/libp2p-gossipsub": "^13.0.0", diff --git a/packages/beacon-node/src/chain/bls/multithread/index.ts b/packages/beacon-node/src/chain/bls/multithread/index.ts index 4b1867c3793f..74e2dbbca4f7 100644 --- a/packages/beacon-node/src/chain/bls/multithread/index.ts +++ b/packages/beacon-node/src/chain/bls/multithread/index.ts @@ -394,7 +394,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier { try { // Note: This can throw, must be handled per-job. // Pubkey and signature aggregation is defered here - workReq = await jobItemWorkReq(job, this.metrics); + workReq = jobItemWorkReq(job, this.metrics); } catch (e) { this.metrics?.blsThreadPool.errorAggregateSignatureSetsCount.inc({type: job.type}); diff --git a/packages/beacon-node/src/chain/bls/multithread/jobItem.ts b/packages/beacon-node/src/chain/bls/multithread/jobItem.ts index efaaf36fd88f..9f0c74fbcf32 100644 --- a/packages/beacon-node/src/chain/bls/multithread/jobItem.ts +++ b/packages/beacon-node/src/chain/bls/multithread/jobItem.ts @@ -1,4 +1,4 @@ -import {PublicKey, asyncAggregateWithRandomness} from "@chainsafe/blst"; +import {PublicKey, aggregateWithRandomness} from "@chainsafe/blst"; import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition"; import {Metrics} from "../../../metrics/metrics.js"; import {LinkedList} from "../../../util/array.js"; @@ -48,7 +48,7 @@ export function jobItemSigSets(job: JobQueueItem): number { * Prepare BlsWorkReq from JobQueueItem * WARNING: May throw with untrusted user input */ -export async function jobItemWorkReq(job: JobQueueItem, metrics: Metrics | null): Promise { +export function jobItemWorkReq(job: JobQueueItem, metrics: Metrics | null): BlsWorkReq { switch (job.type) { case JobQueueItemType.default: return { @@ -61,9 +61,17 @@ export async function jobItemWorkReq(job: JobQueueItem, metrics: Metrics | null) })), }; case JobQueueItemType.sameMessage: { - const {pk, sig} = await asyncAggregateWithRandomness( - job.sets.map((set) => ({pk: set.publicKey, sig: set.signature})) - ); + // This is slow code on main thread (mainly signature deserialization + group check). + // Ideally it can be taken off-thread, but in the mean time, keep track of total time spent here. + // As of July 2024, for a node subscribing to all subnets, with 1 signature per validator per epoch, + // it takes around 2.02 min to perform this operation for a single epoch. + // cpu profile on main thread has 250s idle so this only works until we reach 3M validators + // However, for normal node with only 2 to 7 subnet subscriptions per epoch this works until 27M validators + // and not a problem in the near future + // this is monitored on v1.21.0 https://github.com/ChainSafe/lodestar/pull/6894/files#r1687359225 + const timer = metrics?.blsThreadPool.aggregateWithRandomnessMainThreadDuration.startTimer(); + const {pk, sig} = aggregateWithRandomness(job.sets.map((set) => ({pk: set.publicKey, sig: set.signature}))); + timer?.(); return { opts: job.opts, diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index c138a8dfe26a..af8d87daa246 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -497,6 +497,11 @@ export function createLodestarMetrics( name: "lodestar_bls_thread_pool_batchable_sig_sets_total", help: "Count of total batchable signature sets", }), + aggregateWithRandomnessMainThreadDuration: register.histogram({ + name: "lodestar_bls_thread_pool_aggregate_with_randomness_main_thread_time_seconds", + help: "Total time performing aggregateWithRandomness on main thread", + buckets: [0.001, 0.005, 0.01, 0.1], + }), pubkeysAggregationMainThreadDuration: register.histogram({ name: "lodestar_bls_thread_pool_pubkeys_aggregation_main_thread_time_seconds", help: "Total time spent aggregating pubkeys on main thread", diff --git a/packages/cli/package.json b/packages/cli/package.json index 40a58a43c754..3634ccd84424 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -53,7 +53,7 @@ "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", "@chainsafe/bls-keystore": "^3.1.0", - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@chainsafe/discv5": "^9.0.0", "@chainsafe/enr": "^3.0.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", diff --git a/packages/flare/package.json b/packages/flare/package.json index 0c073c431f38..f8bd37f5abb5 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -59,7 +59,7 @@ ], "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@lodestar/api": "^1.22.0", "@lodestar/config": "^1.22.0", "@lodestar/params": "^1.22.0", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index a836d742eb8e..80a6cf45c28f 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -59,7 +59,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/as-sha256": "^0.5.0", - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/persistent-ts": "^0.19.1", "@chainsafe/ssz": "^0.18.0", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index dbb15817cd2a..1b18c3b5a33e 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -58,7 +58,7 @@ ], "dependencies": { "@chainsafe/bls-keystore": "^3.1.0", - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@lodestar/params": "^1.22.0", "@lodestar/utils": "^1.22.0", "axios": "^1.3.4", diff --git a/packages/validator/package.json b/packages/validator/package.json index 7cd6f06a626b..a781d62b0111 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -45,7 +45,7 @@ "blockchain" ], "dependencies": { - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@chainsafe/ssz": "^0.18.0", "@lodestar/api": "^1.22.0", "@lodestar/config": "^1.22.0", diff --git a/yarn.lock b/yarn.lock index 846335c80676..a9cb9ebe4fdc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -399,40 +399,40 @@ "@chainsafe/bls-keygen" "^0.4.0" bls-eth-wasm "^0.4.8" -"@chainsafe/blst-darwin-arm64@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-arm64/-/blst-darwin-arm64-2.2.0.tgz#0ab9083805c308106c2f2107df1e6376d9190b1b" - integrity sha512-BOOy2KHbV028cioPWaAMqHdLRKd6/3XyEmUEcQC2E/SpyYLdNcaKiBUYIU4pT9CrWBbJJxX68UI+3vZVg0M8/w== +"@chainsafe/blst-darwin-arm64@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-arm64/-/blst-darwin-arm64-2.1.0.tgz#8871d62dc0402df30adbd6f52fbbd02d59f3c5ff" + integrity sha512-7iPRlSbQxEZ2AblmkFLuhnVPUipvA0UenEaUCaLC1MhGFpSwy5bSrF8Krs/E++GN3p2LVz7ZH3tlDfFL0z1EvQ== -"@chainsafe/blst-darwin-x64@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-x64/-/blst-darwin-x64-2.2.0.tgz#231943a7736f3f89d35e03fec890b7809c98ff1a" - integrity sha512-jG64cwIdPT7u/haRrW26tWCpfMfHBQCfGY169mFQifCwO4VEwvaiVBPOh5olFis6LjpcmD+O0jpM8GqrnsmUHQ== +"@chainsafe/blst-darwin-x64@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-x64/-/blst-darwin-x64-2.1.0.tgz#8fe58d92b72b1b872f8b687a0aad8beda3e09072" + integrity sha512-aeoidOpOYVmRFeHVm1p/Axd6CfqWpr6SIift216/HTDBTiuJCGSJqHzk9RHf7gzkr6WtxO7g/6AtkagZA2VPFg== -"@chainsafe/blst-linux-arm64-gnu@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-gnu/-/blst-linux-arm64-gnu-2.2.0.tgz#721aeec63e8e02aba3358a0084c095403a5438fa" - integrity sha512-L8xV2uuLn8we76vdzfryS9ePdheuZrmY6yArGUFaF1Uzcwml6V1/VvyPl9/uooo/YfVRIrvF/D+lQfI2GFAnhw== +"@chainsafe/blst-linux-arm64-gnu@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-gnu/-/blst-linux-arm64-gnu-2.1.0.tgz#323789a10679cf81813b1e664ef4187a2e941cff" + integrity sha512-d2zgqoJOqkWg2sZbNR7pv8f+oYPOJmnMu46Uulm6NkW3iYNZIc2KkVjBXGYk7xJ+U8ZEzb7KZ7gRB9315sWBcg== -"@chainsafe/blst-linux-arm64-musl@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-musl/-/blst-linux-arm64-musl-2.2.0.tgz#dbbabaab93156548c86e2b2b3a1d27160b715000" - integrity sha512-0Vn0luxLYVgC3lvWT1MapFHSAoz99PldqjhilXTGv0AcAk/X5LXPH2RC9Dp2KJGqthyUkpbk1j47jUBfBI+BIg== +"@chainsafe/blst-linux-arm64-musl@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-musl/-/blst-linux-arm64-musl-2.1.0.tgz#4a308d6b1f71a57a6ecc6cc0531746f5cd8ae3d0" + integrity sha512-w+KiL8ViLXigZVS++tdCwnMBnbc4HXb8claKOnlCppE1rAeF0Dt186AU2TRpqOop3QoOqckqvsguR9iQwZlTUw== -"@chainsafe/blst-linux-x64-gnu@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-gnu/-/blst-linux-x64-gnu-2.2.0.tgz#9f8ab825621b75227c75bb75d369d3d42e91fa74" - integrity sha512-gEY/z2SDBA7kXtFEI9VNhWTJAIjx16jdeAyCaS2k4ACGurWZaWk+Ee4KniTsr4WieSqeuNTUr7Pdja0Sr4EKNQ== +"@chainsafe/blst-linux-x64-gnu@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-gnu/-/blst-linux-x64-gnu-2.1.0.tgz#c015f9f25aab10bba7720518ba9dc19bb850dcc3" + integrity sha512-2xdOIkkJTvi+/gUoiPQO+p+2o19pixLsH5BOrwxY+EABLL6wxZ82w5LatV3x27YJTk7PbAlyT36n7CjmzaZ/tw== -"@chainsafe/blst-linux-x64-musl@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-musl/-/blst-linux-x64-musl-2.2.0.tgz#11e99ac12b0f83cad68da56f4e9cfc4aa403a2e6" - integrity sha512-58GKtiUmtVSuerRzPEcMNQZpICPboBKFnL7+1Wo+PSuajkvbae7tEFrFTtWeMoKIPgOEsPMnk96LF+0yNgavUg== +"@chainsafe/blst-linux-x64-musl@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-musl/-/blst-linux-x64-musl-2.1.0.tgz#da4ac690cc3b59bc21c4578d30502490c044f7fb" + integrity sha512-/ddO38KkTTgTmXBLAubU1fjUWcQy90sdUi0IoRm5RprdpXvTSGZ1m8XrcxwEYkUO+KpnacOuU0UDwerHMJl4DA== -"@chainsafe/blst-win32-x64-msvc@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-win32-x64-msvc/-/blst-win32-x64-msvc-2.2.0.tgz#f32b164721ff5edc279f6d6cd0fffde0ad2fe16c" - integrity sha512-UFrZshl4dfX5Uh2zeKXAZtrkQ+otczHMON2tsrapQNICWmfHZrzE6pKuBL+9QeGAbgflwpbz7+D5nQRDpiuHxQ== +"@chainsafe/blst-win32-x64-msvc@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-win32-x64-msvc/-/blst-win32-x64-msvc-2.1.0.tgz#edaff899194caa4e40901af90779721673671631" + integrity sha512-wSRVGoLrluus38fmYYS0ft3VSG2EaeeWvb7yxvrAS8xUsaRFRClYo/3kaEHR3D9B9Nu5wiuWfob6DoM3w9deLw== "@chainsafe/blst@^0.2.0": version "0.2.11" @@ -443,18 +443,18 @@ node-fetch "^2.6.1" node-gyp "^8.4.0" -"@chainsafe/blst@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-2.2.0.tgz#ced8b861b94934e3c1c53e173c3e1205d775d93b" - integrity sha512-VBaQoNE2a9d9+skAjQKv3Suk0yGKqp3mZM0YWYJNPj/Ae/f6lAyeVSgKqo2LrsNQBzD/LqrJLKUY8rJT3vDKLA== +"@chainsafe/blst@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-2.1.0.tgz#1df4fa8e390db5c3cceed673b57468e23b4da36f" + integrity sha512-oY5k4whglgVOkisfujO0s1QgCOp3N/J3GogRbHhuNLrf6KN0zs1C3pKHg66EQhQqWVYnFY2Shx2s71/NFD7y+A== optionalDependencies: - "@chainsafe/blst-darwin-arm64" "2.2.0" - "@chainsafe/blst-darwin-x64" "2.2.0" - "@chainsafe/blst-linux-arm64-gnu" "2.2.0" - "@chainsafe/blst-linux-arm64-musl" "2.2.0" - "@chainsafe/blst-linux-x64-gnu" "2.2.0" - "@chainsafe/blst-linux-x64-musl" "2.2.0" - "@chainsafe/blst-win32-x64-msvc" "2.2.0" + "@chainsafe/blst-darwin-arm64" "2.1.0" + "@chainsafe/blst-darwin-x64" "2.1.0" + "@chainsafe/blst-linux-arm64-gnu" "2.1.0" + "@chainsafe/blst-linux-arm64-musl" "2.1.0" + "@chainsafe/blst-linux-x64-gnu" "2.1.0" + "@chainsafe/blst-linux-x64-musl" "2.1.0" + "@chainsafe/blst-win32-x64-msvc" "2.1.0" "@chainsafe/discv5@^9.0.0": version "9.0.0" From a00dbf0dc5bf95b312b8913d3f6564eefa90d081 Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Thu, 7 Nov 2024 12:25:24 +0800 Subject: [PATCH 193/259] chore: revert async aggregate with randomness (#7218) Revert "feat: asyncAggregateWithRandomness (#7204)" This reverts commit e31d535bb59d209827cbab61cb4381dccac90171. --- packages/beacon-node/package.json | 2 +- .../src/chain/bls/multithread/index.ts | 2 +- .../src/chain/bls/multithread/jobItem.ts | 18 +++-- .../src/metrics/metrics/lodestar.ts | 5 ++ packages/cli/package.json | 2 +- packages/flare/package.json | 2 +- packages/state-transition/package.json | 2 +- packages/test-utils/package.json | 2 +- packages/validator/package.json | 2 +- yarn.lock | 78 +++++++++---------- 10 files changed, 64 insertions(+), 51 deletions(-) diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 7e400b69ad3f..87d80d27039c 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -95,7 +95,7 @@ }, "dependencies": { "@chainsafe/as-sha256": "^0.5.0", - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@chainsafe/discv5": "^9.0.0", "@chainsafe/enr": "^3.0.0", "@chainsafe/libp2p-gossipsub": "^13.0.0", diff --git a/packages/beacon-node/src/chain/bls/multithread/index.ts b/packages/beacon-node/src/chain/bls/multithread/index.ts index fc8ea7534ad7..cb18ca86e42f 100644 --- a/packages/beacon-node/src/chain/bls/multithread/index.ts +++ b/packages/beacon-node/src/chain/bls/multithread/index.ts @@ -394,7 +394,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier { try { // Note: This can throw, must be handled per-job. // Pubkey and signature aggregation is defered here - workReq = await jobItemWorkReq(job, this.metrics); + workReq = jobItemWorkReq(job, this.metrics); } catch (e) { this.metrics?.blsThreadPool.errorAggregateSignatureSetsCount.inc({type: job.type}); diff --git a/packages/beacon-node/src/chain/bls/multithread/jobItem.ts b/packages/beacon-node/src/chain/bls/multithread/jobItem.ts index 63591af5ee77..035d56e56df2 100644 --- a/packages/beacon-node/src/chain/bls/multithread/jobItem.ts +++ b/packages/beacon-node/src/chain/bls/multithread/jobItem.ts @@ -1,4 +1,4 @@ -import {PublicKey, asyncAggregateWithRandomness} from "@chainsafe/blst"; +import {PublicKey, aggregateWithRandomness} from "@chainsafe/blst"; import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition"; import {VerifySignatureOpts} from "../interface.js"; import {getAggregatedPubkey} from "../utils.js"; @@ -48,7 +48,7 @@ export function jobItemSigSets(job: JobQueueItem): number { * Prepare BlsWorkReq from JobQueueItem * WARNING: May throw with untrusted user input */ -export async function jobItemWorkReq(job: JobQueueItem, metrics: Metrics | null): Promise { +export function jobItemWorkReq(job: JobQueueItem, metrics: Metrics | null): BlsWorkReq { switch (job.type) { case JobQueueItemType.default: return { @@ -61,9 +61,17 @@ export async function jobItemWorkReq(job: JobQueueItem, metrics: Metrics | null) })), }; case JobQueueItemType.sameMessage: { - const {pk, sig} = await asyncAggregateWithRandomness( - job.sets.map((set) => ({pk: set.publicKey, sig: set.signature})) - ); + // This is slow code on main thread (mainly signature deserialization + group check). + // Ideally it can be taken off-thread, but in the mean time, keep track of total time spent here. + // As of July 2024, for a node subscribing to all subnets, with 1 signature per validator per epoch, + // it takes around 2.02 min to perform this operation for a single epoch. + // cpu profile on main thread has 250s idle so this only works until we reach 3M validators + // However, for normal node with only 2 to 7 subnet subscriptions per epoch this works until 27M validators + // and not a problem in the near future + // this is monitored on v1.21.0 https://github.com/ChainSafe/lodestar/pull/6894/files#r1687359225 + const timer = metrics?.blsThreadPool.aggregateWithRandomnessMainThreadDuration.startTimer(); + const {pk, sig} = aggregateWithRandomness(job.sets.map((set) => ({pk: set.publicKey, sig: set.signature}))); + timer?.(); return { opts: job.opts, diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index ac2cca319775..f15e195faa20 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -497,6 +497,11 @@ export function createLodestarMetrics( name: "lodestar_bls_thread_pool_batchable_sig_sets_total", help: "Count of total batchable signature sets", }), + aggregateWithRandomnessMainThreadDuration: register.histogram({ + name: "lodestar_bls_thread_pool_aggregate_with_randomness_main_thread_time_seconds", + help: "Total time performing aggregateWithRandomness on main thread", + buckets: [0.001, 0.005, 0.01, 0.1], + }), pubkeysAggregationMainThreadDuration: register.histogram({ name: "lodestar_bls_thread_pool_pubkeys_aggregation_main_thread_time_seconds", help: "Total time spent aggregating pubkeys on main thread", diff --git a/packages/cli/package.json b/packages/cli/package.json index 6f44a6c2926e..287300183a7f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -53,7 +53,7 @@ "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", "@chainsafe/bls-keystore": "^3.1.0", - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@chainsafe/discv5": "^9.0.0", "@chainsafe/enr": "^3.0.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", diff --git a/packages/flare/package.json b/packages/flare/package.json index 8239eec52e2a..1ec88f28ac4d 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -59,7 +59,7 @@ ], "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@lodestar/api": "^1.23.0", "@lodestar/config": "^1.23.0", "@lodestar/params": "^1.23.0", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 1c1d0f0c7754..5dfecfa9bbf6 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -59,7 +59,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/as-sha256": "^0.5.0", - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/persistent-ts": "^0.19.1", "@chainsafe/pubkey-index-map": "2.0.0", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index efc9c96ff5b1..c8fc5cd41c55 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -58,7 +58,7 @@ ], "dependencies": { "@chainsafe/bls-keystore": "^3.1.0", - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@lodestar/params": "^1.23.0", "@lodestar/utils": "^1.23.0", "axios": "^1.3.4", diff --git a/packages/validator/package.json b/packages/validator/package.json index 9cbb560965fd..1566c08668b9 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -45,7 +45,7 @@ "blockchain" ], "dependencies": { - "@chainsafe/blst": "^2.2.0", + "@chainsafe/blst": "^2.1.0", "@chainsafe/ssz": "^0.18.0", "@lodestar/api": "^1.23.0", "@lodestar/config": "^1.23.0", diff --git a/yarn.lock b/yarn.lock index 846335c80676..a9cb9ebe4fdc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -399,40 +399,40 @@ "@chainsafe/bls-keygen" "^0.4.0" bls-eth-wasm "^0.4.8" -"@chainsafe/blst-darwin-arm64@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-arm64/-/blst-darwin-arm64-2.2.0.tgz#0ab9083805c308106c2f2107df1e6376d9190b1b" - integrity sha512-BOOy2KHbV028cioPWaAMqHdLRKd6/3XyEmUEcQC2E/SpyYLdNcaKiBUYIU4pT9CrWBbJJxX68UI+3vZVg0M8/w== +"@chainsafe/blst-darwin-arm64@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-arm64/-/blst-darwin-arm64-2.1.0.tgz#8871d62dc0402df30adbd6f52fbbd02d59f3c5ff" + integrity sha512-7iPRlSbQxEZ2AblmkFLuhnVPUipvA0UenEaUCaLC1MhGFpSwy5bSrF8Krs/E++GN3p2LVz7ZH3tlDfFL0z1EvQ== -"@chainsafe/blst-darwin-x64@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-x64/-/blst-darwin-x64-2.2.0.tgz#231943a7736f3f89d35e03fec890b7809c98ff1a" - integrity sha512-jG64cwIdPT7u/haRrW26tWCpfMfHBQCfGY169mFQifCwO4VEwvaiVBPOh5olFis6LjpcmD+O0jpM8GqrnsmUHQ== +"@chainsafe/blst-darwin-x64@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-darwin-x64/-/blst-darwin-x64-2.1.0.tgz#8fe58d92b72b1b872f8b687a0aad8beda3e09072" + integrity sha512-aeoidOpOYVmRFeHVm1p/Axd6CfqWpr6SIift216/HTDBTiuJCGSJqHzk9RHf7gzkr6WtxO7g/6AtkagZA2VPFg== -"@chainsafe/blst-linux-arm64-gnu@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-gnu/-/blst-linux-arm64-gnu-2.2.0.tgz#721aeec63e8e02aba3358a0084c095403a5438fa" - integrity sha512-L8xV2uuLn8we76vdzfryS9ePdheuZrmY6yArGUFaF1Uzcwml6V1/VvyPl9/uooo/YfVRIrvF/D+lQfI2GFAnhw== +"@chainsafe/blst-linux-arm64-gnu@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-gnu/-/blst-linux-arm64-gnu-2.1.0.tgz#323789a10679cf81813b1e664ef4187a2e941cff" + integrity sha512-d2zgqoJOqkWg2sZbNR7pv8f+oYPOJmnMu46Uulm6NkW3iYNZIc2KkVjBXGYk7xJ+U8ZEzb7KZ7gRB9315sWBcg== -"@chainsafe/blst-linux-arm64-musl@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-musl/-/blst-linux-arm64-musl-2.2.0.tgz#dbbabaab93156548c86e2b2b3a1d27160b715000" - integrity sha512-0Vn0luxLYVgC3lvWT1MapFHSAoz99PldqjhilXTGv0AcAk/X5LXPH2RC9Dp2KJGqthyUkpbk1j47jUBfBI+BIg== +"@chainsafe/blst-linux-arm64-musl@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-arm64-musl/-/blst-linux-arm64-musl-2.1.0.tgz#4a308d6b1f71a57a6ecc6cc0531746f5cd8ae3d0" + integrity sha512-w+KiL8ViLXigZVS++tdCwnMBnbc4HXb8claKOnlCppE1rAeF0Dt186AU2TRpqOop3QoOqckqvsguR9iQwZlTUw== -"@chainsafe/blst-linux-x64-gnu@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-gnu/-/blst-linux-x64-gnu-2.2.0.tgz#9f8ab825621b75227c75bb75d369d3d42e91fa74" - integrity sha512-gEY/z2SDBA7kXtFEI9VNhWTJAIjx16jdeAyCaS2k4ACGurWZaWk+Ee4KniTsr4WieSqeuNTUr7Pdja0Sr4EKNQ== +"@chainsafe/blst-linux-x64-gnu@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-gnu/-/blst-linux-x64-gnu-2.1.0.tgz#c015f9f25aab10bba7720518ba9dc19bb850dcc3" + integrity sha512-2xdOIkkJTvi+/gUoiPQO+p+2o19pixLsH5BOrwxY+EABLL6wxZ82w5LatV3x27YJTk7PbAlyT36n7CjmzaZ/tw== -"@chainsafe/blst-linux-x64-musl@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-musl/-/blst-linux-x64-musl-2.2.0.tgz#11e99ac12b0f83cad68da56f4e9cfc4aa403a2e6" - integrity sha512-58GKtiUmtVSuerRzPEcMNQZpICPboBKFnL7+1Wo+PSuajkvbae7tEFrFTtWeMoKIPgOEsPMnk96LF+0yNgavUg== +"@chainsafe/blst-linux-x64-musl@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-linux-x64-musl/-/blst-linux-x64-musl-2.1.0.tgz#da4ac690cc3b59bc21c4578d30502490c044f7fb" + integrity sha512-/ddO38KkTTgTmXBLAubU1fjUWcQy90sdUi0IoRm5RprdpXvTSGZ1m8XrcxwEYkUO+KpnacOuU0UDwerHMJl4DA== -"@chainsafe/blst-win32-x64-msvc@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst-win32-x64-msvc/-/blst-win32-x64-msvc-2.2.0.tgz#f32b164721ff5edc279f6d6cd0fffde0ad2fe16c" - integrity sha512-UFrZshl4dfX5Uh2zeKXAZtrkQ+otczHMON2tsrapQNICWmfHZrzE6pKuBL+9QeGAbgflwpbz7+D5nQRDpiuHxQ== +"@chainsafe/blst-win32-x64-msvc@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst-win32-x64-msvc/-/blst-win32-x64-msvc-2.1.0.tgz#edaff899194caa4e40901af90779721673671631" + integrity sha512-wSRVGoLrluus38fmYYS0ft3VSG2EaeeWvb7yxvrAS8xUsaRFRClYo/3kaEHR3D9B9Nu5wiuWfob6DoM3w9deLw== "@chainsafe/blst@^0.2.0": version "0.2.11" @@ -443,18 +443,18 @@ node-fetch "^2.6.1" node-gyp "^8.4.0" -"@chainsafe/blst@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-2.2.0.tgz#ced8b861b94934e3c1c53e173c3e1205d775d93b" - integrity sha512-VBaQoNE2a9d9+skAjQKv3Suk0yGKqp3mZM0YWYJNPj/Ae/f6lAyeVSgKqo2LrsNQBzD/LqrJLKUY8rJT3vDKLA== +"@chainsafe/blst@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-2.1.0.tgz#1df4fa8e390db5c3cceed673b57468e23b4da36f" + integrity sha512-oY5k4whglgVOkisfujO0s1QgCOp3N/J3GogRbHhuNLrf6KN0zs1C3pKHg66EQhQqWVYnFY2Shx2s71/NFD7y+A== optionalDependencies: - "@chainsafe/blst-darwin-arm64" "2.2.0" - "@chainsafe/blst-darwin-x64" "2.2.0" - "@chainsafe/blst-linux-arm64-gnu" "2.2.0" - "@chainsafe/blst-linux-arm64-musl" "2.2.0" - "@chainsafe/blst-linux-x64-gnu" "2.2.0" - "@chainsafe/blst-linux-x64-musl" "2.2.0" - "@chainsafe/blst-win32-x64-msvc" "2.2.0" + "@chainsafe/blst-darwin-arm64" "2.1.0" + "@chainsafe/blst-darwin-x64" "2.1.0" + "@chainsafe/blst-linux-arm64-gnu" "2.1.0" + "@chainsafe/blst-linux-arm64-musl" "2.1.0" + "@chainsafe/blst-linux-x64-gnu" "2.1.0" + "@chainsafe/blst-linux-x64-musl" "2.1.0" + "@chainsafe/blst-win32-x64-msvc" "2.1.0" "@chainsafe/discv5@^9.0.0": version "9.0.0" From 224267817d688cf55af5b60db4c885c06240a65e Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 1 Nov 2024 00:19:35 +0000 Subject: [PATCH 194/259] feat: add mekong network option (#7212) --- packages/cli/src/networks/index.ts | 6 +- packages/cli/src/networks/mekong.ts | 130 ++++++++++++++++++ .../config/src/chainConfig/networks/mekong.ts | 44 ++++++ packages/config/src/networks.ts | 9 +- 4 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 packages/cli/src/networks/mekong.ts create mode 100644 packages/config/src/chainConfig/networks/mekong.ts diff --git a/packages/cli/src/networks/index.ts b/packages/cli/src/networks/index.ts index e2fc9dd621b6..13e55685e353 100644 --- a/packages/cli/src/networks/index.ts +++ b/packages/cli/src/networks/index.ts @@ -22,8 +22,9 @@ import * as sepolia from "./sepolia.js"; import * as holesky from "./holesky.js"; import * as chiado from "./chiado.js"; import * as ephemery from "./ephemery.js"; +import * as mekong from "./mekong.js"; -export type NetworkName = "mainnet" | "dev" | "gnosis" | "sepolia" | "holesky" | "chiado" | "ephemery"; +export type NetworkName = "mainnet" | "dev" | "gnosis" | "sepolia" | "holesky" | "chiado" | "ephemery" | "mekong"; export const networkNames: NetworkName[] = [ "mainnet", "gnosis", @@ -31,6 +32,7 @@ export const networkNames: NetworkName[] = [ "holesky", "chiado", "ephemery", + "mekong", // Leave always as last network. The order matters for the --help printout "dev", @@ -70,6 +72,8 @@ export function getNetworkData(network: NetworkName): { return chiado; case "ephemery": return ephemery; + case "mekong": + return mekong; default: throw Error(`Network not supported: ${network}`); } diff --git a/packages/cli/src/networks/mekong.ts b/packages/cli/src/networks/mekong.ts new file mode 100644 index 000000000000..44b45cd8d7ea --- /dev/null +++ b/packages/cli/src/networks/mekong.ts @@ -0,0 +1,130 @@ +export {mekongChainConfig as chainConfig} from "@lodestar/config/networks"; + +export const depositContractDeployBlock = 0; +export const genesisFileUrl = + "https://raw.githubusercontent.com/ethpandaops/mekong-devnets/master/network-configs/devnet-0/metadata/genesis.ssz"; +export const bootnodesFileUrl = + "https://raw.githubusercontent.com/ethpandaops/mekong-devnets/master/network-configs/devnet-0/metadata/bootstrap_nodes.txt"; + +export const bootEnrs = [ + "enr:-Iq4QNDvMuJuQDFx0NERRjcJzjUlpv-MG5ea22uVCNtFbBAbYdQXcL2ylwiZYKVR4ARyHL-ZIFQ45J3UdM3bCVPzTIaGAZLeJx23gmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQJJ3h8aUO3GJHv-bdvHtsQZ2OEisutelYfGjXO4lSg8BYN1ZHCCIzI", + "enr:-LK4QNmKwqyvCkLGM2MC8dnIE5Mg_j3PvEztzwAbRT2rwa97RCjVvEApmk6E6Tcrfae-jicCz646GX0B46Ksgfk9jY4Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQPrLuUBjXUN4pFbO9NX5UmF0TXzRLFxKQYshOmGXadK34N0Y3CCIyiDdWRwgiMo", + "enr:-Mm4QMycpeBzbXonM4_D6rG4OlCj3IiomsrKTAo5Lt4WiNR_UjHbqqzWDL4cU_DiRciLGtYZ7FplIBPo3Cc5sokaStUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82iEYRxdWljgiMpiXNlY3AyNTZrMaECFnLfbU62fXESKwDiGHjuh3Nt43sFPkpBK4RoiK7vLNiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QGLaP2hOFOCRyqpaJgXPQZSbB5QGRsoicY4U7UZx9RlkYLw9DoLXVxZFfPX7PNAszqMvBzN77FbkOjhPg_yPSFMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MADIRxdWljgiMpiXNlY3AyNTZrMaECbGSZZPqxqAcE_F48V2iNmHt6j60wSptDzsW--MalaYOIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMloS1eJUl8kTCumpRa-gPRV_3vHaznwqrkyZEqdNg_gMQZrdAs521F2CMDfb_QClmB1zc9mD-iqd7IHUpSiy-cBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEoSM7S4RxdWljgiMpiXNlY3AyNTZrMaEDG_p92y4TqYPE1uHfYJhEFYJicbhur6M3INxMDntMAdWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QK5ZHmY0IYdyaiCgNVG8PvmN-4iSC7bIDAqT159eQKzbZfC53fnsjyYc0fXhp3g-U8ClnxHIG6wvMeNwK-OuDLUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEjl3-GYRxdWljgiMpiXNlY3AyNTZrMaED1CTZowO74kS-gZr1mcUtOc3X8HuQ8M0Jlm9QN2A5jSmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMF5aX5M4399B7ixyj5srUR3Wcnpa6cfHuRofq5Rej9vGVvFCl1xt1p2PGgqUqxpoMBLM7--bVqPDtcaBBVtBV4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBQvoRxdWljgiMpiXNlY3AyNTZrMaECnjsDyKbztA9AZkfvAuM0M7BHE6LP65VagkNiausnwf2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QE_YVaRRiUZab27Hwu6kLWSkVRuke4Vx7L3dN8PHSuOqY2CjfnntxTeHRAc2_qS-lB8R35nNbu5D0xNdwWtbMfwBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEj26p9YRxdWljgiMpiXNlY3AyNTZrMaECxR5wgxcH2sTg4chkH2XctRjCRU9nBEMu8U0ixvYVOb6Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QAN_kY7-FlY9w3MiRh8Cm3h6SFLSomuWm8ezpAw9IWpvEZmqG_Y8Puq4rABVEqjoebUkiPdJ4km0YQDAP6CCD7wBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEisVoUYRxdWljgiMpiXNlY3AyNTZrMaEDbwUNCVBNIaDjC3soF1-UroKYk8SCzkDENCIM-eo2eQKIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QHlp8QeXe1YLemM0piknoBOVUyV-c-RxRpjoK9Eovv3wVwQV8ur2L4K1if_dyuYDiz-1vQWjdPKHt3t1HeGsxOkBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MnPIRxdWljgiMpiXNlY3AyNTZrMaECCmUZTe-r6wI4Hl1rZoa_KYB5q_2mGhHQpAuJcB7N3PiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJOUCJF0hWpdYKe9DW2b4n9-a9AwRkYbqa29arOanFBjHon2oamjS64Cpw1ayvTFTSwjFF1Ff6Yt9yf6y92cQ9gBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibgchYRxdWljgiMpiXNlY3AyNTZrMaEC2n4usqrewig49bgZaF1taS26cgVf-HiAE8DZ2Bg6QB2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QOkxdUkUVe8ChY2aX88BxuuAipS7LzH0qzqBwRfmYJ3cJVrfWTJll7lsHgE4FIlU2i9rH9wZWr0mqD3O-T7mMb0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEvKb94YRxdWljgiMpiXNlY3AyNTZrMaECEirgYfVhl9O8-apVAF4E19KST_SoQNdYB-dMK481lhCIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBctddDFJHQsWbwhViVGv7QQJrfiSCRbAmSB_vxLvUwoTF_4jgPdicOI25v8Sexde3K7VmoDumAqbfkDjKv59FsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkH7L54RxdWljgiMpiXNlY3AyNTZrMaEDvSYw5ZRCKA9lGJSjIqbWYikww-HYIay9IJuciFbG56SIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QNvGXzTNoMw9yRHgBSAMQ97pKZBqJvRzP_WQacha-WTDFXpm476LP5NZTJqZm949bOjI7UXFtk-Dq_f9qO9wf0MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MG04RxdWljgiMpiXNlY3AyNTZrMaECbNgYXUYuG0NleWcIX13YfwjVvF_BNt8hKk3yFCgrtWyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QLRk9InGH-I_MoWioQ70snhkdwNh_PJd06JXwaeZQSO9ChrhZO_IAnsZP9UKDMjwK4OWvGqhM7XpNRiSYk-LkB0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJB6D4RxdWljgiMpiXNlY3AyNTZrMaECgGQkX-iULENiOedHQ6q9VexGaI8lBQpyoB8IXGbjWGuIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QD2mxNJuYdUWUlMz51UT51LTsoTXoq5PgQ3OWzXgXOfvI3PlOl6pdynkOYbn2xz2S6PG3VhgzGWwaEbgy5-bKY4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82n3IRxdWljgiMpiXNlY3AyNTZrMaECPPNezPrn-hWXsZ0bXCGvjMNhIDVL6_faIpbMcdWGNeyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QHi9wOHG1kwBa5WVLM27nFBbULVWf-b5pRbsNknKKSo7cq0DcB9YFPCO55xrne5ncLuc5tsLVah588kITWoYZ44Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBRjIRxdWljgiMpiXNlY3AyNTZrMaECREuBzwWs5GJch31Gced8RLlNGcAUdzhexoBwket_gaGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QAVF7D6xLmKDFl19COzYWvUFyq7MqWpoWOCZCYHVIu6xL2tMaV7SzCSbCz0BDBy8I909i60MP3ASMSH3qelCaK0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBi-4RxdWljgiMpiXNlY3AyNTZrMaEDxLQPy6TvG7xuZHgovpv2fP1isHNUj6mff_k0XAMEobGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QGs_9j4e0D_v5jC-pKEltiT6fe9lbwgSVwwmRDNaUL_nOxZfmbvp1qOGRRCHBn5lOerol6_ykgmjDQf7R12eXncBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCrsz4RxdWljgiMpiXNlY3AyNTZrMaED36hK9w-REZSBnK1n1b1wpted08g5Zg2NAWfTm29r7UyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QAp_Du2XkinTcMU2LjMaOwb9dLqQpvik72s_ACpEa18KLqj-FDHjSw2iSSkLdMRiej_nRAmIoXPym1ZYWCsuspABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeNaNoRxdWljgiMpiXNlY3AyNTZrMaECe6WEfRco9dWv-lYOOkJ79oC6h1TsGwfE0qwwUyonCsqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QHjDYxMiuCYPV-u3Fd_EbKdKCXOa9UTUJM-2_ArMSXzBM5Hk6Re1uw9cQrWwzrGyZOqe-DhTlo38kOjENUv6wjMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibhIf4RxdWljgiMpiXNlY3AyNTZrMaECTysK1szima_WiGWZmsfCF39hYWJx4vBn3sw-EacZ2RqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QNtcDYVV2m40bIdResWh0ZcMAByENmg9BHvCtJlUUVZ2FheFMVh8JHPT5RYkkYCivlprbA_HRfv2yR5Vd4DKwoIBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCE0SYdtIRxdWljgiMpiXNlY3AyNTZrMaEDhmsIJt_vylwj9vVpe9xSxplR6yLv1-lcGG3t7kt7eQ-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJBF0ITYJn9deemoje7vB2lEOPTw1LcAbR7vDsUtN1X8QS4uBXHegmlxO_xo_eej94y6SpfeUZfsGI8TxXQO9eMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2ObP4RxdWljgiMpiXNlY3AyNTZrMaEDsGgIhgQBTv7AtHdxPxn6muNOSMSBeYTa8R3a6leiQJmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QKORSYhuvgwEULz5YTbKAFoFxIDUSUprw6-XhSWCI-R5dY74fgfmFWlnfQAWbrlxFPEQFlnFrJgoGJZBfx8qX3MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEneYo34RxdWljgiMpiXNlY3AyNTZrMaEDgOCZaXRC9ru0SM0TTN3rH8Z1rRvHZB6tN9pRiw_dH4mIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPALAj30065etXUSLBv1TCpIPjyu5Sc2jS1pq1dLxcWKCA-TZ7agz_iKHUd7qqKDjU8jkKEI6OZx75SD7hCFMdABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsj4zroRxdWljgiMpiXNlY3AyNTZrMaECscmuK1mmVZABEZ06513uRJNsRbPQ-dDRKtwbIDhBSaeIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJ9ivFpkcKKHcCWgwjRRsFnkHDfsCmf-oShjZ8GP1I3fPsfpoc3m5Al7hEWhiggU1D3DfTKDJLUGTWunO_ZpUbQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCr3YYRxdWljgiMpiXNlY3AyNTZrMaEDS30xNn9X05FEDU8E_mQjkmAGvEUHPjsGvM0-hOa2o2uIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBMzcDyzwpm2E5AMBGwyUEe0cmKfqB8M7zt9t8txyFcANxPcFvqW_uFcJsbv9oWLAAurBHxYRsrcjNXa-yzAiCsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEikSL4oRxdWljgiMpiXNlY3AyNTZrMaED0jwFiAei2MqwdAA2Jb2tG09PInLJDHRKHCEBcOWD1iaIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QGYTvW_cBJzsY3az9nseyDY-QGE9W0i65oSYjC6mYcwPUEaygRfuP8apw3cJ-gyn_4LnSFgiZQJulZoWohmHKr8Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtEjL4RxdWljgiMpiXNlY3AyNTZrMaEDTbzFw2ZRCyW6IMOPv0XjGPaF3KwEm8bIoiXS9YiZ_K2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QAGbFeFkhgZj2gytJlzx3un6Fpof5jA1siTpjzZweK5cO2U-NtmUgh7-cZKRY5cKXySnP-IkXxFwsg1Q9yYmC4QBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEgMcixoRxdWljgiMpiXNlY3AyNTZrMaECHpCu_6mFkwl9SZWYGm5np8J3IUCeW_9SB-3QOQe8ZgKIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QEdec6LFcVat6y4WbhoOp3VsdqE140XhMXaFbXLrser2fyFmaTWVwkwqDKwNwCk_ln5U39nf2HUyrli3MOxyQE4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeOpZYRxdWljgiMpiXNlY3AyNTZrMaECtDxrZZAg0FmSmOXOxtiTMnhiVAFbYJ_2LN624_7d_bmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QCwzClelxvQD72WYzAqszuwt4jPbDGnVMiLcSR5K8DUxbYxaT4irgnBmGaroK5BWYoeP2FcOzwy30qZx_eLSqS0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeMtMYRxdWljgiMpiXNlY3AyNTZrMaECxV_FCOTDHqVWw0egWAQawy7pt8vqsxhfXKsZive3jYSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QN7FBq4fhf-r_klVwhkhs0dw1QvNh-R0U64CaNeDT1C5IAYJmi_H_85vfl7EGqenQXM5igA0vT3Xj1GNlrjmv7QBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtGam4RxdWljgiMpiXNlY3AyNTZrMaECgqkFNSwP0y1X5VZcisA_7U5SAba1arLu5hdrY3nqXD-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QDMC6sQ0fBXCzm6-k4XOqcuCn7mKzntt-93j_pN4_J_3PFvXas6ExyaRr17v_omQm9u1VPTI03iBBrr7NnwOoeABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeiA-oRxdWljgiMpiXNlY3AyNTZrMaECqpIvWTdEaaXvjFLP_kLJr4Fa0lWkQTm42SJzc8KOk0OIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJ-oW-TTrAGfJd_iDN9zHFIlyEE6mFzmWvVIPiEvIWHXH4ExBg-vnOKpfFFHlGdCbfEclqaBOZ6D1nx1bLzxjtUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBqxIRxdWljgiMpiXNlY3AyNTZrMaEDIMB7xB2Sj6Y4p5n2h4TdxPzRnxxgTy-a5WAR9P3FKKCIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QG4hIWEcJJi2Gj6Ql-HhfVK2rmkLamUwEu06czdipkPeDro-wnWcBB1zpVd-QcOPzYiExZQb57gPJOD484otj-oBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfXIRYRxdWljgiMpiXNlY3AyNTZrMaEDwjfI--Oeet9BjyOkNbTOBSINLOkdOKZvbreigno_P96Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QEf-tOBH_isvG9Jjwn-itg_Ax461wK8gN53hxoFgjk_5WqZmSEGrFrfmnkIsKtCNH_JkNtqRPpgR4xi7mDDdG7YBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEizulmoRxdWljgiMpiXNlY3AyNTZrMaECsXckk_ngZJ0ZBmAvefKo5POpLi7tgvj6RBlrfIJxtU-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QOTA6CDkXHMJGzzK4Qw0bt2NvjN5hi0GFHM9FShjUkLzNwhAEO4GDqjJCT8_Vxhuz0s2W7RpWGVh3hYGjlvMBacBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEn0Hy14RxdWljgiMpiXNlY3AyNTZrMaEDimNy71F_6PL6FWsPubnH20GDHm1GS7Fe85P_MJ_CqWqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMkLbE9WDjXPLCRYoQ9G0532uDnHk1gzQFvOKz4W1YkzRKbdsFpvxLId4mhgQn27qcvXSCk9nhQM0MQcsVpDzooBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEaPjC2YRxdWljgiMpiXNlY3AyNTZrMaED3p7pPbl4e4vpW1BAjSTKP3GDbyBPFn-OsFqILK_rCAiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMnUw-6zNtXoKfRXPt5BJBO8TkAxU9rdTzltVtPh30WAb2M3LHYjSfb5DyEpAGPGEK6zSiAbMh9YOKGcrmbXMkUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQOJWSIRxdWljgiMpiXNlY3AyNTZrMaEDty9z1mk9zYbD6COhp-s5I-SnBbvIhgvrDQ7Ompd2IXSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QKwleyLEbKns19VjBa_TaUS7QbmHcZ0sFM1MXhXJ_qCJRWzS-h8BLgBkPqOwUpLFTBKFGpblaJF43tgwpI1iVPUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpRbtA4RxdWljgiMpiXNlY3AyNTZrMaECFTMVLpwC7LnVDFb18UGq_c8eSHCyes7YaXB7v_tKXDmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMYOJD6e010NIMR0abp7m23jDDG6Xrr2qvNvy9kq-QrHUN1B_JyL6mEV1NbqsIIiG9BzN1Kd2LIJEk46l7h29eoBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfVSpIRxdWljgiMpiXNlY3AyNTZrMaED1G20YrHlnMEMpJlZ3uRIN1yL3nKzBrlaw6NVJI8pm-qIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QL-Wv0r30Lu1xV6MvcKHtgzbNwfoMFji6dvMxh-Qp8gDDbFl24RZ6iimexWjw0g62ARz-l8dVfDW_MKjt8QY01UBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkr7eV4RxdWljgiMpiXNlY3AyNTZrMaECE4_MnOcmfF4kkp2fvKBc0XiA1mXl327K-tbZi25cAXOIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QGkPvBD9iEoIJ9bL_LBuERaeHRt-u3GMjJT2wK96GTQZBYmG2yWdSLLZY6N28Ah4n02tZj7XDQia88Zyhm1mg18Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp0fSfYRxdWljgiMpiXNlY3AyNTZrMaED2V8OumEq1Xyc-T_D8Rz_uErhd4ExFaA2Y9ggZ2Q-gaqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-MS4QHP454KmJRQ6QvtYPGDVISUWxt9u66kRS4Y2xG-yGNwrQeCXt2CRn3QOz4K0EYT_qJ4escUKK228aW53SAOoCmcEh2F0dG5ldHOIAQAAAAAAAICEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_Gf0iJc2VjcDI1NmsxoQKcmNIRud0TxGGBowMH6KgQuBL1I6QDisI67IqsT1NcFIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QD3QTJHvr_ozW4XhGWtQAA1faQ5qTPlgsh54Fr-UYHmxWBuwd5kvxCRUU2VFrqwU25MSO2UiIH0ni6eFHTEydx8Eh2F0dG5ldHOIAAAAAACAAQCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2s4qJc2VjcDI1NmsxoQMS7AXi54diXAl7JtCOIuqXTgdQLTI7DoAwoUHtT9M12ohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QMrvDNykHH-uY1LkpFdBQG2j7BTWm4Zu_DZKk7yJgDvqQrgR5ebdrkRbP9JWgB4yQ34GnOvRwKpQH6Fm0n7UR1wEh2F0dG5ldHOIMAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3e-OJc2VjcDI1NmsxoQKoG9efdprL9xdFAFWCwTNVy04G6ogkhxrv66lcem3BUIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QLmLjJYXt2stbFs_xSUsGtPU-e5ZRNI7kK_6EXfMcn-wY8Y0kkI2Y1RNNOKdY6CVRz6bFJHRVuN_Ke-Eev-iK2IEh2F0dG5ldHOIBgAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31WCWJc2VjcDI1NmsxoQLu-LLSTeIaXnVTY_AfGhaDvt8EzO9oSTkS7l9mp2FOsYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QIfHbHSR_wT6eNqWLSwZuwX8Vggfimr9UvQ7CqzyTRZ6RpiMH3WgSfRe2vLZ6XHzsWsEBPb8uIEB1bPznK26c1kEh2F0dG5ldHOIAAMAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69VfuJc2VjcDI1NmsxoQMzBsv9977GwLbPePCR2_215ob8vbuLkl7jw4Xjt4iHWYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QM-FMAwX9YAu3dNrWZ7-mR90ETH8Wi7HLNkzxHG91Ay2RZUZ5E2jNgE1nllpGrJ-PrEbx7ZLZam9pyyWuJUwVxsEh2F0dG5ldHOIgAEAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKAJmyJc2VjcDI1NmsxoQNi_YVV1IKWUYr4WtQX0GQlo_smd7RG9Px1Djgm2ddrjohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QNpXfFe6sv4pZr18EAS-MN7-6vR3BQRUFR2BUF8JYgdFfRIubi4CX7MZPxB_TTwa1QIbsJPpIE6xfgjRGTh8A4AEh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIrFV6KJc2VjcDI1NmsxoQONhJoWb2B8LK4SU3rMbJE_qS8fA7HC8pbQ3PYlBcyO8ohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QH1jbdpyatJUXruCSNlE6A-XKzoz-C74lHdONmCY8vjPFNVsHAOzc_tbsR3PkRHevG8PYZ2n7SGIn1MHtIhCy3wEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRzgOJc2VjcDI1NmsxoQJ_PRvNg4wOXMckP_vRbDc0hFtDX82mYxMrdc0sC8Rj6IhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QOItMJJrAKDahrxwk4TR237U9aQO4Zq199oc8GWjkg_BbQJo_YwMuduki7bXZuzp0AnOibhU_J2JxA1j8-PSYVYEh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3H5uJc2VjcDI1NmsxoQOSxZPyLv5s8ai4FD64JwMvhP8PVq8J3BJRrLB5IBeVhYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QOXTwRX2CPb5t10VXqqBWeH4ZKTuuYMRjtTdO_oua67rSYCJxZgXpcvd4qYDO5JuZacRrfL0yNZjrCsGBdbWK_4Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31NHGJc2VjcDI1NmsxoQOWGlZFPoKXBWSVvkFV2HSoBosBZ-8lELgZT-jWuZVMaohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QBbix4UUs0W6RiDVao4AxqL6vmTQ_ZbRDWtb6oZu2qnbTfeu7rI0ryBoC-3wDi6BrlY9VNAX6nNPLBQazJodN9wEh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7uVSJc2VjcDI1NmsxoQMMAOwLh6oGZWR5ix4Rj1zitDGV1u9hn1sssgqhsxmfaohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QAdIwFds5c1XoHY768YHDWQXE88sZq7x--TbIt8DywC-eKf63P59YopC9MhUXtyAjiPEUdFLGsbnZ8hDm-9QCF0Eh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjHhOJc2VjcDI1NmsxoQLoCYpIP0YsPoZhEdgfDFa9_h18rskEBOtgP0wtA8_Ix4hzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QFbvhD3YZ_d-7MDbwVAqQ9mouMZtHBcyJRyQOb9wCJXoISrFHMlXoghcwXMjK4L8jkpW0u0gAVJlj4KsYwv3CB0Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fqkuJc2VjcDI1NmsxoQPI_G4rCR_WldHte9rlywGwk_CMndXwVZL5vD-Uxx7bnYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QC65D5GPZpOqc_N62YzTHPFqPoIYzTlvkK1QcKIMreBLPiQ0S8crFQI4UR2QtHQwrSoST639jPIev9haCeGt-VcDh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3cBaJc2VjcDI1NmsxoQIyVTK8QH8HZRU5yXxq_9O1e-uNbMKCqeQ8Pnz614EAFohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QEb-gSH1pYzes12yGGMW0LS1VTFQWyChZG0hyHI4uzARMOEknslqIOwFYLwFuIQT6Xo57wY8k1lB2bD7F9erWHUDh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GpWiJc2VjcDI1NmsxoQKq3cwFVO4pfId5ZKR8FFLFjljUd0cM9nCJGDsRlD48bohzeW5jbmV0cwaDdGNwgiMog3VkcIIjKA", + "enr:-LK4QJjwmILrkfb7WcNFNW_6y0rIaje53iiPsnl8EXtlSIeDULOfeib1vI4arkRvtVf8e5NDJVNpC4OCsBM7geTQ09oCh2F0dG5ldHOIAAADAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNoYaJc2VjcDI1NmsxoQKjjHUHsAhI8k7Y9I8Jtcd4be186t5cbzK8Pe4rlNFSOIN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QC_SKLTMsQAA6xHhua6He-3tbTjHX5ldGsiD95pSQCFWAiLuRNg00WL-UqqWV213n2PxZUM2t5FKbUo6s6PEEgADh2F0dG5ldHOIAAAAGAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjPAeJc2VjcDI1NmsxoQJ6_2ty7xIQjMxh_BSVBc7wUNK_zavLTT9YyzBBZigwlohzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QEqg0X9eT-UeeQ_2owzG66lxi9Q02nMu_zOWjI_npLCAbzwffvokHJSUiVjTD5LWNnkZybI46Qd3hy8eCfNWHSYDh2F0dG5ldHOIAAAAAAAGAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-6KJc2VjcDI1NmsxoQNGyONNiNXLU_IhDDCDl7yPv6SxYDYW9zGte2S8Z9oI2IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QGztwj48eJUFLgDdAkX3KheH-Fk88PqSZNRULqu9QGbYI-mUoBOkVtEnUMGBTlbSuGuoev_qFrcEyS_R0ngCNXwDh2F0dG5ldHOIAAAAAAAABgCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhC5lURmJc2VjcDI1NmsxoQOUc7rqSZMXu7aOOH-b73MWd4mOIl4e-vxJJfYP0Hh9DIhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-Ly4QJSbkyL6Rmdt6cpVm9IjVOLURMZLygqwRyGQRrK3kio8DAZR0xN4GskcdMzAnGSQ20WiTBmsWBRfTqTAphoCqcMDh2F0dG5ldHOIAAAAAwAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4ByyJc2VjcDI1NmsxoQMw1fNhMLg9Xin7SkEQtLuGTnbN7-Wnw8fS0AJfnZ2BRohzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", + "enr:-Ly4QKLEnEf0XteI_IHP4zwX9eJss6S5nElWxSvNdbN8n7ijb3ETscGrirR30Vg-0i93zxY1XRo7FQ-rOEfvunFsjCUDh2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLymYWaJc2VjcDI1NmsxoQJ-lebNvZ8CGA_XLb8eQ4Lfn1O0877FaxzQ59D4_BZ2nYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QLf2HnD_AIAN9QUqZVRmzHEM97_WLsWL0suneZGjooQMKLrp1SxaGoyMYTSKwM6Y73BeslKSg_cJc957_j91bIADh2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPPX46Jc2VjcDI1NmsxoQPEQ5EUa259oEjbqaISDsur_X0sYukB30oNTL3FilEP4IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QKzWObYxzgx731J5wl23AjvYWKabGQUBQffvKQnvURfEKJB7R1vIIABd1u59-2TrW4nU3qX_DkYV97INFDImH_EDh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJK-Uy2Jc2VjcDI1NmsxoQJj5WlbVgIRjphmVVGJHnBTwVNKXOUDvLZChgx_JMCst4hzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QGseVCdo_fVjvMY_QGqcyve40Xdd0jYrcTyCq8S0EJy_Nx56YGxqjoHUUxKuMa0PU_iSQBQz2FbLFaDG74ek8y0Dh2F0dG5ldHOIAAAAAAAGAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRuLmJc2VjcDI1NmsxoQKhIIw9enpaKZdfmSvFfK9wDtQLpM-qrlHCd0MTDLNqOIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-LK4QPMXekagH7MNlJQqVIPR5NpGthHPcXJnaIzIejWK0narAo3N3Xs_Og_SwJLb_2Y5zjpKkmUEK2jUkPZ1WQAf5AMCh2F0dG5ldHOIDAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKesmW2Jc2VjcDI1NmsxoQLAQnSQdJeqTKVS-030kSAALKOWJbxD3bMTYnf8S97UZYN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QG8F0cB_Zxl0oKIbACCW8IMjQn10VWZkWCITw93BZh_FImJJXs3jhsZ5e10bw5nltAXkedIxHjNPzAMU3m-uNxcDh2F0dG5ldHOIAAAAAAAAGACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO21QqJc2VjcDI1NmsxoQPL1Q4Ri0_WvBK-G_Dkhb1hDnPfuizAn6EJ13TaAi2C84hzeW5jbmV0cwyDdGNwgiMog3VkcIIjKA", + "enr:-MK4QOeEXnB7mMNwk5tTvmn5ZqUIc7aMUTsDW42IRe39czdtRahIYzQU8f7VY-V26WLy6esPh_ah8JFCrHBErSVsiFWGAZLeT7Kzh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjybOJc2VjcDI1NmsxoQJpe2nb80QWjTg8OV7XQGj9_5HbFSPkb1BLSs52_E7TdohzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-MK4QP-QVRYlqxAZEGaK5EBtNFpF2cw68sprwnvPImwIjeJpWiDVvG2gdQYACH099DrRhS0rVvnvjnDiZc9eW_t3jlKGAZLeT8qUh2F0dG5ldHOIAAAAABgAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fSeGJc2VjcDI1NmsxoQMibnTlWZSEQrFdTWtwbGxwgzNfQugREcWXDzMAlubdQIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QC4Qu0GMY0208CpOOXJ_2Z7GbpPfkFHFj72Cz4kt-wu2Q3Hm_BGovRbHLlPrpF8uByVCV2-AtJVRBn84BHVEMnmGAZLeT7aVh2F0dG5ldHOIAAAAAAAAAGCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5dy46Jc2VjcDI1NmsxoQJsE-K2kx_vWKVVnIforrd-kHKsTjB4BPb3WzkSH1Lz1IhzeW5jbmV0cwqDdGNwgiMog3VkcIIjKA", + "enr:-MK4QKOofW71FNRlgsHUOCeV9AQ70UevGamBKDKnleTPROtrXEP6v9FIqo3pl25M2xN40gD4v1a00VlCDoVYkuPJ3_mGAZLeT8UPh2F0dG5ldHOIAAAAgAEAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES34myJc2VjcDI1NmsxoQMLSTJIF8gzlFEwia6qaD5gsKqT3Z23iaICK81VqretZIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QHXxbNuKKho7NcmdtuSBDNdkMi-cm6tC0AMyJTnYsGcobpX5es-NoxB4WY-kG3bFECGrRh2-tEsI7t28wa3YGTSGAZLeT7e7h2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXU2Jc2VjcDI1NmsxoQIKaSq5y43WBT8dVCHB84d2REc3wBX_tRk9-MOgpT1jB4hzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", + "enr:-MK4QIM-1UP2HB0pKx2jHndjWYzodWEtpEA2sosqoXffqsCrLa-SKOPCKr7x0JpeER2afgK3iqU1fs6rz1nUCuvL8FmGAZLeT7XZh2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhMbHVWCJc2VjcDI1NmsxoQObZKwNbXAMbuIQO_8nnSFd93JE_jMUmSd6kznKTfX-hIhzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-MK4QJM_-BhvBXnUBqQDNJcp3MdbKZ_1SIfzFS-3yFpxR5ZXQ0TRzzaBHNZnfjD24uSDNCaXbMlosEyl4ryPy-0XH02GAZLeT8U5h2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAyyGJc2VjcDI1NmsxoQPESmSk4h2lnhyRIa_lxBb1ITF8NfEPHXSFHJXVzS9n5IhzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-MK4QEzKtIksM5EURBpZ0FZ4fXLtecoS1JJ2icOpT2w-owpbO2P2Oug73jhspMuTOf8kK7cC_BN4gK28klfP_TNGo4-GAZLeT7rwh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GdHKJc2VjcDI1NmsxoQJgKsArRY2WPBuUYLZVUSSBpk4H5wh8zq5GrwjsSdRRcohzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", + "enr:-MK4QKz4NtZlKDRz9775jgPwsRePFX3vbw6pQbFqiIJg1J--eGZchwoG1N1nRXy9NjM4Bfi1XWG4E7Mv0Fdj5QCKr6SGAZLeT8A9h2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3mJJeJc2VjcDI1NmsxoQPgcbrdUs4Cl2iqnDEVlxCv5kmdL3PfoVwz7hFsEYkHbohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QOQd4uWnmwJXQgN26AXaxTf3IUWO4YgfBA9tvxuHEsv9dqg8fee11wGxxisvvRyG-JM4E1WqdMovcFH8dEW1r2-GAZLeT7Sgh2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoaVWJc2VjcDI1NmsxoQOpq1Sbb6wDrBz4d7_RAsXS_xLLh3848cZA_vTKkHNuA4hzeW5jbmV0cwWDdGNwgiMog3VkcIIjKA", + "enr:-MK4QFHjVhYt6eNGd-EGuWSx0FNoH0VobqyChYBb8Xf9YzLzPId1emfv9V-w5jEDndmdDOG2bbh6YH_wFfx548bszlGGAZLeT8cPh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES37GeJc2VjcDI1NmsxoQMZXzxzYiYyeZD4z_ByhY1BEBPdf1nAuLjxTpLlxOrRp4hzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-MK4QAqwAW8TghKOjYIWH5a9RXT1yvsUWOazdzP59eRPvJp5Ho1dWc-_NQiNqgKfZe0_7FT0eI1Erl4lqw7HTc0JM_SGAZLeT7ddh2F0dG5ldHOIAAAAAAAAwACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6aWJc2VjcDI1NmsxoQIGmyFT5c3IsH8psIugRpU9MsjD_ftbaIIzrDwOFvys6IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QPohqNkdiuEBihGI2rkBJX3Tk563kpN9zqYjSmiNdcChAldd_byrT5_MjnQ9bi24R2gQ7uxNYr4NH9UhUTZSd9qGAZLeT70Bh2F0dG5ldHOIAAAAAAAABgCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGiDI7CJc2VjcDI1NmsxoQKGVoBF9cfB3GV4M7Zl_-mTjbbWBCi7QW5C05ibiwuA3YhzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", + "enr:-MK4QP2DRiKhUiUsC4wJjJtITJBN2avNjW9egmAu-y4_B_WUQOhJBT2KJLI_9R73J18PuARPeR4eEVg-c-B5e8bfmKCGAZLeT7b3h2F0dG5ldHOIAAAAYAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKA-BqJc2VjcDI1NmsxoQJIWcsdtYM4mgdzTXwmUaMVoUbLIdVNDWweOsUrjI3UwIhzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", + "enr:-MK4QIiJTCxyJYWDZ1QQoOtBuIEuChMzNYGbVB64AxZE6FAnaNznjwz0Nwf5HJyMHRLiSwgxenjyymjMF3WfZZZtnvCGAZLeT7fch2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjdKaJc2VjcDI1NmsxoQNVGjVbnmG_42TCsv_fSh8VDxU6QzLGRoB40-F_zWq104hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QCVT912AAMDsucNOqG-0yf-biSVNaJub9k3ixr4Sg99NQ2AD4MpE3GSE2c4Jv1J0X2ZvTX1ggnYgbTC5x1yDa8qGAZLeT7ich2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2m8KJc2VjcDI1NmsxoQMpHGgKJECJqncISNxicGI89eIBdjm1scnNr7-DmDa6G4hzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-MK4QO-5av0dVBhDrwNoBkMeBt7ZJN0F8NrOOSNi2mq-CRWiTZZG-CqcOp7t9qjuuQhIi-RscfJyHxRW1yvcPyC5ufiGAZLeT8uNh2F0dG5ldHOIAAAAAAMAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7BZaJc2VjcDI1NmsxoQIJMx1m9LIofaV4RCXF5RyzaLZkRq61IaJbu7yRG9lIXIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QF6UfAiGKckerLH-N3EuPpcBqkRXPbXWq-ir9N-kDdBQZxiafoF9I5zcZDhZtlqCF3sVoE9TMi4NQppf-Z1rxYWGAZLeT8dRh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GaKKJc2VjcDI1NmsxoQJFec8UuFmn0tmu07iNakrK600BGlrxHh_sK2f82qYALYhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QDFSrh_p694cIm6RZ4uONpMkEaRcH9LHnrd99glEoGXpIEpmoIa8YCJJr9DrTRfuURml3_mncRXoajg4dmtFweGGAZLeT7xHh2F0dG5ldHOIAAAAAIABAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4xiSJc2VjcDI1NmsxoQOpjekMNl4V9McivNC7eRKkZQi1Lf_WX46aDF-TpMk864hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QLsNKnDBw1Ho_-SEg1MXS5sFVJjA4DWblUE6Y7IXWLiYQ4W0lDsSy7CpEzwyNU7SrXe1-RlSW_5H5LzU_ywsrPeGAZLeT8Twh2F0dG5ldHOIMAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjQ9WJc2VjcDI1NmsxoQIg-vBB9-5OOrarYUzumiirQZ01OeWbUF1Wi-CBEtJRoIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QI4JBnn2NoAAjb5Kb9k0SiniAUnLPLa4rgV39iBDBqIuCYQSXsjXiQguby7QitFRUznZMiVghIiz9p9GjXdgd0CGAZLeT7hbh2F0dG5ldHOIAAAAAAMAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6zuJc2VjcDI1NmsxoQJ5-KR2npQdVUZAd1HdHYts7qDfVeHvJDOCth0prC-ElIhzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", + "enr:-MK4QL4S9A8qoGT_8GCITvPBL7TCx57ULUlq2aPZjjPnmGLweeAft-punq4XjST99Jhh3S5UeugIl3rH9q3RrnDvXkqGAZLeT7mQh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_LaLyJc2VjcDI1NmsxoQNWzuY7G7y9FJlESwsCrG7DMzUrE7ESs1CdBwGC8CmpLohzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", + "enr:-MK4QF4vFBE44lGXPmNR0YdPC1XKgcXVxGi6pNo3SM7SZmtfJiDuypBq3SBlsNkcTG-d0WEyCXtRdhN5l2DMvLKhjgiGAZLeT7cJh2F0dG5ldHOIAAAAGAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4WPmJc2VjcDI1NmsxoQOEFAnO0rF8u_LHcT1hZKPcJKc_pjxxzS8q_jLEXyjYgohzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", + "enr:-MK4QOtmjWv0SLF7-sCbDXTidUu3eDaO5LRH0_1UBBRv3BfZDCW1f0IE9AGsPt8CfzCKZwhLM6qDg9i6Q7QqueoVv2yGAZLeT7x3h2F0dG5ldHOIAAAYAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoREOJc2VjcDI1NmsxoQLd7bMKI1z0ZzOPVmbsJTUZwuh09sEK60PJTBkr8Z5d0YhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QGPZwfQ1VRvztck8puc-l4453wOlE_GDLkZf21oekvenYGRil0bNPZfy99omIYDo_8Lfj-gTjtyMQNhfX-Gxf7KGAZLeT72vh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI9u1yKJc2VjcDI1NmsxoQOqOuh9qoiDqaOA9P3Zqe9Kr6LtA7BGX6HApTOwTw8JEYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QNoB0qr5S04EqGfFd2oC-8zfJ40EpEKX6comkVAhVGpzRcS5miDn3i7vI8xMq4rcP1f9UNmjf5synrMpkjtl2RCGAZLeT7LYh2F0dG5ldHOIAAAAMAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fp9qJc2VjcDI1NmsxoQM00pJ11HAcuKC2lu3qsmrFfinrKyEIJfI5AgaAXKwQqIhzeW5jbmV0cwyDdGNwgiMog3VkcIIjKA", + "enr:-MK4QPsx1H6cUFhgDo8IeVRxPIevJY2m3cdIcfDm67PQlT3SE_GLHiMXbt7OwNcLfDnmadblfze_qnIfLPxLbvlEdVmGAZLeT7FUh2F0dG5ldHOIAAYAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4z1uJc2VjcDI1NmsxoQJ3uZasVkJgtNwojOc12o_OGa95JidVTiTf2ZNg6v1evYhzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-MK4QLLmvX5uDrkBoxlU32GAniNWyfuq5dGdzp54Nr-NXwYBPFffMC8TRPV5qJtXRPCF0TMOfGRGtVUScaGHK7WhYKGGAZLeT7tLh2F0dG5ldHOIAAAAAAAAMACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7dg6Jc2VjcDI1NmsxoQPPUGx-0Q1GggcWhaFjoBRNM1zxb3-GZet_XVsCjQuQfohzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", + "enr:-LK4QHPZyuxlcLUFzQlV14cUrVEnk0R8-v0gI7LyFmrRbNsWGBRcv1bVBr4OsuDsQe7WCXw_MbzIPbRil-l8lqlktUsEh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ9Z7GWJc2VjcDI1NmsxoQLQ5jTn1P7lwT8_jmjdgTbtknYQYN1diCnUJ1meLGDVI4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QKsnDouz3ORWxyOj86zLs9Y6EPzGGmAQvetPJYVi1OA8EgS6iqTMUumFGYlkrhwhlgl--RhVdJnGn6BT4nWbWsIEh2F0dG5ldHOIAAAAAAAAAMCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-E2Jc2VjcDI1NmsxoQPiM0IiXdbtvibXIinl9tTnU2oxUtQVCsSD8C5Fw5kkvIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QBPu32Td8-yRXOiCr6oZ8Kx_U9l2CtrgtTdS7JJSrya7XmYrhR5PLufbQ_qheDZ5220i1GHFejGrUctcKqXL5b0Eh2F0dG5ldHOIAQAAAAAAAICEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GfsCJc2VjcDI1NmsxoQPVIZx2mp-hC6O-8Sc2trinfPTX1ldcVm872npcbECL84N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QCTAUicPEGC27830Tk47FIOJjLLXAucO2JWZBmUpqyRqdqgx7htej1mbSGOwdkvMy2wr1ppQqNNHpg09Nq7atbAEh2F0dG5ldHOIBgAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdH2zWJc2VjcDI1NmsxoQOa8jxBZtnN1XafI2exkfdQfYrCpf5nIN7NJbM8UaAQ4YN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QBD2UExDYapUhx4Gwwmj0sZOOe8b_Z_7LOwvupuKvHH7S3y-i1tM-a9MUzfKp0f05Lnyd1OebLqAe06SpN0RVokEh2F0dG5ldHOIAAAABgAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjWVmJc2VjcDI1NmsxoQNy5g7s97V6c_bliDX29X02VEt7lFtykziQ6yAQz4B7B4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QKNgqPGYJb0gd6sPYicjvhzxX_4fwIs3UoKfv2Km7hAnILqc4HfLG46fwiaCGuGO8HWqhauYJyElmKl95HdkcnYEh2F0dG5ldHOIAAAAAAAADACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXyKJc2VjcDI1NmsxoQMd0ERS9Kijwan6Ok4AnconhbpavC3ChksqpaeMfFUgYIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QHJU03COhJsMUjgIfZgqe5L9X6NTfBprKwmhq7MMi8pUYkWNplTk0mOFZFDCUdxQoAdXWBMghCg_siFW29NdSacEh2F0dG5ldHOIAAAAAIABAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAkzeJc2VjcDI1NmsxoQIKR_4srED3KxIv8t5HgcGDItwksuAZGkuTiy0Sj-nP94N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QIBsXm9oo2rBww1rjpa8gfUFgtC0zfdQOyj9Lds9vhNmUj9HTjeUSr2np5CmDQbpELn2y_5c68yHCk2HikCsbH8Eh2F0dG5ldHOIAAAAAAAAABiEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69nQ6Jc2VjcDI1NmsxoQKkClbynlGIlGlgJrwz_g-4ClmmbQZlLCrQDFwHWhV414N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QLKcBiOOWyItntw97roB2K9giftNayxWd66H5qiat7h1QuopDgg0RGF6_KRuh6jHWIlhUVUX9kIJfTkQYBq9hrUEh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLI-E7uJc2VjcDI1NmsxoQIPizTcMpW9300gIUyA6wzxPJVehLzRGzep9VcRIcZB4IN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QAW64M2-Mtv6f_IJ-wqKuf-uczJxwzIPs4aKFOu0dMKdROuPHYcsDKNHPoOgOvBM2fD6lI2XeIMmPlkHQs7fSbsEh2F0dG5ldHOIAAAAAAAAgAGEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEji72Jc2VjcDI1NmsxoQOwaeQ96C8h5DJ9qnIwi0MD_EW9mWnVqq8YP7A8IhRxf4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QI_7bYzk-6IKSGx0hwXoUp_4SE37TVNrIo05XsYuCwewL1ANoIv1wTlFPiqhSSdUppGEQr7m_dBCMIiE5YvYfZkEh2F0dG5ldHOIAAAAAABgAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_f11yJc2VjcDI1NmsxoQJcyXAkRddQMRW8Wq_uDDaqhfRix2FsTlQpaeNg3cTL6YN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QOcFoKeISpC6WEzMFOs0Fd8g5O3zxHR4YrtOti-Qrm-iHZX7R8Cm-ZlWaBAC_tv-KQ31POPAiVE26QpRgmnERHoEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDiYIuJc2VjcDI1NmsxoQOM0fzW5xagH42YOYCaUR6TlIWaurBsnTa41TOg5IMBRYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QDwhH0TLPcX9EkImgdegz9n4DN9U-u6rx-qA03Idi3WvL1tqnEWB54qSofoLPlpRCk1LEhPcekgUE2IrgfSKAGcEh2F0dG5ldHOIAAAAAAAAwACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjJ-CJc2VjcDI1NmsxoQJJnCea2UoBVZUPpyZPNZ8lCj1sPxtWP7v44pA3bAXFFoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QDWc9ARKxtQzvcfhsSSuOQVBXtJf4uBN5khbopSvlB5mRhqKJD0DoWr1brq0Fu7aXtwxLwz3tmW88gHRyfgNeXsEh2F0dG5ldHOIwAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW3BOJc2VjcDI1NmsxoQP08nTiii_CUneyjjQiQOxlSJRGOBy5RxAltma_eD2kqYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QHzsDl0sImNgHoUUQZHERvokg6bzOIMRqld5y_I3Dq76OcCRlR1B1NNUBZomkckV752vh6xwgh_nuU8gC5vhkqAEh2F0dG5ldHOIAAAAAAAMAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fxziJc2VjcDI1NmsxoQIcnSoMB5m__EkBOblmx6pFVb2gWMgytvG0DCK-7Dc454N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QLaDD0Ce92HbHN_Odx8gOLWetZBBkdObRIK_tGnbyAMZF1D0lOmSazEXtqb_gcYyYWloH2aLvUiIhFyfBcqdFKgEh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNp5mJc2VjcDI1NmsxoQLthQWPCxwf6ElsjcoeDy7xWTVy0oyZGsWLyWJhT0AVZoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QNbU3sIX2x1pEdOMlHnyTnf_qKCftwHH7PtruMWDcQ2FeYxji2tu79tZy2slCZYcHC3Kt2yY6YNA8xuXmny-qf0Eh2F0dG5ldHOIAAAAAAAYAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs75jmJc2VjcDI1NmsxoQO3hlCHVZ2KkCuU3J0cmy32kyeaygleHpvTj1e43JJLJIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QP45lW8RQIrJrUYu8JaBbdHsFCL7c5cTwnbsf1v_I6M-R1Ugjq2j77Fzzpj7eE1omCrXkq9NGuN02EqnhAG0BYMEh2F0dG5ldHOIAAAAABgAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjX6-Jc2VjcDI1NmsxoQKmt4RKybkmaCeLp5hZ4ubq8aOrMujHCsZQGkEIfQX63YN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QPm1dSEh4ejPKAgCUmVW8YfTCnot8TBcjPl_9DUK9x8pHAMdgLBG4dQYU1cVy0VkdQ-y7PrCWuS2HVGVWgXs-w0Eh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRrmKJc2VjcDI1NmsxoQJ3YV-wCUUU6e7D41mVpE6Pl2IxB6u4Xp3RiuVW72jrKoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QCcjOXE6AFoUfRAPy2ADwoHrKA8e1AEvONG_TfeNEA0lFQCgrffj14h3aZtqzRSmDx4kdmz9Aq4xI_OERsFSwsIEh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjnAqJc2VjcDI1NmsxoQLrpyFMatvbIPm9lThrW9SdBdscw1Ctj4OL4Cg71wC1SIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QODfmZ3HU4QHVggOpxp1HVczob3ce9UwTGhSxE5tiQLCH0TATU2t4i_WEaicUJMRJi66Bmeb8c9rEoGvTLdmOSEEh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5deB6Jc2VjcDI1NmsxoQNj36dwUn-Vk4qn0H6Pe4qhOYluSopCikb6fF2Kh-26JYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QAaQ9jSV48tiTtHzL1aocXbrJnt0r1uSituGZCTjl8mINNxn5Z_Brf9J9oThAK7U67uO9ChPzEarhfhvTGO677MEh2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4YuJc2VjcDI1NmsxoQKdiOidyLx2IMQyrI-L-a169keDHUmAjMZ3_8vurIiHF4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QM8rHJc9l75ns1i9tuZyux2m9CtFi7zh9Rjh6t38OhCGTLE_Nq8ZMyg0oy5ktpkIoIp6v5T2DVrmx_P6iDbtHrwEh2F0dG5ldHOIADAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJgq582Jc2VjcDI1NmsxoQMXBD2dqEKFbP0hIM624HswH20R-LlZIQIuTsB9nIygh4N0Y3CCIyiDdWRwgiMo", +]; diff --git a/packages/config/src/chainConfig/networks/mekong.ts b/packages/config/src/chainConfig/networks/mekong.ts new file mode 100644 index 000000000000..d7f2d15cb525 --- /dev/null +++ b/packages/config/src/chainConfig/networks/mekong.ts @@ -0,0 +1,44 @@ +import {fromHex as b} from "@lodestar/utils"; +import {ChainConfig} from "../types.js"; +import {chainConfig as mainnet} from "../configs/mainnet.js"; + +// Mekong beacon chain config: +// https://github.com/ethpandaops/mekong-devnets/blob/master/network-configs/devnet-0/metadata/config.yaml + +export const mekongChainConfig: ChainConfig = { + ...mainnet, + + CONFIG_NAME: "mekong", + + // Genesis + // --------------------------------------------------------------- + MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 100000, + MIN_GENESIS_TIME: 1730372340, + GENESIS_FORK_VERSION: b("0x10000000"), + GENESIS_DELAY: 60, + + // Forking + // --------------------------------------------------------------- + // # Altair + ALTAIR_FORK_VERSION: b("0x20000000"), + ALTAIR_FORK_EPOCH: 0, + // # Merge + BELLATRIX_FORK_VERSION: b("0x30000000"), + BELLATRIX_FORK_EPOCH: 0, + TERMINAL_TOTAL_DIFFICULTY: BigInt("0"), + // Capella + CAPELLA_FORK_VERSION: b("0x40000000"), + CAPELLA_FORK_EPOCH: 0, + // Deneb + DENEB_FORK_VERSION: b("0x50637624"), + DENEB_FORK_EPOCH: 0, + // Electra + ELECTRA_FORK_VERSION: b("0x60637624"), + ELECTRA_FORK_EPOCH: 256, + + // Deposit contract + // --------------------------------------------------------------- + DEPOSIT_CHAIN_ID: 7078815900, + DEPOSIT_NETWORK_ID: 7078815900, + DEPOSIT_CONTRACT_ADDRESS: b("0x4242424242424242424242424242424242424242"), +}; diff --git a/packages/config/src/networks.ts b/packages/config/src/networks.ts index 819c02b995b0..df39ae15d09e 100644 --- a/packages/config/src/networks.ts +++ b/packages/config/src/networks.ts @@ -5,6 +5,7 @@ import {sepoliaChainConfig} from "./chainConfig/networks/sepolia.js"; import {holeskyChainConfig} from "./chainConfig/networks/holesky.js"; import {chiadoChainConfig} from "./chainConfig/networks/chiado.js"; import {ephemeryChainConfig} from "./chainConfig/networks/ephemery.js"; +import {mekongChainConfig} from "./chainConfig/networks/mekong.js"; export { mainnetChainConfig, @@ -13,9 +14,10 @@ export { holeskyChainConfig, chiadoChainConfig, ephemeryChainConfig, + mekongChainConfig, }; -export type NetworkName = "mainnet" | "gnosis" | "sepolia" | "holesky" | "chiado" | "ephemery"; +export type NetworkName = "mainnet" | "gnosis" | "sepolia" | "holesky" | "chiado" | "ephemery" | "mekong"; export const networksChainConfig: Record = { mainnet: mainnetChainConfig, gnosis: gnosisChainConfig, @@ -23,6 +25,7 @@ export const networksChainConfig: Record = { holesky: holeskyChainConfig, chiado: chiadoChainConfig, ephemery: ephemeryChainConfig, + mekong: mekongChainConfig, }; export type GenesisData = { @@ -55,4 +58,8 @@ export const genesisData: Record = { genesisTime: ephemeryChainConfig.MIN_GENESIS_TIME + ephemeryChainConfig.GENESIS_DELAY, genesisValidatorsRoot: "0x0000000000000000000000000000000000000000000000000000000000000000", }, + mekong: { + genesisTime: 1730372340, + genesisValidatorsRoot: "0x9838240bca889c52818d7502179b393a828f61f15119d9027827c36caeb67db7", + }, }; From 2e8b8bb4781c703704a163596a7e851281b0b7af Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 8 Nov 2024 14:23:45 +0800 Subject: [PATCH 195/259] fix: update config for relaunched mekong network (#7220) --- packages/cli/src/networks/mekong.ts | 240 +++++++++--------- .../config/src/chainConfig/networks/mekong.ts | 19 +- 2 files changed, 134 insertions(+), 125 deletions(-) diff --git a/packages/cli/src/networks/mekong.ts b/packages/cli/src/networks/mekong.ts index 44b45cd8d7ea..62ac8bf89292 100644 --- a/packages/cli/src/networks/mekong.ts +++ b/packages/cli/src/networks/mekong.ts @@ -7,124 +7,124 @@ export const bootnodesFileUrl = "https://raw.githubusercontent.com/ethpandaops/mekong-devnets/master/network-configs/devnet-0/metadata/bootstrap_nodes.txt"; export const bootEnrs = [ - "enr:-Iq4QNDvMuJuQDFx0NERRjcJzjUlpv-MG5ea22uVCNtFbBAbYdQXcL2ylwiZYKVR4ARyHL-ZIFQ45J3UdM3bCVPzTIaGAZLeJx23gmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQJJ3h8aUO3GJHv-bdvHtsQZ2OEisutelYfGjXO4lSg8BYN1ZHCCIzI", - "enr:-LK4QNmKwqyvCkLGM2MC8dnIE5Mg_j3PvEztzwAbRT2rwa97RCjVvEApmk6E6Tcrfae-jicCz646GX0B46Ksgfk9jY4Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQPrLuUBjXUN4pFbO9NX5UmF0TXzRLFxKQYshOmGXadK34N0Y3CCIyiDdWRwgiMo", - "enr:-Mm4QMycpeBzbXonM4_D6rG4OlCj3IiomsrKTAo5Lt4WiNR_UjHbqqzWDL4cU_DiRciLGtYZ7FplIBPo3Cc5sokaStUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82iEYRxdWljgiMpiXNlY3AyNTZrMaECFnLfbU62fXESKwDiGHjuh3Nt43sFPkpBK4RoiK7vLNiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QGLaP2hOFOCRyqpaJgXPQZSbB5QGRsoicY4U7UZx9RlkYLw9DoLXVxZFfPX7PNAszqMvBzN77FbkOjhPg_yPSFMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MADIRxdWljgiMpiXNlY3AyNTZrMaECbGSZZPqxqAcE_F48V2iNmHt6j60wSptDzsW--MalaYOIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QMloS1eJUl8kTCumpRa-gPRV_3vHaznwqrkyZEqdNg_gMQZrdAs521F2CMDfb_QClmB1zc9mD-iqd7IHUpSiy-cBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEoSM7S4RxdWljgiMpiXNlY3AyNTZrMaEDG_p92y4TqYPE1uHfYJhEFYJicbhur6M3INxMDntMAdWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QK5ZHmY0IYdyaiCgNVG8PvmN-4iSC7bIDAqT159eQKzbZfC53fnsjyYc0fXhp3g-U8ClnxHIG6wvMeNwK-OuDLUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEjl3-GYRxdWljgiMpiXNlY3AyNTZrMaED1CTZowO74kS-gZr1mcUtOc3X8HuQ8M0Jlm9QN2A5jSmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QMF5aX5M4399B7ixyj5srUR3Wcnpa6cfHuRofq5Rej9vGVvFCl1xt1p2PGgqUqxpoMBLM7--bVqPDtcaBBVtBV4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBQvoRxdWljgiMpiXNlY3AyNTZrMaECnjsDyKbztA9AZkfvAuM0M7BHE6LP65VagkNiausnwf2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QE_YVaRRiUZab27Hwu6kLWSkVRuke4Vx7L3dN8PHSuOqY2CjfnntxTeHRAc2_qS-lB8R35nNbu5D0xNdwWtbMfwBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEj26p9YRxdWljgiMpiXNlY3AyNTZrMaECxR5wgxcH2sTg4chkH2XctRjCRU9nBEMu8U0ixvYVOb6Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QAN_kY7-FlY9w3MiRh8Cm3h6SFLSomuWm8ezpAw9IWpvEZmqG_Y8Puq4rABVEqjoebUkiPdJ4km0YQDAP6CCD7wBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEisVoUYRxdWljgiMpiXNlY3AyNTZrMaEDbwUNCVBNIaDjC3soF1-UroKYk8SCzkDENCIM-eo2eQKIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QHlp8QeXe1YLemM0piknoBOVUyV-c-RxRpjoK9Eovv3wVwQV8ur2L4K1if_dyuYDiz-1vQWjdPKHt3t1HeGsxOkBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MnPIRxdWljgiMpiXNlY3AyNTZrMaECCmUZTe-r6wI4Hl1rZoa_KYB5q_2mGhHQpAuJcB7N3PiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QJOUCJF0hWpdYKe9DW2b4n9-a9AwRkYbqa29arOanFBjHon2oamjS64Cpw1ayvTFTSwjFF1Ff6Yt9yf6y92cQ9gBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibgchYRxdWljgiMpiXNlY3AyNTZrMaEC2n4usqrewig49bgZaF1taS26cgVf-HiAE8DZ2Bg6QB2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QOkxdUkUVe8ChY2aX88BxuuAipS7LzH0qzqBwRfmYJ3cJVrfWTJll7lsHgE4FIlU2i9rH9wZWr0mqD3O-T7mMb0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEvKb94YRxdWljgiMpiXNlY3AyNTZrMaECEirgYfVhl9O8-apVAF4E19KST_SoQNdYB-dMK481lhCIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QBctddDFJHQsWbwhViVGv7QQJrfiSCRbAmSB_vxLvUwoTF_4jgPdicOI25v8Sexde3K7VmoDumAqbfkDjKv59FsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkH7L54RxdWljgiMpiXNlY3AyNTZrMaEDvSYw5ZRCKA9lGJSjIqbWYikww-HYIay9IJuciFbG56SIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QNvGXzTNoMw9yRHgBSAMQ97pKZBqJvRzP_WQacha-WTDFXpm476LP5NZTJqZm949bOjI7UXFtk-Dq_f9qO9wf0MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MG04RxdWljgiMpiXNlY3AyNTZrMaECbNgYXUYuG0NleWcIX13YfwjVvF_BNt8hKk3yFCgrtWyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QLRk9InGH-I_MoWioQ70snhkdwNh_PJd06JXwaeZQSO9ChrhZO_IAnsZP9UKDMjwK4OWvGqhM7XpNRiSYk-LkB0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJB6D4RxdWljgiMpiXNlY3AyNTZrMaECgGQkX-iULENiOedHQ6q9VexGaI8lBQpyoB8IXGbjWGuIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QD2mxNJuYdUWUlMz51UT51LTsoTXoq5PgQ3OWzXgXOfvI3PlOl6pdynkOYbn2xz2S6PG3VhgzGWwaEbgy5-bKY4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82n3IRxdWljgiMpiXNlY3AyNTZrMaECPPNezPrn-hWXsZ0bXCGvjMNhIDVL6_faIpbMcdWGNeyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QHi9wOHG1kwBa5WVLM27nFBbULVWf-b5pRbsNknKKSo7cq0DcB9YFPCO55xrne5ncLuc5tsLVah588kITWoYZ44Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBRjIRxdWljgiMpiXNlY3AyNTZrMaECREuBzwWs5GJch31Gced8RLlNGcAUdzhexoBwket_gaGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QAVF7D6xLmKDFl19COzYWvUFyq7MqWpoWOCZCYHVIu6xL2tMaV7SzCSbCz0BDBy8I909i60MP3ASMSH3qelCaK0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBi-4RxdWljgiMpiXNlY3AyNTZrMaEDxLQPy6TvG7xuZHgovpv2fP1isHNUj6mff_k0XAMEobGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QGs_9j4e0D_v5jC-pKEltiT6fe9lbwgSVwwmRDNaUL_nOxZfmbvp1qOGRRCHBn5lOerol6_ykgmjDQf7R12eXncBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCrsz4RxdWljgiMpiXNlY3AyNTZrMaED36hK9w-REZSBnK1n1b1wpted08g5Zg2NAWfTm29r7UyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QAp_Du2XkinTcMU2LjMaOwb9dLqQpvik72s_ACpEa18KLqj-FDHjSw2iSSkLdMRiej_nRAmIoXPym1ZYWCsuspABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeNaNoRxdWljgiMpiXNlY3AyNTZrMaECe6WEfRco9dWv-lYOOkJ79oC6h1TsGwfE0qwwUyonCsqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QHjDYxMiuCYPV-u3Fd_EbKdKCXOa9UTUJM-2_ArMSXzBM5Hk6Re1uw9cQrWwzrGyZOqe-DhTlo38kOjENUv6wjMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibhIf4RxdWljgiMpiXNlY3AyNTZrMaECTysK1szima_WiGWZmsfCF39hYWJx4vBn3sw-EacZ2RqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QNtcDYVV2m40bIdResWh0ZcMAByENmg9BHvCtJlUUVZ2FheFMVh8JHPT5RYkkYCivlprbA_HRfv2yR5Vd4DKwoIBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCE0SYdtIRxdWljgiMpiXNlY3AyNTZrMaEDhmsIJt_vylwj9vVpe9xSxplR6yLv1-lcGG3t7kt7eQ-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QJBF0ITYJn9deemoje7vB2lEOPTw1LcAbR7vDsUtN1X8QS4uBXHegmlxO_xo_eej94y6SpfeUZfsGI8TxXQO9eMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2ObP4RxdWljgiMpiXNlY3AyNTZrMaEDsGgIhgQBTv7AtHdxPxn6muNOSMSBeYTa8R3a6leiQJmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QKORSYhuvgwEULz5YTbKAFoFxIDUSUprw6-XhSWCI-R5dY74fgfmFWlnfQAWbrlxFPEQFlnFrJgoGJZBfx8qX3MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEneYo34RxdWljgiMpiXNlY3AyNTZrMaEDgOCZaXRC9ru0SM0TTN3rH8Z1rRvHZB6tN9pRiw_dH4mIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QPALAj30065etXUSLBv1TCpIPjyu5Sc2jS1pq1dLxcWKCA-TZ7agz_iKHUd7qqKDjU8jkKEI6OZx75SD7hCFMdABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsj4zroRxdWljgiMpiXNlY3AyNTZrMaECscmuK1mmVZABEZ06513uRJNsRbPQ-dDRKtwbIDhBSaeIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QJ9ivFpkcKKHcCWgwjRRsFnkHDfsCmf-oShjZ8GP1I3fPsfpoc3m5Al7hEWhiggU1D3DfTKDJLUGTWunO_ZpUbQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCr3YYRxdWljgiMpiXNlY3AyNTZrMaEDS30xNn9X05FEDU8E_mQjkmAGvEUHPjsGvM0-hOa2o2uIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QBMzcDyzwpm2E5AMBGwyUEe0cmKfqB8M7zt9t8txyFcANxPcFvqW_uFcJsbv9oWLAAurBHxYRsrcjNXa-yzAiCsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEikSL4oRxdWljgiMpiXNlY3AyNTZrMaED0jwFiAei2MqwdAA2Jb2tG09PInLJDHRKHCEBcOWD1iaIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QGYTvW_cBJzsY3az9nseyDY-QGE9W0i65oSYjC6mYcwPUEaygRfuP8apw3cJ-gyn_4LnSFgiZQJulZoWohmHKr8Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtEjL4RxdWljgiMpiXNlY3AyNTZrMaEDTbzFw2ZRCyW6IMOPv0XjGPaF3KwEm8bIoiXS9YiZ_K2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QAGbFeFkhgZj2gytJlzx3un6Fpof5jA1siTpjzZweK5cO2U-NtmUgh7-cZKRY5cKXySnP-IkXxFwsg1Q9yYmC4QBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEgMcixoRxdWljgiMpiXNlY3AyNTZrMaECHpCu_6mFkwl9SZWYGm5np8J3IUCeW_9SB-3QOQe8ZgKIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QEdec6LFcVat6y4WbhoOp3VsdqE140XhMXaFbXLrser2fyFmaTWVwkwqDKwNwCk_ln5U39nf2HUyrli3MOxyQE4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeOpZYRxdWljgiMpiXNlY3AyNTZrMaECtDxrZZAg0FmSmOXOxtiTMnhiVAFbYJ_2LN624_7d_bmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QCwzClelxvQD72WYzAqszuwt4jPbDGnVMiLcSR5K8DUxbYxaT4irgnBmGaroK5BWYoeP2FcOzwy30qZx_eLSqS0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeMtMYRxdWljgiMpiXNlY3AyNTZrMaECxV_FCOTDHqVWw0egWAQawy7pt8vqsxhfXKsZive3jYSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QN7FBq4fhf-r_klVwhkhs0dw1QvNh-R0U64CaNeDT1C5IAYJmi_H_85vfl7EGqenQXM5igA0vT3Xj1GNlrjmv7QBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtGam4RxdWljgiMpiXNlY3AyNTZrMaECgqkFNSwP0y1X5VZcisA_7U5SAba1arLu5hdrY3nqXD-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QDMC6sQ0fBXCzm6-k4XOqcuCn7mKzntt-93j_pN4_J_3PFvXas6ExyaRr17v_omQm9u1VPTI03iBBrr7NnwOoeABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeiA-oRxdWljgiMpiXNlY3AyNTZrMaECqpIvWTdEaaXvjFLP_kLJr4Fa0lWkQTm42SJzc8KOk0OIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QJ-oW-TTrAGfJd_iDN9zHFIlyEE6mFzmWvVIPiEvIWHXH4ExBg-vnOKpfFFHlGdCbfEclqaBOZ6D1nx1bLzxjtUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBqxIRxdWljgiMpiXNlY3AyNTZrMaEDIMB7xB2Sj6Y4p5n2h4TdxPzRnxxgTy-a5WAR9P3FKKCIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QG4hIWEcJJi2Gj6Ql-HhfVK2rmkLamUwEu06czdipkPeDro-wnWcBB1zpVd-QcOPzYiExZQb57gPJOD484otj-oBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfXIRYRxdWljgiMpiXNlY3AyNTZrMaEDwjfI--Oeet9BjyOkNbTOBSINLOkdOKZvbreigno_P96Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QEf-tOBH_isvG9Jjwn-itg_Ax461wK8gN53hxoFgjk_5WqZmSEGrFrfmnkIsKtCNH_JkNtqRPpgR4xi7mDDdG7YBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEizulmoRxdWljgiMpiXNlY3AyNTZrMaECsXckk_ngZJ0ZBmAvefKo5POpLi7tgvj6RBlrfIJxtU-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QOTA6CDkXHMJGzzK4Qw0bt2NvjN5hi0GFHM9FShjUkLzNwhAEO4GDqjJCT8_Vxhuz0s2W7RpWGVh3hYGjlvMBacBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEn0Hy14RxdWljgiMpiXNlY3AyNTZrMaEDimNy71F_6PL6FWsPubnH20GDHm1GS7Fe85P_MJ_CqWqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QMkLbE9WDjXPLCRYoQ9G0532uDnHk1gzQFvOKz4W1YkzRKbdsFpvxLId4mhgQn27qcvXSCk9nhQM0MQcsVpDzooBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEaPjC2YRxdWljgiMpiXNlY3AyNTZrMaED3p7pPbl4e4vpW1BAjSTKP3GDbyBPFn-OsFqILK_rCAiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QMnUw-6zNtXoKfRXPt5BJBO8TkAxU9rdTzltVtPh30WAb2M3LHYjSfb5DyEpAGPGEK6zSiAbMh9YOKGcrmbXMkUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQOJWSIRxdWljgiMpiXNlY3AyNTZrMaEDty9z1mk9zYbD6COhp-s5I-SnBbvIhgvrDQ7Ompd2IXSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QKwleyLEbKns19VjBa_TaUS7QbmHcZ0sFM1MXhXJ_qCJRWzS-h8BLgBkPqOwUpLFTBKFGpblaJF43tgwpI1iVPUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpRbtA4RxdWljgiMpiXNlY3AyNTZrMaECFTMVLpwC7LnVDFb18UGq_c8eSHCyes7YaXB7v_tKXDmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QMYOJD6e010NIMR0abp7m23jDDG6Xrr2qvNvy9kq-QrHUN1B_JyL6mEV1NbqsIIiG9BzN1Kd2LIJEk46l7h29eoBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfVSpIRxdWljgiMpiXNlY3AyNTZrMaED1G20YrHlnMEMpJlZ3uRIN1yL3nKzBrlaw6NVJI8pm-qIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QL-Wv0r30Lu1xV6MvcKHtgzbNwfoMFji6dvMxh-Qp8gDDbFl24RZ6iimexWjw0g62ARz-l8dVfDW_MKjt8QY01UBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkr7eV4RxdWljgiMpiXNlY3AyNTZrMaECE4_MnOcmfF4kkp2fvKBc0XiA1mXl327K-tbZi25cAXOIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QGkPvBD9iEoIJ9bL_LBuERaeHRt-u3GMjJT2wK96GTQZBYmG2yWdSLLZY6N28Ah4n02tZj7XDQia88Zyhm1mg18Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp0fSfYRxdWljgiMpiXNlY3AyNTZrMaED2V8OumEq1Xyc-T_D8Rz_uErhd4ExFaA2Y9ggZ2Q-gaqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-MS4QHP454KmJRQ6QvtYPGDVISUWxt9u66kRS4Y2xG-yGNwrQeCXt2CRn3QOz4K0EYT_qJ4escUKK228aW53SAOoCmcEh2F0dG5ldHOIAQAAAAAAAICEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_Gf0iJc2VjcDI1NmsxoQKcmNIRud0TxGGBowMH6KgQuBL1I6QDisI67IqsT1NcFIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QD3QTJHvr_ozW4XhGWtQAA1faQ5qTPlgsh54Fr-UYHmxWBuwd5kvxCRUU2VFrqwU25MSO2UiIH0ni6eFHTEydx8Eh2F0dG5ldHOIAAAAAACAAQCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2s4qJc2VjcDI1NmsxoQMS7AXi54diXAl7JtCOIuqXTgdQLTI7DoAwoUHtT9M12ohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QMrvDNykHH-uY1LkpFdBQG2j7BTWm4Zu_DZKk7yJgDvqQrgR5ebdrkRbP9JWgB4yQ34GnOvRwKpQH6Fm0n7UR1wEh2F0dG5ldHOIMAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3e-OJc2VjcDI1NmsxoQKoG9efdprL9xdFAFWCwTNVy04G6ogkhxrv66lcem3BUIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QLmLjJYXt2stbFs_xSUsGtPU-e5ZRNI7kK_6EXfMcn-wY8Y0kkI2Y1RNNOKdY6CVRz6bFJHRVuN_Ke-Eev-iK2IEh2F0dG5ldHOIBgAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31WCWJc2VjcDI1NmsxoQLu-LLSTeIaXnVTY_AfGhaDvt8EzO9oSTkS7l9mp2FOsYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QIfHbHSR_wT6eNqWLSwZuwX8Vggfimr9UvQ7CqzyTRZ6RpiMH3WgSfRe2vLZ6XHzsWsEBPb8uIEB1bPznK26c1kEh2F0dG5ldHOIAAMAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69VfuJc2VjcDI1NmsxoQMzBsv9977GwLbPePCR2_215ob8vbuLkl7jw4Xjt4iHWYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QM-FMAwX9YAu3dNrWZ7-mR90ETH8Wi7HLNkzxHG91Ay2RZUZ5E2jNgE1nllpGrJ-PrEbx7ZLZam9pyyWuJUwVxsEh2F0dG5ldHOIgAEAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKAJmyJc2VjcDI1NmsxoQNi_YVV1IKWUYr4WtQX0GQlo_smd7RG9Px1Djgm2ddrjohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QNpXfFe6sv4pZr18EAS-MN7-6vR3BQRUFR2BUF8JYgdFfRIubi4CX7MZPxB_TTwa1QIbsJPpIE6xfgjRGTh8A4AEh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIrFV6KJc2VjcDI1NmsxoQONhJoWb2B8LK4SU3rMbJE_qS8fA7HC8pbQ3PYlBcyO8ohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QH1jbdpyatJUXruCSNlE6A-XKzoz-C74lHdONmCY8vjPFNVsHAOzc_tbsR3PkRHevG8PYZ2n7SGIn1MHtIhCy3wEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRzgOJc2VjcDI1NmsxoQJ_PRvNg4wOXMckP_vRbDc0hFtDX82mYxMrdc0sC8Rj6IhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QOItMJJrAKDahrxwk4TR237U9aQO4Zq199oc8GWjkg_BbQJo_YwMuduki7bXZuzp0AnOibhU_J2JxA1j8-PSYVYEh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3H5uJc2VjcDI1NmsxoQOSxZPyLv5s8ai4FD64JwMvhP8PVq8J3BJRrLB5IBeVhYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QOXTwRX2CPb5t10VXqqBWeH4ZKTuuYMRjtTdO_oua67rSYCJxZgXpcvd4qYDO5JuZacRrfL0yNZjrCsGBdbWK_4Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31NHGJc2VjcDI1NmsxoQOWGlZFPoKXBWSVvkFV2HSoBosBZ-8lELgZT-jWuZVMaohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QBbix4UUs0W6RiDVao4AxqL6vmTQ_ZbRDWtb6oZu2qnbTfeu7rI0ryBoC-3wDi6BrlY9VNAX6nNPLBQazJodN9wEh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7uVSJc2VjcDI1NmsxoQMMAOwLh6oGZWR5ix4Rj1zitDGV1u9hn1sssgqhsxmfaohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QAdIwFds5c1XoHY768YHDWQXE88sZq7x--TbIt8DywC-eKf63P59YopC9MhUXtyAjiPEUdFLGsbnZ8hDm-9QCF0Eh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjHhOJc2VjcDI1NmsxoQLoCYpIP0YsPoZhEdgfDFa9_h18rskEBOtgP0wtA8_Ix4hzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QFbvhD3YZ_d-7MDbwVAqQ9mouMZtHBcyJRyQOb9wCJXoISrFHMlXoghcwXMjK4L8jkpW0u0gAVJlj4KsYwv3CB0Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fqkuJc2VjcDI1NmsxoQPI_G4rCR_WldHte9rlywGwk_CMndXwVZL5vD-Uxx7bnYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-Ly4QC65D5GPZpOqc_N62YzTHPFqPoIYzTlvkK1QcKIMreBLPiQ0S8crFQI4UR2QtHQwrSoST639jPIev9haCeGt-VcDh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3cBaJc2VjcDI1NmsxoQIyVTK8QH8HZRU5yXxq_9O1e-uNbMKCqeQ8Pnz614EAFohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QEb-gSH1pYzes12yGGMW0LS1VTFQWyChZG0hyHI4uzARMOEknslqIOwFYLwFuIQT6Xo57wY8k1lB2bD7F9erWHUDh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GpWiJc2VjcDI1NmsxoQKq3cwFVO4pfId5ZKR8FFLFjljUd0cM9nCJGDsRlD48bohzeW5jbmV0cwaDdGNwgiMog3VkcIIjKA", - "enr:-LK4QJjwmILrkfb7WcNFNW_6y0rIaje53iiPsnl8EXtlSIeDULOfeib1vI4arkRvtVf8e5NDJVNpC4OCsBM7geTQ09oCh2F0dG5ldHOIAAADAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNoYaJc2VjcDI1NmsxoQKjjHUHsAhI8k7Y9I8Jtcd4be186t5cbzK8Pe4rlNFSOIN0Y3CCIyiDdWRwgiMo", - "enr:-Ly4QC_SKLTMsQAA6xHhua6He-3tbTjHX5ldGsiD95pSQCFWAiLuRNg00WL-UqqWV213n2PxZUM2t5FKbUo6s6PEEgADh2F0dG5ldHOIAAAAGAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjPAeJc2VjcDI1NmsxoQJ6_2ty7xIQjMxh_BSVBc7wUNK_zavLTT9YyzBBZigwlohzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QEqg0X9eT-UeeQ_2owzG66lxi9Q02nMu_zOWjI_npLCAbzwffvokHJSUiVjTD5LWNnkZybI46Qd3hy8eCfNWHSYDh2F0dG5ldHOIAAAAAAAGAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-6KJc2VjcDI1NmsxoQNGyONNiNXLU_IhDDCDl7yPv6SxYDYW9zGte2S8Z9oI2IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QGztwj48eJUFLgDdAkX3KheH-Fk88PqSZNRULqu9QGbYI-mUoBOkVtEnUMGBTlbSuGuoev_qFrcEyS_R0ngCNXwDh2F0dG5ldHOIAAAAAAAABgCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhC5lURmJc2VjcDI1NmsxoQOUc7rqSZMXu7aOOH-b73MWd4mOIl4e-vxJJfYP0Hh9DIhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", - "enr:-Ly4QJSbkyL6Rmdt6cpVm9IjVOLURMZLygqwRyGQRrK3kio8DAZR0xN4GskcdMzAnGSQ20WiTBmsWBRfTqTAphoCqcMDh2F0dG5ldHOIAAAAAwAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4ByyJc2VjcDI1NmsxoQMw1fNhMLg9Xin7SkEQtLuGTnbN7-Wnw8fS0AJfnZ2BRohzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", - "enr:-Ly4QKLEnEf0XteI_IHP4zwX9eJss6S5nElWxSvNdbN8n7ijb3ETscGrirR30Vg-0i93zxY1XRo7FQ-rOEfvunFsjCUDh2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLymYWaJc2VjcDI1NmsxoQJ-lebNvZ8CGA_XLb8eQ4Lfn1O0877FaxzQ59D4_BZ2nYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QLf2HnD_AIAN9QUqZVRmzHEM97_WLsWL0suneZGjooQMKLrp1SxaGoyMYTSKwM6Y73BeslKSg_cJc957_j91bIADh2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPPX46Jc2VjcDI1NmsxoQPEQ5EUa259oEjbqaISDsur_X0sYukB30oNTL3FilEP4IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QKzWObYxzgx731J5wl23AjvYWKabGQUBQffvKQnvURfEKJB7R1vIIABd1u59-2TrW4nU3qX_DkYV97INFDImH_EDh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJK-Uy2Jc2VjcDI1NmsxoQJj5WlbVgIRjphmVVGJHnBTwVNKXOUDvLZChgx_JMCst4hzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QGseVCdo_fVjvMY_QGqcyve40Xdd0jYrcTyCq8S0EJy_Nx56YGxqjoHUUxKuMa0PU_iSQBQz2FbLFaDG74ek8y0Dh2F0dG5ldHOIAAAAAAAGAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRuLmJc2VjcDI1NmsxoQKhIIw9enpaKZdfmSvFfK9wDtQLpM-qrlHCd0MTDLNqOIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-LK4QPMXekagH7MNlJQqVIPR5NpGthHPcXJnaIzIejWK0narAo3N3Xs_Og_SwJLb_2Y5zjpKkmUEK2jUkPZ1WQAf5AMCh2F0dG5ldHOIDAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKesmW2Jc2VjcDI1NmsxoQLAQnSQdJeqTKVS-030kSAALKOWJbxD3bMTYnf8S97UZYN0Y3CCIyiDdWRwgiMo", - "enr:-Ly4QG8F0cB_Zxl0oKIbACCW8IMjQn10VWZkWCITw93BZh_FImJJXs3jhsZ5e10bw5nltAXkedIxHjNPzAMU3m-uNxcDh2F0dG5ldHOIAAAAAAAAGACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO21QqJc2VjcDI1NmsxoQPL1Q4Ri0_WvBK-G_Dkhb1hDnPfuizAn6EJ13TaAi2C84hzeW5jbmV0cwyDdGNwgiMog3VkcIIjKA", - "enr:-MK4QOeEXnB7mMNwk5tTvmn5ZqUIc7aMUTsDW42IRe39czdtRahIYzQU8f7VY-V26WLy6esPh_ah8JFCrHBErSVsiFWGAZLeT7Kzh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjybOJc2VjcDI1NmsxoQJpe2nb80QWjTg8OV7XQGj9_5HbFSPkb1BLSs52_E7TdohzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", - "enr:-MK4QP-QVRYlqxAZEGaK5EBtNFpF2cw68sprwnvPImwIjeJpWiDVvG2gdQYACH099DrRhS0rVvnvjnDiZc9eW_t3jlKGAZLeT8qUh2F0dG5ldHOIAAAAABgAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fSeGJc2VjcDI1NmsxoQMibnTlWZSEQrFdTWtwbGxwgzNfQugREcWXDzMAlubdQIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QC4Qu0GMY0208CpOOXJ_2Z7GbpPfkFHFj72Cz4kt-wu2Q3Hm_BGovRbHLlPrpF8uByVCV2-AtJVRBn84BHVEMnmGAZLeT7aVh2F0dG5ldHOIAAAAAAAAAGCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5dy46Jc2VjcDI1NmsxoQJsE-K2kx_vWKVVnIforrd-kHKsTjB4BPb3WzkSH1Lz1IhzeW5jbmV0cwqDdGNwgiMog3VkcIIjKA", - "enr:-MK4QKOofW71FNRlgsHUOCeV9AQ70UevGamBKDKnleTPROtrXEP6v9FIqo3pl25M2xN40gD4v1a00VlCDoVYkuPJ3_mGAZLeT8UPh2F0dG5ldHOIAAAAgAEAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES34myJc2VjcDI1NmsxoQMLSTJIF8gzlFEwia6qaD5gsKqT3Z23iaICK81VqretZIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QHXxbNuKKho7NcmdtuSBDNdkMi-cm6tC0AMyJTnYsGcobpX5es-NoxB4WY-kG3bFECGrRh2-tEsI7t28wa3YGTSGAZLeT7e7h2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXU2Jc2VjcDI1NmsxoQIKaSq5y43WBT8dVCHB84d2REc3wBX_tRk9-MOgpT1jB4hzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", - "enr:-MK4QIM-1UP2HB0pKx2jHndjWYzodWEtpEA2sosqoXffqsCrLa-SKOPCKr7x0JpeER2afgK3iqU1fs6rz1nUCuvL8FmGAZLeT7XZh2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhMbHVWCJc2VjcDI1NmsxoQObZKwNbXAMbuIQO_8nnSFd93JE_jMUmSd6kznKTfX-hIhzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", - "enr:-MK4QJM_-BhvBXnUBqQDNJcp3MdbKZ_1SIfzFS-3yFpxR5ZXQ0TRzzaBHNZnfjD24uSDNCaXbMlosEyl4ryPy-0XH02GAZLeT8U5h2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAyyGJc2VjcDI1NmsxoQPESmSk4h2lnhyRIa_lxBb1ITF8NfEPHXSFHJXVzS9n5IhzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", - "enr:-MK4QEzKtIksM5EURBpZ0FZ4fXLtecoS1JJ2icOpT2w-owpbO2P2Oug73jhspMuTOf8kK7cC_BN4gK28klfP_TNGo4-GAZLeT7rwh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GdHKJc2VjcDI1NmsxoQJgKsArRY2WPBuUYLZVUSSBpk4H5wh8zq5GrwjsSdRRcohzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", - "enr:-MK4QKz4NtZlKDRz9775jgPwsRePFX3vbw6pQbFqiIJg1J--eGZchwoG1N1nRXy9NjM4Bfi1XWG4E7Mv0Fdj5QCKr6SGAZLeT8A9h2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3mJJeJc2VjcDI1NmsxoQPgcbrdUs4Cl2iqnDEVlxCv5kmdL3PfoVwz7hFsEYkHbohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QOQd4uWnmwJXQgN26AXaxTf3IUWO4YgfBA9tvxuHEsv9dqg8fee11wGxxisvvRyG-JM4E1WqdMovcFH8dEW1r2-GAZLeT7Sgh2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoaVWJc2VjcDI1NmsxoQOpq1Sbb6wDrBz4d7_RAsXS_xLLh3848cZA_vTKkHNuA4hzeW5jbmV0cwWDdGNwgiMog3VkcIIjKA", - "enr:-MK4QFHjVhYt6eNGd-EGuWSx0FNoH0VobqyChYBb8Xf9YzLzPId1emfv9V-w5jEDndmdDOG2bbh6YH_wFfx548bszlGGAZLeT8cPh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES37GeJc2VjcDI1NmsxoQMZXzxzYiYyeZD4z_ByhY1BEBPdf1nAuLjxTpLlxOrRp4hzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", - "enr:-MK4QAqwAW8TghKOjYIWH5a9RXT1yvsUWOazdzP59eRPvJp5Ho1dWc-_NQiNqgKfZe0_7FT0eI1Erl4lqw7HTc0JM_SGAZLeT7ddh2F0dG5ldHOIAAAAAAAAwACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6aWJc2VjcDI1NmsxoQIGmyFT5c3IsH8psIugRpU9MsjD_ftbaIIzrDwOFvys6IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QPohqNkdiuEBihGI2rkBJX3Tk563kpN9zqYjSmiNdcChAldd_byrT5_MjnQ9bi24R2gQ7uxNYr4NH9UhUTZSd9qGAZLeT70Bh2F0dG5ldHOIAAAAAAAABgCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGiDI7CJc2VjcDI1NmsxoQKGVoBF9cfB3GV4M7Zl_-mTjbbWBCi7QW5C05ibiwuA3YhzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", - "enr:-MK4QP2DRiKhUiUsC4wJjJtITJBN2avNjW9egmAu-y4_B_WUQOhJBT2KJLI_9R73J18PuARPeR4eEVg-c-B5e8bfmKCGAZLeT7b3h2F0dG5ldHOIAAAAYAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKA-BqJc2VjcDI1NmsxoQJIWcsdtYM4mgdzTXwmUaMVoUbLIdVNDWweOsUrjI3UwIhzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", - "enr:-MK4QIiJTCxyJYWDZ1QQoOtBuIEuChMzNYGbVB64AxZE6FAnaNznjwz0Nwf5HJyMHRLiSwgxenjyymjMF3WfZZZtnvCGAZLeT7fch2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjdKaJc2VjcDI1NmsxoQNVGjVbnmG_42TCsv_fSh8VDxU6QzLGRoB40-F_zWq104hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QCVT912AAMDsucNOqG-0yf-biSVNaJub9k3ixr4Sg99NQ2AD4MpE3GSE2c4Jv1J0X2ZvTX1ggnYgbTC5x1yDa8qGAZLeT7ich2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2m8KJc2VjcDI1NmsxoQMpHGgKJECJqncISNxicGI89eIBdjm1scnNr7-DmDa6G4hzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", - "enr:-MK4QO-5av0dVBhDrwNoBkMeBt7ZJN0F8NrOOSNi2mq-CRWiTZZG-CqcOp7t9qjuuQhIi-RscfJyHxRW1yvcPyC5ufiGAZLeT8uNh2F0dG5ldHOIAAAAAAMAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7BZaJc2VjcDI1NmsxoQIJMx1m9LIofaV4RCXF5RyzaLZkRq61IaJbu7yRG9lIXIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QF6UfAiGKckerLH-N3EuPpcBqkRXPbXWq-ir9N-kDdBQZxiafoF9I5zcZDhZtlqCF3sVoE9TMi4NQppf-Z1rxYWGAZLeT8dRh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GaKKJc2VjcDI1NmsxoQJFec8UuFmn0tmu07iNakrK600BGlrxHh_sK2f82qYALYhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", - "enr:-MK4QDFSrh_p694cIm6RZ4uONpMkEaRcH9LHnrd99glEoGXpIEpmoIa8YCJJr9DrTRfuURml3_mncRXoajg4dmtFweGGAZLeT7xHh2F0dG5ldHOIAAAAAIABAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4xiSJc2VjcDI1NmsxoQOpjekMNl4V9McivNC7eRKkZQi1Lf_WX46aDF-TpMk864hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QLsNKnDBw1Ho_-SEg1MXS5sFVJjA4DWblUE6Y7IXWLiYQ4W0lDsSy7CpEzwyNU7SrXe1-RlSW_5H5LzU_ywsrPeGAZLeT8Twh2F0dG5ldHOIMAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjQ9WJc2VjcDI1NmsxoQIg-vBB9-5OOrarYUzumiirQZ01OeWbUF1Wi-CBEtJRoIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QI4JBnn2NoAAjb5Kb9k0SiniAUnLPLa4rgV39iBDBqIuCYQSXsjXiQguby7QitFRUznZMiVghIiz9p9GjXdgd0CGAZLeT7hbh2F0dG5ldHOIAAAAAAMAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6zuJc2VjcDI1NmsxoQJ5-KR2npQdVUZAd1HdHYts7qDfVeHvJDOCth0prC-ElIhzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", - "enr:-MK4QL4S9A8qoGT_8GCITvPBL7TCx57ULUlq2aPZjjPnmGLweeAft-punq4XjST99Jhh3S5UeugIl3rH9q3RrnDvXkqGAZLeT7mQh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_LaLyJc2VjcDI1NmsxoQNWzuY7G7y9FJlESwsCrG7DMzUrE7ESs1CdBwGC8CmpLohzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", - "enr:-MK4QF4vFBE44lGXPmNR0YdPC1XKgcXVxGi6pNo3SM7SZmtfJiDuypBq3SBlsNkcTG-d0WEyCXtRdhN5l2DMvLKhjgiGAZLeT7cJh2F0dG5ldHOIAAAAGAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4WPmJc2VjcDI1NmsxoQOEFAnO0rF8u_LHcT1hZKPcJKc_pjxxzS8q_jLEXyjYgohzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", - "enr:-MK4QOtmjWv0SLF7-sCbDXTidUu3eDaO5LRH0_1UBBRv3BfZDCW1f0IE9AGsPt8CfzCKZwhLM6qDg9i6Q7QqueoVv2yGAZLeT7x3h2F0dG5ldHOIAAAYAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoREOJc2VjcDI1NmsxoQLd7bMKI1z0ZzOPVmbsJTUZwuh09sEK60PJTBkr8Z5d0YhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", - "enr:-MK4QGPZwfQ1VRvztck8puc-l4453wOlE_GDLkZf21oekvenYGRil0bNPZfy99omIYDo_8Lfj-gTjtyMQNhfX-Gxf7KGAZLeT72vh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI9u1yKJc2VjcDI1NmsxoQOqOuh9qoiDqaOA9P3Zqe9Kr6LtA7BGX6HApTOwTw8JEYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QNoB0qr5S04EqGfFd2oC-8zfJ40EpEKX6comkVAhVGpzRcS5miDn3i7vI8xMq4rcP1f9UNmjf5synrMpkjtl2RCGAZLeT7LYh2F0dG5ldHOIAAAAMAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fp9qJc2VjcDI1NmsxoQM00pJ11HAcuKC2lu3qsmrFfinrKyEIJfI5AgaAXKwQqIhzeW5jbmV0cwyDdGNwgiMog3VkcIIjKA", - "enr:-MK4QPsx1H6cUFhgDo8IeVRxPIevJY2m3cdIcfDm67PQlT3SE_GLHiMXbt7OwNcLfDnmadblfze_qnIfLPxLbvlEdVmGAZLeT7FUh2F0dG5ldHOIAAYAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4z1uJc2VjcDI1NmsxoQJ3uZasVkJgtNwojOc12o_OGa95JidVTiTf2ZNg6v1evYhzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", - "enr:-MK4QLLmvX5uDrkBoxlU32GAniNWyfuq5dGdzp54Nr-NXwYBPFffMC8TRPV5qJtXRPCF0TMOfGRGtVUScaGHK7WhYKGGAZLeT7tLh2F0dG5ldHOIAAAAAAAAMACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7dg6Jc2VjcDI1NmsxoQPPUGx-0Q1GggcWhaFjoBRNM1zxb3-GZet_XVsCjQuQfohzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", - "enr:-LK4QHPZyuxlcLUFzQlV14cUrVEnk0R8-v0gI7LyFmrRbNsWGBRcv1bVBr4OsuDsQe7WCXw_MbzIPbRil-l8lqlktUsEh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ9Z7GWJc2VjcDI1NmsxoQLQ5jTn1P7lwT8_jmjdgTbtknYQYN1diCnUJ1meLGDVI4N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QKsnDouz3ORWxyOj86zLs9Y6EPzGGmAQvetPJYVi1OA8EgS6iqTMUumFGYlkrhwhlgl--RhVdJnGn6BT4nWbWsIEh2F0dG5ldHOIAAAAAAAAAMCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-E2Jc2VjcDI1NmsxoQPiM0IiXdbtvibXIinl9tTnU2oxUtQVCsSD8C5Fw5kkvIN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QBPu32Td8-yRXOiCr6oZ8Kx_U9l2CtrgtTdS7JJSrya7XmYrhR5PLufbQ_qheDZ5220i1GHFejGrUctcKqXL5b0Eh2F0dG5ldHOIAQAAAAAAAICEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GfsCJc2VjcDI1NmsxoQPVIZx2mp-hC6O-8Sc2trinfPTX1ldcVm872npcbECL84N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QCTAUicPEGC27830Tk47FIOJjLLXAucO2JWZBmUpqyRqdqgx7htej1mbSGOwdkvMy2wr1ppQqNNHpg09Nq7atbAEh2F0dG5ldHOIBgAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdH2zWJc2VjcDI1NmsxoQOa8jxBZtnN1XafI2exkfdQfYrCpf5nIN7NJbM8UaAQ4YN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QBD2UExDYapUhx4Gwwmj0sZOOe8b_Z_7LOwvupuKvHH7S3y-i1tM-a9MUzfKp0f05Lnyd1OebLqAe06SpN0RVokEh2F0dG5ldHOIAAAABgAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjWVmJc2VjcDI1NmsxoQNy5g7s97V6c_bliDX29X02VEt7lFtykziQ6yAQz4B7B4N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QKNgqPGYJb0gd6sPYicjvhzxX_4fwIs3UoKfv2Km7hAnILqc4HfLG46fwiaCGuGO8HWqhauYJyElmKl95HdkcnYEh2F0dG5ldHOIAAAAAAAADACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXyKJc2VjcDI1NmsxoQMd0ERS9Kijwan6Ok4AnconhbpavC3ChksqpaeMfFUgYIN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QHJU03COhJsMUjgIfZgqe5L9X6NTfBprKwmhq7MMi8pUYkWNplTk0mOFZFDCUdxQoAdXWBMghCg_siFW29NdSacEh2F0dG5ldHOIAAAAAIABAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAkzeJc2VjcDI1NmsxoQIKR_4srED3KxIv8t5HgcGDItwksuAZGkuTiy0Sj-nP94N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QIBsXm9oo2rBww1rjpa8gfUFgtC0zfdQOyj9Lds9vhNmUj9HTjeUSr2np5CmDQbpELn2y_5c68yHCk2HikCsbH8Eh2F0dG5ldHOIAAAAAAAAABiEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69nQ6Jc2VjcDI1NmsxoQKkClbynlGIlGlgJrwz_g-4ClmmbQZlLCrQDFwHWhV414N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QLKcBiOOWyItntw97roB2K9giftNayxWd66H5qiat7h1QuopDgg0RGF6_KRuh6jHWIlhUVUX9kIJfTkQYBq9hrUEh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLI-E7uJc2VjcDI1NmsxoQIPizTcMpW9300gIUyA6wzxPJVehLzRGzep9VcRIcZB4IN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QAW64M2-Mtv6f_IJ-wqKuf-uczJxwzIPs4aKFOu0dMKdROuPHYcsDKNHPoOgOvBM2fD6lI2XeIMmPlkHQs7fSbsEh2F0dG5ldHOIAAAAAAAAgAGEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEji72Jc2VjcDI1NmsxoQOwaeQ96C8h5DJ9qnIwi0MD_EW9mWnVqq8YP7A8IhRxf4N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QI_7bYzk-6IKSGx0hwXoUp_4SE37TVNrIo05XsYuCwewL1ANoIv1wTlFPiqhSSdUppGEQr7m_dBCMIiE5YvYfZkEh2F0dG5ldHOIAAAAAABgAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_f11yJc2VjcDI1NmsxoQJcyXAkRddQMRW8Wq_uDDaqhfRix2FsTlQpaeNg3cTL6YN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QOcFoKeISpC6WEzMFOs0Fd8g5O3zxHR4YrtOti-Qrm-iHZX7R8Cm-ZlWaBAC_tv-KQ31POPAiVE26QpRgmnERHoEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDiYIuJc2VjcDI1NmsxoQOM0fzW5xagH42YOYCaUR6TlIWaurBsnTa41TOg5IMBRYN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QDwhH0TLPcX9EkImgdegz9n4DN9U-u6rx-qA03Idi3WvL1tqnEWB54qSofoLPlpRCk1LEhPcekgUE2IrgfSKAGcEh2F0dG5ldHOIAAAAAAAAwACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjJ-CJc2VjcDI1NmsxoQJJnCea2UoBVZUPpyZPNZ8lCj1sPxtWP7v44pA3bAXFFoN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QDWc9ARKxtQzvcfhsSSuOQVBXtJf4uBN5khbopSvlB5mRhqKJD0DoWr1brq0Fu7aXtwxLwz3tmW88gHRyfgNeXsEh2F0dG5ldHOIwAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW3BOJc2VjcDI1NmsxoQP08nTiii_CUneyjjQiQOxlSJRGOBy5RxAltma_eD2kqYN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QHzsDl0sImNgHoUUQZHERvokg6bzOIMRqld5y_I3Dq76OcCRlR1B1NNUBZomkckV752vh6xwgh_nuU8gC5vhkqAEh2F0dG5ldHOIAAAAAAAMAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fxziJc2VjcDI1NmsxoQIcnSoMB5m__EkBOblmx6pFVb2gWMgytvG0DCK-7Dc454N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QLaDD0Ce92HbHN_Odx8gOLWetZBBkdObRIK_tGnbyAMZF1D0lOmSazEXtqb_gcYyYWloH2aLvUiIhFyfBcqdFKgEh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNp5mJc2VjcDI1NmsxoQLthQWPCxwf6ElsjcoeDy7xWTVy0oyZGsWLyWJhT0AVZoN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QNbU3sIX2x1pEdOMlHnyTnf_qKCftwHH7PtruMWDcQ2FeYxji2tu79tZy2slCZYcHC3Kt2yY6YNA8xuXmny-qf0Eh2F0dG5ldHOIAAAAAAAYAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs75jmJc2VjcDI1NmsxoQO3hlCHVZ2KkCuU3J0cmy32kyeaygleHpvTj1e43JJLJIN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QP45lW8RQIrJrUYu8JaBbdHsFCL7c5cTwnbsf1v_I6M-R1Ugjq2j77Fzzpj7eE1omCrXkq9NGuN02EqnhAG0BYMEh2F0dG5ldHOIAAAAABgAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjX6-Jc2VjcDI1NmsxoQKmt4RKybkmaCeLp5hZ4ubq8aOrMujHCsZQGkEIfQX63YN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QPm1dSEh4ejPKAgCUmVW8YfTCnot8TBcjPl_9DUK9x8pHAMdgLBG4dQYU1cVy0VkdQ-y7PrCWuS2HVGVWgXs-w0Eh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRrmKJc2VjcDI1NmsxoQJ3YV-wCUUU6e7D41mVpE6Pl2IxB6u4Xp3RiuVW72jrKoN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QCcjOXE6AFoUfRAPy2ADwoHrKA8e1AEvONG_TfeNEA0lFQCgrffj14h3aZtqzRSmDx4kdmz9Aq4xI_OERsFSwsIEh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjnAqJc2VjcDI1NmsxoQLrpyFMatvbIPm9lThrW9SdBdscw1Ctj4OL4Cg71wC1SIN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QODfmZ3HU4QHVggOpxp1HVczob3ce9UwTGhSxE5tiQLCH0TATU2t4i_WEaicUJMRJi66Bmeb8c9rEoGvTLdmOSEEh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5deB6Jc2VjcDI1NmsxoQNj36dwUn-Vk4qn0H6Pe4qhOYluSopCikb6fF2Kh-26JYN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QAaQ9jSV48tiTtHzL1aocXbrJnt0r1uSituGZCTjl8mINNxn5Z_Brf9J9oThAK7U67uO9ChPzEarhfhvTGO677MEh2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4YuJc2VjcDI1NmsxoQKdiOidyLx2IMQyrI-L-a169keDHUmAjMZ3_8vurIiHF4N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QM8rHJc9l75ns1i9tuZyux2m9CtFi7zh9Rjh6t38OhCGTLE_Nq8ZMyg0oy5ktpkIoIp6v5T2DVrmx_P6iDbtHrwEh2F0dG5ldHOIADAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJgq582Jc2VjcDI1NmsxoQMXBD2dqEKFbP0hIM624HswH20R-LlZIQIuTsB9nIygh4N0Y3CCIyiDdWRwgiMo", + "enr:-Iq4QB2ny1q6gkBjqNRU_e-GTbpcJQcI4i3cIZDea0mnAzGgbUTKH8j81g9PRl_-m40F1V4GFBlqZElrcbGnUj9AjGeGAZL8bgmtgmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQJJ3h8aUO3GJHv-bdvHtsQZ2OEisutelYfGjXO4lSg8BYN1ZHCCIzI", + "enr:-LK4QF2XD_Fe5H9QMVVwBoDs6P_37eURcFvNTcLzOc60p_XlDKIBleMgudA7nltZ7TyAiOuY0BSQzHsdv5iUs7sFyWQEh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQJJ7y6LF_to7NYQd3BVRW1840gm5r1Lm3lfAfC9Wqmw8YN0Y3CCIyiDdWRwgiMo", + "enr:-Mm4QMpfvuUXcMcRx0sCtnzvE8zTJEm7BAwhFtU6CvXCv1i5Wsksx0P7ocBEJLPHULf_O3w159cnbUoB-XZuyDBfME0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82iEYRxdWljgiMpiXNlY3AyNTZrMaECDdViaSTH6xjxrJT_gIaha3_CzJ64OQDQwTdbcN84BGuIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QNLiswecY50ofHVF3twuOmJCqqdzOviXI9xAmKU3SBmbdDUr_v-dpxcP_AHoYMBw62yEcpPRsKzY-yes3wMoJnUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MADIRxdWljgiMpiXNlY3AyNTZrMaEDgRLt4r0C6K63co6eoGRvi55-viwcW_ijblPrlNVulAqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMM5lT_k074lQ094vF8rGQXkM4sLmti9kTbwuZF-6fZ5KhTlTxEAWI8x5-EKRduIMoCaz6z0SfaYeOsfS35jr0EBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEoSM7S4RxdWljgiMpiXNlY3AyNTZrMaECW3vJ2OZ6yjQfrDB9AW_5J_YZUuQRFsp3U5z7VvCdu9GIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPw3-nzQ6CXpRWLR_eo4KYcoshqRtaTlmqYTlwqcW5AtWMDuF6o9oVyUhYJ9BdqP7x-vi4D5C83wJ2N-sRX0D6YBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEjl3-GYRxdWljgiMpiXNlY3AyNTZrMaED9NVIDXAwA2kDI9wU2y1KV7oGALUrc6h6LQ2zqcWD7UWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QO3f8z6h8uhY2fOr4iOmUkfGN8Q_ej-DOwcHJ6P4dCqWa20aA6Jxac5Ta6dcfnwdvSfWUz3ZFWUU3n3mmkNvjuEBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBQvoRxdWljgiMpiXNlY3AyNTZrMaEDMSbjjMae81uRoMG_hZjfbXnLLuI9eEKUkKShaTBkfEaIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QFJKhdNYDyWgtK1rM_QsbocVqvkQGVrecxbcMSMzw58JN7Cw5uJoUVJJxxlY1bWzZZ6Y6fuL0MxVKVj2jQS-F-MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEj26p9YRxdWljgiMpiXNlY3AyNTZrMaEDx6X-X_2EgQ2AUWkwmm1GFB2SYrm7XihW-IUlx5u0-FuIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJkcqvThmP8DfQ7T-kwsIc_7J9VZovhRWNJJ_3mWksaiJPT0YYsLwIRMxhZaIoQ96umQDyXaAnYccJHXo4UWqdQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEisVoUYRxdWljgiMpiXNlY3AyNTZrMaECcdygVaepRRqO6BpryxhbQCCZNRxJ6C4pUujAXUdM1E-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QH8zBo5Jxm8c6Tindg5gE6Ju94Zqik8Jli6t7p8gelwJX9hacP-9UteVI-PnQZNnXuTQ8MEWfkl_zyklzF4dP9IBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MnPIRxdWljgiMpiXNlY3AyNTZrMaECRHo92MBzVuUg9l0XPGpT7SUm060N40IShmk39pg_TWmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QCaIOIsJoVLQfna3OK6gMN0YBBpAhjrD6wh1zKb9SRA8GsJAQMREOg6uK137hV2IkqfieKvIEPiYUOsJ8LsaBf8Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibgchYRxdWljgiMpiXNlY3AyNTZrMaEDbe9GtmMNbJRzijDmQfDQQN2YkGFTr7ImH9yPyveaxOqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QDkVL9-sXu44WnfRdLee3nlGAiDFE0mqcahIKzPcQx5IMDcWsKddzjk7sIa1t_A3OrbgKZ-myxp-9Ft98lc7jYEBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEvKb94YRxdWljgiMpiXNlY3AyNTZrMaEDz6UjXFkPJYpRmVYPyJVGefekeG1Qxkg_AcDKIc6KNEaIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPqcZ_jT7ZUOkLi-BgCExPlUytIP6jIvhV56nPV1A5pyMzKDnk4e-6a5_1seXtyQQluHkfAjZn9_H1NVXVdkA94Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkH7L54RxdWljgiMpiXNlY3AyNTZrMaED0EyYkEKk31vfdXMLYneEyiCNimlOgdm0qcoI5YVZ7b-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QFjWfPILQklP6hndcbtDNhl3vGWQkXf7pR8Kun039DRpClIEwvxg3MW6-JUcVNjmD3MtJFsS8702ZG3fB8YHEJsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MG04RxdWljgiMpiXNlY3AyNTZrMaECYV9wARPI7Y69DK_yoe0D58LPTF3WaIHZmkTzzC-4PZyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QANhzPcE163m_6hv99UOWiKNmD_qvUkZOhBP1jezm-wdfji1fL0L1yue7l5kb8TiSs_6dSEeaykst-bZ4OpChQoBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJB6D4RxdWljgiMpiXNlY3AyNTZrMaECOcOVxvzmKm5yFLyZBA50bzAWCi4wHzlYBIEujIFt46SIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QFGHCpBCazbxQbjG-QQXVNt0XKjOSpRXaseRQ7eCciBpWfT7VrRJ1btLOuNMzyKpQcRMfmywxH7LwK5awZhdpS4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82n3IRxdWljgiMpiXNlY3AyNTZrMaEC8WOCzbdKFeg3dYciZ7QKfXxNss29CqaHG5iwm4EHQcWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QCGRQd2a8-pIgsH3PuqA5NZjcwIjVH9H7Dh6cPJJRsEzNojxFtDzY8rRebHKb1xrVAZPXneMuw5K3okA1k2KOOwBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBRjIRxdWljgiMpiXNlY3AyNTZrMaEDMOw8ey6EZ_4GyR0kNDoB55it-p7PzFPpsXyc4TFMPRGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QLaFtJfw-TGxUNAHQO2xmnvYDnmKgjfJve2MgrWG9OPaMnVDlLIAIz9v1_SdDTS1FH3vt10iU7YI5t7CIA7sKLsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBi-4RxdWljgiMpiXNlY3AyNTZrMaED4PMVrXwoLyISWzFzYU4cd76TnpxIZwIK1SwyFyN9rWSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPUpI9m3garHkV47o8jKj8VGTaJTOwpIWnUb4GlD5r-vK6xC06h-wPtUzQngBFk_FOUfuw1mcqAP5L0yTUozdHsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCrsz4RxdWljgiMpiXNlY3AyNTZrMaECfWt_Vji8tocNvFs6orlyMLsoNkQa19BNqsbXN_tUhkyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QHJGsttZD0_WxO_CjaP1s_gqJcb9gCYLnYI8G4qUi3t4FYGX3oJvkZD49kNfRx38a48GjpuBCxnHpd78OSxxgnUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeNaNoRxdWljgiMpiXNlY3AyNTZrMaECseT38XZgU025QL32df-blQfLLYdrby3pO-d7axe0zF-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPtT8J4rpYkixx-COebnEPreuWv9OpgOGOvM01hqZ19eeySxCxOEEVHl2r2c0BYwBuct_yZhvkLqUQatRORlIP4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibhIf4RxdWljgiMpiXNlY3AyNTZrMaEDjight_62uShKNt4IorH13hfqm7kZzVyFxXKI_qDlsTGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QIW31dzBPtPxCAKvj-T29sFb9wCDM509ANmDizLq5ys1YJCcILx6PotmJxF4g829FlDiqSsREm4da7smcPcAalMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCE0SYdtIRxdWljgiMpiXNlY3AyNTZrMaECNWg27r6a05oup0qlmM9iSuw2sj1ulbCSGGPKDYjvGDKIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBwdkGDZH5GMc49ZkabCo4PbLDxKUxjy9AdUZSe6zGK4NCrGq27i4bkEXwg7IrZtzCJXhfgMocUz7a7uBWq_jrQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2ObP4RxdWljgiMpiXNlY3AyNTZrMaEDRDkl8RqHIqP0kgd1-bhZY18QRV9nfpWPr8FEKdRRwZaIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QFCmA4GNnGBuIdevzwZ4-5GFN0cYDqGQucQ_zZyjr3m1Srqg1eN6RuRj3gKbxChAcAp6hVOX-wl2fFzqRpsZJ-UBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEneYo34RxdWljgiMpiXNlY3AyNTZrMaEDX6gmy0PDR51SEtytWsA0IxCE_LZdY_x9FiMT0WIYJV-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBOzKDeXEfUTFsEBk3tX2-OvfpU7uPdQRl6iex1r-N-oJaB2Xw9Bfney1x4k8ZMsHlHFPBCRrcR2Lzmu2ghHqVEBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsj4zroRxdWljgiMpiXNlY3AyNTZrMaECpp1D7pHZbF8l6vl4_DWdm4NJVDNMxGxvti-8ZqHrHCuIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBL6auezk-Zi385j0PyjkzGwQJW7TdOFZKGZMKTGRkI4fxTSTiHLe7kTvdjhBq4kgjPXvUnFiXR6AisA8a0w2lQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCr3YYRxdWljgiMpiXNlY3AyNTZrMaEDJ4xl2Our0Y7OKsSDX9f908HznXm3PKzmC9zD8OB2d0mIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QDOEqa8lWRsJXIoFqGGytT8xBJuGu_eE1p8Nob_QQI1-B4S0_6JjVoyH3pwfezShdUj9RdgdETUon3bXM06UVSUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEikSL4oRxdWljgiMpiXNlY3AyNTZrMaEDe4qmuHzM_TfUgfRc_0nuiQRz7S2_UhphHbgC9ilzgnGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QIPjOKp5Y9Gr2gS3OnAr3_1GxNU2yqs5Nwv-3r44yPriBJv5pIDm0vyJe7Pi9FQCBmikt00IXoO_pF0zwWHv5b0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtEjL4RxdWljgiMpiXNlY3AyNTZrMaEDeCId8CCbXbvI53xmkqjFgJgsqmxbnWE76f90OiFsmYqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBOCEcm86USjdb2n8zRwzDfdEo9T_rKvRGLJ25y2PL9Zbc4RKEi8yOWk-vJ4QRZtgQ9PwgBUi0Zi478X_Wc6nlsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEgMcixoRxdWljgiMpiXNlY3AyNTZrMaEDBTPknXjsIhdfxDYucKiVm6SgYTC9zohYC5s0YV_6EeyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QEgoppH7VZWNAb398z96aK2gDlWc0x_EQlDjOKcp6DJMahC6LSf9yjXHmnHzdii_r9ztNMXw0_b9gsfmIG6so14Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeOpZYRxdWljgiMpiXNlY3AyNTZrMaECR7znvBtmDQ80qnoAeO_FFgwB5_tALE_aZiub5YgHJx-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QCnjdBwJ6xUGvP0wOAizMDUtFJ--0Zq37c6plEGsiuu3XUk_JMytx7I_LjQHsFx54GXxSP5T1x9-tJFMKq-mBbEBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeMtMYRxdWljgiMpiXNlY3AyNTZrMaECm_3lxmnovulk3kxkt9SRc8CJX591ufqSGLDUl2vFulWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJRpkRrnmIUApBcQsRl8my3qx_ThNeMuY7PZTRzgqDqpIOrISZOFpCcXRTMRo_va_AzAMNSLCt21xWsvc4iX_FUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtGam4RxdWljgiMpiXNlY3AyNTZrMaECTsHuqtUTyvnbr_-bBlPQrDjJ2fK_fo6EI8cGBlkT1taIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QHF_2oiGaRM13lElGu9KVq6DcllqoHVbXKnT9BMZsQHDeQYJFrzRl2GZuzzjdzMsb_Qa0_fpwPqacrwKA1hCbaoBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeiA-oRxdWljgiMpiXNlY3AyNTZrMaEC5n6EKmWkFr_F_xhKlyL04Q1R9l6bPX-ew3l4_aX3tw-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QLZkxDCSlFHNHrELwY3Wbck4uEBfDe--Oe-ymSSdb54fajSDO91ILmm5UWJbiEpgaQ-tOaRBI_mzkzrBK9vOLiABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBqxIRxdWljgiMpiXNlY3AyNTZrMaED4YrrKCAARO7iCBkBCKg18IRChlSsrdgLXUFlWN7cAVSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QM__NZQmR1Ujykum0flKS6es2lXTCsKMnGC4s4J3g_m-ZEk8TADO5s8BtdJMnBSJIXsqQsPvGZRCOrSye7UrcWMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfXIRYRxdWljgiMpiXNlY3AyNTZrMaED-132tNKgfT5Kvdtyoy08SWPtnmqbKZYCTcw8F4HL6iWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QIDMKaGp33io88FS5RJXLftryhiGmne8QSjP2ZlCqB2mAQu3uOEOoeeNQYrd6ZJaA16xDvcO1PnqLCEwzuOuoiEBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEizulmoRxdWljgiMpiXNlY3AyNTZrMaEC9Oi3dcFrr0j1P39XIVsXdoNc9AeRZG-UVkEG1C6j8aOIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QD3COs2fIKQrvFG4cphKA0U4Bg7IltWfnnAzxrONjqkhWjbrXP14d3EGUIEuOd7FzfZaIL6bK7CwBSQRH_dGm6ABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEn0Hy14RxdWljgiMpiXNlY3AyNTZrMaEC02svkGF3_0dOYuBvvHKP5WqW8Vp8hfh6FOTPgREZWZeIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPyFixsMFYX5FEqsq6Su1kZF0qUlR9WSdSlXGki2a1NSNdKPYx7teRVfnny22rCgjWQzEJrh9tqI_WcFNg_9wWgBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEaPjC2YRxdWljgiMpiXNlY3AyNTZrMaEDg8vFkCPwfrszMGSNp9O1d24cq_A-4XIxFlMAaBNP10WIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QLTvtxuCz_GEJclTPTbY2PFtq4sD3LD4HWglNJIO_tUcQ6QrtgHThuyKz_sIqE1_aW24aedXXpC2p_zPWO_WV9MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQOJWSIRxdWljgiMpiXNlY3AyNTZrMaEDZpd0NBAzCF2-LHUVu9_g0wJKoQvnEH3PfX-rz-WoC-yIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QDZSQ1JfQl9jqm4kIEzOTlvO9KMjG5J8xDB6cKRBGWtuaYItPaRDzXJybMr0yV-XmE3Vp24s5jks22dCE-nlRyQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpRbtA4RxdWljgiMpiXNlY3AyNTZrMaEC2YFYSOh3-zoIqHNAN3dzKXxZcfzaTcIO2eubX3BiEQ-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QNti3RuTSPH3aneI9m5R-4c5SUZqaOH_njvk2ezJUj2UQDFkgm2deWLOGkn0jMUjRyMOxXAluMvIS_-fDcySS8EBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfVSpIRxdWljgiMpiXNlY3AyNTZrMaECAZcUD06u8vG4odGwNWwnqd5YvLQzWpZWbcNJrUXl5UqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QFtC2SkZ1Fmyfjg2r-lew5YX6AJU43EmOhvGTKLjDclPEqx22L809fuZibYzdUC4QziO4lw1NfvW7q3fGbmobCgBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkr7eV4RxdWljgiMpiXNlY3AyNTZrMaECWM-19HsETwrty153VQK2Qf0lggex_NP-RUhkOgepnBWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QLaSJFtlYxdSqJvJFn7K1CSD5ctr8EC113_aQYB4V4aCEn1h1rxw4z1WFUcHhsLVvtXiRQT8E7rEuNA-zJYDe1sBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp0fSfYRxdWljgiMpiXNlY3AyNTZrMaEDJzRMI6aBykFmWsQZ2TFFjQmZ2rbHqTZ-LYzbvOobl8eIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-MS4QL7la6R4Sp8mD6nbUto7mXQpCPIucMXYonbxaihETbddQGirx9-Qqvtx4Ngw1g4_mleYM_I0H8i0-KPQQkbQjjMEh2F0dG5ldHOIABgAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_Gf0iJc2VjcDI1NmsxoQI4KtS1lao9CxXhT-dthQGovzUEnODDPFYl7SBfEA08R4hzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QFSt__5LhjnRp9F-Q0v93uvlKpYyeb42V5qvRNSFkHxDPTHJ84j31_HZVJtCfeIyfnKpScbEklmAC3O8D75hdE8Eh2F0dG5ldHOIAIABAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2s4qJc2VjcDI1NmsxoQPDA64YfJmZDlj1LFjnJczhWpTEl32kc4RXy0cMiA6hcYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QBqSz2fdFrHnpZnrjpOXXX7DRhO8IZiDM_Du2M_I6uYwEEcwfBPsa9v2D9Pxz2eTXJPKQav_hHMzeO3-59Nz-VIEh2F0dG5ldHOIAAAAAAAADACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3e-OJc2VjcDI1NmsxoQJ6gbvJoChFGM3fziLl6TfKD4Ddt_DKmIpA3F-nijLMHIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QMdKhukqEi_AnWG-_qI_t3CrFQ8p-uGOEYBbXuJnbDxBSqdPnbpx1K7b42H8TQpxr3bJeOZuZ4vz1ret7VkJPocEh2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31WCWJc2VjcDI1NmsxoQIEdDMa4eWOEzJPjVoElGm5CKpvUdD2VF-Q-o25AyV43YhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QLB-DtV5j-GdScoGse3R0ZsEXQYkh3pZzgLElGH__jN7cIaFuFfyw5vrTbxWMKJbHIYaaHfVcPrz2YFGSIJ_hXQEh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69VfuJc2VjcDI1NmsxoQL2OAp25wYmzzzJKubNowvK5I3nHC4I5eEVS6R43Z4C-ohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QE3-f8qUWYbx1zNdoh0WMjYaHuRvdo33xP5dNJQ56pBaMI8GpGwvLeaWun2UbF7OexlrL8evl39yhuUOPrepD0oEh2F0dG5ldHOIAAAAAAAAAAaEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKAJmyJc2VjcDI1NmsxoQNE22g9OW0JX2MsomMWm64rCbsiSrZ4rB3cWB2-kT1oWYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QHYLVxO7IRuJpcYeQJK81tow8_P58XnIfYkVoQwOBDnLU2QiLTNtzDVHBLTLwpMrth5XwOJhjlC4z8L6Y3ffUBgEh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIrFV6KJc2VjcDI1NmsxoQKA5AkBxLZePDZUsYHLgsf10Ib7x_PdYZ_ORAvLNHVOoohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QNJOA_EYx3fSHmfWFz5ffCCfRZW5n3C9gVAn64-1Vq4vZzYsmtF2fm6l4GQd53bIbDJO5XXwr-Ltaow2PbbNxq8Eh2F0dG5ldHOIAAAAAwAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRzgOJc2VjcDI1NmsxoQLownRcAKPtJvJ24jFhNL-XVkf0CUKRpaQCMaOX1DdbMYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QKjT4PY-Bf8hyxURb8ONCVH4CPTc8DSp1mTlEDyPcr6rTR1G3AbDuFEDcL5z97K2OfeKwMwp9V82HmwRwC6UWMoEh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3H5uJc2VjcDI1NmsxoQJjQFB0Q6Z8mh1dbe8DsbvVvfgX7na14JR8OnzOVongfohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QAhMlMk0Sr4K29zo0qVw1ef4ufyealQRdIAXqbgtZVh6ab3o7WKx5Hvr3MK3sc60nBQB3hNaMpt--isKv09IM2EEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31NHGJc2VjcDI1NmsxoQP0uJtV8gdLm995mg98Gfp9L9TP4AA7wCZKSZcl0aYeLohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QOu9DJTE50sYY-z_lU6xozdB5LJwhfCIPCUNozdhjeihLAA9CHyL1GBeJqJjvoIm5RIO6iiNZFp3ZB4uWB4hzuwEh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7uVSJc2VjcDI1NmsxoQNWqxvo4uv00UaK_ETex9kqaB3xX17slXTxdvMqeHWUIIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QGFtyo4ejnaQuOf6w62R7pWAkVQs02zZqiKB06ARhNsRJGL4TIewlqV0-cPSdSguuZYPSRJddrhHMRSnIa6kcvUEh2F0dG5ldHOIAAAAAAAAADCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjHhOJc2VjcDI1NmsxoQJiLwrZNj46tPKMIaXyZp2D_dExmxjHMH_W0bDlSw4xEIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QDa4tn2FRJLfuAPGrIIEYcPMaTlJlUqoHnZZBN7VX95Rbwn9cFN93mdYq5klQRfL3pSNo-iYCmN1SqIkm3B_fGkEh2F0dG5ldHOIAAYAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fqkuJc2VjcDI1NmsxoQJX1m_Dyt2QJekkL2O3f44GeJvqGXLPLLevk5oM5rNjpYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QOxOkGvFqhKllD4vfg4xfwf1OH555pTPxd9n2IKddj9cC3v6XpALXuQOoFe3MeXuKcRSWx61LcTn-8kzkmFEIEADh2F0dG5ldHOIAAAAAAAAAAyEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3cBaJc2VjcDI1NmsxoQLi9EnRObjSmOysxaGITFdArRXVmpJCMKRkMX8KSc4rS4hzeW5jbmV0cwaDdGNwgiMog3VkcIIjKA", + "enr:-Ly4QH89XtIf-D3uX6m0YjkoTH7eGRhBGSZiu39ib2jXX6V5fa0QxUYabZdPl-5Fdew-rUPJ8sYuDQXYdEVeDjKwmKQDh2F0dG5ldHOIGAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GpWiJc2VjcDI1NmsxoQM2u9Syt4BkQn-WSycLUXp7ajuESEUtVdtsjNMJ7n7Me4hzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", + "enr:-LK4QAH0JWA-ME1EiLIcJmQ7h9mStB0pkcV4R8d4BkG8t1hOe47k6vBNtEkMV9rBlRXlFIFfKwMcqH6h8sw7rgK0ORMCh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNoYaJc2VjcDI1NmsxoQK-pYgRudAjqNz7OVA5a2qmtxtsx_ZmDKwZm_Vub7lWPIN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QDVEJYjwK3H8Tj857ZmNZRo_20B7fYPR53keYS8pPIrHeiPFCwOBok6fvWr4457kOwXoszf41IpJEmFNXingyN8Dh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjPAeJc2VjcDI1NmsxoQP6kCCPnIwk94L0eTPSyEnqtvM1yQZzg1WkDkZKjLdaTIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QETJyo6kF40C8v3SYt_49v2tFHxuJiGNGFtr2GUHtn_pdHIEXYEFCAkooMLstcQY20qlLk_EYzs4nPx66swzZnQDh2F0dG5ldHOIADAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-6KJc2VjcDI1NmsxoQKIjpnE7-XBEpSfEM3OTxwMirrmlWmuWxYTtuwQDaJ2XYhzeW5jbmV0cwKDdGNwgiMog3VkcIIjKA", + "enr:-Ly4QPJX60M6LiSApuKzABdZGcRZdXeNs9YK_RXkOi7mu-XBeT4p6ws6TV6UOWaQNghtOQBGt2dwDhA75oK_ZoktMCMDh2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhC5lURmJc2VjcDI1NmsxoQPyysL6sOJtdbbxCZ5R1aJjUfQmJhmE-I_xYqO9-i90johzeW5jbmV0cwqDdGNwgiMog3VkcIIjKA", + "enr:-Ly4QAw204L45p1Mp3ryCSdVvsHlBHMVJrwScuqXELpp7k6WQ8Vt7BypqMOSOVd3uL4ROT4R_paqzfrMIR-fFKItNMsDh2F0dG5ldHOIAAAYAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4ByyJc2VjcDI1NmsxoQMJdFDFq8q3DhC943QMFSxkkluGHNsNvbrTTWKD-LYr94hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QKJJaj_g8L8Okg4S3MJmQ9ZcNLytmtrPx_FY60TD_Pn2cVdm-PaIE9p5csITOvIpu6TYY4zBwc1uIE5FC4Vmh8YDh2F0dG5ldHOIAAAAAAAAwACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLymYWaJc2VjcDI1NmsxoQLB7079lklX_9vsCAj2LZx71-4Dzj-MlLn2qmj6UiDjd4hzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QMZw5ndFHQP8xRF46D_k1eyibF7FAypRq_oPkQioIJPBB2VdI43v2UV8Y_A0Ll0Rr1IoVkxGUW6JSP_naF3oStYDh2F0dG5ldHOIAAAAAIABAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPPX46Jc2VjcDI1NmsxoQI2VB9Qwv9Azwm5oM2MXDd-wILue3jE2DxVsVv3HKoBNohzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QLpIqVziOnAZ-U2-uUgNq9EiEukP-Hsmr1rX5q9RN6bbOaMEJfgiQftGVje33Xz1z0YOqRR136VEn8r0jS5IFd8Dh2F0dG5ldHOIAAAAAAAAABiEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJK-Uy2Jc2VjcDI1NmsxoQLH5B5DL6IO9nhqNoj4sVyyYteRN1j012_LZ5HDGFaLvIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QKYuxsuhgcWTcwC-LfLKwBQLVTDmMg8iGNwa6Fu462j2IMCNKx1I-Vb77JxpDQs6JIq23O0sgvAv2sGkxnDAf9wDh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRuLmJc2VjcDI1NmsxoQJoV-IcjTx1TkZqUDsKULphwU9maN4y7uLmAzQFycAAtohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-LK4QDJp2U08hakweMKge9h1AHrsr28cIAMeY18b8-7PAathFBuUuO6sXyJABhloJ94uWqKS26YC2UgA6H3Moju7Bb4Ch2F0dG5ldHOIDAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKesmW2Jc2VjcDI1NmsxoQI_jFdc5GSJ0TnwA5DlKK-doN89Tr6oXDmB4KxWwzYoWIN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QH42VUJjJxw24sBTppaF190Pcn0laRqa3UUxcR5EoA-kLDPl0EAnH7hqnD4JBJ4BjkJ4IQGgDjquHUoWJpneAWcDh2F0dG5ldHOIAAAYAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO21QqJc2VjcDI1NmsxoQKU8u3T4sCtMUkucKyRFXMGebCffrMnss3P_52W55RJIohzeW5jbmV0cwSDdGNwgiMog3VkcIIjKA", + "enr:-MK4QHMmDt1EuRPEgjoUJ5-leNqpUqIZBwWmzBrR-a_2AO5eFYukPyiE_2VHH8rVTu-CXpPwX2KBkSJBeacgF5VYCwiGAZL8lfxmh2F0dG5ldHOIAIABAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjybOJc2VjcDI1NmsxoQJS3R2VkqpdkwyZkZQMDMU_IF04dLxQt6NAf70kWcXYvohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QItySKXmpWDl3tLnVqAP00A5rFrlzBqfYbEXriD1gnIpWpiQIQ5fPLyUQq3leYmC-GpbtV6VQ2Iz9E_0hfKWaQKGAZL8lgN5h2F0dG5ldHOIAAAAAAAAAGCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fSeGJc2VjcDI1NmsxoQPMIZKzBRt9YGP7hlJHA1LzFAm8URxH98D4RDmQhKc-yIhzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", + "enr:-MK4QBlCr5bxnEMn3xk0GsS48gxy66ZVUBu6hJKvCJGTy6NhM2d8M4l08S-bqkN43z6swzN57bJ86Lcq9LXkNd-xLC-GAZL8lgKnh2F0dG5ldHOIAAAMAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5dy46Jc2VjcDI1NmsxoQJoK-aOOTD9lMwTCcO37Ihmcnknp9FxO9lsFYBuTZRfGohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QFP-ZBOIUZKl24rwQ2MDBiWioMBQ4Oi_rMBXRikKX0XDMV9-nXe9ITJJPQlWPFcSNrVIwcah3Trw5ImLKblk3ymGAZL8lgu_h2F0dG5ldHOIAAAAAAAAMACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES34myJc2VjcDI1NmsxoQNTVdI6Vw-YubsEVxTl5-JECJHcsESDoq60UruR5JwjcohzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QFEPaQEsgH8YL5Gu9Xw1HdSaCjfHBaavRcuwRlEq3QulQdU3xLoPXV0l_zRoEMkdMGh-5e3AY842xFamYub7ojGGAZL8lgByh2F0dG5ldHOIAAAAAAAAAMCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXU2Jc2VjcDI1NmsxoQIUCDXAKfrPVgTp5yIYkGgneVdc5FaYQjnRSAMD50_LIYhzeW5jbmV0cwSDdGNwgiMog3VkcIIjKA", + "enr:-MK4QNOSfKR0-_DO35S3ogEDB0HyS5O1KVG3AG56YUsSdTbvDq7nLS_BQBtYF3W_JwHjOLidbyCdsSpEZ73iMJuFhEeGAZL8lf2nh2F0dG5ldHOIAAAAADAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhMbHVWCJc2VjcDI1NmsxoQJmKRg0hEM-TnwPj2ilnshK9hGixG55MaGHv_vnYASWBYhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QABR7d4ppxIxFOvg5jUTJ2mBzkPjvsFAmx4ijBOlYgk7AU41gNphw78hzxmeCEw0Wq7LK5YTuHUahjz8WM7i3tmGAZL8lgVIh2F0dG5ldHOIAAAAAAAAgAGEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAyyGJc2VjcDI1NmsxoQM9MtxjAx2y-mL3gQD25yWl3Gks7nrEHGEM5DvSpX1rLohzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-MK4QCfAmFbSe4QLoUDERuSZ7aE74lIfXnXRkvm7cjjayHFLMVy0XRQxxvxRLBoLpZV_-SS-lQyaVDkjhmNuv-igbTeGAZL8lfv7h2F0dG5ldHOIGAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GdHKJc2VjcDI1NmsxoQKl9J1dyW1CnoiAN9is5uNLnk9op4wIIXWVahx6DsLmDYhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QEjbxm5EwlJUp062pFTwpbnyOHUZJOE0BnxBuQYro80aWwzPxuYsj9S1zdOEhtMCadpHaueKsoJtD6x2be06XwyGAZL8lg22h2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3mJJeJc2VjcDI1NmsxoQP68-24KkowwXNVIM5A5BlStNX8dUR636iyStKqFuXDIYhzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", + "enr:-MK4QPTbd5CgBXLtFu34aJw8TR4Mpk55PBJj6RQTZP_HPfSFOhOpLI4cLbR39tBBShjc43GGKhANt2RK0hHYUrMUNIeGAZL8lf3ch2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoaVWJc2VjcDI1NmsxoQK9VrHPA291SJwcKGe4cdSJdnRc2imeTGuUscFIlzIRSIhzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", + "enr:-MK4QM6qzQ2kwTRRe9dRGEGqpvdN_6czu0t3gSAO7ojsuennXtY2y2h3HlNoI8lFvQtjXFVz-TDJTia1aabby113GgSGAZL8lgc-h2F0dG5ldHOIAAAAAAAAAGCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES37GeJc2VjcDI1NmsxoQLGSNIMObiRYK12eYlHVqXrRtkjld2qnfqeymyqS09vNYhzeW5jbmV0cwSDdGNwgiMog3VkcIIjKA", + "enr:-MK4QC1IbLWxtbrF4aiHmvelea2gn0DUjRQLbOVjfDvIg7NeCDkmgHcAULDfyv8nokHVadeHU_nZtXx5KFSWMRThXpeGAZL8lfxSh2F0dG5ldHOIAAAAAABgAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6aWJc2VjcDI1NmsxoQIRdEG4LqcWFxuGL8rKnuloHMaXaWcyTAW36bQF-vq43ohzeW5jbmV0cwaDdGNwgiMog3VkcIIjKA", + "enr:-MK4QB2VcgCAj5ZZW8ItWHT7kT115pGK9U2jQt9e6A-_blQCGgZYCVfsAoUPnFoatzpolSqfq5yDqaOUZVRqfble4-6GAZL8lf37h2F0dG5ldHOIAAAAADAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGiDI7CJc2VjcDI1NmsxoQP1gXjy89Aq_qC3q4h6YpMAQ7ArRyOAkNSdt2uxR95aRYhzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", + "enr:-MK4QE5FCzl2lOL1yLeUI9sOKol9sMDIP_2_829ONxfEKJ0RCMJ5fVoVCgAzkQeCB3Qy5cTc-J_xvV0BTUGwVncUeSuGAZL8lf3ah2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKA-BqJc2VjcDI1NmsxoQOsPITil6o4aZGLJU4QVOouhwA_asQYKzx73WQrX9mKJ4hzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", + "enr:-MK4QDTSMAJnlzM5ge0zFDYIf3Dm1jo-QlW16bGEK1c5V4XqROkjICrItNtTHn_rWZ7sFLJ-HEJrEXuelLoNRq4Mk7KGAZL8lf41h2F0dG5ldHOIAAAAAAAAABiEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjdKaJc2VjcDI1NmsxoQLd_yMbZ703FvFi-XREC6rLHnbD_UWUCza99qjnAmrv4IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QM6zcrPDsArscPtgE1vIUYUttaaaoy9KK1UVJt_v2vltRucEOoJf1Y0YhSmEjVTnxtquUnNsthr1xEbzlINJMaCGAZL8lgbDh2F0dG5ldHOIAAAYAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2m8KJc2VjcDI1NmsxoQP-z75gbAYqR6_LCL2rpPTZmrOz8NnS1UFhqjsmwVbw9IhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QL18SZHDapmjGWInRUZYBuU3CTkqVLyhxpovPLcnMgsiPx6b2uf2jHQnj3lK8y0mLxv74y6Ww2kBFdrLKFLxZTmGAZL8lgfth2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7BZaJc2VjcDI1NmsxoQM1pgLIjSoQCDzGaH6k-xiL_H9FP_aO62iZXpnRFU_6zohzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-MK4QAKZrFxKHiZlNYqq3a3t5SSbg36XL1ipI93wPvj6nhmfVSi5iNK9qRxQmhRt8b6S5iEAcPhnHNiO4gtaZdGg3DKGAZL8lgRah2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GaKKJc2VjcDI1NmsxoQMYWC2DzvQ8_K9V6kU3g2Bfr7qkp0MkkpLcc04szxTQ_ohzeW5jbmV0cwKDdGNwgiMog3VkcIIjKA", + "enr:-MK4QAeVsVSVHkpiv2wpX4JovFW-8zlNJGQvso-cu25VIRIkYDs1uokbt_XexoabwaneyuftPbDFnNbuTVFjOiixIAqGAZL8lgJOh2F0dG5ldHOIAQAAAAAAAICEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4xiSJc2VjcDI1NmsxoQNj5zT1FZCoZp2vu0xyPvIn3nTGjbIweVwEkAAeqdMJ9YhzeW5jbmV0cwWDdGNwgiMog3VkcIIjKA", + "enr:-MK4QIejUXUsOX2Zt0gaZ0L0nNjE40rCu5S3H_lNaug79Gk2aNObUAorRsTXKslKTc2oFRFd68vn_294oKtOjKQ6lP2GAZL8lgrih2F0dG5ldHOIABgAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjQ9WJc2VjcDI1NmsxoQNBNJ9KuHDBEp0PnogcADqdijjfYEI94yP91iLwFNM6johzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-MK4QN0Jin_u-UobugNNP9ux3Fin5tk93ax5tCwNTWhIQNmkf4hKHVQc7n39zaYTauxHg44byC_F1XAroTedeudWKMCGAZL8lgHwh2F0dG5ldHOIAAAAABgAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6zuJc2VjcDI1NmsxoQJKQP5WBCZz89oRMDF0ZK657hmXuScPIKk22SQMBXBseYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QAySvod_fX8760QzGJ6pMeZGGY05vUG7HY2IndLnkvJBYR48NdvtvqWWTXmScVEy4blZoxDuRIKiu1FX3ym2XjaGAZL8lgNyh2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_LaLyJc2VjcDI1NmsxoQLVROfxZ1332xSDedlu954b4dQKw3stV5r7PMKWS0VD94hzeW5jbmV0cwWDdGNwgiMog3VkcIIjKA", + "enr:-MK4QKThqho0pK2Ez22RIJkCqWasVhyFkXxQKTq1B_o05Yx9elbWfAMvoyl15XfE1u5oNRP6JGLSNoBGPwfAHDQT_XmGAZL8lgFxh2F0dG5ldHOIAAAAYAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4WPmJc2VjcDI1NmsxoQIt33J7LcbYU-dhqYzMYlK9NNZoGq6Pd6Gkei5LITPYHYhzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", + "enr:-MK4QPvlUxfKTEuGcjtgBmh6dmMVlJ9kXCuvEJVxhXLpHokLcQO70_HIiPhTifc7nL9uVYf-aLsR9i9_Ju0juMl2obqGAZL8lgRih2F0dG5ldHOIAIABAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoREOJc2VjcDI1NmsxoQP8EniEQ3S7NIc7G0eCJ-4fmsBmPEsXLLAIBTqhiEr1dohzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", + "enr:-MK4QPVLA2XuDDDHyJv6a6vs1zKf-QucEokYhtG5pJtwPWBza6TXV8q1SgwU_FdkK-ngvd4VX4VkqFxgTc0Rjc9xrASGAZL8lgHph2F0dG5ldHOIAAAAAAAAAwCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI9u1yKJc2VjcDI1NmsxoQMdrx7mbyTnW_cSUJci7F6zPiIRtn99q5F6l_m0jQqtA4hzeW5jbmV0cwqDdGNwgiMog3VkcIIjKA", + "enr:-MK4QE7dJR9k1mKgRM8N5i_MGxWwqGRX3jUD_ODVlu3ai9zEd59l9Cc1LcUzcrNhnsxsY7ESwvGA1WsR-uvbpwMNz4OGAZL8lfirh2F0dG5ldHOIAAAAAAAAYACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fp9qJc2VjcDI1NmsxoQIslFIGQRB_VFWMPevzyxhMDX9CkCnJp4PEFRG5n7jk2YhzeW5jbmV0cwSDdGNwgiMog3VkcIIjKA", + "enr:-MK4QEuke5XW36g1t9fIhgBBdTsBsbVxUy6BPT5I-QMZ0gylMLKTO8OWrxprpOL_bqFM24x4YbpKzCcGlJet1m8P6D6GAZL8lfmLh2F0dG5ldHOIgAEAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4z1uJc2VjcDI1NmsxoQLsGvwvgwBKlErW3e4Wxlp_C-2LoemsgxNh4YXhzYh184hzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QOKr0la5UiDsWR0svdmz5bRU2cAO8q2gbVGFVP_5zUjUTAyS482sVR2EEMU84R5Vag1rmKN2B50N62SAeFDvmUmGAZL8lgXAh2F0dG5ldHOIAAAAAAAAAwCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7dg6Jc2VjcDI1NmsxoQI_Abpl-E4Sm5BYS-Rq19nAYTj3xG2t1GwsR6azMDvjjYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-LK4QGKKpJY2mO2wwRWE1GrSOo0YbIhvGU3Q-jCp89LHJRZKObPECBJFrkx55lBHmBdofOU42tjHtcdaDEuz1y3mWOkEh2F0dG5ldHOIAAAAAMAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ9Z7GWJc2VjcDI1NmsxoQMcuYnhiF7_6Qlli7BHk-HtRJAJF1sAQIjBMMZFhHibLYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QDE7XQf1xXn_1svSTXMAGEfMCB06HojK0hGLFufHu65SBXvlV1oPxy9O_Ww4hqSwK_Ttn9RujfEpAl4p2Yp3Ox8Eh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-E2Jc2VjcDI1NmsxoQO1c8OIsBWo_BTB2AcTOi3qr8PvnYK1mM5kIfuyJZ5ptIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QHbSqmyPO4e25hz5dAjD9R70Am45I757aI1VOivcheRnCL0IGR1srnCizSDmV0DAN-pgPPB7v4D_e8WIPpCKtWIEh2F0dG5ldHOIMAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GfsCJc2VjcDI1NmsxoQPRD80hT3L5trkyN7YR6dTa0eY8m8-BPEQ9VzVHr-KCm4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QDiQXp7rnmRd32bGVtboxwh-MFBpIAWTSUXAaxWhjVE9UERQUvGLsMYMcOHSRTND2Q7ViZ-t-VdnWG37q-ModXQEh2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdH2zWJc2VjcDI1NmsxoQLlA-CJY9lvScDxC3c0gbqgv0fVcK8__JhCLi-OWqjLooN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QF4azbnoYa11BniDYhO9-U14PRHaGGgU9VkUBXxiaQQLBoEXnE5PitCXZksrjr6IXZs1Rtk_rYat6Kg56rVl7A8Eh2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjWVmJc2VjcDI1NmsxoQJ-BjW6tpjmiDKUW-KNDVRL_avDPmK_yRo5HSGvJYgt04N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QFPSLoXEbUBBQTlZEwJtNqX8hVq1GccfOqUYPY7UEggpGrC0IFuIpZGi1yLetMUd9gc055On116W36EaRtlxVeYEh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXyKJc2VjcDI1NmsxoQI47lLtfQTztWdm3pVhY6giqC1PKudRwODxTQZEpGpcY4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QFFn8IQKKhPTcIos-3CSClVm7r102YpoTnjUvSZ6syyNWyJGeIDF6Uvm8SwzXKjfKmdV7g5TGyCgA0hO0-PNRFoEh2F0dG5ldHOIAAAADAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAkzeJc2VjcDI1NmsxoQPk4qNUMWmRxQKwDA99a2CjqktjXKi5wqCmNHQmFtegDYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QL2JLllEpB8OyarfTP9CxjpgsHAHsPZoY19qBjR85HYTI76d64iTA0RxusXCiJdTLRJWgE6DE8ArpbkRvAWYJ6sEh2F0dG5ldHOIAAAAAwAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69nQ6Jc2VjcDI1NmsxoQJIB8SxOEE4zHpubxYwAEFTFPvCvH1PK-aAawd5X_IfeoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QAW2bNcn_byPRldddp4zOJQrdZ0Tm_rmPLNIOUC0VUFjInLcNFLdxfUgWouL3VNN0sfs7zT0nfcSTWL4joj_0IMEh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLI-E7uJc2VjcDI1NmsxoQLBU9O0JOoFxULrs225uuzI--xb3VzeV-Ub_i7ylzWp2YN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QF83C8OV4vbbr1HS0LFL1Fy4ZpJKOIi9QlSEJkfrDyRqIyy-D-Dp8A_vRVcJbbV5SbjBq1g-pQh7j1zzctlBXWoEh2F0dG5ldHOIAAAAAAAMAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEji72Jc2VjcDI1NmsxoQPEmmzHJQH9TRjb_K5yanwJ6Cakw3ki3ChgFXYOqLR-3IN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QDKtIFH1vZaG2pMhLPrgY-4g0zFk2iXOVs3WySC3MikxAhBdDEttTKSH1opVZOhnI_5Ivxp8raDNhMhntvJVTkUEh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_f11yJc2VjcDI1NmsxoQLdayDMFPEnWPa_1MkL0YDmom_3zQKH2D3atBAIIt9rpIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QAt1xPThwZtp4fFdytsWwzuBuN_Kh_rlV0aJjkjWQUbddvBYctYLrzHAo7mFWktctMsGUO0VoBQdnm3ZiMoo3lEEh2F0dG5ldHOIAAAAAAAYAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDiYIuJc2VjcDI1NmsxoQOkRH_IBZwuZmpxh9ldiwDYUqChz6_ei6yXAxqQ9z8QyYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QPYpTeJc1dtO_CB2Lvp7TCg6iQOU_WfpKPrTt_e3fHVKRZnmkGMA7aUzA-lxEgQQgb72TyPECN4z_vbO_XbJCL8Eh2F0dG5ldHOIAAAAAAAAgAGEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjJ-CJc2VjcDI1NmsxoQOuuqf6k-s_yOnNLcDNv0tIhesiYvvdphMIgyOBLDNeKoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QG0SdN74uXa3ZthPN7B-1egIGMBzW5wlR7QX3Y0eoJwRAetxow_pyIBPsTRkPY2FHLhv8jEqna_kPHt7eXe1A_AEh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW3BOJc2VjcDI1NmsxoQJKVmvTZgOjFKGc3ShLgTA1H192A5PLYAPaFW3CVxEmHIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QFBL2CvVr5Sz-P3nkE6jvAQdArjrLkYkxlhAxNrOHPauOsaBaa5m5OF2IzIkw09hosGwOs4XOnhVPHuYfFdV2YIEh2F0dG5ldHOIAAAAAAAAAMCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fxziJc2VjcDI1NmsxoQPfWXddZQ4UAiu178G3WlyghgoIpgrZATEBNsApnA9b5YN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QPsih3HzKvodMe13_S7G7-LdHARWSWqGrfjBwpld7uBZAmE5509YBXunP5YOVfN7-65FjBRkR4HmImaVTW-3ILIEh2F0dG5ldHOIAAYAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNp5mJc2VjcDI1NmsxoQPKHJGGjFBqh9a3p0xyykr1iyzYG1YGPujEkx_hilG9tIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QHRInI7TYE6LVBAAsU1ahJONNnYjGpJEVZMOgLH3hEPzQsEWzYAMWTIU_d9mlL4SAT3jMHi0RUOQ1tNvKpdFo5cEh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs75jmJc2VjcDI1NmsxoQJTVNZQIGja0Btyt1pPX21sQ25PAIs16JYqRpc2OIOHMIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QJOiEnrs_7W2xD5ni1S4HGGXKhrzuluvt3XGMM-4HZl2OM5gtKY3OtkKKUPYYTFbkz8-IZh27fimVhiYHAr7rwwEh2F0dG5ldHOIAADAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjX6-Jc2VjcDI1NmsxoQLDUVY1B_Y7uKNnNuFBqVjsXXZPF4UcHYwlRIX8bOqwDIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QGJlf3p3S3hfJTs2Bmj2YoidPP_QWT14t6eMySxYa22cDWdNPDY3gmFkevT_C_f1J1DAbQCCEELcjh2Y2gQ9U6sEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRrmKJc2VjcDI1NmsxoQND9l9iIY92LxR5Yg0JThjZt2atGz9Wu7V-_Zn1JFsPgoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QIzc1HoQowg-CyrkruCbNxJ19dcn_UpWh07zKhyl_b3TBhjju0QVnwMC0HBUo-mFPlLqVI-v4dvS7pIp5llr1cAEh2F0dG5ldHOIgAEAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjnAqJc2VjcDI1NmsxoQJI2HA4O9X4qs7K2Tgh637dz876s8f40wanbnnPxJcBKYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QG9_qJS-qov-VWaRJB7NDD1XJExA2zaTqSUsXS87mqsGdLbNlMEUcUl6-Jjn2h5JCrgjdekJajxIDBSozs2FLPIEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5deB6Jc2VjcDI1NmsxoQL0hy3fyx2QhB-qxvdBIB1RqBIXwEcpNAspkyMESe-Ds4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QMjMMPjyls4JEnYlNcQi7k9j66Z6aDvmyLGh-MmK6Do_CncBF2dTEvrXJPcbDgIrpFrImsyw6tF4YUzO0OhHaGYEh2F0dG5ldHOIwAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4YuJc2VjcDI1NmsxoQLP3iDQVX979MeG4JUG5TEEOfcBDq4DL6IwV_vMO-iMsIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QPNn6P_ydDEeOPMp77RH7NHZtEdFstujjbM_mg9N9mHDEGaAim7qZo5jWgMC1HZpf0c4-tf0Y6eFkDdw9EbhPlAEh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJgq582Jc2VjcDI1NmsxoQN2tk0LwZ9dacFxiUApBGnqfHwLTiOjtC8Kstlel29Xw4N0Y3CCIyiDdWRwgiMo", ]; diff --git a/packages/config/src/chainConfig/networks/mekong.ts b/packages/config/src/chainConfig/networks/mekong.ts index 191d801e22b2..194956c0d6c0 100644 --- a/packages/config/src/chainConfig/networks/mekong.ts +++ b/packages/config/src/chainConfig/networks/mekong.ts @@ -13,21 +13,21 @@ export const mekongChainConfig: ChainConfig = { // Genesis // --------------------------------------------------------------- MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 100000, - MIN_GENESIS_TIME: 1730372340, - GENESIS_FORK_VERSION: b("0x10000000"), + MIN_GENESIS_TIME: 1730822340, // 2024-Nov-05 03:59:00 PM UTC + GENESIS_FORK_VERSION: b("0x10637624"), GENESIS_DELAY: 60, // Forking // --------------------------------------------------------------- // # Altair - ALTAIR_FORK_VERSION: b("0x20000000"), + ALTAIR_FORK_VERSION: b("0x20637624"), ALTAIR_FORK_EPOCH: 0, // # Merge - BELLATRIX_FORK_VERSION: b("0x30000000"), + BELLATRIX_FORK_VERSION: b("0x30637624"), BELLATRIX_FORK_EPOCH: 0, TERMINAL_TOTAL_DIFFICULTY: BigInt("0"), // Capella - CAPELLA_FORK_VERSION: b("0x40000000"), + CAPELLA_FORK_VERSION: b("0x40637624"), CAPELLA_FORK_EPOCH: 0, // Deneb DENEB_FORK_VERSION: b("0x50637624"), @@ -36,6 +36,15 @@ export const mekongChainConfig: ChainConfig = { ELECTRA_FORK_VERSION: b("0x60637624"), ELECTRA_FORK_EPOCH: 256, + // Time parameters + // --------------------------------------------------------------- + MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 2, + + // Validator cycle + // --------------------------------------------------------------- + EJECTION_BALANCE: 30000000000, + CHURN_LIMIT_QUOTIENT: 128, + // Deposit contract // --------------------------------------------------------------- DEPOSIT_CHAIN_ID: 7078815900, From 54d5886a4b7ba311d65ae5b5a5574bd6ac7cfd93 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 8 Nov 2024 14:23:45 +0800 Subject: [PATCH 196/259] fix: update config for relaunched mekong network (#7220) --- packages/cli/src/networks/mekong.ts | 240 +++++++++--------- .../config/src/chainConfig/networks/mekong.ts | 19 +- 2 files changed, 134 insertions(+), 125 deletions(-) diff --git a/packages/cli/src/networks/mekong.ts b/packages/cli/src/networks/mekong.ts index 44b45cd8d7ea..62ac8bf89292 100644 --- a/packages/cli/src/networks/mekong.ts +++ b/packages/cli/src/networks/mekong.ts @@ -7,124 +7,124 @@ export const bootnodesFileUrl = "https://raw.githubusercontent.com/ethpandaops/mekong-devnets/master/network-configs/devnet-0/metadata/bootstrap_nodes.txt"; export const bootEnrs = [ - "enr:-Iq4QNDvMuJuQDFx0NERRjcJzjUlpv-MG5ea22uVCNtFbBAbYdQXcL2ylwiZYKVR4ARyHL-ZIFQ45J3UdM3bCVPzTIaGAZLeJx23gmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQJJ3h8aUO3GJHv-bdvHtsQZ2OEisutelYfGjXO4lSg8BYN1ZHCCIzI", - "enr:-LK4QNmKwqyvCkLGM2MC8dnIE5Mg_j3PvEztzwAbRT2rwa97RCjVvEApmk6E6Tcrfae-jicCz646GX0B46Ksgfk9jY4Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQPrLuUBjXUN4pFbO9NX5UmF0TXzRLFxKQYshOmGXadK34N0Y3CCIyiDdWRwgiMo", - "enr:-Mm4QMycpeBzbXonM4_D6rG4OlCj3IiomsrKTAo5Lt4WiNR_UjHbqqzWDL4cU_DiRciLGtYZ7FplIBPo3Cc5sokaStUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82iEYRxdWljgiMpiXNlY3AyNTZrMaECFnLfbU62fXESKwDiGHjuh3Nt43sFPkpBK4RoiK7vLNiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QGLaP2hOFOCRyqpaJgXPQZSbB5QGRsoicY4U7UZx9RlkYLw9DoLXVxZFfPX7PNAszqMvBzN77FbkOjhPg_yPSFMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MADIRxdWljgiMpiXNlY3AyNTZrMaECbGSZZPqxqAcE_F48V2iNmHt6j60wSptDzsW--MalaYOIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QMloS1eJUl8kTCumpRa-gPRV_3vHaznwqrkyZEqdNg_gMQZrdAs521F2CMDfb_QClmB1zc9mD-iqd7IHUpSiy-cBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEoSM7S4RxdWljgiMpiXNlY3AyNTZrMaEDG_p92y4TqYPE1uHfYJhEFYJicbhur6M3INxMDntMAdWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QK5ZHmY0IYdyaiCgNVG8PvmN-4iSC7bIDAqT159eQKzbZfC53fnsjyYc0fXhp3g-U8ClnxHIG6wvMeNwK-OuDLUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEjl3-GYRxdWljgiMpiXNlY3AyNTZrMaED1CTZowO74kS-gZr1mcUtOc3X8HuQ8M0Jlm9QN2A5jSmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QMF5aX5M4399B7ixyj5srUR3Wcnpa6cfHuRofq5Rej9vGVvFCl1xt1p2PGgqUqxpoMBLM7--bVqPDtcaBBVtBV4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBQvoRxdWljgiMpiXNlY3AyNTZrMaECnjsDyKbztA9AZkfvAuM0M7BHE6LP65VagkNiausnwf2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QE_YVaRRiUZab27Hwu6kLWSkVRuke4Vx7L3dN8PHSuOqY2CjfnntxTeHRAc2_qS-lB8R35nNbu5D0xNdwWtbMfwBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEj26p9YRxdWljgiMpiXNlY3AyNTZrMaECxR5wgxcH2sTg4chkH2XctRjCRU9nBEMu8U0ixvYVOb6Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QAN_kY7-FlY9w3MiRh8Cm3h6SFLSomuWm8ezpAw9IWpvEZmqG_Y8Puq4rABVEqjoebUkiPdJ4km0YQDAP6CCD7wBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEisVoUYRxdWljgiMpiXNlY3AyNTZrMaEDbwUNCVBNIaDjC3soF1-UroKYk8SCzkDENCIM-eo2eQKIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QHlp8QeXe1YLemM0piknoBOVUyV-c-RxRpjoK9Eovv3wVwQV8ur2L4K1if_dyuYDiz-1vQWjdPKHt3t1HeGsxOkBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MnPIRxdWljgiMpiXNlY3AyNTZrMaECCmUZTe-r6wI4Hl1rZoa_KYB5q_2mGhHQpAuJcB7N3PiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QJOUCJF0hWpdYKe9DW2b4n9-a9AwRkYbqa29arOanFBjHon2oamjS64Cpw1ayvTFTSwjFF1Ff6Yt9yf6y92cQ9gBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibgchYRxdWljgiMpiXNlY3AyNTZrMaEC2n4usqrewig49bgZaF1taS26cgVf-HiAE8DZ2Bg6QB2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QOkxdUkUVe8ChY2aX88BxuuAipS7LzH0qzqBwRfmYJ3cJVrfWTJll7lsHgE4FIlU2i9rH9wZWr0mqD3O-T7mMb0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEvKb94YRxdWljgiMpiXNlY3AyNTZrMaECEirgYfVhl9O8-apVAF4E19KST_SoQNdYB-dMK481lhCIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QBctddDFJHQsWbwhViVGv7QQJrfiSCRbAmSB_vxLvUwoTF_4jgPdicOI25v8Sexde3K7VmoDumAqbfkDjKv59FsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkH7L54RxdWljgiMpiXNlY3AyNTZrMaEDvSYw5ZRCKA9lGJSjIqbWYikww-HYIay9IJuciFbG56SIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QNvGXzTNoMw9yRHgBSAMQ97pKZBqJvRzP_WQacha-WTDFXpm476LP5NZTJqZm949bOjI7UXFtk-Dq_f9qO9wf0MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MG04RxdWljgiMpiXNlY3AyNTZrMaECbNgYXUYuG0NleWcIX13YfwjVvF_BNt8hKk3yFCgrtWyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QLRk9InGH-I_MoWioQ70snhkdwNh_PJd06JXwaeZQSO9ChrhZO_IAnsZP9UKDMjwK4OWvGqhM7XpNRiSYk-LkB0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJB6D4RxdWljgiMpiXNlY3AyNTZrMaECgGQkX-iULENiOedHQ6q9VexGaI8lBQpyoB8IXGbjWGuIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QD2mxNJuYdUWUlMz51UT51LTsoTXoq5PgQ3OWzXgXOfvI3PlOl6pdynkOYbn2xz2S6PG3VhgzGWwaEbgy5-bKY4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82n3IRxdWljgiMpiXNlY3AyNTZrMaECPPNezPrn-hWXsZ0bXCGvjMNhIDVL6_faIpbMcdWGNeyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QHi9wOHG1kwBa5WVLM27nFBbULVWf-b5pRbsNknKKSo7cq0DcB9YFPCO55xrne5ncLuc5tsLVah588kITWoYZ44Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBRjIRxdWljgiMpiXNlY3AyNTZrMaECREuBzwWs5GJch31Gced8RLlNGcAUdzhexoBwket_gaGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QAVF7D6xLmKDFl19COzYWvUFyq7MqWpoWOCZCYHVIu6xL2tMaV7SzCSbCz0BDBy8I909i60MP3ASMSH3qelCaK0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBi-4RxdWljgiMpiXNlY3AyNTZrMaEDxLQPy6TvG7xuZHgovpv2fP1isHNUj6mff_k0XAMEobGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QGs_9j4e0D_v5jC-pKEltiT6fe9lbwgSVwwmRDNaUL_nOxZfmbvp1qOGRRCHBn5lOerol6_ykgmjDQf7R12eXncBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCrsz4RxdWljgiMpiXNlY3AyNTZrMaED36hK9w-REZSBnK1n1b1wpted08g5Zg2NAWfTm29r7UyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QAp_Du2XkinTcMU2LjMaOwb9dLqQpvik72s_ACpEa18KLqj-FDHjSw2iSSkLdMRiej_nRAmIoXPym1ZYWCsuspABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeNaNoRxdWljgiMpiXNlY3AyNTZrMaECe6WEfRco9dWv-lYOOkJ79oC6h1TsGwfE0qwwUyonCsqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QHjDYxMiuCYPV-u3Fd_EbKdKCXOa9UTUJM-2_ArMSXzBM5Hk6Re1uw9cQrWwzrGyZOqe-DhTlo38kOjENUv6wjMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibhIf4RxdWljgiMpiXNlY3AyNTZrMaECTysK1szima_WiGWZmsfCF39hYWJx4vBn3sw-EacZ2RqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QNtcDYVV2m40bIdResWh0ZcMAByENmg9BHvCtJlUUVZ2FheFMVh8JHPT5RYkkYCivlprbA_HRfv2yR5Vd4DKwoIBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCE0SYdtIRxdWljgiMpiXNlY3AyNTZrMaEDhmsIJt_vylwj9vVpe9xSxplR6yLv1-lcGG3t7kt7eQ-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QJBF0ITYJn9deemoje7vB2lEOPTw1LcAbR7vDsUtN1X8QS4uBXHegmlxO_xo_eej94y6SpfeUZfsGI8TxXQO9eMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2ObP4RxdWljgiMpiXNlY3AyNTZrMaEDsGgIhgQBTv7AtHdxPxn6muNOSMSBeYTa8R3a6leiQJmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QKORSYhuvgwEULz5YTbKAFoFxIDUSUprw6-XhSWCI-R5dY74fgfmFWlnfQAWbrlxFPEQFlnFrJgoGJZBfx8qX3MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEneYo34RxdWljgiMpiXNlY3AyNTZrMaEDgOCZaXRC9ru0SM0TTN3rH8Z1rRvHZB6tN9pRiw_dH4mIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QPALAj30065etXUSLBv1TCpIPjyu5Sc2jS1pq1dLxcWKCA-TZ7agz_iKHUd7qqKDjU8jkKEI6OZx75SD7hCFMdABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsj4zroRxdWljgiMpiXNlY3AyNTZrMaECscmuK1mmVZABEZ06513uRJNsRbPQ-dDRKtwbIDhBSaeIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QJ9ivFpkcKKHcCWgwjRRsFnkHDfsCmf-oShjZ8GP1I3fPsfpoc3m5Al7hEWhiggU1D3DfTKDJLUGTWunO_ZpUbQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCr3YYRxdWljgiMpiXNlY3AyNTZrMaEDS30xNn9X05FEDU8E_mQjkmAGvEUHPjsGvM0-hOa2o2uIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QBMzcDyzwpm2E5AMBGwyUEe0cmKfqB8M7zt9t8txyFcANxPcFvqW_uFcJsbv9oWLAAurBHxYRsrcjNXa-yzAiCsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEikSL4oRxdWljgiMpiXNlY3AyNTZrMaED0jwFiAei2MqwdAA2Jb2tG09PInLJDHRKHCEBcOWD1iaIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QGYTvW_cBJzsY3az9nseyDY-QGE9W0i65oSYjC6mYcwPUEaygRfuP8apw3cJ-gyn_4LnSFgiZQJulZoWohmHKr8Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtEjL4RxdWljgiMpiXNlY3AyNTZrMaEDTbzFw2ZRCyW6IMOPv0XjGPaF3KwEm8bIoiXS9YiZ_K2Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QAGbFeFkhgZj2gytJlzx3un6Fpof5jA1siTpjzZweK5cO2U-NtmUgh7-cZKRY5cKXySnP-IkXxFwsg1Q9yYmC4QBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEgMcixoRxdWljgiMpiXNlY3AyNTZrMaECHpCu_6mFkwl9SZWYGm5np8J3IUCeW_9SB-3QOQe8ZgKIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QEdec6LFcVat6y4WbhoOp3VsdqE140XhMXaFbXLrser2fyFmaTWVwkwqDKwNwCk_ln5U39nf2HUyrli3MOxyQE4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeOpZYRxdWljgiMpiXNlY3AyNTZrMaECtDxrZZAg0FmSmOXOxtiTMnhiVAFbYJ_2LN624_7d_bmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QCwzClelxvQD72WYzAqszuwt4jPbDGnVMiLcSR5K8DUxbYxaT4irgnBmGaroK5BWYoeP2FcOzwy30qZx_eLSqS0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeMtMYRxdWljgiMpiXNlY3AyNTZrMaECxV_FCOTDHqVWw0egWAQawy7pt8vqsxhfXKsZive3jYSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QN7FBq4fhf-r_klVwhkhs0dw1QvNh-R0U64CaNeDT1C5IAYJmi_H_85vfl7EGqenQXM5igA0vT3Xj1GNlrjmv7QBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtGam4RxdWljgiMpiXNlY3AyNTZrMaECgqkFNSwP0y1X5VZcisA_7U5SAba1arLu5hdrY3nqXD-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QDMC6sQ0fBXCzm6-k4XOqcuCn7mKzntt-93j_pN4_J_3PFvXas6ExyaRr17v_omQm9u1VPTI03iBBrr7NnwOoeABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeiA-oRxdWljgiMpiXNlY3AyNTZrMaECqpIvWTdEaaXvjFLP_kLJr4Fa0lWkQTm42SJzc8KOk0OIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QJ-oW-TTrAGfJd_iDN9zHFIlyEE6mFzmWvVIPiEvIWHXH4ExBg-vnOKpfFFHlGdCbfEclqaBOZ6D1nx1bLzxjtUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBqxIRxdWljgiMpiXNlY3AyNTZrMaEDIMB7xB2Sj6Y4p5n2h4TdxPzRnxxgTy-a5WAR9P3FKKCIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QG4hIWEcJJi2Gj6Ql-HhfVK2rmkLamUwEu06czdipkPeDro-wnWcBB1zpVd-QcOPzYiExZQb57gPJOD484otj-oBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfXIRYRxdWljgiMpiXNlY3AyNTZrMaEDwjfI--Oeet9BjyOkNbTOBSINLOkdOKZvbreigno_P96Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QEf-tOBH_isvG9Jjwn-itg_Ax461wK8gN53hxoFgjk_5WqZmSEGrFrfmnkIsKtCNH_JkNtqRPpgR4xi7mDDdG7YBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEizulmoRxdWljgiMpiXNlY3AyNTZrMaECsXckk_ngZJ0ZBmAvefKo5POpLi7tgvj6RBlrfIJxtU-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QOTA6CDkXHMJGzzK4Qw0bt2NvjN5hi0GFHM9FShjUkLzNwhAEO4GDqjJCT8_Vxhuz0s2W7RpWGVh3hYGjlvMBacBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEn0Hy14RxdWljgiMpiXNlY3AyNTZrMaEDimNy71F_6PL6FWsPubnH20GDHm1GS7Fe85P_MJ_CqWqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QMkLbE9WDjXPLCRYoQ9G0532uDnHk1gzQFvOKz4W1YkzRKbdsFpvxLId4mhgQn27qcvXSCk9nhQM0MQcsVpDzooBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEaPjC2YRxdWljgiMpiXNlY3AyNTZrMaED3p7pPbl4e4vpW1BAjSTKP3GDbyBPFn-OsFqILK_rCAiIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QMnUw-6zNtXoKfRXPt5BJBO8TkAxU9rdTzltVtPh30WAb2M3LHYjSfb5DyEpAGPGEK6zSiAbMh9YOKGcrmbXMkUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQOJWSIRxdWljgiMpiXNlY3AyNTZrMaEDty9z1mk9zYbD6COhp-s5I-SnBbvIhgvrDQ7Ompd2IXSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QKwleyLEbKns19VjBa_TaUS7QbmHcZ0sFM1MXhXJ_qCJRWzS-h8BLgBkPqOwUpLFTBKFGpblaJF43tgwpI1iVPUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpRbtA4RxdWljgiMpiXNlY3AyNTZrMaECFTMVLpwC7LnVDFb18UGq_c8eSHCyes7YaXB7v_tKXDmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QMYOJD6e010NIMR0abp7m23jDDG6Xrr2qvNvy9kq-QrHUN1B_JyL6mEV1NbqsIIiG9BzN1Kd2LIJEk46l7h29eoBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfVSpIRxdWljgiMpiXNlY3AyNTZrMaED1G20YrHlnMEMpJlZ3uRIN1yL3nKzBrlaw6NVJI8pm-qIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QL-Wv0r30Lu1xV6MvcKHtgzbNwfoMFji6dvMxh-Qp8gDDbFl24RZ6iimexWjw0g62ARz-l8dVfDW_MKjt8QY01UBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkr7eV4RxdWljgiMpiXNlY3AyNTZrMaECE4_MnOcmfF4kkp2fvKBc0XiA1mXl327K-tbZi25cAXOIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-Mm4QGkPvBD9iEoIJ9bL_LBuERaeHRt-u3GMjJT2wK96GTQZBYmG2yWdSLLZY6N28Ah4n02tZj7XDQia88Zyhm1mg18Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp0fSfYRxdWljgiMpiXNlY3AyNTZrMaED2V8OumEq1Xyc-T_D8Rz_uErhd4ExFaA2Y9ggZ2Q-gaqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", - "enr:-MS4QHP454KmJRQ6QvtYPGDVISUWxt9u66kRS4Y2xG-yGNwrQeCXt2CRn3QOz4K0EYT_qJ4escUKK228aW53SAOoCmcEh2F0dG5ldHOIAQAAAAAAAICEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_Gf0iJc2VjcDI1NmsxoQKcmNIRud0TxGGBowMH6KgQuBL1I6QDisI67IqsT1NcFIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QD3QTJHvr_ozW4XhGWtQAA1faQ5qTPlgsh54Fr-UYHmxWBuwd5kvxCRUU2VFrqwU25MSO2UiIH0ni6eFHTEydx8Eh2F0dG5ldHOIAAAAAACAAQCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2s4qJc2VjcDI1NmsxoQMS7AXi54diXAl7JtCOIuqXTgdQLTI7DoAwoUHtT9M12ohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QMrvDNykHH-uY1LkpFdBQG2j7BTWm4Zu_DZKk7yJgDvqQrgR5ebdrkRbP9JWgB4yQ34GnOvRwKpQH6Fm0n7UR1wEh2F0dG5ldHOIMAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3e-OJc2VjcDI1NmsxoQKoG9efdprL9xdFAFWCwTNVy04G6ogkhxrv66lcem3BUIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QLmLjJYXt2stbFs_xSUsGtPU-e5ZRNI7kK_6EXfMcn-wY8Y0kkI2Y1RNNOKdY6CVRz6bFJHRVuN_Ke-Eev-iK2IEh2F0dG5ldHOIBgAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31WCWJc2VjcDI1NmsxoQLu-LLSTeIaXnVTY_AfGhaDvt8EzO9oSTkS7l9mp2FOsYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QIfHbHSR_wT6eNqWLSwZuwX8Vggfimr9UvQ7CqzyTRZ6RpiMH3WgSfRe2vLZ6XHzsWsEBPb8uIEB1bPznK26c1kEh2F0dG5ldHOIAAMAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69VfuJc2VjcDI1NmsxoQMzBsv9977GwLbPePCR2_215ob8vbuLkl7jw4Xjt4iHWYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QM-FMAwX9YAu3dNrWZ7-mR90ETH8Wi7HLNkzxHG91Ay2RZUZ5E2jNgE1nllpGrJ-PrEbx7ZLZam9pyyWuJUwVxsEh2F0dG5ldHOIgAEAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKAJmyJc2VjcDI1NmsxoQNi_YVV1IKWUYr4WtQX0GQlo_smd7RG9Px1Djgm2ddrjohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QNpXfFe6sv4pZr18EAS-MN7-6vR3BQRUFR2BUF8JYgdFfRIubi4CX7MZPxB_TTwa1QIbsJPpIE6xfgjRGTh8A4AEh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIrFV6KJc2VjcDI1NmsxoQONhJoWb2B8LK4SU3rMbJE_qS8fA7HC8pbQ3PYlBcyO8ohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QH1jbdpyatJUXruCSNlE6A-XKzoz-C74lHdONmCY8vjPFNVsHAOzc_tbsR3PkRHevG8PYZ2n7SGIn1MHtIhCy3wEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRzgOJc2VjcDI1NmsxoQJ_PRvNg4wOXMckP_vRbDc0hFtDX82mYxMrdc0sC8Rj6IhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QOItMJJrAKDahrxwk4TR237U9aQO4Zq199oc8GWjkg_BbQJo_YwMuduki7bXZuzp0AnOibhU_J2JxA1j8-PSYVYEh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3H5uJc2VjcDI1NmsxoQOSxZPyLv5s8ai4FD64JwMvhP8PVq8J3BJRrLB5IBeVhYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QOXTwRX2CPb5t10VXqqBWeH4ZKTuuYMRjtTdO_oua67rSYCJxZgXpcvd4qYDO5JuZacRrfL0yNZjrCsGBdbWK_4Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31NHGJc2VjcDI1NmsxoQOWGlZFPoKXBWSVvkFV2HSoBosBZ-8lELgZT-jWuZVMaohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QBbix4UUs0W6RiDVao4AxqL6vmTQ_ZbRDWtb6oZu2qnbTfeu7rI0ryBoC-3wDi6BrlY9VNAX6nNPLBQazJodN9wEh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7uVSJc2VjcDI1NmsxoQMMAOwLh6oGZWR5ix4Rj1zitDGV1u9hn1sssgqhsxmfaohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QAdIwFds5c1XoHY768YHDWQXE88sZq7x--TbIt8DywC-eKf63P59YopC9MhUXtyAjiPEUdFLGsbnZ8hDm-9QCF0Eh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjHhOJc2VjcDI1NmsxoQLoCYpIP0YsPoZhEdgfDFa9_h18rskEBOtgP0wtA8_Ix4hzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-MS4QFbvhD3YZ_d-7MDbwVAqQ9mouMZtHBcyJRyQOb9wCJXoISrFHMlXoghcwXMjK4L8jkpW0u0gAVJlj4KsYwv3CB0Eh2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fqkuJc2VjcDI1NmsxoQPI_G4rCR_WldHte9rlywGwk_CMndXwVZL5vD-Uxx7bnYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", - "enr:-Ly4QC65D5GPZpOqc_N62YzTHPFqPoIYzTlvkK1QcKIMreBLPiQ0S8crFQI4UR2QtHQwrSoST639jPIev9haCeGt-VcDh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3cBaJc2VjcDI1NmsxoQIyVTK8QH8HZRU5yXxq_9O1e-uNbMKCqeQ8Pnz614EAFohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QEb-gSH1pYzes12yGGMW0LS1VTFQWyChZG0hyHI4uzARMOEknslqIOwFYLwFuIQT6Xo57wY8k1lB2bD7F9erWHUDh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GpWiJc2VjcDI1NmsxoQKq3cwFVO4pfId5ZKR8FFLFjljUd0cM9nCJGDsRlD48bohzeW5jbmV0cwaDdGNwgiMog3VkcIIjKA", - "enr:-LK4QJjwmILrkfb7WcNFNW_6y0rIaje53iiPsnl8EXtlSIeDULOfeib1vI4arkRvtVf8e5NDJVNpC4OCsBM7geTQ09oCh2F0dG5ldHOIAAADAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNoYaJc2VjcDI1NmsxoQKjjHUHsAhI8k7Y9I8Jtcd4be186t5cbzK8Pe4rlNFSOIN0Y3CCIyiDdWRwgiMo", - "enr:-Ly4QC_SKLTMsQAA6xHhua6He-3tbTjHX5ldGsiD95pSQCFWAiLuRNg00WL-UqqWV213n2PxZUM2t5FKbUo6s6PEEgADh2F0dG5ldHOIAAAAGAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjPAeJc2VjcDI1NmsxoQJ6_2ty7xIQjMxh_BSVBc7wUNK_zavLTT9YyzBBZigwlohzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QEqg0X9eT-UeeQ_2owzG66lxi9Q02nMu_zOWjI_npLCAbzwffvokHJSUiVjTD5LWNnkZybI46Qd3hy8eCfNWHSYDh2F0dG5ldHOIAAAAAAAGAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-6KJc2VjcDI1NmsxoQNGyONNiNXLU_IhDDCDl7yPv6SxYDYW9zGte2S8Z9oI2IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QGztwj48eJUFLgDdAkX3KheH-Fk88PqSZNRULqu9QGbYI-mUoBOkVtEnUMGBTlbSuGuoev_qFrcEyS_R0ngCNXwDh2F0dG5ldHOIAAAAAAAABgCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhC5lURmJc2VjcDI1NmsxoQOUc7rqSZMXu7aOOH-b73MWd4mOIl4e-vxJJfYP0Hh9DIhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", - "enr:-Ly4QJSbkyL6Rmdt6cpVm9IjVOLURMZLygqwRyGQRrK3kio8DAZR0xN4GskcdMzAnGSQ20WiTBmsWBRfTqTAphoCqcMDh2F0dG5ldHOIAAAAAwAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4ByyJc2VjcDI1NmsxoQMw1fNhMLg9Xin7SkEQtLuGTnbN7-Wnw8fS0AJfnZ2BRohzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", - "enr:-Ly4QKLEnEf0XteI_IHP4zwX9eJss6S5nElWxSvNdbN8n7ijb3ETscGrirR30Vg-0i93zxY1XRo7FQ-rOEfvunFsjCUDh2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLymYWaJc2VjcDI1NmsxoQJ-lebNvZ8CGA_XLb8eQ4Lfn1O0877FaxzQ59D4_BZ2nYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QLf2HnD_AIAN9QUqZVRmzHEM97_WLsWL0suneZGjooQMKLrp1SxaGoyMYTSKwM6Y73BeslKSg_cJc957_j91bIADh2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPPX46Jc2VjcDI1NmsxoQPEQ5EUa259oEjbqaISDsur_X0sYukB30oNTL3FilEP4IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QKzWObYxzgx731J5wl23AjvYWKabGQUBQffvKQnvURfEKJB7R1vIIABd1u59-2TrW4nU3qX_DkYV97INFDImH_EDh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJK-Uy2Jc2VjcDI1NmsxoQJj5WlbVgIRjphmVVGJHnBTwVNKXOUDvLZChgx_JMCst4hzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", - "enr:-Ly4QGseVCdo_fVjvMY_QGqcyve40Xdd0jYrcTyCq8S0EJy_Nx56YGxqjoHUUxKuMa0PU_iSQBQz2FbLFaDG74ek8y0Dh2F0dG5ldHOIAAAAAAAGAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRuLmJc2VjcDI1NmsxoQKhIIw9enpaKZdfmSvFfK9wDtQLpM-qrlHCd0MTDLNqOIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-LK4QPMXekagH7MNlJQqVIPR5NpGthHPcXJnaIzIejWK0narAo3N3Xs_Og_SwJLb_2Y5zjpKkmUEK2jUkPZ1WQAf5AMCh2F0dG5ldHOIDAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKesmW2Jc2VjcDI1NmsxoQLAQnSQdJeqTKVS-030kSAALKOWJbxD3bMTYnf8S97UZYN0Y3CCIyiDdWRwgiMo", - "enr:-Ly4QG8F0cB_Zxl0oKIbACCW8IMjQn10VWZkWCITw93BZh_FImJJXs3jhsZ5e10bw5nltAXkedIxHjNPzAMU3m-uNxcDh2F0dG5ldHOIAAAAAAAAGACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO21QqJc2VjcDI1NmsxoQPL1Q4Ri0_WvBK-G_Dkhb1hDnPfuizAn6EJ13TaAi2C84hzeW5jbmV0cwyDdGNwgiMog3VkcIIjKA", - "enr:-MK4QOeEXnB7mMNwk5tTvmn5ZqUIc7aMUTsDW42IRe39czdtRahIYzQU8f7VY-V26WLy6esPh_ah8JFCrHBErSVsiFWGAZLeT7Kzh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjybOJc2VjcDI1NmsxoQJpe2nb80QWjTg8OV7XQGj9_5HbFSPkb1BLSs52_E7TdohzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", - "enr:-MK4QP-QVRYlqxAZEGaK5EBtNFpF2cw68sprwnvPImwIjeJpWiDVvG2gdQYACH099DrRhS0rVvnvjnDiZc9eW_t3jlKGAZLeT8qUh2F0dG5ldHOIAAAAABgAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fSeGJc2VjcDI1NmsxoQMibnTlWZSEQrFdTWtwbGxwgzNfQugREcWXDzMAlubdQIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QC4Qu0GMY0208CpOOXJ_2Z7GbpPfkFHFj72Cz4kt-wu2Q3Hm_BGovRbHLlPrpF8uByVCV2-AtJVRBn84BHVEMnmGAZLeT7aVh2F0dG5ldHOIAAAAAAAAAGCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5dy46Jc2VjcDI1NmsxoQJsE-K2kx_vWKVVnIforrd-kHKsTjB4BPb3WzkSH1Lz1IhzeW5jbmV0cwqDdGNwgiMog3VkcIIjKA", - "enr:-MK4QKOofW71FNRlgsHUOCeV9AQ70UevGamBKDKnleTPROtrXEP6v9FIqo3pl25M2xN40gD4v1a00VlCDoVYkuPJ3_mGAZLeT8UPh2F0dG5ldHOIAAAAgAEAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES34myJc2VjcDI1NmsxoQMLSTJIF8gzlFEwia6qaD5gsKqT3Z23iaICK81VqretZIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QHXxbNuKKho7NcmdtuSBDNdkMi-cm6tC0AMyJTnYsGcobpX5es-NoxB4WY-kG3bFECGrRh2-tEsI7t28wa3YGTSGAZLeT7e7h2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXU2Jc2VjcDI1NmsxoQIKaSq5y43WBT8dVCHB84d2REc3wBX_tRk9-MOgpT1jB4hzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", - "enr:-MK4QIM-1UP2HB0pKx2jHndjWYzodWEtpEA2sosqoXffqsCrLa-SKOPCKr7x0JpeER2afgK3iqU1fs6rz1nUCuvL8FmGAZLeT7XZh2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhMbHVWCJc2VjcDI1NmsxoQObZKwNbXAMbuIQO_8nnSFd93JE_jMUmSd6kznKTfX-hIhzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", - "enr:-MK4QJM_-BhvBXnUBqQDNJcp3MdbKZ_1SIfzFS-3yFpxR5ZXQ0TRzzaBHNZnfjD24uSDNCaXbMlosEyl4ryPy-0XH02GAZLeT8U5h2F0dG5ldHOIYAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAyyGJc2VjcDI1NmsxoQPESmSk4h2lnhyRIa_lxBb1ITF8NfEPHXSFHJXVzS9n5IhzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", - "enr:-MK4QEzKtIksM5EURBpZ0FZ4fXLtecoS1JJ2icOpT2w-owpbO2P2Oug73jhspMuTOf8kK7cC_BN4gK28klfP_TNGo4-GAZLeT7rwh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GdHKJc2VjcDI1NmsxoQJgKsArRY2WPBuUYLZVUSSBpk4H5wh8zq5GrwjsSdRRcohzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", - "enr:-MK4QKz4NtZlKDRz9775jgPwsRePFX3vbw6pQbFqiIJg1J--eGZchwoG1N1nRXy9NjM4Bfi1XWG4E7Mv0Fdj5QCKr6SGAZLeT8A9h2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3mJJeJc2VjcDI1NmsxoQPgcbrdUs4Cl2iqnDEVlxCv5kmdL3PfoVwz7hFsEYkHbohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QOQd4uWnmwJXQgN26AXaxTf3IUWO4YgfBA9tvxuHEsv9dqg8fee11wGxxisvvRyG-JM4E1WqdMovcFH8dEW1r2-GAZLeT7Sgh2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoaVWJc2VjcDI1NmsxoQOpq1Sbb6wDrBz4d7_RAsXS_xLLh3848cZA_vTKkHNuA4hzeW5jbmV0cwWDdGNwgiMog3VkcIIjKA", - "enr:-MK4QFHjVhYt6eNGd-EGuWSx0FNoH0VobqyChYBb8Xf9YzLzPId1emfv9V-w5jEDndmdDOG2bbh6YH_wFfx548bszlGGAZLeT8cPh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES37GeJc2VjcDI1NmsxoQMZXzxzYiYyeZD4z_ByhY1BEBPdf1nAuLjxTpLlxOrRp4hzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", - "enr:-MK4QAqwAW8TghKOjYIWH5a9RXT1yvsUWOazdzP59eRPvJp5Ho1dWc-_NQiNqgKfZe0_7FT0eI1Erl4lqw7HTc0JM_SGAZLeT7ddh2F0dG5ldHOIAAAAAAAAwACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6aWJc2VjcDI1NmsxoQIGmyFT5c3IsH8psIugRpU9MsjD_ftbaIIzrDwOFvys6IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QPohqNkdiuEBihGI2rkBJX3Tk563kpN9zqYjSmiNdcChAldd_byrT5_MjnQ9bi24R2gQ7uxNYr4NH9UhUTZSd9qGAZLeT70Bh2F0dG5ldHOIAAAAAAAABgCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGiDI7CJc2VjcDI1NmsxoQKGVoBF9cfB3GV4M7Zl_-mTjbbWBCi7QW5C05ibiwuA3YhzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", - "enr:-MK4QP2DRiKhUiUsC4wJjJtITJBN2avNjW9egmAu-y4_B_WUQOhJBT2KJLI_9R73J18PuARPeR4eEVg-c-B5e8bfmKCGAZLeT7b3h2F0dG5ldHOIAAAAYAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKA-BqJc2VjcDI1NmsxoQJIWcsdtYM4mgdzTXwmUaMVoUbLIdVNDWweOsUrjI3UwIhzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", - "enr:-MK4QIiJTCxyJYWDZ1QQoOtBuIEuChMzNYGbVB64AxZE6FAnaNznjwz0Nwf5HJyMHRLiSwgxenjyymjMF3WfZZZtnvCGAZLeT7fch2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjdKaJc2VjcDI1NmsxoQNVGjVbnmG_42TCsv_fSh8VDxU6QzLGRoB40-F_zWq104hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QCVT912AAMDsucNOqG-0yf-biSVNaJub9k3ixr4Sg99NQ2AD4MpE3GSE2c4Jv1J0X2ZvTX1ggnYgbTC5x1yDa8qGAZLeT7ich2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2m8KJc2VjcDI1NmsxoQMpHGgKJECJqncISNxicGI89eIBdjm1scnNr7-DmDa6G4hzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", - "enr:-MK4QO-5av0dVBhDrwNoBkMeBt7ZJN0F8NrOOSNi2mq-CRWiTZZG-CqcOp7t9qjuuQhIi-RscfJyHxRW1yvcPyC5ufiGAZLeT8uNh2F0dG5ldHOIAAAAAAMAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7BZaJc2VjcDI1NmsxoQIJMx1m9LIofaV4RCXF5RyzaLZkRq61IaJbu7yRG9lIXIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QF6UfAiGKckerLH-N3EuPpcBqkRXPbXWq-ir9N-kDdBQZxiafoF9I5zcZDhZtlqCF3sVoE9TMi4NQppf-Z1rxYWGAZLeT8dRh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GaKKJc2VjcDI1NmsxoQJFec8UuFmn0tmu07iNakrK600BGlrxHh_sK2f82qYALYhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", - "enr:-MK4QDFSrh_p694cIm6RZ4uONpMkEaRcH9LHnrd99glEoGXpIEpmoIa8YCJJr9DrTRfuURml3_mncRXoajg4dmtFweGGAZLeT7xHh2F0dG5ldHOIAAAAAIABAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4xiSJc2VjcDI1NmsxoQOpjekMNl4V9McivNC7eRKkZQi1Lf_WX46aDF-TpMk864hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QLsNKnDBw1Ho_-SEg1MXS5sFVJjA4DWblUE6Y7IXWLiYQ4W0lDsSy7CpEzwyNU7SrXe1-RlSW_5H5LzU_ywsrPeGAZLeT8Twh2F0dG5ldHOIMAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjQ9WJc2VjcDI1NmsxoQIg-vBB9-5OOrarYUzumiirQZ01OeWbUF1Wi-CBEtJRoIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QI4JBnn2NoAAjb5Kb9k0SiniAUnLPLa4rgV39iBDBqIuCYQSXsjXiQguby7QitFRUznZMiVghIiz9p9GjXdgd0CGAZLeT7hbh2F0dG5ldHOIAAAAAAMAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6zuJc2VjcDI1NmsxoQJ5-KR2npQdVUZAd1HdHYts7qDfVeHvJDOCth0prC-ElIhzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", - "enr:-MK4QL4S9A8qoGT_8GCITvPBL7TCx57ULUlq2aPZjjPnmGLweeAft-punq4XjST99Jhh3S5UeugIl3rH9q3RrnDvXkqGAZLeT7mQh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_LaLyJc2VjcDI1NmsxoQNWzuY7G7y9FJlESwsCrG7DMzUrE7ESs1CdBwGC8CmpLohzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", - "enr:-MK4QF4vFBE44lGXPmNR0YdPC1XKgcXVxGi6pNo3SM7SZmtfJiDuypBq3SBlsNkcTG-d0WEyCXtRdhN5l2DMvLKhjgiGAZLeT7cJh2F0dG5ldHOIAAAAGAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4WPmJc2VjcDI1NmsxoQOEFAnO0rF8u_LHcT1hZKPcJKc_pjxxzS8q_jLEXyjYgohzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", - "enr:-MK4QOtmjWv0SLF7-sCbDXTidUu3eDaO5LRH0_1UBBRv3BfZDCW1f0IE9AGsPt8CfzCKZwhLM6qDg9i6Q7QqueoVv2yGAZLeT7x3h2F0dG5ldHOIAAAYAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoREOJc2VjcDI1NmsxoQLd7bMKI1z0ZzOPVmbsJTUZwuh09sEK60PJTBkr8Z5d0YhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", - "enr:-MK4QGPZwfQ1VRvztck8puc-l4453wOlE_GDLkZf21oekvenYGRil0bNPZfy99omIYDo_8Lfj-gTjtyMQNhfX-Gxf7KGAZLeT72vh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI9u1yKJc2VjcDI1NmsxoQOqOuh9qoiDqaOA9P3Zqe9Kr6LtA7BGX6HApTOwTw8JEYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", - "enr:-MK4QNoB0qr5S04EqGfFd2oC-8zfJ40EpEKX6comkVAhVGpzRcS5miDn3i7vI8xMq4rcP1f9UNmjf5synrMpkjtl2RCGAZLeT7LYh2F0dG5ldHOIAAAAMAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fp9qJc2VjcDI1NmsxoQM00pJ11HAcuKC2lu3qsmrFfinrKyEIJfI5AgaAXKwQqIhzeW5jbmV0cwyDdGNwgiMog3VkcIIjKA", - "enr:-MK4QPsx1H6cUFhgDo8IeVRxPIevJY2m3cdIcfDm67PQlT3SE_GLHiMXbt7OwNcLfDnmadblfze_qnIfLPxLbvlEdVmGAZLeT7FUh2F0dG5ldHOIAAYAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4z1uJc2VjcDI1NmsxoQJ3uZasVkJgtNwojOc12o_OGa95JidVTiTf2ZNg6v1evYhzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", - "enr:-MK4QLLmvX5uDrkBoxlU32GAniNWyfuq5dGdzp54Nr-NXwYBPFffMC8TRPV5qJtXRPCF0TMOfGRGtVUScaGHK7WhYKGGAZLeT7tLh2F0dG5ldHOIAAAAAAAAMACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7dg6Jc2VjcDI1NmsxoQPPUGx-0Q1GggcWhaFjoBRNM1zxb3-GZet_XVsCjQuQfohzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", - "enr:-LK4QHPZyuxlcLUFzQlV14cUrVEnk0R8-v0gI7LyFmrRbNsWGBRcv1bVBr4OsuDsQe7WCXw_MbzIPbRil-l8lqlktUsEh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ9Z7GWJc2VjcDI1NmsxoQLQ5jTn1P7lwT8_jmjdgTbtknYQYN1diCnUJ1meLGDVI4N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QKsnDouz3ORWxyOj86zLs9Y6EPzGGmAQvetPJYVi1OA8EgS6iqTMUumFGYlkrhwhlgl--RhVdJnGn6BT4nWbWsIEh2F0dG5ldHOIAAAAAAAAAMCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-E2Jc2VjcDI1NmsxoQPiM0IiXdbtvibXIinl9tTnU2oxUtQVCsSD8C5Fw5kkvIN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QBPu32Td8-yRXOiCr6oZ8Kx_U9l2CtrgtTdS7JJSrya7XmYrhR5PLufbQ_qheDZ5220i1GHFejGrUctcKqXL5b0Eh2F0dG5ldHOIAQAAAAAAAICEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GfsCJc2VjcDI1NmsxoQPVIZx2mp-hC6O-8Sc2trinfPTX1ldcVm872npcbECL84N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QCTAUicPEGC27830Tk47FIOJjLLXAucO2JWZBmUpqyRqdqgx7htej1mbSGOwdkvMy2wr1ppQqNNHpg09Nq7atbAEh2F0dG5ldHOIBgAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdH2zWJc2VjcDI1NmsxoQOa8jxBZtnN1XafI2exkfdQfYrCpf5nIN7NJbM8UaAQ4YN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QBD2UExDYapUhx4Gwwmj0sZOOe8b_Z_7LOwvupuKvHH7S3y-i1tM-a9MUzfKp0f05Lnyd1OebLqAe06SpN0RVokEh2F0dG5ldHOIAAAABgAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjWVmJc2VjcDI1NmsxoQNy5g7s97V6c_bliDX29X02VEt7lFtykziQ6yAQz4B7B4N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QKNgqPGYJb0gd6sPYicjvhzxX_4fwIs3UoKfv2Km7hAnILqc4HfLG46fwiaCGuGO8HWqhauYJyElmKl95HdkcnYEh2F0dG5ldHOIAAAAAAAADACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXyKJc2VjcDI1NmsxoQMd0ERS9Kijwan6Ok4AnconhbpavC3ChksqpaeMfFUgYIN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QHJU03COhJsMUjgIfZgqe5L9X6NTfBprKwmhq7MMi8pUYkWNplTk0mOFZFDCUdxQoAdXWBMghCg_siFW29NdSacEh2F0dG5ldHOIAAAAAIABAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAkzeJc2VjcDI1NmsxoQIKR_4srED3KxIv8t5HgcGDItwksuAZGkuTiy0Sj-nP94N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QIBsXm9oo2rBww1rjpa8gfUFgtC0zfdQOyj9Lds9vhNmUj9HTjeUSr2np5CmDQbpELn2y_5c68yHCk2HikCsbH8Eh2F0dG5ldHOIAAAAAAAAABiEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69nQ6Jc2VjcDI1NmsxoQKkClbynlGIlGlgJrwz_g-4ClmmbQZlLCrQDFwHWhV414N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QLKcBiOOWyItntw97roB2K9giftNayxWd66H5qiat7h1QuopDgg0RGF6_KRuh6jHWIlhUVUX9kIJfTkQYBq9hrUEh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLI-E7uJc2VjcDI1NmsxoQIPizTcMpW9300gIUyA6wzxPJVehLzRGzep9VcRIcZB4IN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QAW64M2-Mtv6f_IJ-wqKuf-uczJxwzIPs4aKFOu0dMKdROuPHYcsDKNHPoOgOvBM2fD6lI2XeIMmPlkHQs7fSbsEh2F0dG5ldHOIAAAAAAAAgAGEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEji72Jc2VjcDI1NmsxoQOwaeQ96C8h5DJ9qnIwi0MD_EW9mWnVqq8YP7A8IhRxf4N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QI_7bYzk-6IKSGx0hwXoUp_4SE37TVNrIo05XsYuCwewL1ANoIv1wTlFPiqhSSdUppGEQr7m_dBCMIiE5YvYfZkEh2F0dG5ldHOIAAAAAABgAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_f11yJc2VjcDI1NmsxoQJcyXAkRddQMRW8Wq_uDDaqhfRix2FsTlQpaeNg3cTL6YN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QOcFoKeISpC6WEzMFOs0Fd8g5O3zxHR4YrtOti-Qrm-iHZX7R8Cm-ZlWaBAC_tv-KQ31POPAiVE26QpRgmnERHoEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDiYIuJc2VjcDI1NmsxoQOM0fzW5xagH42YOYCaUR6TlIWaurBsnTa41TOg5IMBRYN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QDwhH0TLPcX9EkImgdegz9n4DN9U-u6rx-qA03Idi3WvL1tqnEWB54qSofoLPlpRCk1LEhPcekgUE2IrgfSKAGcEh2F0dG5ldHOIAAAAAAAAwACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjJ-CJc2VjcDI1NmsxoQJJnCea2UoBVZUPpyZPNZ8lCj1sPxtWP7v44pA3bAXFFoN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QDWc9ARKxtQzvcfhsSSuOQVBXtJf4uBN5khbopSvlB5mRhqKJD0DoWr1brq0Fu7aXtwxLwz3tmW88gHRyfgNeXsEh2F0dG5ldHOIwAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW3BOJc2VjcDI1NmsxoQP08nTiii_CUneyjjQiQOxlSJRGOBy5RxAltma_eD2kqYN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QHzsDl0sImNgHoUUQZHERvokg6bzOIMRqld5y_I3Dq76OcCRlR1B1NNUBZomkckV752vh6xwgh_nuU8gC5vhkqAEh2F0dG5ldHOIAAAAAAAMAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fxziJc2VjcDI1NmsxoQIcnSoMB5m__EkBOblmx6pFVb2gWMgytvG0DCK-7Dc454N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QLaDD0Ce92HbHN_Odx8gOLWetZBBkdObRIK_tGnbyAMZF1D0lOmSazEXtqb_gcYyYWloH2aLvUiIhFyfBcqdFKgEh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNp5mJc2VjcDI1NmsxoQLthQWPCxwf6ElsjcoeDy7xWTVy0oyZGsWLyWJhT0AVZoN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QNbU3sIX2x1pEdOMlHnyTnf_qKCftwHH7PtruMWDcQ2FeYxji2tu79tZy2slCZYcHC3Kt2yY6YNA8xuXmny-qf0Eh2F0dG5ldHOIAAAAAAAYAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs75jmJc2VjcDI1NmsxoQO3hlCHVZ2KkCuU3J0cmy32kyeaygleHpvTj1e43JJLJIN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QP45lW8RQIrJrUYu8JaBbdHsFCL7c5cTwnbsf1v_I6M-R1Ugjq2j77Fzzpj7eE1omCrXkq9NGuN02EqnhAG0BYMEh2F0dG5ldHOIAAAAABgAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjX6-Jc2VjcDI1NmsxoQKmt4RKybkmaCeLp5hZ4ubq8aOrMujHCsZQGkEIfQX63YN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QPm1dSEh4ejPKAgCUmVW8YfTCnot8TBcjPl_9DUK9x8pHAMdgLBG4dQYU1cVy0VkdQ-y7PrCWuS2HVGVWgXs-w0Eh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRrmKJc2VjcDI1NmsxoQJ3YV-wCUUU6e7D41mVpE6Pl2IxB6u4Xp3RiuVW72jrKoN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QCcjOXE6AFoUfRAPy2ADwoHrKA8e1AEvONG_TfeNEA0lFQCgrffj14h3aZtqzRSmDx4kdmz9Aq4xI_OERsFSwsIEh2F0dG5ldHOIAAAAAAADAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjnAqJc2VjcDI1NmsxoQLrpyFMatvbIPm9lThrW9SdBdscw1Ctj4OL4Cg71wC1SIN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QODfmZ3HU4QHVggOpxp1HVczob3ce9UwTGhSxE5tiQLCH0TATU2t4i_WEaicUJMRJi66Bmeb8c9rEoGvTLdmOSEEh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5deB6Jc2VjcDI1NmsxoQNj36dwUn-Vk4qn0H6Pe4qhOYluSopCikb6fF2Kh-26JYN0Y3CCIyiDdWRwgiMo", - "enr:-LK4QAaQ9jSV48tiTtHzL1aocXbrJnt0r1uSituGZCTjl8mINNxn5Z_Brf9J9oThAK7U67uO9ChPzEarhfhvTGO677MEh2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4YuJc2VjcDI1NmsxoQKdiOidyLx2IMQyrI-L-a169keDHUmAjMZ3_8vurIiHF4N0Y3CCIyiDdWRwgiMo", - "enr:-LK4QM8rHJc9l75ns1i9tuZyux2m9CtFi7zh9Rjh6t38OhCGTLE_Nq8ZMyg0oy5ktpkIoIp6v5T2DVrmx_P6iDbtHrwEh2F0dG5ldHOIADAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJgq582Jc2VjcDI1NmsxoQMXBD2dqEKFbP0hIM624HswH20R-LlZIQIuTsB9nIygh4N0Y3CCIyiDdWRwgiMo", + "enr:-Iq4QB2ny1q6gkBjqNRU_e-GTbpcJQcI4i3cIZDea0mnAzGgbUTKH8j81g9PRl_-m40F1V4GFBlqZElrcbGnUj9AjGeGAZL8bgmtgmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQJJ3h8aUO3GJHv-bdvHtsQZ2OEisutelYfGjXO4lSg8BYN1ZHCCIzI", + "enr:-LK4QF2XD_Fe5H9QMVVwBoDs6P_37eURcFvNTcLzOc60p_XlDKIBleMgudA7nltZ7TyAiOuY0BSQzHsdv5iUs7sFyWQEh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4Z6Jc2VjcDI1NmsxoQJJ7y6LF_to7NYQd3BVRW1840gm5r1Lm3lfAfC9Wqmw8YN0Y3CCIyiDdWRwgiMo", + "enr:-Mm4QMpfvuUXcMcRx0sCtnzvE8zTJEm7BAwhFtU6CvXCv1i5Wsksx0P7ocBEJLPHULf_O3w159cnbUoB-XZuyDBfME0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82iEYRxdWljgiMpiXNlY3AyNTZrMaECDdViaSTH6xjxrJT_gIaha3_CzJ64OQDQwTdbcN84BGuIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QNLiswecY50ofHVF3twuOmJCqqdzOviXI9xAmKU3SBmbdDUr_v-dpxcP_AHoYMBw62yEcpPRsKzY-yes3wMoJnUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MADIRxdWljgiMpiXNlY3AyNTZrMaEDgRLt4r0C6K63co6eoGRvi55-viwcW_ijblPrlNVulAqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QMM5lT_k074lQ094vF8rGQXkM4sLmti9kTbwuZF-6fZ5KhTlTxEAWI8x5-EKRduIMoCaz6z0SfaYeOsfS35jr0EBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEoSM7S4RxdWljgiMpiXNlY3AyNTZrMaECW3vJ2OZ6yjQfrDB9AW_5J_YZUuQRFsp3U5z7VvCdu9GIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPw3-nzQ6CXpRWLR_eo4KYcoshqRtaTlmqYTlwqcW5AtWMDuF6o9oVyUhYJ9BdqP7x-vi4D5C83wJ2N-sRX0D6YBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEjl3-GYRxdWljgiMpiXNlY3AyNTZrMaED9NVIDXAwA2kDI9wU2y1KV7oGALUrc6h6LQ2zqcWD7UWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QO3f8z6h8uhY2fOr4iOmUkfGN8Q_ej-DOwcHJ6P4dCqWa20aA6Jxac5Ta6dcfnwdvSfWUz3ZFWUU3n3mmkNvjuEBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBQvoRxdWljgiMpiXNlY3AyNTZrMaEDMSbjjMae81uRoMG_hZjfbXnLLuI9eEKUkKShaTBkfEaIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QFJKhdNYDyWgtK1rM_QsbocVqvkQGVrecxbcMSMzw58JN7Cw5uJoUVJJxxlY1bWzZZ6Y6fuL0MxVKVj2jQS-F-MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEj26p9YRxdWljgiMpiXNlY3AyNTZrMaEDx6X-X_2EgQ2AUWkwmm1GFB2SYrm7XihW-IUlx5u0-FuIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJkcqvThmP8DfQ7T-kwsIc_7J9VZovhRWNJJ_3mWksaiJPT0YYsLwIRMxhZaIoQ96umQDyXaAnYccJHXo4UWqdQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEisVoUYRxdWljgiMpiXNlY3AyNTZrMaECcdygVaepRRqO6BpryxhbQCCZNRxJ6C4pUujAXUdM1E-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QH8zBo5Jxm8c6Tindg5gE6Ju94Zqik8Jli6t7p8gelwJX9hacP-9UteVI-PnQZNnXuTQ8MEWfkl_zyklzF4dP9IBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MnPIRxdWljgiMpiXNlY3AyNTZrMaECRHo92MBzVuUg9l0XPGpT7SUm060N40IShmk39pg_TWmIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QCaIOIsJoVLQfna3OK6gMN0YBBpAhjrD6wh1zKb9SRA8GsJAQMREOg6uK137hV2IkqfieKvIEPiYUOsJ8LsaBf8Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibgchYRxdWljgiMpiXNlY3AyNTZrMaEDbe9GtmMNbJRzijDmQfDQQN2YkGFTr7ImH9yPyveaxOqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QDkVL9-sXu44WnfRdLee3nlGAiDFE0mqcahIKzPcQx5IMDcWsKddzjk7sIa1t_A3OrbgKZ-myxp-9Ft98lc7jYEBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEvKb94YRxdWljgiMpiXNlY3AyNTZrMaEDz6UjXFkPJYpRmVYPyJVGefekeG1Qxkg_AcDKIc6KNEaIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPqcZ_jT7ZUOkLi-BgCExPlUytIP6jIvhV56nPV1A5pyMzKDnk4e-6a5_1seXtyQQluHkfAjZn9_H1NVXVdkA94Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkH7L54RxdWljgiMpiXNlY3AyNTZrMaED0EyYkEKk31vfdXMLYneEyiCNimlOgdm0qcoI5YVZ7b-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QFjWfPILQklP6hndcbtDNhl3vGWQkXf7pR8Kun039DRpClIEwvxg3MW6-JUcVNjmD3MtJFsS8702ZG3fB8YHEJsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2MG04RxdWljgiMpiXNlY3AyNTZrMaECYV9wARPI7Y69DK_yoe0D58LPTF3WaIHZmkTzzC-4PZyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QANhzPcE163m_6hv99UOWiKNmD_qvUkZOhBP1jezm-wdfji1fL0L1yue7l5kb8TiSs_6dSEeaykst-bZ4OpChQoBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJB6D4RxdWljgiMpiXNlY3AyNTZrMaECOcOVxvzmKm5yFLyZBA50bzAWCi4wHzlYBIEujIFt46SIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QFGHCpBCazbxQbjG-QQXVNt0XKjOSpRXaseRQ7eCciBpWfT7VrRJ1btLOuNMzyKpQcRMfmywxH7LwK5awZhdpS4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQ82n3IRxdWljgiMpiXNlY3AyNTZrMaEC8WOCzbdKFeg3dYciZ7QKfXxNss29CqaHG5iwm4EHQcWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QCGRQd2a8-pIgsH3PuqA5NZjcwIjVH9H7Dh6cPJJRsEzNojxFtDzY8rRebHKb1xrVAZPXneMuw5K3okA1k2KOOwBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsoBRjIRxdWljgiMpiXNlY3AyNTZrMaEDMOw8ey6EZ_4GyR0kNDoB55it-p7PzFPpsXyc4TFMPRGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QLaFtJfw-TGxUNAHQO2xmnvYDnmKgjfJve2MgrWG9OPaMnVDlLIAIz9v1_SdDTS1FH3vt10iU7YI5t7CIA7sKLsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBi-4RxdWljgiMpiXNlY3AyNTZrMaED4PMVrXwoLyISWzFzYU4cd76TnpxIZwIK1SwyFyN9rWSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPUpI9m3garHkV47o8jKj8VGTaJTOwpIWnUb4GlD5r-vK6xC06h-wPtUzQngBFk_FOUfuw1mcqAP5L0yTUozdHsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCrsz4RxdWljgiMpiXNlY3AyNTZrMaECfWt_Vji8tocNvFs6orlyMLsoNkQa19BNqsbXN_tUhkyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QHJGsttZD0_WxO_CjaP1s_gqJcb9gCYLnYI8G4qUi3t4FYGX3oJvkZD49kNfRx38a48GjpuBCxnHpd78OSxxgnUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeNaNoRxdWljgiMpiXNlY3AyNTZrMaECseT38XZgU025QL32df-blQfLLYdrby3pO-d7axe0zF-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPtT8J4rpYkixx-COebnEPreuWv9OpgOGOvM01hqZ19eeySxCxOEEVHl2r2c0BYwBuct_yZhvkLqUQatRORlIP4Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEibhIf4RxdWljgiMpiXNlY3AyNTZrMaEDjight_62uShKNt4IorH13hfqm7kZzVyFxXKI_qDlsTGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QIW31dzBPtPxCAKvj-T29sFb9wCDM509ANmDizLq5ys1YJCcILx6PotmJxF4g829FlDiqSsREm4da7smcPcAalMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCE0SYdtIRxdWljgiMpiXNlY3AyNTZrMaECNWg27r6a05oup0qlmM9iSuw2sj1ulbCSGGPKDYjvGDKIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBwdkGDZH5GMc49ZkabCo4PbLDxKUxjy9AdUZSe6zGK4NCrGq27i4bkEXwg7IrZtzCJXhfgMocUz7a7uBWq_jrQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp2ObP4RxdWljgiMpiXNlY3AyNTZrMaEDRDkl8RqHIqP0kgd1-bhZY18QRV9nfpWPr8FEKdRRwZaIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QFCmA4GNnGBuIdevzwZ4-5GFN0cYDqGQucQ_zZyjr3m1Srqg1eN6RuRj3gKbxChAcAp6hVOX-wl2fFzqRpsZJ-UBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEneYo34RxdWljgiMpiXNlY3AyNTZrMaEDX6gmy0PDR51SEtytWsA0IxCE_LZdY_x9FiMT0WIYJV-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBOzKDeXEfUTFsEBk3tX2-OvfpU7uPdQRl6iex1r-N-oJaB2Xw9Bfney1x4k8ZMsHlHFPBCRrcR2Lzmu2ghHqVEBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEsj4zroRxdWljgiMpiXNlY3AyNTZrMaECpp1D7pHZbF8l6vl4_DWdm4NJVDNMxGxvti-8ZqHrHCuIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBL6auezk-Zi385j0PyjkzGwQJW7TdOFZKGZMKTGRkI4fxTSTiHLe7kTvdjhBq4kgjPXvUnFiXR6AisA8a0w2lQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEmCr3YYRxdWljgiMpiXNlY3AyNTZrMaEDJ4xl2Our0Y7OKsSDX9f908HznXm3PKzmC9zD8OB2d0mIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QDOEqa8lWRsJXIoFqGGytT8xBJuGu_eE1p8Nob_QQI1-B4S0_6JjVoyH3pwfezShdUj9RdgdETUon3bXM06UVSUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEikSL4oRxdWljgiMpiXNlY3AyNTZrMaEDe4qmuHzM_TfUgfRc_0nuiQRz7S2_UhphHbgC9ilzgnGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QIPjOKp5Y9Gr2gS3OnAr3_1GxNU2yqs5Nwv-3r44yPriBJv5pIDm0vyJe7Pi9FQCBmikt00IXoO_pF0zwWHv5b0Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtEjL4RxdWljgiMpiXNlY3AyNTZrMaEDeCId8CCbXbvI53xmkqjFgJgsqmxbnWE76f90OiFsmYqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QBOCEcm86USjdb2n8zRwzDfdEo9T_rKvRGLJ25y2PL9Zbc4RKEi8yOWk-vJ4QRZtgQ9PwgBUi0Zi478X_Wc6nlsBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEgMcixoRxdWljgiMpiXNlY3AyNTZrMaEDBTPknXjsIhdfxDYucKiVm6SgYTC9zohYC5s0YV_6EeyIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QEgoppH7VZWNAb398z96aK2gDlWc0x_EQlDjOKcp6DJMahC6LSf9yjXHmnHzdii_r9ztNMXw0_b9gsfmIG6so14Bh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeOpZYRxdWljgiMpiXNlY3AyNTZrMaECR7znvBtmDQ80qnoAeO_FFgwB5_tALE_aZiub5YgHJx-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QCnjdBwJ6xUGvP0wOAizMDUtFJ--0Zq37c6plEGsiuu3XUk_JMytx7I_LjQHsFx54GXxSP5T1x9-tJFMKq-mBbEBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeMtMYRxdWljgiMpiXNlY3AyNTZrMaECm_3lxmnovulk3kxkt9SRc8CJX591ufqSGLDUl2vFulWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QJRpkRrnmIUApBcQsRl8my3qx_ThNeMuY7PZTRzgqDqpIOrISZOFpCcXRTMRo_va_AzAMNSLCt21xWsvc4iX_FUBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEhtGam4RxdWljgiMpiXNlY3AyNTZrMaECTsHuqtUTyvnbr_-bBlPQrDjJ2fK_fo6EI8cGBlkT1taIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QHF_2oiGaRM13lElGu9KVq6DcllqoHVbXKnT9BMZsQHDeQYJFrzRl2GZuzzjdzMsb_Qa0_fpwPqacrwKA1hCbaoBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpeiA-oRxdWljgiMpiXNlY3AyNTZrMaEC5n6EKmWkFr_F_xhKlyL04Q1R9l6bPX-ew3l4_aX3tw-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QLZkxDCSlFHNHrELwY3Wbck4uEBfDe--Oe-ymSSdb54fajSDO91ILmm5UWJbiEpgaQ-tOaRBI_mzkzrBK9vOLiABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEGJBqxIRxdWljgiMpiXNlY3AyNTZrMaED4YrrKCAARO7iCBkBCKg18IRChlSsrdgLXUFlWN7cAVSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QM__NZQmR1Ujykum0flKS6es2lXTCsKMnGC4s4J3g_m-ZEk8TADO5s8BtdJMnBSJIXsqQsPvGZRCOrSye7UrcWMBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfXIRYRxdWljgiMpiXNlY3AyNTZrMaED-132tNKgfT5Kvdtyoy08SWPtnmqbKZYCTcw8F4HL6iWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QIDMKaGp33io88FS5RJXLftryhiGmne8QSjP2ZlCqB2mAQu3uOEOoeeNQYrd6ZJaA16xDvcO1PnqLCEwzuOuoiEBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEizulmoRxdWljgiMpiXNlY3AyNTZrMaEC9Oi3dcFrr0j1P39XIVsXdoNc9AeRZG-UVkEG1C6j8aOIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QD3COs2fIKQrvFG4cphKA0U4Bg7IltWfnnAzxrONjqkhWjbrXP14d3EGUIEuOd7FzfZaIL6bK7CwBSQRH_dGm6ABh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEn0Hy14RxdWljgiMpiXNlY3AyNTZrMaEC02svkGF3_0dOYuBvvHKP5WqW8Vp8hfh6FOTPgREZWZeIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QPyFixsMFYX5FEqsq6Su1kZF0qUlR9WSdSlXGki2a1NSNdKPYx7teRVfnny22rCgjWQzEJrh9tqI_WcFNg_9wWgBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEaPjC2YRxdWljgiMpiXNlY3AyNTZrMaEDg8vFkCPwfrszMGSNp9O1d24cq_A-4XIxFlMAaBNP10WIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QLTvtxuCz_GEJclTPTbY2PFtq4sD3LD4HWglNJIO_tUcQ6QrtgHThuyKz_sIqE1_aW24aedXXpC2p_zPWO_WV9MBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEQOJWSIRxdWljgiMpiXNlY3AyNTZrMaEDZpd0NBAzCF2-LHUVu9_g0wJKoQvnEH3PfX-rz-WoC-yIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QDZSQ1JfQl9jqm4kIEzOTlvO9KMjG5J8xDB6cKRBGWtuaYItPaRDzXJybMr0yV-XmE3Vp24s5jks22dCE-nlRyQBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEpRbtA4RxdWljgiMpiXNlY3AyNTZrMaEC2YFYSOh3-zoIqHNAN3dzKXxZcfzaTcIO2eubX3BiEQ-Ic3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QNti3RuTSPH3aneI9m5R-4c5SUZqaOH_njvk2ezJUj2UQDFkgm2deWLOGkn0jMUjRyMOxXAluMvIS_-fDcySS8EBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEnfVSpIRxdWljgiMpiXNlY3AyNTZrMaECAZcUD06u8vG4odGwNWwnqd5YvLQzWpZWbcNJrUXl5UqIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QFtC2SkZ1Fmyfjg2r-lew5YX6AJU43EmOhvGTKLjDclPEqx22L809fuZibYzdUC4QziO4lw1NfvW7q3fGbmobCgBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEkr7eV4RxdWljgiMpiXNlY3AyNTZrMaECWM-19HsETwrty153VQK2Qf0lggex_NP-RUhkOgepnBWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-Mm4QLaSJFtlYxdSqJvJFn7K1CSD5ctr8EC113_aQYB4V4aCEn1h1rxw4z1WFUcHhsLVvtXiRQT8E7rEuNA-zJYDe1sBh2F0dG5ldHOIAAAAAAAAAACDY3NjBIRldGgykNjdQwZgY3YkAAEAAAAAAACCaWSCdjSCaXCEp0fSfYRxdWljgiMpiXNlY3AyNTZrMaEDJzRMI6aBykFmWsQZ2TFFjQmZ2rbHqTZ-LYzbvOobl8eIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg", + "enr:-MS4QL7la6R4Sp8mD6nbUto7mXQpCPIucMXYonbxaihETbddQGirx9-Qqvtx4Ngw1g4_mleYM_I0H8i0-KPQQkbQjjMEh2F0dG5ldHOIABgAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_Gf0iJc2VjcDI1NmsxoQI4KtS1lao9CxXhT-dthQGovzUEnODDPFYl7SBfEA08R4hzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QFSt__5LhjnRp9F-Q0v93uvlKpYyeb42V5qvRNSFkHxDPTHJ84j31_HZVJtCfeIyfnKpScbEklmAC3O8D75hdE8Eh2F0dG5ldHOIAIABAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2s4qJc2VjcDI1NmsxoQPDA64YfJmZDlj1LFjnJczhWpTEl32kc4RXy0cMiA6hcYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QBqSz2fdFrHnpZnrjpOXXX7DRhO8IZiDM_Du2M_I6uYwEEcwfBPsa9v2D9Pxz2eTXJPKQav_hHMzeO3-59Nz-VIEh2F0dG5ldHOIAAAAAAAADACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3e-OJc2VjcDI1NmsxoQJ6gbvJoChFGM3fziLl6TfKD4Ddt_DKmIpA3F-nijLMHIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QMdKhukqEi_AnWG-_qI_t3CrFQ8p-uGOEYBbXuJnbDxBSqdPnbpx1K7b42H8TQpxr3bJeOZuZ4vz1ret7VkJPocEh2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31WCWJc2VjcDI1NmsxoQIEdDMa4eWOEzJPjVoElGm5CKpvUdD2VF-Q-o25AyV43YhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QLB-DtV5j-GdScoGse3R0ZsEXQYkh3pZzgLElGH__jN7cIaFuFfyw5vrTbxWMKJbHIYaaHfVcPrz2YFGSIJ_hXQEh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69VfuJc2VjcDI1NmsxoQL2OAp25wYmzzzJKubNowvK5I3nHC4I5eEVS6R43Z4C-ohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QE3-f8qUWYbx1zNdoh0WMjYaHuRvdo33xP5dNJQ56pBaMI8GpGwvLeaWun2UbF7OexlrL8evl39yhuUOPrepD0oEh2F0dG5ldHOIAAAAAAAAAAaEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKAJmyJc2VjcDI1NmsxoQNE22g9OW0JX2MsomMWm64rCbsiSrZ4rB3cWB2-kT1oWYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QHYLVxO7IRuJpcYeQJK81tow8_P58XnIfYkVoQwOBDnLU2QiLTNtzDVHBLTLwpMrth5XwOJhjlC4z8L6Y3ffUBgEh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIrFV6KJc2VjcDI1NmsxoQKA5AkBxLZePDZUsYHLgsf10Ib7x_PdYZ_ORAvLNHVOoohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QNJOA_EYx3fSHmfWFz5ffCCfRZW5n3C9gVAn64-1Vq4vZzYsmtF2fm6l4GQd53bIbDJO5XXwr-Ltaow2PbbNxq8Eh2F0dG5ldHOIAAAAAwAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRzgOJc2VjcDI1NmsxoQLownRcAKPtJvJ24jFhNL-XVkf0CUKRpaQCMaOX1DdbMYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QKjT4PY-Bf8hyxURb8ONCVH4CPTc8DSp1mTlEDyPcr6rTR1G3AbDuFEDcL5z97K2OfeKwMwp9V82HmwRwC6UWMoEh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3H5uJc2VjcDI1NmsxoQJjQFB0Q6Z8mh1dbe8DsbvVvfgX7na14JR8OnzOVongfohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QAhMlMk0Sr4K29zo0qVw1ef4ufyealQRdIAXqbgtZVh6ab3o7WKx5Hvr3MK3sc60nBQB3hNaMpt--isKv09IM2EEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ31NHGJc2VjcDI1NmsxoQP0uJtV8gdLm995mg98Gfp9L9TP4AA7wCZKSZcl0aYeLohzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QOu9DJTE50sYY-z_lU6xozdB5LJwhfCIPCUNozdhjeihLAA9CHyL1GBeJqJjvoIm5RIO6iiNZFp3ZB4uWB4hzuwEh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7uVSJc2VjcDI1NmsxoQNWqxvo4uv00UaK_ETex9kqaB3xX17slXTxdvMqeHWUIIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QGFtyo4ejnaQuOf6w62R7pWAkVQs02zZqiKB06ARhNsRJGL4TIewlqV0-cPSdSguuZYPSRJddrhHMRSnIa6kcvUEh2F0dG5ldHOIAAAAAAAAADCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjHhOJc2VjcDI1NmsxoQJiLwrZNj46tPKMIaXyZp2D_dExmxjHMH_W0bDlSw4xEIhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-MS4QDa4tn2FRJLfuAPGrIIEYcPMaTlJlUqoHnZZBN7VX95Rbwn9cFN93mdYq5klQRfL3pSNo-iYCmN1SqIkm3B_fGkEh2F0dG5ldHOIAAYAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fqkuJc2VjcDI1NmsxoQJX1m_Dyt2QJekkL2O3f44GeJvqGXLPLLevk5oM5rNjpYhzeW5jbmV0c4gAAAAAAAAAAIN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QOxOkGvFqhKllD4vfg4xfwf1OH555pTPxd9n2IKddj9cC3v6XpALXuQOoFe3MeXuKcRSWx61LcTn-8kzkmFEIEADh2F0dG5ldHOIAAAAAAAAAAyEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES3cBaJc2VjcDI1NmsxoQLi9EnRObjSmOysxaGITFdArRXVmpJCMKRkMX8KSc4rS4hzeW5jbmV0cwaDdGNwgiMog3VkcIIjKA", + "enr:-Ly4QH89XtIf-D3uX6m0YjkoTH7eGRhBGSZiu39ib2jXX6V5fa0QxUYabZdPl-5Fdew-rUPJ8sYuDQXYdEVeDjKwmKQDh2F0dG5ldHOIGAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GpWiJc2VjcDI1NmsxoQM2u9Syt4BkQn-WSycLUXp7ajuESEUtVdtsjNMJ7n7Me4hzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", + "enr:-LK4QAH0JWA-ME1EiLIcJmQ7h9mStB0pkcV4R8d4BkG8t1hOe47k6vBNtEkMV9rBlRXlFIFfKwMcqH6h8sw7rgK0ORMCh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNoYaJc2VjcDI1NmsxoQK-pYgRudAjqNz7OVA5a2qmtxtsx_ZmDKwZm_Vub7lWPIN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QDVEJYjwK3H8Tj857ZmNZRo_20B7fYPR53keYS8pPIrHeiPFCwOBok6fvWr4457kOwXoszf41IpJEmFNXingyN8Dh2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjPAeJc2VjcDI1NmsxoQP6kCCPnIwk94L0eTPSyEnqtvM1yQZzg1WkDkZKjLdaTIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QETJyo6kF40C8v3SYt_49v2tFHxuJiGNGFtr2GUHtn_pdHIEXYEFCAkooMLstcQY20qlLk_EYzs4nPx66swzZnQDh2F0dG5ldHOIADAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-6KJc2VjcDI1NmsxoQKIjpnE7-XBEpSfEM3OTxwMirrmlWmuWxYTtuwQDaJ2XYhzeW5jbmV0cwKDdGNwgiMog3VkcIIjKA", + "enr:-Ly4QPJX60M6LiSApuKzABdZGcRZdXeNs9YK_RXkOi7mu-XBeT4p6ws6TV6UOWaQNghtOQBGt2dwDhA75oK_ZoktMCMDh2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhC5lURmJc2VjcDI1NmsxoQPyysL6sOJtdbbxCZ5R1aJjUfQmJhmE-I_xYqO9-i90johzeW5jbmV0cwqDdGNwgiMog3VkcIIjKA", + "enr:-Ly4QAw204L45p1Mp3ryCSdVvsHlBHMVJrwScuqXELpp7k6WQ8Vt7BypqMOSOVd3uL4ROT4R_paqzfrMIR-fFKItNMsDh2F0dG5ldHOIAAAYAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4ByyJc2VjcDI1NmsxoQMJdFDFq8q3DhC943QMFSxkkluGHNsNvbrTTWKD-LYr94hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QKJJaj_g8L8Okg4S3MJmQ9ZcNLytmtrPx_FY60TD_Pn2cVdm-PaIE9p5csITOvIpu6TYY4zBwc1uIE5FC4Vmh8YDh2F0dG5ldHOIAAAAAAAAwACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLymYWaJc2VjcDI1NmsxoQLB7079lklX_9vsCAj2LZx71-4Dzj-MlLn2qmj6UiDjd4hzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QMZw5ndFHQP8xRF46D_k1eyibF7FAypRq_oPkQioIJPBB2VdI43v2UV8Y_A0Ll0Rr1IoVkxGUW6JSP_naF3oStYDh2F0dG5ldHOIAAAAAIABAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPPX46Jc2VjcDI1NmsxoQI2VB9Qwv9Azwm5oM2MXDd-wILue3jE2DxVsVv3HKoBNohzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QLpIqVziOnAZ-U2-uUgNq9EiEukP-Hsmr1rX5q9RN6bbOaMEJfgiQftGVje33Xz1z0YOqRR136VEn8r0jS5IFd8Dh2F0dG5ldHOIAAAAAAAAABiEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJK-Uy2Jc2VjcDI1NmsxoQLH5B5DL6IO9nhqNoj4sVyyYteRN1j012_LZ5HDGFaLvIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-Ly4QKYuxsuhgcWTcwC-LfLKwBQLVTDmMg8iGNwa6Fu462j2IMCNKx1I-Vb77JxpDQs6JIq23O0sgvAv2sGkxnDAf9wDh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRuLmJc2VjcDI1NmsxoQJoV-IcjTx1TkZqUDsKULphwU9maN4y7uLmAzQFycAAtohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-LK4QDJp2U08hakweMKge9h1AHrsr28cIAMeY18b8-7PAathFBuUuO6sXyJABhloJ94uWqKS26YC2UgA6H3Moju7Bb4Ch2F0dG5ldHOIDAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKesmW2Jc2VjcDI1NmsxoQI_jFdc5GSJ0TnwA5DlKK-doN89Tr6oXDmB4KxWwzYoWIN0Y3CCIyiDdWRwgiMo", + "enr:-Ly4QH42VUJjJxw24sBTppaF190Pcn0laRqa3UUxcR5EoA-kLDPl0EAnH7hqnD4JBJ4BjkJ4IQGgDjquHUoWJpneAWcDh2F0dG5ldHOIAAAYAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO21QqJc2VjcDI1NmsxoQKU8u3T4sCtMUkucKyRFXMGebCffrMnss3P_52W55RJIohzeW5jbmV0cwSDdGNwgiMog3VkcIIjKA", + "enr:-MK4QHMmDt1EuRPEgjoUJ5-leNqpUqIZBwWmzBrR-a_2AO5eFYukPyiE_2VHH8rVTu-CXpPwX2KBkSJBeacgF5VYCwiGAZL8lfxmh2F0dG5ldHOIAIABAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjybOJc2VjcDI1NmsxoQJS3R2VkqpdkwyZkZQMDMU_IF04dLxQt6NAf70kWcXYvohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QItySKXmpWDl3tLnVqAP00A5rFrlzBqfYbEXriD1gnIpWpiQIQ5fPLyUQq3leYmC-GpbtV6VQ2Iz9E_0hfKWaQKGAZL8lgN5h2F0dG5ldHOIAAAAAAAAAGCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fSeGJc2VjcDI1NmsxoQPMIZKzBRt9YGP7hlJHA1LzFAm8URxH98D4RDmQhKc-yIhzeW5jbmV0cwmDdGNwgiMog3VkcIIjKA", + "enr:-MK4QBlCr5bxnEMn3xk0GsS48gxy66ZVUBu6hJKvCJGTy6NhM2d8M4l08S-bqkN43z6swzN57bJ86Lcq9LXkNd-xLC-GAZL8lgKnh2F0dG5ldHOIAAAMAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5dy46Jc2VjcDI1NmsxoQJoK-aOOTD9lMwTCcO37Ihmcnknp9FxO9lsFYBuTZRfGohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QFP-ZBOIUZKl24rwQ2MDBiWioMBQ4Oi_rMBXRikKX0XDMV9-nXe9ITJJPQlWPFcSNrVIwcah3Trw5ImLKblk3ymGAZL8lgu_h2F0dG5ldHOIAAAAAAAAMACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES34myJc2VjcDI1NmsxoQNTVdI6Vw-YubsEVxTl5-JECJHcsESDoq60UruR5JwjcohzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QFEPaQEsgH8YL5Gu9Xw1HdSaCjfHBaavRcuwRlEq3QulQdU3xLoPXV0l_zRoEMkdMGh-5e3AY842xFamYub7ojGGAZL8lgByh2F0dG5ldHOIAAAAAAAAAMCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXU2Jc2VjcDI1NmsxoQIUCDXAKfrPVgTp5yIYkGgneVdc5FaYQjnRSAMD50_LIYhzeW5jbmV0cwSDdGNwgiMog3VkcIIjKA", + "enr:-MK4QNOSfKR0-_DO35S3ogEDB0HyS5O1KVG3AG56YUsSdTbvDq7nLS_BQBtYF3W_JwHjOLidbyCdsSpEZ73iMJuFhEeGAZL8lf2nh2F0dG5ldHOIAAAAADAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhMbHVWCJc2VjcDI1NmsxoQJmKRg0hEM-TnwPj2ilnshK9hGixG55MaGHv_vnYASWBYhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QABR7d4ppxIxFOvg5jUTJ2mBzkPjvsFAmx4ijBOlYgk7AU41gNphw78hzxmeCEw0Wq7LK5YTuHUahjz8WM7i3tmGAZL8lgVIh2F0dG5ldHOIAAAAAAAAgAGEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAyyGJc2VjcDI1NmsxoQM9MtxjAx2y-mL3gQD25yWl3Gks7nrEHGEM5DvSpX1rLohzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-MK4QCfAmFbSe4QLoUDERuSZ7aE74lIfXnXRkvm7cjjayHFLMVy0XRQxxvxRLBoLpZV_-SS-lQyaVDkjhmNuv-igbTeGAZL8lfv7h2F0dG5ldHOIGAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GdHKJc2VjcDI1NmsxoQKl9J1dyW1CnoiAN9is5uNLnk9op4wIIXWVahx6DsLmDYhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QEjbxm5EwlJUp062pFTwpbnyOHUZJOE0BnxBuQYro80aWwzPxuYsj9S1zdOEhtMCadpHaueKsoJtD6x2be06XwyGAZL8lg22h2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3mJJeJc2VjcDI1NmsxoQP68-24KkowwXNVIM5A5BlStNX8dUR636iyStKqFuXDIYhzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", + "enr:-MK4QPTbd5CgBXLtFu34aJw8TR4Mpk55PBJj6RQTZP_HPfSFOhOpLI4cLbR39tBBShjc43GGKhANt2RK0hHYUrMUNIeGAZL8lf3ch2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoaVWJc2VjcDI1NmsxoQK9VrHPA291SJwcKGe4cdSJdnRc2imeTGuUscFIlzIRSIhzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", + "enr:-MK4QM6qzQ2kwTRRe9dRGEGqpvdN_6czu0t3gSAO7ojsuennXtY2y2h3HlNoI8lFvQtjXFVz-TDJTia1aabby113GgSGAZL8lgc-h2F0dG5ldHOIAAAAAAAAAGCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhES37GeJc2VjcDI1NmsxoQLGSNIMObiRYK12eYlHVqXrRtkjld2qnfqeymyqS09vNYhzeW5jbmV0cwSDdGNwgiMog3VkcIIjKA", + "enr:-MK4QC1IbLWxtbrF4aiHmvelea2gn0DUjRQLbOVjfDvIg7NeCDkmgHcAULDfyv8nokHVadeHU_nZtXx5KFSWMRThXpeGAZL8lfxSh2F0dG5ldHOIAAAAAABgAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6aWJc2VjcDI1NmsxoQIRdEG4LqcWFxuGL8rKnuloHMaXaWcyTAW36bQF-vq43ohzeW5jbmV0cwaDdGNwgiMog3VkcIIjKA", + "enr:-MK4QB2VcgCAj5ZZW8ItWHT7kT115pGK9U2jQt9e6A-_blQCGgZYCVfsAoUPnFoatzpolSqfq5yDqaOUZVRqfble4-6GAZL8lf37h2F0dG5ldHOIAAAAADAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGiDI7CJc2VjcDI1NmsxoQP1gXjy89Aq_qC3q4h6YpMAQ7ArRyOAkNSdt2uxR95aRYhzeW5jbmV0cwiDdGNwgiMog3VkcIIjKA", + "enr:-MK4QE5FCzl2lOL1yLeUI9sOKol9sMDIP_2_829ONxfEKJ0RCMJ5fVoVCgAzkQeCB3Qy5cTc-J_xvV0BTUGwVncUeSuGAZL8lf3ah2F0dG5ldHOIAACAAQAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLKA-BqJc2VjcDI1NmsxoQOsPITil6o4aZGLJU4QVOouhwA_asQYKzx73WQrX9mKJ4hzeW5jbmV0cwuDdGNwgiMog3VkcIIjKA", + "enr:-MK4QDTSMAJnlzM5ge0zFDYIf3Dm1jo-QlW16bGEK1c5V4XqROkjICrItNtTHn_rWZ7sFLJ-HEJrEXuelLoNRq4Mk7KGAZL8lf41h2F0dG5ldHOIAAAAAAAAABiEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDjdKaJc2VjcDI1NmsxoQLd_yMbZ703FvFi-XREC6rLHnbD_UWUCza99qjnAmrv4IhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QM6zcrPDsArscPtgE1vIUYUttaaaoy9KK1UVJt_v2vltRucEOoJf1Y0YhSmEjVTnxtquUnNsthr1xEbzlINJMaCGAZL8lgbDh2F0dG5ldHOIAAAYAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJO2m8KJc2VjcDI1NmsxoQP-z75gbAYqR6_LCL2rpPTZmrOz8NnS1UFhqjsmwVbw9IhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QL18SZHDapmjGWInRUZYBuU3CTkqVLyhxpovPLcnMgsiPx6b2uf2jHQnj3lK8y0mLxv74y6Ww2kBFdrLKFLxZTmGAZL8lgfth2F0dG5ldHOIAAAAAAYAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7BZaJc2VjcDI1NmsxoQM1pgLIjSoQCDzGaH6k-xiL_H9FP_aO62iZXpnRFU_6zohzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-MK4QAKZrFxKHiZlNYqq3a3t5SSbg36XL1ipI93wPvj6nhmfVSi5iNK9qRxQmhRt8b6S5iEAcPhnHNiO4gtaZdGg3DKGAZL8lgRah2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GaKKJc2VjcDI1NmsxoQMYWC2DzvQ8_K9V6kU3g2Bfr7qkp0MkkpLcc04szxTQ_ohzeW5jbmV0cwKDdGNwgiMog3VkcIIjKA", + "enr:-MK4QAeVsVSVHkpiv2wpX4JovFW-8zlNJGQvso-cu25VIRIkYDs1uokbt_XexoabwaneyuftPbDFnNbuTVFjOiixIAqGAZL8lgJOh2F0dG5ldHOIAQAAAAAAAICEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4xiSJc2VjcDI1NmsxoQNj5zT1FZCoZp2vu0xyPvIn3nTGjbIweVwEkAAeqdMJ9YhzeW5jbmV0cwWDdGNwgiMog3VkcIIjKA", + "enr:-MK4QIejUXUsOX2Zt0gaZ0L0nNjE40rCu5S3H_lNaug79Gk2aNObUAorRsTXKslKTc2oFRFd68vn_294oKtOjKQ6lP2GAZL8lgrih2F0dG5ldHOIABgAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjQ9WJc2VjcDI1NmsxoQNBNJ9KuHDBEp0PnogcADqdijjfYEI94yP91iLwFNM6johzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA", + "enr:-MK4QN0Jin_u-UobugNNP9ux3Fin5tk93ax5tCwNTWhIQNmkf4hKHVQc7n39zaYTauxHg44byC_F1XAroTedeudWKMCGAZL8lgHwh2F0dG5ldHOIAAAAABgAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXj6zuJc2VjcDI1NmsxoQJKQP5WBCZz89oRMDF0ZK657hmXuScPIKk22SQMBXBseYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-MK4QAySvod_fX8760QzGJ6pMeZGGY05vUG7HY2IndLnkvJBYR48NdvtvqWWTXmScVEy4blZoxDuRIKiu1FX3ym2XjaGAZL8lgNyh2F0dG5ldHOIAAAAAADAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_LaLyJc2VjcDI1NmsxoQLVROfxZ1332xSDedlu954b4dQKw3stV5r7PMKWS0VD94hzeW5jbmV0cwWDdGNwgiMog3VkcIIjKA", + "enr:-MK4QKThqho0pK2Ez22RIJkCqWasVhyFkXxQKTq1B_o05Yx9elbWfAMvoyl15XfE1u5oNRP6JGLSNoBGPwfAHDQT_XmGAZL8lgFxh2F0dG5ldHOIAAAAYAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhGj4WPmJc2VjcDI1NmsxoQIt33J7LcbYU-dhqYzMYlK9NNZoGq6Pd6Gkei5LITPYHYhzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", + "enr:-MK4QPvlUxfKTEuGcjtgBmh6dmMVlJ9kXCuvEJVxhXLpHokLcQO70_HIiPhTifc7nL9uVYf-aLsR9i9_Ju0juMl2obqGAZL8lgRih2F0dG5ldHOIAIABAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXoREOJc2VjcDI1NmsxoQP8EniEQ3S7NIc7G0eCJ-4fmsBmPEsXLLAIBTqhiEr1dohzeW5jbmV0cwODdGNwgiMog3VkcIIjKA", + "enr:-MK4QPVLA2XuDDDHyJv6a6vs1zKf-QucEokYhtG5pJtwPWBza6TXV8q1SgwU_FdkK-ngvd4VX4VkqFxgTc0Rjc9xrASGAZL8lgHph2F0dG5ldHOIAAAAAAAAAwCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI9u1yKJc2VjcDI1NmsxoQMdrx7mbyTnW_cSUJci7F6zPiIRtn99q5F6l_m0jQqtA4hzeW5jbmV0cwqDdGNwgiMog3VkcIIjKA", + "enr:-MK4QE7dJR9k1mKgRM8N5i_MGxWwqGRX3jUD_ODVlu3ai9zEd59l9Cc1LcUzcrNhnsxsY7ESwvGA1WsR-uvbpwMNz4OGAZL8lfirh2F0dG5ldHOIAAAAAAAAYACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fp9qJc2VjcDI1NmsxoQIslFIGQRB_VFWMPevzyxhMDX9CkCnJp4PEFRG5n7jk2YhzeW5jbmV0cwSDdGNwgiMog3VkcIIjKA", + "enr:-MK4QEuke5XW36g1t9fIhgBBdTsBsbVxUy6BPT5I-QMZ0gylMLKTO8OWrxprpOL_bqFM24x4YbpKzCcGlJet1m8P6D6GAZL8lfmLh2F0dG5ldHOIgAEAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIm4z1uJc2VjcDI1NmsxoQLsGvwvgwBKlErW3e4Wxlp_C-2LoemsgxNh4YXhzYh184hzeW5jbmV0cweDdGNwgiMog3VkcIIjKA", + "enr:-MK4QOKr0la5UiDsWR0svdmz5bRU2cAO8q2gbVGFVP_5zUjUTAyS482sVR2EEMU84R5Vag1rmKN2B50N62SAeFDvmUmGAZL8lgXAh2F0dG5ldHOIAAAAAAAAAwCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs7dg6Jc2VjcDI1NmsxoQI_Abpl-E4Sm5BYS-Rq19nAYTj3xG2t1GwsR6azMDvjjYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA", + "enr:-LK4QGKKpJY2mO2wwRWE1GrSOo0YbIhvGU3Q-jCp89LHJRZKObPECBJFrkx55lBHmBdofOU42tjHtcdaDEuz1y3mWOkEh2F0dG5ldHOIAAAAAMAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ9Z7GWJc2VjcDI1NmsxoQMcuYnhiF7_6Qlli7BHk-HtRJAJF1sAQIjBMMZFhHibLYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QDE7XQf1xXn_1svSTXMAGEfMCB06HojK0hGLFufHu65SBXvlV1oPxy9O_Ww4hqSwK_Ttn9RujfEpAl4p2Yp3Ox8Eh2F0dG5ldHOIAwAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW-E2Jc2VjcDI1NmsxoQO1c8OIsBWo_BTB2AcTOi3qr8PvnYK1mM5kIfuyJZ5ptIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QHbSqmyPO4e25hz5dAjD9R70Am45I757aI1VOivcheRnCL0IGR1srnCizSDmV0DAN-pgPPB7v4D_e8WIPpCKtWIEh2F0dG5ldHOIMAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI_GfsCJc2VjcDI1NmsxoQPRD80hT3L5trkyN7YR6dTa0eY8m8-BPEQ9VzVHr-KCm4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QDiQXp7rnmRd32bGVtboxwh-MFBpIAWTSUXAaxWhjVE9UERQUvGLsMYMcOHSRTND2Q7ViZ-t-VdnWG37q-ModXQEh2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdH2zWJc2VjcDI1NmsxoQLlA-CJY9lvScDxC3c0gbqgv0fVcK8__JhCLi-OWqjLooN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QF4azbnoYa11BniDYhO9-U14PRHaGGgU9VkUBXxiaQQLBoEXnE5PitCXZksrjr6IXZs1Rtk_rYat6Kg56rVl7A8Eh2F0dG5ldHOIAABgAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjWVmJc2VjcDI1NmsxoQJ-BjW6tpjmiDKUW-KNDVRL_avDPmK_yRo5HSGvJYgt04N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QFPSLoXEbUBBQTlZEwJtNqX8hVq1GccfOqUYPY7UEggpGrC0IFuIpZGi1yLetMUd9gc055On116W36EaRtlxVeYEh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhBjHXyKJc2VjcDI1NmsxoQI47lLtfQTztWdm3pVhY6giqC1PKudRwODxTQZEpGpcY4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QFFn8IQKKhPTcIos-3CSClVm7r102YpoTnjUvSZ6syyNWyJGeIDF6Uvm8SwzXKjfKmdV7g5TGyCgA0hO0-PNRFoEh2F0dG5ldHOIAAAADAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKpAkzeJc2VjcDI1NmsxoQPk4qNUMWmRxQKwDA99a2CjqktjXKi5wqCmNHQmFtegDYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QL2JLllEpB8OyarfTP9CxjpgsHAHsPZoY19qBjR85HYTI76d64iTA0RxusXCiJdTLRJWgE6DE8ArpbkRvAWYJ6sEh2F0dG5ldHOIAAAAAwAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhM69nQ6Jc2VjcDI1NmsxoQJIB8SxOEE4zHpubxYwAEFTFPvCvH1PK-aAawd5X_IfeoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QAW2bNcn_byPRldddp4zOJQrdZ0Tm_rmPLNIOUC0VUFjInLcNFLdxfUgWouL3VNN0sfs7zT0nfcSTWL4joj_0IMEh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhLI-E7uJc2VjcDI1NmsxoQLBU9O0JOoFxULrs225uuzI--xb3VzeV-Ub_i7ylzWp2YN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QF83C8OV4vbbr1HS0LFL1Fy4ZpJKOIi9QlSEJkfrDyRqIyy-D-Dp8A_vRVcJbbV5SbjBq1g-pQh7j1zzctlBXWoEh2F0dG5ldHOIAAAAAAAMAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEji72Jc2VjcDI1NmsxoQPEmmzHJQH9TRjb_K5yanwJ6Cakw3ki3ChgFXYOqLR-3IN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QDKtIFH1vZaG2pMhLPrgY-4g0zFk2iXOVs3WySC3MikxAhBdDEttTKSH1opVZOhnI_5Ivxp8raDNhMhntvJVTkUEh2F0dG5ldHOIAAAAAAwAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_f11yJc2VjcDI1NmsxoQLdayDMFPEnWPa_1MkL0YDmom_3zQKH2D3atBAIIt9rpIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QAt1xPThwZtp4fFdytsWwzuBuN_Kh_rlV0aJjkjWQUbddvBYctYLrzHAo7mFWktctMsGUO0VoBQdnm3ZiMoo3lEEh2F0dG5ldHOIAAAAAAAYAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEDiYIuJc2VjcDI1NmsxoQOkRH_IBZwuZmpxh9ldiwDYUqChz6_ei6yXAxqQ9z8QyYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QPYpTeJc1dtO_CB2Lvp7TCg6iQOU_WfpKPrTt_e3fHVKRZnmkGMA7aUzA-lxEgQQgb72TyPECN4z_vbO_XbJCL8Eh2F0dG5ldHOIAAAAAAAAgAGEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKXjJ-CJc2VjcDI1NmsxoQOuuqf6k-s_yOnNLcDNv0tIhesiYvvdphMIgyOBLDNeKoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QG0SdN74uXa3ZthPN7B-1egIGMBzW5wlR7QX3Y0eoJwRAetxow_pyIBPsTRkPY2FHLhv8jEqna_kPHt7eXe1A_AEh2F0dG5ldHOIAAwAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKUW3BOJc2VjcDI1NmsxoQJKVmvTZgOjFKGc3ShLgTA1H192A5PLYAPaFW3CVxEmHIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QFBL2CvVr5Sz-P3nkE6jvAQdArjrLkYkxlhAxNrOHPauOsaBaa5m5OF2IzIkw09hosGwOs4XOnhVPHuYfFdV2YIEh2F0dG5ldHOIAAAAAAAAAMCEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ_fxziJc2VjcDI1NmsxoQPfWXddZQ4UAiu178G3WlyghgoIpgrZATEBNsApnA9b5YN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QPsih3HzKvodMe13_S7G7-LdHARWSWqGrfjBwpld7uBZAmE5509YBXunP5YOVfN7-65FjBRkR4HmImaVTW-3ILIEh2F0dG5ldHOIAAYAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhEPNp5mJc2VjcDI1NmsxoQPKHJGGjFBqh9a3p0xyykr1iyzYG1YGPujEkx_hilG9tIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QHRInI7TYE6LVBAAsU1ahJONNnYjGpJEVZMOgLH3hEPzQsEWzYAMWTIU_d9mlL4SAT3jMHi0RUOQ1tNvKpdFo5cEh2F0dG5ldHOIAAAwAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIs75jmJc2VjcDI1NmsxoQJTVNZQIGja0Btyt1pPX21sQ25PAIs16JYqRpc2OIOHMIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QJOiEnrs_7W2xD5ni1S4HGGXKhrzuluvt3XGMM-4HZl2OM5gtKY3OtkKKUPYYTFbkz8-IZh27fimVhiYHAr7rwwEh2F0dG5ldHOIAADAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKdjX6-Jc2VjcDI1NmsxoQLDUVY1B_Y7uKNnNuFBqVjsXXZPF4UcHYwlRIX8bOqwDIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QGJlf3p3S3hfJTs2Bmj2YoidPP_QWT14t6eMySxYa22cDWdNPDY3gmFkevT_C_f1J1DAbQCCEELcjh2Y2gQ9U6sEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhIbRrmKJc2VjcDI1NmsxoQND9l9iIY92LxR5Yg0JThjZt2atGz9Wu7V-_Zn1JFsPgoN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QIzc1HoQowg-CyrkruCbNxJ19dcn_UpWh07zKhyl_b3TBhjju0QVnwMC0HBUo-mFPlLqVI-v4dvS7pIp5llr1cAEh2F0dG5ldHOIgAEAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhKEjnAqJc2VjcDI1NmsxoQJI2HA4O9X4qs7K2Tgh637dz876s8f40wanbnnPxJcBKYN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QG9_qJS-qov-VWaRJB7NDD1XJExA2zaTqSUsXS87mqsGdLbNlMEUcUl6-Jjn2h5JCrgjdekJajxIDBSozs2FLPIEh2F0dG5ldHOIAAAAAAAwAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhI5deB6Jc2VjcDI1NmsxoQL0hy3fyx2QhB-qxvdBIB1RqBIXwEcpNAspkyMESe-Ds4N0Y3CCIyiDdWRwgiMo", + "enr:-LK4QMjMMPjyls4JEnYlNcQi7k9j66Z6aDvmyLGh-MmK6Do_CncBF2dTEvrXJPcbDgIrpFrImsyw6tF4YUzO0OhHaGYEh2F0dG5ldHOIwAAAAAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJ3m4YuJc2VjcDI1NmsxoQLP3iDQVX979MeG4JUG5TEEOfcBDq4DL6IwV_vMO-iMsIN0Y3CCIyiDdWRwgiMo", + "enr:-LK4QPNn6P_ydDEeOPMp77RH7NHZtEdFstujjbM_mg9N9mHDEGaAim7qZo5jWgMC1HZpf0c4-tf0Y6eFkDdw9EbhPlAEh2F0dG5ldHOIAAAAwAAAAACEZXRoMpDY3UMGYGN2JAABAAAAAAAAgmlkgnY0gmlwhJgq582Jc2VjcDI1NmsxoQN2tk0LwZ9dacFxiUApBGnqfHwLTiOjtC8Kstlel29Xw4N0Y3CCIyiDdWRwgiMo", ]; diff --git a/packages/config/src/chainConfig/networks/mekong.ts b/packages/config/src/chainConfig/networks/mekong.ts index d7f2d15cb525..106c2abe67fa 100644 --- a/packages/config/src/chainConfig/networks/mekong.ts +++ b/packages/config/src/chainConfig/networks/mekong.ts @@ -13,21 +13,21 @@ export const mekongChainConfig: ChainConfig = { // Genesis // --------------------------------------------------------------- MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 100000, - MIN_GENESIS_TIME: 1730372340, - GENESIS_FORK_VERSION: b("0x10000000"), + MIN_GENESIS_TIME: 1730822340, // 2024-Nov-05 03:59:00 PM UTC + GENESIS_FORK_VERSION: b("0x10637624"), GENESIS_DELAY: 60, // Forking // --------------------------------------------------------------- // # Altair - ALTAIR_FORK_VERSION: b("0x20000000"), + ALTAIR_FORK_VERSION: b("0x20637624"), ALTAIR_FORK_EPOCH: 0, // # Merge - BELLATRIX_FORK_VERSION: b("0x30000000"), + BELLATRIX_FORK_VERSION: b("0x30637624"), BELLATRIX_FORK_EPOCH: 0, TERMINAL_TOTAL_DIFFICULTY: BigInt("0"), // Capella - CAPELLA_FORK_VERSION: b("0x40000000"), + CAPELLA_FORK_VERSION: b("0x40637624"), CAPELLA_FORK_EPOCH: 0, // Deneb DENEB_FORK_VERSION: b("0x50637624"), @@ -36,6 +36,15 @@ export const mekongChainConfig: ChainConfig = { ELECTRA_FORK_VERSION: b("0x60637624"), ELECTRA_FORK_EPOCH: 256, + // Time parameters + // --------------------------------------------------------------- + MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 2, + + // Validator cycle + // --------------------------------------------------------------- + EJECTION_BALANCE: 30000000000, + CHURN_LIMIT_QUOTIENT: 128, + // Deposit contract // --------------------------------------------------------------- DEPOSIT_CHAIN_ID: 7078815900, From 10d15dce1f62eaa0e5570f6790827f2c091c616d Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:04:55 +0800 Subject: [PATCH 197/259] fix: light client generating `LightClientUpdate` with wrong length of branches (#7187) * initial commit * Rewrite SyncCommitteeWitnessRepository * Fix finality branch * Update unit test * fix e2e * Review PR --------- Co-authored-by: Nico Flaig --- .../src/chain/lightClient/index.ts | 28 ++++- .../src/chain/lightClient/proofs.ts | 54 ++++++--- .../src/chain/lightClient/types.ts | 2 +- .../lightclientSyncCommitteeWitness.ts | 55 ++++++++- .../test/unit/chain/lightclient/proof.test.ts | 107 +++++++++++++++--- packages/light-client/src/spec/index.ts | 4 +- packages/light-client/src/spec/utils.ts | 10 +- packages/light-client/src/validation.ts | 13 ++- packages/types/src/utils/typeguards.ts | 11 ++ 9 files changed, 240 insertions(+), 44 deletions(-) diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index 94dadbd2a646..57a26a4f267a 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -16,6 +16,7 @@ import { SYNC_COMMITTEE_SIZE, forkLightClient, highestFork, + isForkPostElectra, } from "@lodestar/params"; import { CachedBeaconStateAltair, @@ -38,6 +39,7 @@ import { Slot, SyncPeriod, altair, + electra, phase0, ssz, sszTypesFor, @@ -46,6 +48,7 @@ import {Logger, MapDef, pruneSetToMax, toRootHex} from "@lodestar/utils"; import {ZERO_HASH} from "../../constants/index.js"; import {IBeaconDb} from "../../db/index.js"; +import {NUM_WITNESS, NUM_WITNESS_ELECTRA} from "../../db/repositories/lightclientSyncCommitteeWitness.js"; import {Metrics} from "../../metrics/index.js"; import {byteArrayEquals} from "../../util/bytes.js"; import {ChainEventEmitter} from "../emitter.js"; @@ -208,7 +211,10 @@ export class LightClientServer { private checkpointHeaders = new Map(); private latestHeadUpdate: LightClientOptimisticUpdate | null = null; - private readonly zero: Pick; + private readonly zero: Pick< + altair.LightClientUpdate | electra.LightClientUpdate, + "finalityBranch" | "finalizedHeader" + >; private finalized: LightClientFinalityUpdate | null = null; constructor( @@ -225,7 +231,9 @@ export class LightClientServer { this.zero = { // Assign the hightest fork's default value because it can always be typecasted down to correct fork finalizedHeader: sszTypesFor(highestFork(forkLightClient)).LightClientHeader.defaultValue(), - finalityBranch: ssz.altair.LightClientUpdate.fields.finalityBranch.defaultValue(), + // Electra finalityBranch has fixed length of 5 whereas altair has 4. The fifth element will be ignored + // when serializing as altair LightClientUpdate + finalityBranch: ssz.electra.LightClientUpdate.fields.finalityBranch.defaultValue(), }; if (metrics) { @@ -388,12 +396,13 @@ export class LightClientServer { parentBlockSlot: Slot ): Promise { const blockSlot = block.slot; - const header = blockToLightClientHeader(this.config.getForkName(blockSlot), block); + const fork = this.config.getForkName(blockSlot); + const header = blockToLightClientHeader(fork, block); const blockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(header.beacon); const blockRootHex = toRootHex(blockRoot); - const syncCommitteeWitness = getSyncCommitteesWitness(postState); + const syncCommitteeWitness = getSyncCommitteesWitness(fork, postState); // Only store current sync committee once per run if (!this.storedCurrentSyncCommittee) { @@ -621,6 +630,16 @@ export class LightClientServer { if (!syncCommitteeWitness) { throw Error(`syncCommitteeWitness not available at ${toRootHex(attestedData.blockRoot)}`); } + + const attestedFork = this.config.getForkName(attestedHeader.beacon.slot); + const numWitness = syncCommitteeWitness.witness.length; + if (isForkPostElectra(attestedFork) && numWitness !== NUM_WITNESS_ELECTRA) { + throw Error(`Expected ${NUM_WITNESS_ELECTRA} witnesses in post-Electra numWitness=${numWitness}`); + } + if (!isForkPostElectra(attestedFork) && numWitness !== NUM_WITNESS) { + throw Error(`Expected ${NUM_WITNESS} witnesses in pre-Electra numWitness=${numWitness}`); + } + const nextSyncCommittee = await this.db.syncCommittee.get(syncCommitteeWitness.nextSyncCommitteeRoot); if (!nextSyncCommittee) { throw Error("nextSyncCommittee not available"); @@ -641,7 +660,6 @@ export class LightClientServer { finalityBranch = attestedData.finalityBranch; finalizedHeader = finalizedHeaderAttested; // Fork of LightClientUpdate is based off on attested header's fork - const attestedFork = this.config.getForkName(attestedHeader.beacon.slot); if (this.config.getForkName(finalizedHeader.beacon.slot) !== attestedFork) { finalizedHeader = upgradeLightClientHeader(this.config, attestedFork, finalizedHeader); } diff --git a/packages/beacon-node/src/chain/lightClient/proofs.ts b/packages/beacon-node/src/chain/lightClient/proofs.ts index d4380e66255f..fe8ca7881a76 100644 --- a/packages/beacon-node/src/chain/lightClient/proofs.ts +++ b/packages/beacon-node/src/chain/lightClient/proofs.ts @@ -4,29 +4,55 @@ import { FINALIZED_ROOT_GINDEX, FINALIZED_ROOT_GINDEX_ELECTRA, ForkExecution, + ForkName, + isForkPostElectra, } from "@lodestar/params"; import {BeaconStateAllForks, CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {BeaconBlockBody, SSZTypesFor, ssz} from "@lodestar/types"; import {SyncCommitteeWitness} from "./types.js"; -export function getSyncCommitteesWitness(state: BeaconStateAllForks): SyncCommitteeWitness { +export function getSyncCommitteesWitness(fork: ForkName, state: BeaconStateAllForks): SyncCommitteeWitness { state.commit(); const n1 = state.node; - const n3 = n1.right; // [1]0110 - const n6 = n3.left; // 1[0]110 - const n13 = n6.right; // 10[1]10 - const n27 = n13.right; // 101[1]0 - const currentSyncCommitteeRoot = n27.left.root; // n54 1011[0] - const nextSyncCommitteeRoot = n27.right.root; // n55 1011[1] + let witness: Uint8Array[]; + let currentSyncCommitteeRoot: Uint8Array; + let nextSyncCommitteeRoot: Uint8Array; - // Witness branch is sorted by descending gindex - const witness = [ - n13.left.root, // 26 - n6.left.root, // 12 - n3.right.root, // 7 - n1.left.root, // 2 - ]; + if (isForkPostElectra(fork)) { + const n2 = n1.left; + const n5 = n2.right; + const n10 = n5.left; + const n21 = n10.right; + const n43 = n21.right; + + currentSyncCommitteeRoot = n43.left.root; // n86 + nextSyncCommitteeRoot = n43.right.root; // n87 + + // Witness branch is sorted by descending gindex + witness = [ + n21.left.root, // 42 + n10.left.root, // 20 + n5.right.root, // 11 + n2.left.root, // 4 + n1.right.root, // 3 + ]; + } else { + const n3 = n1.right; // [1]0110 + const n6 = n3.left; // 1[0]110 + const n13 = n6.right; // 10[1]10 + const n27 = n13.right; // 101[1]0 + currentSyncCommitteeRoot = n27.left.root; // n54 1011[0] + nextSyncCommitteeRoot = n27.right.root; // n55 1011[1] + + // Witness branch is sorted by descending gindex + witness = [ + n13.left.root, // 26 + n6.left.root, // 12 + n3.right.root, // 7 + n1.left.root, // 2 + ]; + } return { witness, diff --git a/packages/beacon-node/src/chain/lightClient/types.ts b/packages/beacon-node/src/chain/lightClient/types.ts index b253c05d45fb..b9723df501b3 100644 --- a/packages/beacon-node/src/chain/lightClient/types.ts +++ b/packages/beacon-node/src/chain/lightClient/types.ts @@ -26,7 +26,7 @@ * ``` */ export type SyncCommitteeWitness = { - /** Vector[Bytes32, 4] */ + /** Vector[Bytes32, 4] or Vector[Bytes32, 5] depending on the fork */ witness: Uint8Array[]; currentSyncCommitteeRoot: Uint8Array; nextSyncCommitteeRoot: Uint8Array; diff --git a/packages/beacon-node/src/db/repositories/lightclientSyncCommitteeWitness.ts b/packages/beacon-node/src/db/repositories/lightclientSyncCommitteeWitness.ts index 45f91f159997..e323c3e55f61 100644 --- a/packages/beacon-node/src/db/repositories/lightclientSyncCommitteeWitness.ts +++ b/packages/beacon-node/src/db/repositories/lightclientSyncCommitteeWitness.ts @@ -5,6 +5,15 @@ import {ssz} from "@lodestar/types"; import {SyncCommitteeWitness} from "../../chain/lightClient/types.js"; import {Bucket, getBucketNameByValue} from "../buckets.js"; +// We add a 1-byte prefix where 0 means pre-electra and 1 means post-electra +enum PrefixByte { + PRE_ELECTRA = 0, + POST_ELECTRA = 1, +} + +export const NUM_WITNESS = 4; +export const NUM_WITNESS_ELECTRA = 5; + /** * Historical sync committees witness by block root * @@ -13,12 +22,56 @@ import {Bucket, getBucketNameByValue} from "../buckets.js"; export class SyncCommitteeWitnessRepository extends Repository { constructor(config: ChainForkConfig, db: DatabaseController) { const bucket = Bucket.lightClient_syncCommitteeWitness; + // Pick some type but won't be used. Witness can be 4 or 5 so need to handle dynamically const type = new ContainerType({ - witness: new VectorCompositeType(ssz.Root, 4), + witness: new VectorCompositeType(ssz.Root, NUM_WITNESS), currentSyncCommitteeRoot: ssz.Root, nextSyncCommitteeRoot: ssz.Root, }); super(config, db, bucket, type, getBucketNameByValue(bucket)); } + + // Overrides for multi-fork + encodeValue(value: SyncCommitteeWitness): Uint8Array { + const numWitness = value.witness.length; + + if (numWitness !== NUM_WITNESS && numWitness !== NUM_WITNESS_ELECTRA) { + throw Error(`Number of witness can only be 4 pre-electra or 5 post-electra numWitness=${numWitness}`); + } + + const type = new ContainerType({ + witness: new VectorCompositeType(ssz.Root, numWitness), + currentSyncCommitteeRoot: ssz.Root, + nextSyncCommitteeRoot: ssz.Root, + }); + + const valueBytes = type.serialize(value); + + // We need to differentiate between post-electra and pre-electra witness + // such that we can deserialize correctly + const isPostElectra = numWitness === NUM_WITNESS_ELECTRA; + const prefixByte = new Uint8Array(1); + prefixByte[0] = isPostElectra ? PrefixByte.POST_ELECTRA : PrefixByte.PRE_ELECTRA; + + const prefixedData = new Uint8Array(1 + valueBytes.length); + prefixedData.set(prefixByte, 0); + prefixedData.set(valueBytes, 1); + + return prefixedData; + } + + decodeValue(data: Uint8Array): SyncCommitteeWitness { + // First byte is written + const prefix = data.subarray(0, 1); + const isPostElectra = prefix[0] === PrefixByte.POST_ELECTRA; + + const type = new ContainerType({ + witness: new VectorCompositeType(ssz.Root, isPostElectra ? NUM_WITNESS_ELECTRA : NUM_WITNESS), + currentSyncCommitteeRoot: ssz.Root, + nextSyncCommitteeRoot: ssz.Root, + }); + + return type.deserialize(data.subarray(1)); + } } diff --git a/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts b/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts index 1ae4812ea200..769fe49f690c 100644 --- a/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts +++ b/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts @@ -1,73 +1,146 @@ -import {SYNC_COMMITTEE_SIZE} from "@lodestar/params"; -import {BeaconStateAltair} from "@lodestar/state-transition"; +import {ForkName, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; +import {BeaconStateAltair, BeaconStateElectra} from "@lodestar/state-transition"; import {altair, ssz} from "@lodestar/types"; import {hash, verifyMerkleBranch} from "@lodestar/utils"; import {beforeAll, describe, expect, it} from "vitest"; import {getNextSyncCommitteeBranch, getSyncCommitteesWitness} from "../../../../src/chain/lightClient/proofs.js"; +import {NUM_WITNESS, NUM_WITNESS_ELECTRA} from "../../../../src/db/repositories/lightclientSyncCommitteeWitness.js"; const currentSyncCommitteeGindex = 54; const nextSyncCommitteeGindex = 55; const syncCommitteesGindex = 27; +const currentSyncCommitteeGindexElectra = 86; +const nextSyncCommitteeGindexElectra = 87; +const syncCommitteesGindexElectra = 43; describe("chain / lightclient / proof", () => { - let state: BeaconStateAltair; - let stateRoot: Uint8Array; + let stateAltair: BeaconStateAltair; + let stateElectra: BeaconStateElectra; + let stateRootAltair: Uint8Array; + let stateRootElectra: Uint8Array; const currentSyncCommittee = fillSyncCommittee(Buffer.alloc(48, 0xbb)); const nextSyncCommittee = fillSyncCommittee(Buffer.alloc(48, 0xcc)); beforeAll(() => { - state = ssz.altair.BeaconState.defaultViewDU(); - state.currentSyncCommittee = ssz.altair.SyncCommittee.toViewDU(currentSyncCommittee); - state.nextSyncCommittee = ssz.altair.SyncCommittee.toViewDU(nextSyncCommittee); + stateAltair = ssz.altair.BeaconState.defaultViewDU(); + stateAltair.currentSyncCommittee = ssz.altair.SyncCommittee.toViewDU(currentSyncCommittee); + stateAltair.nextSyncCommittee = ssz.altair.SyncCommittee.toViewDU(nextSyncCommittee); // Note: .hashTreeRoot() automatically commits() - stateRoot = state.hashTreeRoot(); + stateRootAltair = stateAltair.hashTreeRoot(); + + stateElectra = ssz.electra.BeaconState.defaultViewDU(); + stateElectra.currentSyncCommittee = ssz.altair.SyncCommittee.toViewDU(currentSyncCommittee); + stateElectra.nextSyncCommittee = ssz.altair.SyncCommittee.toViewDU(nextSyncCommittee); + stateRootElectra = stateElectra.hashTreeRoot(); }); - it("SyncCommittees proof", () => { - const syncCommitteesWitness = getSyncCommitteesWitness(state); + it("SyncCommittees proof altair", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.altair, stateAltair); const syncCommitteesLeaf = hash( syncCommitteesWitness.currentSyncCommitteeRoot, syncCommitteesWitness.nextSyncCommitteeRoot ); + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS); expect( verifyMerkleBranch( syncCommitteesLeaf, syncCommitteesWitness.witness, ...fromGindex(syncCommitteesGindex), - stateRoot + stateRootAltair ) ).toBe(true); }); - it("currentSyncCommittee proof", () => { - const syncCommitteesWitness = getSyncCommitteesWitness(state); + it("currentSyncCommittee proof altair", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.altair, stateAltair); const currentSyncCommitteeBranch = [syncCommitteesWitness.nextSyncCommitteeRoot, ...syncCommitteesWitness.witness]; + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS); expect( verifyMerkleBranch( ssz.altair.SyncCommittee.hashTreeRoot(currentSyncCommittee), currentSyncCommitteeBranch, ...fromGindex(currentSyncCommitteeGindex), - stateRoot + stateRootAltair ) ).toBe(true); }); - it("nextSyncCommittee proof", () => { - const syncCommitteesWitness = getSyncCommitteesWitness(state); + it("nextSyncCommittee proof altair", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.altair, stateAltair); const nextSyncCommitteeBranch = getNextSyncCommitteeBranch(syncCommitteesWitness); + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS); expect( verifyMerkleBranch( ssz.altair.SyncCommittee.hashTreeRoot(nextSyncCommittee), nextSyncCommitteeBranch, ...fromGindex(nextSyncCommitteeGindex), - stateRoot + stateRootAltair + ) + ).toBe(true); + }); + + it("SyncCommittees proof electra", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.electra, stateElectra); + const syncCommitteesLeaf = hash( + syncCommitteesWitness.currentSyncCommitteeRoot, + syncCommitteesWitness.nextSyncCommitteeRoot + ); + + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS_ELECTRA); + expect( + verifyMerkleBranch( + syncCommitteesLeaf, + syncCommitteesWitness.witness, + ...fromGindex(syncCommitteesGindexElectra), + stateRootElectra + ) + ).toBe(true); + }); + + it("currentSyncCommittee proof electra", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.electra, stateElectra); + const currentSyncCommitteeBranch = [syncCommitteesWitness.nextSyncCommitteeRoot, ...syncCommitteesWitness.witness]; + + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS_ELECTRA); + expect( + verifyMerkleBranch( + ssz.altair.SyncCommittee.hashTreeRoot(currentSyncCommittee), + currentSyncCommitteeBranch, + ...fromGindex(currentSyncCommitteeGindexElectra), + stateRootElectra + ) + ).toBe(true); + }); + + it("nextSyncCommittee proof electra", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.electra, stateElectra); + const nextSyncCommitteeBranch = getNextSyncCommitteeBranch(syncCommitteesWitness); + + expect( + verifyMerkleBranch( + ssz.altair.SyncCommittee.hashTreeRoot(nextSyncCommittee), + nextSyncCommitteeBranch, + ...fromGindex(nextSyncCommitteeGindexElectra), + stateRootElectra ) ).toBe(true); }); + + it("getSyncCommitteesWitness returns correct number of witness altair", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.altair, stateAltair); + + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS); + }); + + it("getSyncCommitteesWitness returns correct number of witness electra", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.electra, stateElectra); + + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS_ELECTRA); + }); }); function fillSyncCommittee(pubkey: Uint8Array): altair.SyncCommittee { diff --git a/packages/light-client/src/spec/index.ts b/packages/light-client/src/spec/index.ts index ff4fe22b28b0..16afebc32db4 100644 --- a/packages/light-client/src/spec/index.ts +++ b/packages/light-client/src/spec/index.ts @@ -10,7 +10,7 @@ import { import {computeSyncPeriodAtSlot} from "../utils/index.js"; import {ProcessUpdateOpts, getSyncCommitteeAtPeriod, processLightClientUpdate} from "./processLightClientUpdate.js"; import {ILightClientStore, LightClientStore, LightClientStoreEvents} from "./store.js"; -import {ZERO_FINALITY_BRANCH, ZERO_HEADER, ZERO_SYNC_COMMITTEE, getZeroSyncCommitteeBranch} from "./utils.js"; +import {ZERO_HEADER, ZERO_SYNC_COMMITTEE, getZeroFinalityBranch, getZeroSyncCommitteeBranch} from "./utils.js"; export {isBetterUpdate, toLightClientUpdateSummary} from "./isBetterUpdate.js"; export type {LightClientUpdateSummary} from "./isBetterUpdate.js"; @@ -51,7 +51,7 @@ export class LightclientSpec { nextSyncCommittee: ZERO_SYNC_COMMITTEE, nextSyncCommitteeBranch: getZeroSyncCommitteeBranch(this.config.getForkName(optimisticUpdate.signatureSlot)), finalizedHeader: {beacon: ZERO_HEADER}, - finalityBranch: ZERO_FINALITY_BRANCH, + finalityBranch: getZeroFinalityBranch(this.config.getForkName(optimisticUpdate.signatureSlot)), syncAggregate: optimisticUpdate.syncAggregate, signatureSlot: optimisticUpdate.signatureSlot, }); diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index cd0c03fd5b0d..c03f334f284c 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -33,7 +33,6 @@ export const ZERO_HASH = new Uint8Array(32); export const ZERO_PUBKEY = new Uint8Array(48); export const ZERO_SYNC_COMMITTEE = ssz.altair.SyncCommittee.defaultValue(); export const ZERO_HEADER = ssz.phase0.BeaconBlockHeader.defaultValue(); -export const ZERO_FINALITY_BRANCH = Array.from({length: FINALIZED_ROOT_DEPTH}, () => ZERO_HASH); /** From https://notes.ethereum.org/@vbuterin/extended_light_client_protocol#Optimistic-head-determining-function */ const SAFETY_THRESHOLD_FACTOR = 2; @@ -53,6 +52,12 @@ export function getZeroSyncCommitteeBranch(fork: ForkName): Uint8Array[] { return Array.from({length: nextSyncCommitteeDepth}, () => ZERO_HASH); } +export function getZeroFinalityBranch(fork: ForkName): Uint8Array[] { + const finalizedRootDepth = isForkPostElectra(fork) ? FINALIZED_ROOT_DEPTH_ELECTRA : FINALIZED_ROOT_DEPTH; + + return Array.from({length: finalizedRootDepth}, () => ZERO_HASH); +} + export function isSyncCommitteeUpdate(update: LightClientUpdate): boolean { return ( // Fast return for when constructing full LightClientUpdate from partial updates @@ -65,7 +70,8 @@ export function isSyncCommitteeUpdate(update: LightClientUpdate): boolean { export function isFinalityUpdate(update: LightClientUpdate): boolean { return ( // Fast return for when constructing full LightClientUpdate from partial updates - update.finalityBranch !== ZERO_FINALITY_BRANCH && + update.finalityBranch !== + getZeroFinalityBranch(isElectraLightClientUpdate(update) ? ForkName.electra : ForkName.altair) && update.finalityBranch.some((branch) => !byteArrayEquals(branch, ZERO_HASH)) ); } diff --git a/packages/light-client/src/validation.ts b/packages/light-client/src/validation.ts index 22cbf700ed16..d696702307ea 100644 --- a/packages/light-client/src/validation.ts +++ b/packages/light-client/src/validation.ts @@ -6,6 +6,7 @@ import { FINALIZED_ROOT_DEPTH, FINALIZED_ROOT_DEPTH_ELECTRA, FINALIZED_ROOT_INDEX, + FINALIZED_ROOT_INDEX_ELECTRA, MIN_SYNC_COMMITTEE_PARTICIPANTS, NEXT_SYNC_COMMITTEE_DEPTH, NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, @@ -18,6 +19,7 @@ import { Root, Slot, altair, + isELectraLightClientFinalityUpdate, isElectraLightClientUpdate, ssz, } from "@lodestar/types"; @@ -80,12 +82,19 @@ export function assertValidLightClientUpdate( * Where `hashTreeRoot(state) == update.finalityHeader.stateRoot` */ export function assertValidFinalityProof(update: LightClientFinalityUpdate): void { + const finalizedRootDepth = isELectraLightClientFinalityUpdate(update) + ? FINALIZED_ROOT_DEPTH_ELECTRA + : FINALIZED_ROOT_DEPTH; + const finalizedRootIndex = isELectraLightClientFinalityUpdate(update) + ? FINALIZED_ROOT_INDEX_ELECTRA + : FINALIZED_ROOT_INDEX; + if ( !isValidMerkleBranch( ssz.phase0.BeaconBlockHeader.hashTreeRoot(update.finalizedHeader.beacon), update.finalityBranch, - FINALIZED_ROOT_DEPTH, - FINALIZED_ROOT_INDEX, + finalizedRootDepth, + finalizedRootIndex, update.attestedHeader.beacon.stateRoot ) ) { diff --git a/packages/types/src/utils/typeguards.ts b/packages/types/src/utils/typeguards.ts index d4a27e23d1d6..c212e4726e78 100644 --- a/packages/types/src/utils/typeguards.ts +++ b/packages/types/src/utils/typeguards.ts @@ -10,6 +10,7 @@ import { ExecutionPayload, ExecutionPayloadAndBlobsBundle, ExecutionPayloadHeader, + LightClientFinalityUpdate, LightClientUpdate, SignedBeaconBlock, SignedBeaconBlockOrContents, @@ -80,3 +81,13 @@ export function isElectraLightClientUpdate(update: LightClientUpdate): update is updatePostElectra.finalityBranch.length === FINALIZED_ROOT_DEPTH_ELECTRA ); } + +export function isELectraLightClientFinalityUpdate( + update: LightClientFinalityUpdate +): update is LightClientFinalityUpdate { + const updatePostElectra = update as LightClientUpdate; + return ( + updatePostElectra.finalityBranch !== undefined && + updatePostElectra.finalityBranch.length === FINALIZED_ROOT_DEPTH_ELECTRA + ); +} From 7c3f4034abcf94451d5abe42c02b9e479bd811df Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:04:55 +0800 Subject: [PATCH 198/259] fix: light client generating `LightClientUpdate` with wrong length of branches (#7187) * initial commit * Rewrite SyncCommitteeWitnessRepository * Fix finality branch * Update unit test * fix e2e * Review PR --------- Co-authored-by: Nico Flaig --- .../src/chain/lightClient/index.ts | 96 +++++++++------ .../src/chain/lightClient/proofs.ts | 60 +++++++--- .../src/chain/lightClient/types.ts | 2 +- .../lightclientSyncCommitteeWitness.ts | 55 ++++++++- .../test/unit/chain/lightclient/proof.test.ts | 111 +++++++++++++++--- packages/light-client/src/spec/index.ts | 4 +- packages/light-client/src/spec/utils.ts | 10 +- packages/light-client/src/validation.ts | 45 ++++--- packages/types/src/utils/typeguards.ts | 29 +++-- 9 files changed, 304 insertions(+), 108 deletions(-) diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index 0a41ea059e73..57a26a4f267a 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -1,6 +1,31 @@ import {BitArray, CompositeViewDU} from "@chainsafe/ssz"; +import {routes} from "@lodestar/api"; +import {ChainForkConfig} from "@lodestar/config"; +import { + LightClientUpdateSummary, + isBetterUpdate, + toLightClientUpdateSummary, + upgradeLightClientHeader, +} from "@lodestar/light-client/spec"; +import { + ForkExecution, + ForkLightClient, + ForkName, + ForkSeq, + MIN_SYNC_COMMITTEE_PARTICIPANTS, + SYNC_COMMITTEE_SIZE, + forkLightClient, + highestFork, + isForkPostElectra, +} from "@lodestar/params"; +import { + CachedBeaconStateAltair, + computeStartSlotAtEpoch, + computeSyncPeriodAtEpoch, + computeSyncPeriodAtSlot, + executionPayloadToPayloadHeader, +} from "@lodestar/state-transition"; import { - altair, BeaconBlock, BeaconBlockBody, LightClientBootstrap, @@ -8,54 +33,32 @@ import { LightClientHeader, LightClientOptimisticUpdate, LightClientUpdate, - phase0, Root, RootHex, + SSZTypesFor, Slot, + SyncPeriod, + altair, + electra, + phase0, ssz, sszTypesFor, - SSZTypesFor, - SyncPeriod, } from "@lodestar/types"; -import {ChainForkConfig} from "@lodestar/config"; -import { - CachedBeaconStateAltair, - computeStartSlotAtEpoch, - computeSyncPeriodAtEpoch, - computeSyncPeriodAtSlot, - executionPayloadToPayloadHeader, -} from "@lodestar/state-transition"; -import { - isBetterUpdate, - toLightClientUpdateSummary, - LightClientUpdateSummary, - upgradeLightClientHeader, -} from "@lodestar/light-client/spec"; import {Logger, MapDef, pruneSetToMax, toRootHex} from "@lodestar/utils"; -import {routes} from "@lodestar/api"; -import { - MIN_SYNC_COMMITTEE_PARTICIPANTS, - SYNC_COMMITTEE_SIZE, - ForkName, - ForkSeq, - ForkExecution, - ForkLightClient, - highestFork, - forkLightClient, -} from "@lodestar/params"; +import {ZERO_HASH} from "../../constants/index.js"; import {IBeaconDb} from "../../db/index.js"; +import {NUM_WITNESS, NUM_WITNESS_ELECTRA} from "../../db/repositories/lightclientSyncCommitteeWitness.js"; import {Metrics} from "../../metrics/index.js"; -import {ChainEventEmitter} from "../emitter.js"; import {byteArrayEquals} from "../../util/bytes.js"; -import {ZERO_HASH} from "../../constants/index.js"; +import {ChainEventEmitter} from "../emitter.js"; import {LightClientServerError, LightClientServerErrorCode} from "../errors/lightClientError.js"; import { + getBlockBodyExecutionHeaderProof, + getCurrentSyncCommitteeBranch, + getFinalizedRootProof, getNextSyncCommitteeBranch, getSyncCommitteesWitness, - getFinalizedRootProof, - getCurrentSyncCommitteeBranch, - getBlockBodyExecutionHeaderProof, } from "./proofs.js"; export type LightClientServerOpts = { @@ -208,7 +211,10 @@ export class LightClientServer { private checkpointHeaders = new Map(); private latestHeadUpdate: LightClientOptimisticUpdate | null = null; - private readonly zero: Pick; + private readonly zero: Pick< + altair.LightClientUpdate | electra.LightClientUpdate, + "finalityBranch" | "finalizedHeader" + >; private finalized: LightClientFinalityUpdate | null = null; constructor( @@ -225,7 +231,9 @@ export class LightClientServer { this.zero = { // Assign the hightest fork's default value because it can always be typecasted down to correct fork finalizedHeader: sszTypesFor(highestFork(forkLightClient)).LightClientHeader.defaultValue(), - finalityBranch: ssz.altair.LightClientUpdate.fields.finalityBranch.defaultValue(), + // Electra finalityBranch has fixed length of 5 whereas altair has 4. The fifth element will be ignored + // when serializing as altair LightClientUpdate + finalityBranch: ssz.electra.LightClientUpdate.fields.finalityBranch.defaultValue(), }; if (metrics) { @@ -388,12 +396,13 @@ export class LightClientServer { parentBlockSlot: Slot ): Promise { const blockSlot = block.slot; - const header = blockToLightClientHeader(this.config.getForkName(blockSlot), block); + const fork = this.config.getForkName(blockSlot); + const header = blockToLightClientHeader(fork, block); const blockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(header.beacon); const blockRootHex = toRootHex(blockRoot); - const syncCommitteeWitness = getSyncCommitteesWitness(postState); + const syncCommitteeWitness = getSyncCommitteesWitness(fork, postState); // Only store current sync committee once per run if (!this.storedCurrentSyncCommittee) { @@ -621,6 +630,16 @@ export class LightClientServer { if (!syncCommitteeWitness) { throw Error(`syncCommitteeWitness not available at ${toRootHex(attestedData.blockRoot)}`); } + + const attestedFork = this.config.getForkName(attestedHeader.beacon.slot); + const numWitness = syncCommitteeWitness.witness.length; + if (isForkPostElectra(attestedFork) && numWitness !== NUM_WITNESS_ELECTRA) { + throw Error(`Expected ${NUM_WITNESS_ELECTRA} witnesses in post-Electra numWitness=${numWitness}`); + } + if (!isForkPostElectra(attestedFork) && numWitness !== NUM_WITNESS) { + throw Error(`Expected ${NUM_WITNESS} witnesses in pre-Electra numWitness=${numWitness}`); + } + const nextSyncCommittee = await this.db.syncCommittee.get(syncCommitteeWitness.nextSyncCommitteeRoot); if (!nextSyncCommittee) { throw Error("nextSyncCommittee not available"); @@ -641,7 +660,6 @@ export class LightClientServer { finalityBranch = attestedData.finalityBranch; finalizedHeader = finalizedHeaderAttested; // Fork of LightClientUpdate is based off on attested header's fork - const attestedFork = this.config.getForkName(attestedHeader.beacon.slot); if (this.config.getForkName(finalizedHeader.beacon.slot) !== attestedFork) { finalizedHeader = upgradeLightClientHeader(this.config, attestedFork, finalizedHeader); } diff --git a/packages/beacon-node/src/chain/lightClient/proofs.ts b/packages/beacon-node/src/chain/lightClient/proofs.ts index 8d273e30ae5c..fe8ca7881a76 100644 --- a/packages/beacon-node/src/chain/lightClient/proofs.ts +++ b/packages/beacon-node/src/chain/lightClient/proofs.ts @@ -1,32 +1,58 @@ import {Tree} from "@chainsafe/persistent-merkle-tree"; -import {BeaconStateAllForks, CachedBeaconStateAllForks} from "@lodestar/state-transition"; import { - FINALIZED_ROOT_GINDEX, BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX, - ForkExecution, + FINALIZED_ROOT_GINDEX, FINALIZED_ROOT_GINDEX_ELECTRA, + ForkExecution, + ForkName, + isForkPostElectra, } from "@lodestar/params"; +import {BeaconStateAllForks, CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {BeaconBlockBody, SSZTypesFor, ssz} from "@lodestar/types"; import {SyncCommitteeWitness} from "./types.js"; -export function getSyncCommitteesWitness(state: BeaconStateAllForks): SyncCommitteeWitness { +export function getSyncCommitteesWitness(fork: ForkName, state: BeaconStateAllForks): SyncCommitteeWitness { state.commit(); const n1 = state.node; - const n3 = n1.right; // [1]0110 - const n6 = n3.left; // 1[0]110 - const n13 = n6.right; // 10[1]10 - const n27 = n13.right; // 101[1]0 - const currentSyncCommitteeRoot = n27.left.root; // n54 1011[0] - const nextSyncCommitteeRoot = n27.right.root; // n55 1011[1] + let witness: Uint8Array[]; + let currentSyncCommitteeRoot: Uint8Array; + let nextSyncCommitteeRoot: Uint8Array; - // Witness branch is sorted by descending gindex - const witness = [ - n13.left.root, // 26 - n6.left.root, // 12 - n3.right.root, // 7 - n1.left.root, // 2 - ]; + if (isForkPostElectra(fork)) { + const n2 = n1.left; + const n5 = n2.right; + const n10 = n5.left; + const n21 = n10.right; + const n43 = n21.right; + + currentSyncCommitteeRoot = n43.left.root; // n86 + nextSyncCommitteeRoot = n43.right.root; // n87 + + // Witness branch is sorted by descending gindex + witness = [ + n21.left.root, // 42 + n10.left.root, // 20 + n5.right.root, // 11 + n2.left.root, // 4 + n1.right.root, // 3 + ]; + } else { + const n3 = n1.right; // [1]0110 + const n6 = n3.left; // 1[0]110 + const n13 = n6.right; // 10[1]10 + const n27 = n13.right; // 101[1]0 + currentSyncCommitteeRoot = n27.left.root; // n54 1011[0] + nextSyncCommitteeRoot = n27.right.root; // n55 1011[1] + + // Witness branch is sorted by descending gindex + witness = [ + n13.left.root, // 26 + n6.left.root, // 12 + n3.right.root, // 7 + n1.left.root, // 2 + ]; + } return { witness, diff --git a/packages/beacon-node/src/chain/lightClient/types.ts b/packages/beacon-node/src/chain/lightClient/types.ts index b253c05d45fb..b9723df501b3 100644 --- a/packages/beacon-node/src/chain/lightClient/types.ts +++ b/packages/beacon-node/src/chain/lightClient/types.ts @@ -26,7 +26,7 @@ * ``` */ export type SyncCommitteeWitness = { - /** Vector[Bytes32, 4] */ + /** Vector[Bytes32, 4] or Vector[Bytes32, 5] depending on the fork */ witness: Uint8Array[]; currentSyncCommitteeRoot: Uint8Array; nextSyncCommitteeRoot: Uint8Array; diff --git a/packages/beacon-node/src/db/repositories/lightclientSyncCommitteeWitness.ts b/packages/beacon-node/src/db/repositories/lightclientSyncCommitteeWitness.ts index 45f91f159997..e323c3e55f61 100644 --- a/packages/beacon-node/src/db/repositories/lightclientSyncCommitteeWitness.ts +++ b/packages/beacon-node/src/db/repositories/lightclientSyncCommitteeWitness.ts @@ -5,6 +5,15 @@ import {ssz} from "@lodestar/types"; import {SyncCommitteeWitness} from "../../chain/lightClient/types.js"; import {Bucket, getBucketNameByValue} from "../buckets.js"; +// We add a 1-byte prefix where 0 means pre-electra and 1 means post-electra +enum PrefixByte { + PRE_ELECTRA = 0, + POST_ELECTRA = 1, +} + +export const NUM_WITNESS = 4; +export const NUM_WITNESS_ELECTRA = 5; + /** * Historical sync committees witness by block root * @@ -13,12 +22,56 @@ import {Bucket, getBucketNameByValue} from "../buckets.js"; export class SyncCommitteeWitnessRepository extends Repository { constructor(config: ChainForkConfig, db: DatabaseController) { const bucket = Bucket.lightClient_syncCommitteeWitness; + // Pick some type but won't be used. Witness can be 4 or 5 so need to handle dynamically const type = new ContainerType({ - witness: new VectorCompositeType(ssz.Root, 4), + witness: new VectorCompositeType(ssz.Root, NUM_WITNESS), currentSyncCommitteeRoot: ssz.Root, nextSyncCommitteeRoot: ssz.Root, }); super(config, db, bucket, type, getBucketNameByValue(bucket)); } + + // Overrides for multi-fork + encodeValue(value: SyncCommitteeWitness): Uint8Array { + const numWitness = value.witness.length; + + if (numWitness !== NUM_WITNESS && numWitness !== NUM_WITNESS_ELECTRA) { + throw Error(`Number of witness can only be 4 pre-electra or 5 post-electra numWitness=${numWitness}`); + } + + const type = new ContainerType({ + witness: new VectorCompositeType(ssz.Root, numWitness), + currentSyncCommitteeRoot: ssz.Root, + nextSyncCommitteeRoot: ssz.Root, + }); + + const valueBytes = type.serialize(value); + + // We need to differentiate between post-electra and pre-electra witness + // such that we can deserialize correctly + const isPostElectra = numWitness === NUM_WITNESS_ELECTRA; + const prefixByte = new Uint8Array(1); + prefixByte[0] = isPostElectra ? PrefixByte.POST_ELECTRA : PrefixByte.PRE_ELECTRA; + + const prefixedData = new Uint8Array(1 + valueBytes.length); + prefixedData.set(prefixByte, 0); + prefixedData.set(valueBytes, 1); + + return prefixedData; + } + + decodeValue(data: Uint8Array): SyncCommitteeWitness { + // First byte is written + const prefix = data.subarray(0, 1); + const isPostElectra = prefix[0] === PrefixByte.POST_ELECTRA; + + const type = new ContainerType({ + witness: new VectorCompositeType(ssz.Root, isPostElectra ? NUM_WITNESS_ELECTRA : NUM_WITNESS), + currentSyncCommitteeRoot: ssz.Root, + nextSyncCommitteeRoot: ssz.Root, + }); + + return type.deserialize(data.subarray(1)); + } } diff --git a/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts b/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts index b30e0f9a9ddb..769fe49f690c 100644 --- a/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts +++ b/packages/beacon-node/test/unit/chain/lightclient/proof.test.ts @@ -1,73 +1,146 @@ -import {describe, it, expect, beforeAll} from "vitest"; -import {BeaconStateAltair} from "@lodestar/state-transition"; -import {SYNC_COMMITTEE_SIZE} from "@lodestar/params"; +import {ForkName, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; +import {BeaconStateAltair, BeaconStateElectra} from "@lodestar/state-transition"; import {altair, ssz} from "@lodestar/types"; -import {verifyMerkleBranch, hash} from "@lodestar/utils"; +import {hash, verifyMerkleBranch} from "@lodestar/utils"; +import {beforeAll, describe, expect, it} from "vitest"; import {getNextSyncCommitteeBranch, getSyncCommitteesWitness} from "../../../../src/chain/lightClient/proofs.js"; +import {NUM_WITNESS, NUM_WITNESS_ELECTRA} from "../../../../src/db/repositories/lightclientSyncCommitteeWitness.js"; const currentSyncCommitteeGindex = 54; const nextSyncCommitteeGindex = 55; const syncCommitteesGindex = 27; +const currentSyncCommitteeGindexElectra = 86; +const nextSyncCommitteeGindexElectra = 87; +const syncCommitteesGindexElectra = 43; describe("chain / lightclient / proof", () => { - let state: BeaconStateAltair; - let stateRoot: Uint8Array; + let stateAltair: BeaconStateAltair; + let stateElectra: BeaconStateElectra; + let stateRootAltair: Uint8Array; + let stateRootElectra: Uint8Array; const currentSyncCommittee = fillSyncCommittee(Buffer.alloc(48, 0xbb)); const nextSyncCommittee = fillSyncCommittee(Buffer.alloc(48, 0xcc)); beforeAll(() => { - state = ssz.altair.BeaconState.defaultViewDU(); - state.currentSyncCommittee = ssz.altair.SyncCommittee.toViewDU(currentSyncCommittee); - state.nextSyncCommittee = ssz.altair.SyncCommittee.toViewDU(nextSyncCommittee); + stateAltair = ssz.altair.BeaconState.defaultViewDU(); + stateAltair.currentSyncCommittee = ssz.altair.SyncCommittee.toViewDU(currentSyncCommittee); + stateAltair.nextSyncCommittee = ssz.altair.SyncCommittee.toViewDU(nextSyncCommittee); // Note: .hashTreeRoot() automatically commits() - stateRoot = state.hashTreeRoot(); + stateRootAltair = stateAltair.hashTreeRoot(); + + stateElectra = ssz.electra.BeaconState.defaultViewDU(); + stateElectra.currentSyncCommittee = ssz.altair.SyncCommittee.toViewDU(currentSyncCommittee); + stateElectra.nextSyncCommittee = ssz.altair.SyncCommittee.toViewDU(nextSyncCommittee); + stateRootElectra = stateElectra.hashTreeRoot(); }); - it("SyncCommittees proof", () => { - const syncCommitteesWitness = getSyncCommitteesWitness(state); + it("SyncCommittees proof altair", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.altair, stateAltair); const syncCommitteesLeaf = hash( syncCommitteesWitness.currentSyncCommitteeRoot, syncCommitteesWitness.nextSyncCommitteeRoot ); + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS); expect( verifyMerkleBranch( syncCommitteesLeaf, syncCommitteesWitness.witness, ...fromGindex(syncCommitteesGindex), - stateRoot + stateRootAltair ) ).toBe(true); }); - it("currentSyncCommittee proof", () => { - const syncCommitteesWitness = getSyncCommitteesWitness(state); + it("currentSyncCommittee proof altair", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.altair, stateAltair); const currentSyncCommitteeBranch = [syncCommitteesWitness.nextSyncCommitteeRoot, ...syncCommitteesWitness.witness]; + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS); expect( verifyMerkleBranch( ssz.altair.SyncCommittee.hashTreeRoot(currentSyncCommittee), currentSyncCommitteeBranch, ...fromGindex(currentSyncCommitteeGindex), - stateRoot + stateRootAltair ) ).toBe(true); }); - it("nextSyncCommittee proof", () => { - const syncCommitteesWitness = getSyncCommitteesWitness(state); + it("nextSyncCommittee proof altair", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.altair, stateAltair); const nextSyncCommitteeBranch = getNextSyncCommitteeBranch(syncCommitteesWitness); + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS); expect( verifyMerkleBranch( ssz.altair.SyncCommittee.hashTreeRoot(nextSyncCommittee), nextSyncCommitteeBranch, ...fromGindex(nextSyncCommitteeGindex), - stateRoot + stateRootAltair + ) + ).toBe(true); + }); + + it("SyncCommittees proof electra", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.electra, stateElectra); + const syncCommitteesLeaf = hash( + syncCommitteesWitness.currentSyncCommitteeRoot, + syncCommitteesWitness.nextSyncCommitteeRoot + ); + + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS_ELECTRA); + expect( + verifyMerkleBranch( + syncCommitteesLeaf, + syncCommitteesWitness.witness, + ...fromGindex(syncCommitteesGindexElectra), + stateRootElectra + ) + ).toBe(true); + }); + + it("currentSyncCommittee proof electra", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.electra, stateElectra); + const currentSyncCommitteeBranch = [syncCommitteesWitness.nextSyncCommitteeRoot, ...syncCommitteesWitness.witness]; + + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS_ELECTRA); + expect( + verifyMerkleBranch( + ssz.altair.SyncCommittee.hashTreeRoot(currentSyncCommittee), + currentSyncCommitteeBranch, + ...fromGindex(currentSyncCommitteeGindexElectra), + stateRootElectra + ) + ).toBe(true); + }); + + it("nextSyncCommittee proof electra", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.electra, stateElectra); + const nextSyncCommitteeBranch = getNextSyncCommitteeBranch(syncCommitteesWitness); + + expect( + verifyMerkleBranch( + ssz.altair.SyncCommittee.hashTreeRoot(nextSyncCommittee), + nextSyncCommitteeBranch, + ...fromGindex(nextSyncCommitteeGindexElectra), + stateRootElectra ) ).toBe(true); }); + + it("getSyncCommitteesWitness returns correct number of witness altair", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.altair, stateAltair); + + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS); + }); + + it("getSyncCommitteesWitness returns correct number of witness electra", () => { + const syncCommitteesWitness = getSyncCommitteesWitness(ForkName.electra, stateElectra); + + expect(syncCommitteesWitness.witness.length).toBe(NUM_WITNESS_ELECTRA); + }); }); function fillSyncCommittee(pubkey: Uint8Array): altair.SyncCommittee { diff --git a/packages/light-client/src/spec/index.ts b/packages/light-client/src/spec/index.ts index 0934e15b1c17..11ce1f8b3f29 100644 --- a/packages/light-client/src/spec/index.ts +++ b/packages/light-client/src/spec/index.ts @@ -10,7 +10,7 @@ import { import {computeSyncPeriodAtSlot} from "../utils/index.js"; import {getSyncCommitteeAtPeriod, processLightClientUpdate, ProcessUpdateOpts} from "./processLightClientUpdate.js"; import {ILightClientStore, LightClientStore, LightClientStoreEvents} from "./store.js"; -import {ZERO_FINALITY_BRANCH, ZERO_HEADER, ZERO_SYNC_COMMITTEE, getZeroSyncCommitteeBranch} from "./utils.js"; +import {ZERO_HEADER, ZERO_SYNC_COMMITTEE, getZeroFinalityBranch, getZeroSyncCommitteeBranch} from "./utils.js"; export {isBetterUpdate, toLightClientUpdateSummary} from "./isBetterUpdate.js"; export type {LightClientUpdateSummary} from "./isBetterUpdate.js"; @@ -51,7 +51,7 @@ export class LightclientSpec { nextSyncCommittee: ZERO_SYNC_COMMITTEE, nextSyncCommitteeBranch: getZeroSyncCommitteeBranch(this.config.getForkName(optimisticUpdate.signatureSlot)), finalizedHeader: {beacon: ZERO_HEADER}, - finalityBranch: ZERO_FINALITY_BRANCH, + finalityBranch: getZeroFinalityBranch(this.config.getForkName(optimisticUpdate.signatureSlot)), syncAggregate: optimisticUpdate.syncAggregate, signatureSlot: optimisticUpdate.signatureSlot, }); diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 36bc7098fcc5..602e1264e159 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -33,7 +33,6 @@ export const ZERO_HASH = new Uint8Array(32); export const ZERO_PUBKEY = new Uint8Array(48); export const ZERO_SYNC_COMMITTEE = ssz.altair.SyncCommittee.defaultValue(); export const ZERO_HEADER = ssz.phase0.BeaconBlockHeader.defaultValue(); -export const ZERO_FINALITY_BRANCH = Array.from({length: FINALIZED_ROOT_DEPTH}, () => ZERO_HASH); /** From https://notes.ethereum.org/@vbuterin/extended_light_client_protocol#Optimistic-head-determining-function */ const SAFETY_THRESHOLD_FACTOR = 2; @@ -53,6 +52,12 @@ export function getZeroSyncCommitteeBranch(fork: ForkName): Uint8Array[] { return Array.from({length: nextSyncCommitteeDepth}, () => ZERO_HASH); } +export function getZeroFinalityBranch(fork: ForkName): Uint8Array[] { + const finalizedRootDepth = isForkPostElectra(fork) ? FINALIZED_ROOT_DEPTH_ELECTRA : FINALIZED_ROOT_DEPTH; + + return Array.from({length: finalizedRootDepth}, () => ZERO_HASH); +} + export function isSyncCommitteeUpdate(update: LightClientUpdate): boolean { return ( // Fast return for when constructing full LightClientUpdate from partial updates @@ -65,7 +70,8 @@ export function isSyncCommitteeUpdate(update: LightClientUpdate): boolean { export function isFinalityUpdate(update: LightClientUpdate): boolean { return ( // Fast return for when constructing full LightClientUpdate from partial updates - update.finalityBranch !== ZERO_FINALITY_BRANCH && + update.finalityBranch !== + getZeroFinalityBranch(isElectraLightClientUpdate(update) ? ForkName.electra : ForkName.altair) && update.finalityBranch.some((branch) => !byteArrayEquals(branch, ZERO_HASH)) ); } diff --git a/packages/light-client/src/validation.ts b/packages/light-client/src/validation.ts index c756d612f3e7..d696702307ea 100644 --- a/packages/light-client/src/validation.ts +++ b/packages/light-client/src/validation.ts @@ -1,30 +1,32 @@ import bls from "@chainsafe/bls"; import type {PublicKey, Signature} from "@chainsafe/bls/types"; +import {BeaconConfig} from "@lodestar/config"; +import { + DOMAIN_SYNC_COMMITTEE, + FINALIZED_ROOT_DEPTH, + FINALIZED_ROOT_DEPTH_ELECTRA, + FINALIZED_ROOT_INDEX, + FINALIZED_ROOT_INDEX_ELECTRA, + MIN_SYNC_COMMITTEE_PARTICIPANTS, + NEXT_SYNC_COMMITTEE_DEPTH, + NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, + NEXT_SYNC_COMMITTEE_INDEX, + NEXT_SYNC_COMMITTEE_INDEX_ELECTRA, +} from "@lodestar/params"; import { - altair, - isElectraLightClientUpdate, LightClientFinalityUpdate, LightClientUpdate, Root, Slot, + altair, + isELectraLightClientFinalityUpdate, + isElectraLightClientUpdate, ssz, } from "@lodestar/types"; -import { - FINALIZED_ROOT_INDEX, - FINALIZED_ROOT_DEPTH, - NEXT_SYNC_COMMITTEE_INDEX, - NEXT_SYNC_COMMITTEE_DEPTH, - MIN_SYNC_COMMITTEE_PARTICIPANTS, - DOMAIN_SYNC_COMMITTEE, - NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA, - FINALIZED_ROOT_DEPTH_ELECTRA, - NEXT_SYNC_COMMITTEE_INDEX_ELECTRA, -} from "@lodestar/params"; -import {BeaconConfig} from "@lodestar/config"; -import {isValidMerkleBranch} from "./utils/verifyMerkleBranch.js"; -import {assertZeroHashes, getParticipantPubkeys, isEmptyHeader} from "./utils/utils.js"; import {SyncCommitteeFast} from "./types.js"; import {computeSyncPeriodAtSlot} from "./utils/clock.js"; +import {assertZeroHashes, getParticipantPubkeys, isEmptyHeader} from "./utils/utils.js"; +import {isValidMerkleBranch} from "./utils/verifyMerkleBranch.js"; /** * @@ -80,12 +82,19 @@ export function assertValidLightClientUpdate( * Where `hashTreeRoot(state) == update.finalityHeader.stateRoot` */ export function assertValidFinalityProof(update: LightClientFinalityUpdate): void { + const finalizedRootDepth = isELectraLightClientFinalityUpdate(update) + ? FINALIZED_ROOT_DEPTH_ELECTRA + : FINALIZED_ROOT_DEPTH; + const finalizedRootIndex = isELectraLightClientFinalityUpdate(update) + ? FINALIZED_ROOT_INDEX_ELECTRA + : FINALIZED_ROOT_INDEX; + if ( !isValidMerkleBranch( ssz.phase0.BeaconBlockHeader.hashTreeRoot(update.finalizedHeader.beacon), update.finalityBranch, - FINALIZED_ROOT_DEPTH, - FINALIZED_ROOT_INDEX, + finalizedRootDepth, + finalizedRootIndex, update.attestedHeader.beacon.stateRoot ) ) { diff --git a/packages/types/src/utils/typeguards.ts b/packages/types/src/utils/typeguards.ts index a892c3a0c9c0..c212e4726e78 100644 --- a/packages/types/src/utils/typeguards.ts +++ b/packages/types/src/utils/typeguards.ts @@ -1,20 +1,21 @@ import {FINALIZED_ROOT_DEPTH_ELECTRA, ForkBlobs, ForkExecution, ForkPostElectra} from "@lodestar/params"; import { + Attestation, + BeaconBlock, + BeaconBlockBody, + BeaconBlockOrContents, + BlindedBeaconBlock, + BlindedBeaconBlockBody, BlockContents, - SignedBeaconBlock, ExecutionPayload, ExecutionPayloadAndBlobsBundle, - BeaconBlockBody, - BeaconBlockOrContents, - SignedBeaconBlockOrContents, ExecutionPayloadHeader, - BlindedBeaconBlock, + LightClientFinalityUpdate, + LightClientUpdate, + SignedBeaconBlock, + SignedBeaconBlockOrContents, SignedBlindedBeaconBlock, - BlindedBeaconBlockBody, SignedBlockContents, - BeaconBlock, - Attestation, - LightClientUpdate, } from "../types.js"; export function isExecutionPayload( @@ -80,3 +81,13 @@ export function isElectraLightClientUpdate(update: LightClientUpdate): update is updatePostElectra.finalityBranch.length === FINALIZED_ROOT_DEPTH_ELECTRA ); } + +export function isELectraLightClientFinalityUpdate( + update: LightClientFinalityUpdate +): update is LightClientFinalityUpdate { + const updatePostElectra = update as LightClientUpdate; + return ( + updatePostElectra.finalityBranch !== undefined && + updatePostElectra.finalityBranch.length === FINALIZED_ROOT_DEPTH_ELECTRA + ); +} From 0d404f890e36b631ec43b8db192ea9489130f634 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 8 Nov 2024 22:27:21 +0800 Subject: [PATCH 199/259] fix: archive finalized state when shutting down beacon node (#7221) --- packages/beacon-node/src/chain/archiver/archiver.ts | 2 +- packages/beacon-node/src/chain/archiver/interface.ts | 1 + .../chain/archiver/strategies/frequencyStateArchiveStrategy.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/chain/archiver/archiver.ts b/packages/beacon-node/src/chain/archiver/archiver.ts index 6d5be3445eb2..6d54a7f64911 100644 --- a/packages/beacon-node/src/chain/archiver/archiver.ts +++ b/packages/beacon-node/src/chain/archiver/archiver.ts @@ -64,7 +64,7 @@ export class Archiver { /** Archive latest finalized state */ async persistToDisk(): Promise { - return this.statesArchiverStrategy.maybeArchiveState(this.chain.forkChoice.getFinalizedCheckpoint()); + return this.statesArchiverStrategy.archiveState(this.chain.forkChoice.getFinalizedCheckpoint()); } private onFinalizedCheckpoint = async (finalized: CheckpointWithHex): Promise => { diff --git a/packages/beacon-node/src/chain/archiver/interface.ts b/packages/beacon-node/src/chain/archiver/interface.ts index 283fef579024..4c9eb27ecbdc 100644 --- a/packages/beacon-node/src/chain/archiver/interface.ts +++ b/packages/beacon-node/src/chain/archiver/interface.ts @@ -44,4 +44,5 @@ export interface StateArchiveStrategy { onCheckpoint(stateRoot: RootHex, metrics?: Metrics | null): Promise; onFinalizedCheckpoint(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise; maybeArchiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise; + archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise; } diff --git a/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts b/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts index 6ae592ce7c63..dca7a8ed1f22 100644 --- a/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts +++ b/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts @@ -84,7 +84,7 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy { * Archives finalized states from active bucket to archive bucket. * Only the new finalized state is stored to disk */ - private async archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise { + async archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise { // starting from Mar 2024, the finalized state could be from disk or in memory const finalizedStateOrBytes = await this.regen.getCheckpointStateOrBytes(finalized); const {rootHex} = finalized; From 68357abd796ebbff30902f14daf8ba3a33cae715 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 8 Nov 2024 22:27:21 +0800 Subject: [PATCH 200/259] fix: archive finalized state when shutting down beacon node (#7221) --- packages/beacon-node/src/chain/archiver/archiver.ts | 2 +- packages/beacon-node/src/chain/archiver/interface.ts | 1 + .../chain/archiver/strategies/frequencyStateArchiveStrategy.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/chain/archiver/archiver.ts b/packages/beacon-node/src/chain/archiver/archiver.ts index 2d79f584ea79..007eeeed0c94 100644 --- a/packages/beacon-node/src/chain/archiver/archiver.ts +++ b/packages/beacon-node/src/chain/archiver/archiver.ts @@ -64,7 +64,7 @@ export class Archiver { /** Archive latest finalized state */ async persistToDisk(): Promise { - return this.statesArchiverStrategy.maybeArchiveState(this.chain.forkChoice.getFinalizedCheckpoint()); + return this.statesArchiverStrategy.archiveState(this.chain.forkChoice.getFinalizedCheckpoint()); } private onFinalizedCheckpoint = async (finalized: CheckpointWithHex): Promise => { diff --git a/packages/beacon-node/src/chain/archiver/interface.ts b/packages/beacon-node/src/chain/archiver/interface.ts index 48c930c78cd3..d5ac3dac8790 100644 --- a/packages/beacon-node/src/chain/archiver/interface.ts +++ b/packages/beacon-node/src/chain/archiver/interface.ts @@ -44,4 +44,5 @@ export interface StateArchiveStrategy { onCheckpoint(stateRoot: RootHex, metrics?: Metrics | null): Promise; onFinalizedCheckpoint(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise; maybeArchiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise; + archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise; } diff --git a/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts b/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts index a701da5b22ec..c6e4dccfbf6c 100644 --- a/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts +++ b/packages/beacon-node/src/chain/archiver/strategies/frequencyStateArchiveStrategy.ts @@ -84,7 +84,7 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy { * Archives finalized states from active bucket to archive bucket. * Only the new finalized state is stored to disk */ - private async archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise { + async archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise { // starting from Mar 2024, the finalized state could be from disk or in memory const finalizedStateOrBytes = await this.regen.getCheckpointStateOrBytes(finalized); const {rootHex} = finalized; From 1fae9689dc2cd57b042aa5af5b19d499b8b42c8c Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Sun, 17 Nov 2024 12:11:40 +0700 Subject: [PATCH 201/259] Fix typo --- docs/README.md | 2 +- types/vitest/index.d.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 759ca59d8b03..3ac8fd612325 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,4 +22,4 @@ This command starts a local development server and opens up a browser window. Mo $ yarn build ``` -This command generates static content into the `build` directory and can be served using any static contents hosting service. +This command generates static content into the `build` directory and can be served using any static content hosting service. diff --git a/types/vitest/index.d.ts b/types/vitest/index.d.ts index 297ed11e1904..7cbd5d2edb79 100644 --- a/types/vitest/index.d.ts +++ b/types/vitest/index.d.ts @@ -4,7 +4,7 @@ interface CustomMatchers { toBeValidEpochCommittee(opts: {committeeCount: number; validatorsPerCommittee: number; slotsPerEpoch: number}): R; /** * @deprecated - * We highly recommend to not use this matcher instead use detail test case + * We highly recommend to not use this matcher instead use detailed test case * where you don't need message to explain assertion * * @example @@ -27,7 +27,7 @@ interface CustomMatchers { toBeWithMessage(expected: unknown, message: string): R; /** * @deprecated - * We highly recommend to not use this matcher instead use detail test case with .toEqual + * We highly recommend to not use this matcher instead use detailed test case with .toEqual * where you don't need message to explain assertion * */ toEqualWithMessage(expected: unknown, message: string): R; From b78cb92802cfc12c3a75f33a053055e3db5a7c45 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:20:52 +0700 Subject: [PATCH 202/259] feat: remove unfinalized pubkey cache (#7230) * Remove unfinalized pubkey cache * lint * Fix unit test --- packages/beacon-node/src/chain/chain.ts | 22 --- .../beacon-node/src/chain/regen/queued.ts | 50 +----- .../chain/stateCache/blockStateCacheImpl.ts | 2 +- .../beacon-node/src/metrics/metrics/beacon.ts | 7 - .../src/metrics/metrics/lodestar.ts | 11 -- .../test/memory/unfinalizedPubkey2Index.ts | 54 ------- .../updateUnfinalizedPubkeys.test.ts | 114 -------------- .../test/sim/electra-interop.test.ts | 31 +--- packages/state-transition/package.json | 3 +- .../state-transition/src/cache/epochCache.ts | 146 +----------------- .../state-transition/src/cache/pubkeyCache.ts | 36 ----- packages/state-transition/src/index.ts | 7 +- packages/state-transition/src/metrics.ts | 5 - .../test/unit/cachedBeaconState.test.ts | 36 +---- yarn.lock | 5 - 15 files changed, 15 insertions(+), 514 deletions(-) delete mode 100644 packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts delete mode 100644 packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 8b9fa0336283..4751770b3bfc 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -1047,9 +1047,6 @@ export class BeaconChain implements IBeaconChain { metrics.forkChoice.balancesLength.set(forkChoiceMetrics.balancesLength); metrics.forkChoice.nodes.set(forkChoiceMetrics.nodes); metrics.forkChoice.indices.set(forkChoiceMetrics.indices); - - const headState = this.getHeadState(); - metrics.headState.unfinalizedPubkeyCacheSize.set(headState.epochCtx.unfinalizedPubkey2index.size); } private onClockSlot(slot: Slot): void { @@ -1139,27 +1136,8 @@ export class BeaconChain implements IBeaconChain { this.opPool.pruneAll(headBlock, headState); } - const cpEpoch = cp.epoch; - if (headState === null) { this.logger.verbose("Head state is null"); - } else if (cpEpoch >= this.config.ELECTRA_FORK_EPOCH) { - // Get the validator.length from the state at cpEpoch - // We are confident the last element in the list is from headEpoch - // Thus we query from the end of the list. (cpEpoch - headEpoch - 1) is negative number - const pivotValidatorIndex = headState.epochCtx.getValidatorCountAtEpoch(cpEpoch); - - if (pivotValidatorIndex !== undefined) { - // Note EIP-6914 will break this logic - const newFinalizedValidators = headState.epochCtx.unfinalizedPubkey2index.filter( - (index, _pubkey) => index < pivotValidatorIndex - ); - - // Populate finalized pubkey cache and remove unfinalized pubkey cache - if (!newFinalizedValidators.isEmpty()) { - this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); - } - } } // TODO-Electra: Deprecating eth1Data poll requires a check on a finalized checkpoint state. diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index 7b812c04dc8d..b5084d593356 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -1,6 +1,6 @@ import {routes} from "@lodestar/api"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; -import {CachedBeaconStateAllForks, UnfinalizedPubkeyIndexMap, computeEpochAtSlot} from "@lodestar/state-transition"; +import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition"; import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types"; import {Logger, toRootHex} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; @@ -206,54 +206,6 @@ export class QueuedStateRegenerator implements IStateRegenerator { return this.checkpointStateCache.updatePreComputedCheckpoint(rootHex, epoch); } - /** - * Remove `validators` from all unfinalized cache's epochCtx.UnfinalizedPubkey2Index, - * and add them to epochCtx.pubkey2index and epochCtx.index2pubkey - */ - updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { - let numStatesUpdated = 0; - const states = this.blockStateCache.getStates(); - const cpStates = this.checkpointStateCache.getStates(); - - // Add finalized pubkeys to all states. - const addTimer = this.metrics?.regenFnAddPubkeyTime.startTimer(); - - // We only need to add pubkeys to any one of the states since the finalized caches is shared globally across all states - const firstState = (states.next().value ?? cpStates.next().value) as CachedBeaconStateAllForks | undefined; - - if (firstState !== undefined) { - firstState.epochCtx.addFinalizedPubkeys(validators, this.metrics?.epochCache ?? undefined); - } else { - this.logger.warn("Attempt to delete finalized pubkey from unfinalized pubkey cache. But no state is available"); - } - - addTimer?.(); - - // Delete finalized pubkeys from unfinalized pubkey cache for all states - const deleteTimer = this.metrics?.regenFnDeletePubkeyTime.startTimer(); - const pubkeysToDelete = Array.from(validators.keys()); - - for (const s of states) { - s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); - numStatesUpdated++; - } - - for (const s of cpStates) { - s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); - numStatesUpdated++; - } - - // Since first state is consumed from the iterator. Will need to perform delete explicitly - if (firstState !== undefined) { - firstState?.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); - numStatesUpdated++; - } - - deleteTimer?.(); - - this.metrics?.regenFnNumStatesUpdated.observe(numStatesUpdated); - } - /** * Get the state to run with `block`. * - State after `block.parentRoot` dialed forward to block.slot diff --git a/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts index 886f6e386309..f57c9a411923 100644 --- a/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts +++ b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts @@ -34,7 +34,7 @@ export class BlockStateCacheImpl implements BlockStateCache { this.maxStates = maxStates; this.cache = new MapTracker(metrics?.stateCache); if (metrics) { - this.metrics = {...metrics.stateCache, ...metrics.epochCache}; + this.metrics = metrics.stateCache; metrics.stateCache.size.addCollect(() => metrics.stateCache.size.set(this.cache.size)); } } diff --git a/packages/beacon-node/src/metrics/metrics/beacon.ts b/packages/beacon-node/src/metrics/metrics/beacon.ts index f572ec0d3c1f..60a49b0b673d 100644 --- a/packages/beacon-node/src/metrics/metrics/beacon.ts +++ b/packages/beacon-node/src/metrics/metrics/beacon.ts @@ -124,13 +124,6 @@ export function createBeaconMetrics(register: RegistryMetricCreator) { }), }, - headState: { - unfinalizedPubkeyCacheSize: register.gauge({ - name: "beacon_head_state_unfinalized_pubkey_cache_size", - help: "Current size of the unfinalizedPubkey2Index cache in the head state", - }), - }, - parentBlockDistance: register.histogram({ name: "beacon_imported_block_parent_distance", help: "Histogram of distance to parent block of valid imported blocks", diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index af8d87daa246..461f9c9e935b 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -378,17 +378,6 @@ export function createLodestarMetrics( help: "Total count state.validators nodesPopulated is false on stfn for post state", }), - epochCache: { - finalizedPubkeyDuplicateInsert: register.gauge({ - name: "lodestar_epoch_cache_finalized_pubkey_duplicate_insert_total", - help: "Total count of duplicate insert of finalized pubkeys", - }), - newUnFinalizedPubkey: register.gauge({ - name: "lodestar_epoch_cache_new_unfinalized_pubkey_total", - help: "Total count of unfinalized pubkeys added", - }), - }, - // BLS verifier thread pool and queue bls: { diff --git a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts deleted file mode 100644 index 294dde750865..000000000000 --- a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import crypto from "node:crypto"; -import {toMemoryEfficientHexStr} from "@lodestar/state-transition/src/cache/pubkeyCache.js"; -import {ValidatorIndex} from "@lodestar/types"; -// biome-ignore lint/suspicious/noShadowRestrictedNames: We explicitly want `Map` name to be imported -import {Map} from "immutable"; -import {testRunnerMemory} from "./testRunnerMemory.js"; - -// Results in MacOS Nov 2023 -// -// UnfinalizedPubkey2Index 1000 keys - 274956.5 bytes / instance -// UnfinalizedPubkey2Index 10000 keys - 2591129.3 bytes / instance -// UnfinalizedPubkey2Index 100000 keys - 27261443.4 bytes / instance - -testRunnerMemoryBpi([ - { - id: "UnfinalizedPubkey2Index 1000 keys", - getInstance: () => getRandomMap(1000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), - }, - { - id: "UnfinalizedPubkey2Index 10000 keys", - getInstance: () => getRandomMap(10000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), - }, - { - id: "UnfinalizedPubkey2Index 100000 keys", - getInstance: () => getRandomMap(100000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), - }, -]); - -function getRandomMap(n: number, getKey: (i: number) => string): Map { - const map = Map(); - - return map.withMutations((m) => { - for (let i = 0; i < n; i++) { - m.set(getKey(i), i); - } - }); -} - -/** - * Test bytes per instance in different representations of raw binary data - */ -function testRunnerMemoryBpi(testCases: {getInstance: (bytes: number) => unknown; id: string}[]): void { - const longestId = Math.max(...testCases.map(({id}) => id.length)); - - for (const {id, getInstance} of testCases) { - const bpi = testRunnerMemory({ - getInstance, - convergeFactor: 1 / 100, - sampleEvery: 5, - }); - - console.log(`${id.padEnd(longestId)} - ${bpi.toFixed(1)} bytes / instance`); - } -} diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts deleted file mode 100644 index 8009f36c6301..000000000000 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import {digest} from "@chainsafe/as-sha256"; -import {SecretKey} from "@chainsafe/blst"; -import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; -import {itBench, setBenchOpts} from "@dapplion/benchmark"; -import {type CachedBeaconStateAllForks, toMemoryEfficientHexStr} from "@lodestar/state-transition"; -import {ValidatorIndex, ssz} from "@lodestar/types"; -import {bytesToBigInt, intToBytes} from "@lodestar/utils"; -import {toBufferBE} from "bigint-buffer"; -import {Map as ImmutableMap} from "immutable"; -import {BlockStateCacheImpl, InMemoryCheckpointStateCache} from "../../../../src/chain/stateCache/index.js"; -import {BlockStateCache} from "../../../../src/chain/stateCache/types.js"; -import {generateCachedElectraState} from "../../../utils/state.js"; - -// Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz -// ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 1444.173 ops/s 692.4380 us/op - 1057 runs 6.03 s -// ✔ updateUnfinalizedPubkeys - updating 100 pubkeys 189.5965 ops/s 5.274358 ms/op - 57 runs 1.15 s -// ✔ updateUnfinalizedPubkeys - updating 1000 pubkeys 12.90495 ops/s 77.48967 ms/op - 13 runs 1.62 s -describe("updateUnfinalizedPubkeys perf tests", () => { - setBenchOpts({noThreshold: true}); - - const numPubkeysToBeFinalizedCases = [10, 100, 1000]; - const numCheckpointStateCache = 8; - const numStateCache = 3 * 32; - - let checkpointStateCache: InMemoryCheckpointStateCache; - let stateCache: BlockStateCache; - - const unfinalizedPubkey2Index = generatePubkey2Index(0, Math.max.apply(null, numPubkeysToBeFinalizedCases)); - const baseState = generateCachedElectraState(); - - for (const numPubkeysToBeFinalized of numPubkeysToBeFinalizedCases) { - itBench({ - id: `updateUnfinalizedPubkeys - updating ${numPubkeysToBeFinalized} pubkeys`, - beforeEach: async () => { - baseState.epochCtx.unfinalizedPubkey2index = ImmutableMap(unfinalizedPubkey2Index); - baseState.epochCtx.pubkey2index = new PubkeyIndexMap(); - baseState.epochCtx.index2pubkey = []; - - checkpointStateCache = new InMemoryCheckpointStateCache({}); - stateCache = new BlockStateCacheImpl({}); - - for (let i = 0; i < numCheckpointStateCache; i++) { - const clonedState = baseState.clone(); - const checkpoint = ssz.phase0.Checkpoint.defaultValue(); - - clonedState.slot = i; - checkpoint.epoch = i; // Assigning arbitrary non-duplicate values to ensure checkpointStateCache correctly saves all the states - - checkpointStateCache.add(checkpoint, clonedState); - } - - for (let i = 0; i < numStateCache; i++) { - const clonedState = baseState.clone(); - clonedState.slot = i; - stateCache.add(clonedState); - } - }, - fn: async () => { - const newFinalizedValidators = baseState.epochCtx.unfinalizedPubkey2index.filter( - (index, _pubkey) => index < numPubkeysToBeFinalized - ); - - const states = stateCache.getStates(); - const cpStates = checkpointStateCache.getStates(); - - const firstState = states.next().value as CachedBeaconStateAllForks; - firstState.epochCtx.addFinalizedPubkeys(newFinalizedValidators); - - const pubkeysToDelete = Array.from(newFinalizedValidators.keys()); - - firstState.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); - - for (const s of states) { - s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); - } - - for (const s of cpStates) { - s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); - } - }, - }); - } - - type PubkeyHex = string; - - function generatePubkey2Index(startIndex: number, endIndex: number): Map { - const pubkey2Index = new Map(); - const pubkeys = generatePubkeys(endIndex - startIndex); - - for (let i = startIndex; i < endIndex; i++) { - pubkey2Index.set(toMemoryEfficientHexStr(pubkeys[i]), i); - } - - return pubkey2Index; - } - - function generatePubkeys(validatorCount: number): Uint8Array[] { - const keys = []; - - for (let i = 0; i < validatorCount; i++) { - const sk = generatePrivateKey(i); - const pk = sk.toPublicKey().toBytes(); - keys.push(pk); - } - - return keys; - } - - function generatePrivateKey(index: number): SecretKey { - const secretKeyBytes = toBufferBE(bytesToBigInt(digest(intToBytes(index, 32))) % BigInt("38581184513"), 32); - const secret: SecretKey = SecretKey.fromBytes(secretKeyBytes); - return secret; - } -}); diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index 47b7d127fb42..148f210f7f65 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -375,17 +375,8 @@ describe("executionEngine / ExecutionEngineHttp", () => { if (headState.validators.length !== 33 || headState.balances.length !== 33) { throw Error("New validator is not reflected in the beacon state at slot 5"); } - if (epochCtx.index2pubkey.length !== 32 || epochCtx.pubkey2index.size !== 32) { - throw Error("Finalized cache is modified."); - } - if (epochCtx.unfinalizedPubkey2index.size !== 1) { - throw Error( - `Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}` - ); - } - // validator count at epoch 1 should be empty at this point since no epoch transition has happened. - if (epochCtx.getValidatorCountAtEpoch(1) !== undefined) { - throw Error("Historical validator lengths is modified"); + if (epochCtx.index2pubkey.length !== 33 || epochCtx.pubkey2index.size !== 33) { + throw Error("Pubkey cache is not updated"); } await new Promise((resolve, _reject) => { @@ -412,23 +403,7 @@ describe("executionEngine / ExecutionEngineHttp", () => { throw Error("New validator is not reflected in the beacon state."); } if (epochCtx.index2pubkey.length !== 33 || epochCtx.pubkey2index.size !== 33) { - throw Error("New validator is not in finalized cache"); - } - if (!epochCtx.unfinalizedPubkey2index.isEmpty()) { - throw Error("Unfinalized cache still contains new validator"); - } - // After 4 epochs, headState's finalized cp epoch should be 2 - // epochCtx should only have validator count for epoch 3 and 4. - if (epochCtx.getValidatorCountAtEpoch(4) === undefined || epochCtx.getValidatorCountAtEpoch(3) === undefined) { - throw Error("Missing historical validator length for epoch 3 or 4"); - } - - if (epochCtx.getValidatorCountAtEpoch(4) !== 33 || epochCtx.getValidatorCountAtEpoch(3) !== 33) { - throw Error("Incorrect historical validator length for epoch 3 or 4"); - } - - if (epochCtx.getValidatorCountAtEpoch(2) !== undefined || epochCtx.getValidatorCountAtEpoch(1) !== undefined) { - throw Error("Historical validator length for epoch 1 or 2 is not dropped properly"); + throw Error("New validator is not in pubkey cache"); } if (headState.depositRequestsStartIndex === UNSET_DEPOSIT_REQUESTS_START_INDEX) { diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 5dfecfa9bbf6..ac297b240756 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -69,8 +69,7 @@ "@lodestar/params": "^1.23.0", "@lodestar/types": "^1.23.0", "@lodestar/utils": "^1.23.0", - "bigint-buffer": "^1.1.5", - "immutable": "^4.3.2" + "bigint-buffer": "^1.1.5" }, "keywords": [ "ethereum", diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 207267dff4f4..86e63c672024 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -25,10 +25,8 @@ import { electra, phase0, } from "@lodestar/types"; -import {LodestarError, fromHex} from "@lodestar/utils"; -import * as immutable from "immutable"; +import {LodestarError} from "@lodestar/utils"; import {getTotalSlashingsByIncrement} from "../epoch/processSlashings.js"; -import {EpochCacheMetrics} from "../metrics.js"; import {AttesterDuty, calculateCommitteeAssignments} from "../util/calculateCommitteeAssignments.js"; import { EpochShuffling, @@ -51,14 +49,7 @@ import { import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; -import { - Index2PubkeyCache, - PubkeyHex, - UnfinalizedPubkeyIndexMap, - newUnfinalizedPubkeyIndexMap, - syncPubkeys, - toMemoryEfficientHexStr, -} from "./pubkeyCache.js"; +import {Index2PubkeyCache, syncPubkeys} from "./pubkeyCache.js"; import {CachedBeaconStateAllForks} from "./stateCache.js"; import { SyncCommitteeCache, @@ -111,30 +102,20 @@ type ProposersDeferred = {computed: false; seed: Uint8Array} | {computed: true; export class EpochCache { config: BeaconConfig; /** - * Unique globally shared finalized pubkey registry. There should only exist one for the entire application. + * Unique globally shared pubkey registry. There should only exist one for the entire application. * * TODO: this is a hack, we need a safety mechanism in case a bad eth1 majority vote is in, * or handle non finalized data differently, or use an immutable.js structure for cheap copies * - * New: This would include only validators whose activation_eligibility_epoch != FAR_FUTURE_EPOCH and hence it is - * insert only. Validators could be 1) Active 2) In the activation queue 3) Initialized but pending queued - * * $VALIDATOR_COUNT x 192 char String -> Number Map */ pubkey2index: PubkeyIndexMap; /** - * Unique globally shared finalized pubkey registry. There should only exist one for the entire application. - * - * New: This would include only validators whose activation_eligibility_epoch != FAR_FUTURE_EPOCH and hence it is - * insert only. Validators could be 1) Active 2) In the activation queue 3) Initialized but pending queued + * Unique globally shared pubkey registry. There should only exist one for the entire application. * * $VALIDATOR_COUNT x BLST deserialized pubkey (Jacobian coordinates) */ index2pubkey: Index2PubkeyCache; - /** - * Unique pubkey registry shared in the same fork. There should only exist one for the fork. - */ - unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; /** * ShufflingCache is passed in from `beacon-node` so should be available at runtime but may not be * present during testing. @@ -252,15 +233,6 @@ export class EpochCache { // TODO: Helper stats syncPeriod: SyncPeriod; - /** - * state.validators.length of every state at epoch boundary - * They are saved in increasing order of epoch. - * The first validator length in the list corresponds to the state AFTER the latest finalized checkpoint state. ie. state.finalizedCheckpoint.epoch - 1 - * The last validator length corresponds to the latest epoch state ie. this.epoch - * eg. latest epoch = 105, latest finalized cp state epoch = 102 - * then the list will be (in terms of epoch) [103, 104, 105] - */ - historicalValidatorLengths: immutable.List; epoch: Epoch; @@ -272,7 +244,6 @@ export class EpochCache { config: BeaconConfig; pubkey2index: PubkeyIndexMap; index2pubkey: Index2PubkeyCache; - unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; shufflingCache?: IShufflingCache; proposers: number[]; proposersPrevEpoch: number[] | null; @@ -300,12 +271,10 @@ export class EpochCache { nextSyncCommitteeIndexed: SyncCommitteeCache; epoch: Epoch; syncPeriod: SyncPeriod; - historialValidatorLengths: immutable.List; }) { this.config = data.config; this.pubkey2index = data.pubkey2index; this.index2pubkey = data.index2pubkey; - this.unfinalizedPubkey2index = data.unfinalizedPubkey2index; this.shufflingCache = data.shufflingCache; this.proposers = data.proposers; this.proposersPrevEpoch = data.proposersPrevEpoch; @@ -333,12 +302,11 @@ export class EpochCache { this.nextSyncCommitteeIndexed = data.nextSyncCommitteeIndexed; this.epoch = data.epoch; this.syncPeriod = data.syncPeriod; - this.historicalValidatorLengths = data.historialValidatorLengths; } /** * Create an epoch cache - * @param state a finalized beacon state. Passing in unfinalized state may cause unexpected behaviour eg. empty unfinalized cache + * @param state a finalized beacon state. Passing in unfinalized state may cause unexpected behaviour * * SLOW CODE - 🐢 */ @@ -551,8 +519,6 @@ export class EpochCache { config, pubkey2index, index2pubkey, - // `createFromFinalizedState()` creates cache with empty unfinalizedPubkey2index. Be cautious to only pass in finalized state - unfinalizedPubkey2index: newUnfinalizedPubkeyIndexMap(), shufflingCache, proposers, // On first epoch, set to null to prevent unnecessary work since this is only used for metrics @@ -581,7 +547,6 @@ export class EpochCache { nextSyncCommitteeIndexed, epoch: currentEpoch, syncPeriod: computeSyncPeriodAtEpoch(currentEpoch), - historialValidatorLengths: immutable.List(), }); } @@ -597,8 +562,6 @@ export class EpochCache { // Common append-only structures shared with all states, no need to clone pubkey2index: this.pubkey2index, index2pubkey: this.index2pubkey, - // No need to clone this reference. On each mutation the `unfinalizedPubkey2index` reference is replaced, @see `addPubkey` - unfinalizedPubkey2index: this.unfinalizedPubkey2index, shufflingCache: this.shufflingCache, // Immutable data proposers: this.proposers, @@ -630,7 +593,6 @@ export class EpochCache { nextSyncCommitteeIndexed: this.nextSyncCommitteeIndexed, epoch: this.epoch, syncPeriod: this.syncPeriod, - historialValidatorLengths: this.historicalValidatorLengths, }); } @@ -773,25 +735,6 @@ export class EpochCache { // ``` this.epoch = computeEpochAtSlot(state.slot); this.syncPeriod = computeSyncPeriodAtEpoch(this.epoch); - // ELECTRA Only: Add current cpState.validators.length - // Only keep validatorLength for epochs after finalized cpState.epoch - // eg. [100(epoch 1), 102(epoch 2)].push(104(epoch 3)), this.epoch = 3, finalized cp epoch = 1 - // We keep the last (3 - 1) items = [102, 104] - if (upcomingEpoch >= this.config.ELECTRA_FORK_EPOCH) { - this.historicalValidatorLengths = this.historicalValidatorLengths.push(state.validators.length); - - // If number of validatorLengths we want to keep exceeds the current list size, it implies - // finalized checkpoint hasn't advanced, and no need to slice - const hasFinalizedCpAdvanced = - this.epoch - state.finalizedCheckpoint.epoch < this.historicalValidatorLengths.size; - - if (hasFinalizedCpAdvanced) { - // We use finalized cp epoch - this.epoch which is a negative number to keep the last n entries and discard the rest - this.historicalValidatorLengths = this.historicalValidatorLengths.slice( - state.finalizedCheckpoint.epoch - this.epoch - ); - } - } } beforeEpochTransition(): void { @@ -1018,75 +961,19 @@ export class EpochCache { } /** - * Return finalized pubkey given the validator index. - * Only finalized pubkey as we do not store unfinalized pubkey because no where in the spec has a - * need to make such enquiry + * Return pubkey given the validator index. */ getPubkey(index: ValidatorIndex): PublicKey | undefined { return this.index2pubkey[index]; } getValidatorIndex(pubkey: Uint8Array): ValidatorIndex | null { - if (this.isPostElectra()) { - return this.pubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)) ?? null; - } return this.pubkey2index.get(pubkey); } - /** - * - * Add unfinalized pubkeys - * - */ addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { - if (this.isPostElectra()) { - this.addUnFinalizedPubkey(index, pubkey); - } else { - // deposit mechanism pre ELECTRA follows a safe distance with assumption - // that they are already canonical - this.addFinalizedPubkey(index, pubkey); - } - } - - addUnFinalizedPubkey(index: ValidatorIndex, pubkey: PubkeyHex | Uint8Array, metrics?: EpochCacheMetrics): void { - this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); - metrics?.newUnFinalizedPubkey.inc(); - } - - addFinalizedPubkeys(pubkeyMap: UnfinalizedPubkeyIndexMap, metrics?: EpochCacheMetrics): void { - pubkeyMap.forEach((index, pubkey) => this.addFinalizedPubkey(index, pubkey, metrics)); - } - - /** - * Add finalized validator index and pubkey into finalized cache. - * Since addFinalizedPubkey() primarily takes pubkeys from unfinalized cache, it can take pubkey hex string directly - */ - addFinalizedPubkey(index: ValidatorIndex, pubkeyOrHex: PubkeyHex | Uint8Array, metrics?: EpochCacheMetrics): void { - const pubkey = typeof pubkeyOrHex === "string" ? fromHex(pubkeyOrHex) : pubkeyOrHex; - const existingIndex = this.pubkey2index.get(pubkey); - - if (existingIndex !== null) { - if (existingIndex === index) { - // Repeated insert. - metrics?.finalizedPubkeyDuplicateInsert.inc(); - return; - } - // attempt to insert the same pubkey with different index, should never happen. - throw Error( - `inserted existing pubkey into finalizedPubkey2index cache with a different index, index=${index} priorIndex=${existingIndex}` - ); - } - this.pubkey2index.set(pubkey, index); - const pubkeyBytes = pubkey instanceof Uint8Array ? pubkey : fromHex(pubkey); - this.index2pubkey[index] = PublicKey.fromBytes(pubkeyBytes); // Optimize for aggregation - } - - /** - * Delete pubkeys from unfinalized cache - */ - deleteUnfinalizedPubkeys(pubkeys: Iterable): void { - this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.deleteAll(pubkeys); + this.index2pubkey[index] = PublicKey.fromBytes(pubkey); // Optimize for aggregation } getShufflingAtSlot(slot: Slot): EpochShuffling { @@ -1220,25 +1107,6 @@ export class EpochCache { isPostElectra(): boolean { return this.epoch >= this.config.ELECTRA_FORK_EPOCH; } - - getValidatorCountAtEpoch(targetEpoch: Epoch): number | undefined { - const currentEpoch = this.epoch; - - if (targetEpoch === currentEpoch) { - return this.historicalValidatorLengths.get(-1); - } - - // Attempt to get validator count from future epoch - if (targetEpoch > currentEpoch) { - return undefined; - } - - // targetEpoch is so far back that historicalValidatorLengths doesnt contain such info - if (targetEpoch < currentEpoch - this.historicalValidatorLengths.size + 1) { - return undefined; - } - return this.historicalValidatorLengths.get(targetEpoch - currentEpoch - 1); - } } function getEffectiveBalanceIncrementsByteLen(validatorCount: number): number { diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 16c8f3de6787..75281e52e060 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -1,44 +1,8 @@ import {PublicKey} from "@chainsafe/blst"; import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map"; import {ValidatorIndex, phase0} from "@lodestar/types"; -import * as immutable from "immutable"; export type Index2PubkeyCache = PublicKey[]; -/** - * OrderedMap preserves the order of entries in which they are `set()`. - * We assume `values()` yields validator indices in strictly increasing order - * as new validator indices are assigned in increasing order. - * EIP-6914 will break this assumption. - */ -export type UnfinalizedPubkeyIndexMap = immutable.Map; - -export type PubkeyHex = string; - -/** - * toHexString() creates hex strings via string concatenation, which are very memory inefficient. - * Memory benchmarks show that Buffer.toString("hex") produces strings with 10x less memory. - * - * Does not prefix to save memory, thus the prefix is removed from an already string representation. - * - * See https://github.com/ChainSafe/lodestar/issues/3446 - */ -export function toMemoryEfficientHexStr(hex: Uint8Array | string): string { - if (typeof hex === "string") { - if (hex.startsWith("0x")) { - hex = hex.slice(2); - } - return hex; - } - - return Buffer.from(hex.buffer, hex.byteOffset, hex.byteLength).toString("hex"); -} - -/** - * A wrapper for calling immutable.js. To abstract the initialization of UnfinalizedPubkeyIndexMap - */ -export function newUnfinalizedPubkeyIndexMap(): UnfinalizedPubkeyIndexMap { - return immutable.Map(); -} /** * Checks the pubkey indices against a state and adds missing pubkeys diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index 600bbf173462..0e76c5248a97 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -41,15 +41,10 @@ export { EpochCacheError, EpochCacheErrorCode, } from "./cache/epochCache.js"; -export {toMemoryEfficientHexStr} from "./cache/pubkeyCache.js"; export {type EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js"; // Aux data-structures -export { - type Index2PubkeyCache, - type UnfinalizedPubkeyIndexMap, - newUnfinalizedPubkeyIndexMap, -} from "./cache/pubkeyCache.js"; +export {type Index2PubkeyCache} from "./cache/pubkeyCache.js"; export { type EffectiveBalanceIncrements, diff --git a/packages/state-transition/src/metrics.ts b/packages/state-transition/src/metrics.ts index fee20de1d565..d975833ba13c 100644 --- a/packages/state-transition/src/metrics.ts +++ b/packages/state-transition/src/metrics.ts @@ -31,11 +31,6 @@ export type BeaconStateTransitionMetrics = { ) => void; }; -export type EpochCacheMetrics = { - finalizedPubkeyDuplicateInsert: Gauge; - newUnFinalizedPubkey: Gauge; -}; - export function onStateCloneMetrics( state: CachedBeaconStateAllForks, metrics: BeaconStateTransitionMetrics, diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index de2ba5893b02..9466dfd83ab7 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -28,7 +28,7 @@ describe("CachedBeaconState", () => { expect(state2.epochCtx.epoch).toBe(0); }); - it("Clone and mutate cache pre-Electra", () => { + it("Clone and mutate cache", () => { const stateView = ssz.altair.BeaconState.defaultViewDU(); const state1 = createCachedBeaconStateTest(stateView); @@ -52,40 +52,6 @@ describe("CachedBeaconState", () => { expect(state2.epochCtx.getValidatorIndex(pubkey2)).toBe(index2); }); - it("Clone and mutate cache post-Electra", () => { - const stateView = ssz.electra.BeaconState.defaultViewDU(); - const state1 = createCachedBeaconStateTest( - stateView, - createChainForkConfig({ - ALTAIR_FORK_EPOCH: 0, - BELLATRIX_FORK_EPOCH: 0, - CAPELLA_FORK_EPOCH: 0, - DENEB_FORK_EPOCH: 0, - ELECTRA_FORK_EPOCH: 0, - }), - {skipSyncCommitteeCache: true, skipSyncPubkeys: true} - ); - - const pubkey1 = fromHexString( - "0x84105a985058fc8740a48bf1ede9d223ef09e8c6b1735ba0a55cf4a9ff2ff92376b778798365e488dab07a652eb04576" - ); - const index1 = 123; - const pubkey2 = fromHexString( - "0xa41726266b1d83ef609d759ba7796d54cfe549154e01e4730a3378309bc81a7638140d7e184b33593c072595f23f032d" - ); - const index2 = 456; - - state1.epochCtx.addPubkey(index1, pubkey1); - - const state2 = state1.clone(); - state2.epochCtx.addPubkey(index2, pubkey2); - - expect(state1.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); - expect(state2.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); - expect(state1.epochCtx.getValidatorIndex(pubkey2)).toBe(null); - expect(state2.epochCtx.getValidatorIndex(pubkey2)).toBe(index2); - }); - it("Auto-commit on hashTreeRoot", () => { // Use Checkpoint instead of BeaconState to speed up the test const cp1 = ssz.phase0.Checkpoint.defaultViewDU(); diff --git a/yarn.lock b/yarn.lock index a9cb9ebe4fdc..f59b3d082456 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7267,11 +7267,6 @@ ignore@^5.0.4, ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== -immutable@^4.3.2: - version "4.3.5" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.5.tgz#f8b436e66d59f99760dc577f5c99a4fd2a5cc5a0" - integrity sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw== - import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" From 18f421859c1cf569437e8bb727b10067f24169b6 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 27 Nov 2024 07:46:14 +0100 Subject: [PATCH 203/259] chore: skip web3_provider unit tests (#7252) --- packages/prover/test/unit/web3_provider.node.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/prover/test/unit/web3_provider.node.test.ts b/packages/prover/test/unit/web3_provider.node.test.ts index 10f0fee3387d..b370c871d0e6 100644 --- a/packages/prover/test/unit/web3_provider.node.test.ts +++ b/packages/prover/test/unit/web3_provider.node.test.ts @@ -7,7 +7,8 @@ import {JsonRpcRequest, JsonRpcRequestOrBatch, JsonRpcResponse} from "../../src/ import {ELRpcProvider} from "../../src/utils/rpc_provider.js"; import {createVerifiedExecutionProvider} from "../../src/web3_provider.js"; -describe("web3_provider", () => { +// https://github.com/ChainSafe/lodestar/issues/7250 +describe.skip("web3_provider", () => { afterEach(() => { vi.clearAllMocks(); }); From e86e816b1d8418063cd64e238f0d88ca6dd0f5ea Mon Sep 17 00:00:00 2001 From: twoeths Date: Wed, 27 Nov 2024 15:22:24 +0700 Subject: [PATCH 204/259] fix: prune checkpoint states at syncing time (#7241) * fix: prune checkpoint states at syncing time * fix: lint * fix: check-types in test --- packages/beacon-node/src/chain/chain.ts | 1 - .../stateCache/persistentCheckpointsCache.ts | 27 +++---------------- .../persistentCheckpointsCache.test.ts | 18 +++++-------- 3 files changed, 9 insertions(+), 37 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 4751770b3bfc..415158abb2d5 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -293,7 +293,6 @@ export class BeaconChain implements IBeaconChain { metrics, logger, clock, - shufflingCache: this.shufflingCache, blockStateCache, bufferPool: this.bufferPool, datastore: fileDataStore diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 4c9a8b0f1265..7fb67a758673 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -9,7 +9,6 @@ import {AllocSource, BufferPool, BufferWithKey} from "../../util/bufferPool.js"; import {IClock} from "../../util/clock.js"; import {StateCloneOpts} from "../regen/interface.js"; import {serializeState} from "../serializeState.js"; -import {ShufflingCache} from "../shufflingCache.js"; import {CPStateDatastore, DatastoreKey, datastoreKeyToCheckpoint} from "./datastore/index.js"; import {MapTracker} from "./mapMetrics.js"; import {BlockStateCache, CacheItemType, CheckpointHex, CheckpointStateCache} from "./types.js"; @@ -17,8 +16,6 @@ import {BlockStateCache, CacheItemType, CheckpointHex, CheckpointStateCache} fro export type PersistentCheckpointStateCacheOpts = { /** Keep max n states in memory, persist the rest to disk */ maxCPStateEpochsInMemory?: number; - /** for testing only */ - processLateBlock?: boolean; }; type PersistentCheckpointStateCacheModules = { @@ -26,7 +23,6 @@ type PersistentCheckpointStateCacheModules = { logger: Logger; clock?: IClock | null; signal?: AbortSignal; - shufflingCache: ShufflingCache; datastore: CPStateDatastore; blockStateCache: BlockStateCache; bufferPool?: BufferPool | null; @@ -102,24 +98,12 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { private preComputedCheckpoint: string | null = null; private preComputedCheckpointHits: number | null = null; private readonly maxEpochsInMemory: number; - // only for testing, default false for production - private readonly processLateBlock: boolean; private readonly datastore: CPStateDatastore; - private readonly shufflingCache: ShufflingCache; private readonly blockStateCache: BlockStateCache; private readonly bufferPool?: BufferPool | null; constructor( - { - metrics, - logger, - clock, - signal, - shufflingCache, - datastore, - blockStateCache, - bufferPool, - }: PersistentCheckpointStateCacheModules, + {metrics, logger, clock, signal, datastore, blockStateCache, bufferPool}: PersistentCheckpointStateCacheModules, opts: PersistentCheckpointStateCacheOpts ) { this.cache = new MapTracker(metrics?.cpStateCache); @@ -153,10 +137,8 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { throw new Error("maxEpochsInMemory must be >= 0"); } this.maxEpochsInMemory = opts.maxCPStateEpochsInMemory ?? DEFAULT_MAX_CP_STATE_EPOCHS_IN_MEMORY; - this.processLateBlock = opts.processLateBlock ?? false; // Specify different datastore for testing this.datastore = datastore; - this.shufflingCache = shufflingCache; this.blockStateCache = blockStateCache; this.bufferPool = bufferPool; } @@ -487,12 +469,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { // 2/3 of slot is the most free time of every slot, take that chance to persist checkpoint states // normally it should only persist checkpoint states at 2/3 of slot 0 of epoch await sleep(secToTwoThirdsSlot * 1000, this.signal); - } else if (!this.processLateBlock) { - // normally the block persist happens at 2/3 of slot 0 of epoch, if it's already late then just skip to allow other tasks to run - // there are plenty of chances in the same epoch to persist checkpoint states, also if block is late it could be reorged - this.logger.verbose("Skip persist checkpoint states", {blockSlot, root: blockRootHex}); - return 0; } + // at syncing time, it's critical to persist checkpoint states as soon as possible to avoid OOM during unfinality time + // if node is synced this is not a hot time because block comes late, we'll likely miss attestation already, or the block is orphaned const persistEpochs = sortedEpochs.slice(0, sortedEpochs.length - this.maxEpochsInMemory); for (const lowestEpoch of persistEpochs) { diff --git a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts index 5ab3da532948..4e8b62013331 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts @@ -90,10 +90,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 2, processLateBlock: true} + {maxCPStateEpochsInMemory: 2} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -165,10 +164,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 2, processLateBlock: true} + {maxCPStateEpochsInMemory: 2} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -242,10 +240,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 2, processLateBlock: true} + {maxCPStateEpochsInMemory: 2} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -548,10 +545,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 1, processLateBlock: true} + {maxCPStateEpochsInMemory: 1} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -820,10 +816,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 0, processLateBlock: true} + {maxCPStateEpochsInMemory: 0} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -911,10 +906,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 0, processLateBlock: true} + {maxCPStateEpochsInMemory: 0} ); const root1a = Buffer.alloc(32, 100); From 443e3a8ab3dd1c49706f3e9b9b784aebd627f318 Mon Sep 17 00:00:00 2001 From: twoeths Date: Wed, 27 Nov 2024 15:52:43 +0700 Subject: [PATCH 205/259] fix: sync cached isCompoundingValidatorArr at epoch transition (#7247) --- .../src/cache/epochTransitionCache.ts | 25 +++++++++++++------ .../epoch/processEffectiveBalanceUpdates.ts | 7 +++--- .../src/epoch/processPendingDeposits.ts | 3 +++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/state-transition/src/cache/epochTransitionCache.ts b/packages/state-transition/src/cache/epochTransitionCache.ts index d86431c72eee..16279e851188 100644 --- a/packages/state-transition/src/cache/epochTransitionCache.ts +++ b/packages/state-transition/src/cache/epochTransitionCache.ts @@ -9,7 +9,12 @@ import {Epoch, RootHex, ValidatorIndex, phase0} from "@lodestar/types"; import {intDiv, toRootHex} from "@lodestar/utils"; import {processPendingAttestations} from "../epoch/processPendingAttestations.js"; -import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../index.js"; +import { + CachedBeaconStateAllForks, + CachedBeaconStateAltair, + CachedBeaconStatePhase0, + hasCompoundingWithdrawalCredential, +} from "../index.js"; import {computeBaseRewardPerIncrement} from "../util/altair.js"; import { FLAG_CURR_HEAD_ATTESTER, @@ -133,11 +138,7 @@ export interface EpochTransitionCache { flags: number[]; - /** - * Validators in the current epoch, should use it for read-only value instead of accessing state.validators directly. - * Note that during epoch processing, validators could be updated so need to use it with care. - */ - validators: phase0.Validator[]; + isCompoundingValidatorArr: boolean[]; /** * balances array will be populated by processRewardsAndPenalties() and consumed by processEffectiveBalanceUpdates(). @@ -209,6 +210,8 @@ const inclusionDelays = new Array(); /** WARNING: reused, never gc'd */ const flags = new Array(); /** WARNING: reused, never gc'd */ +const isCompoundingValidatorArr = new Array(); +/** WARNING: reused, never gc'd */ const nextEpochShufflingActiveValidatorIndices = new Array(); export function beforeProcessEpoch( @@ -262,6 +265,10 @@ export function beforeProcessEpoch( // TODO: optimize by combining the two loops // likely will require splitting into phase0 and post-phase0 versions + if (forkSeq >= ForkSeq.electra) { + isCompoundingValidatorArr.length = validatorCount; + } + // Clone before being mutated in processEffectiveBalanceUpdates epochCtx.beforeEpochTransition(); @@ -298,6 +305,10 @@ export function beforeProcessEpoch( flags[i] = flag; + if (forkSeq >= ForkSeq.electra) { + isCompoundingValidatorArr[i] = hasCompoundingWithdrawalCredential(validator.withdrawalCredentials); + } + if (isActiveCurr) { totalActiveStakeByIncrement += effectiveBalancesByIncrements[i]; } else { @@ -511,7 +522,7 @@ export function beforeProcessEpoch( proposerIndices, inclusionDelays, flags, - validators, + isCompoundingValidatorArr, // Will be assigned in processRewardsAndPenalties() balances: undefined, }; diff --git a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts index d55f37aba178..b98e5cce9f35 100644 --- a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts +++ b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts @@ -5,10 +5,11 @@ import { HYSTERESIS_QUOTIENT, HYSTERESIS_UPWARD_MULTIPLIER, MAX_EFFECTIVE_BALANCE, + MAX_EFFECTIVE_BALANCE_ELECTRA, + MIN_ACTIVATION_BALANCE, TIMELY_TARGET_FLAG_INDEX, } from "@lodestar/params"; import {BeaconStateAltair, CachedBeaconStateAllForks, EpochTransitionCache} from "../types.js"; -import {getMaxEffectiveBalance} from "../util/validator.js"; /** Same to https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/beacon-chain.md#has_flag */ const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX; @@ -43,7 +44,7 @@ export function processEffectiveBalanceUpdates( // and updated in processPendingDeposits() and processPendingConsolidations() // so it's recycled here for performance. const balances = cache.balances ?? state.balances.getAll(); - const currentEpochValidators = cache.validators; + const isCompoundingValidatorArr = cache.isCompoundingValidatorArr; let numUpdate = 0; for (let i = 0, len = balances.length; i < len; i++) { @@ -58,7 +59,7 @@ export function processEffectiveBalanceUpdates( effectiveBalanceLimit = MAX_EFFECTIVE_BALANCE; } else { // from electra, effectiveBalanceLimit is per validator - effectiveBalanceLimit = getMaxEffectiveBalance(currentEpochValidators[i].withdrawalCredentials); + effectiveBalanceLimit = isCompoundingValidatorArr[i] ? MAX_EFFECTIVE_BALANCE_ELECTRA : MIN_ACTIVATION_BALANCE; } if ( diff --git a/packages/state-transition/src/epoch/processPendingDeposits.ts b/packages/state-transition/src/epoch/processPendingDeposits.ts index 866dcc2510ad..e00e1ef93c8c 100644 --- a/packages/state-transition/src/epoch/processPendingDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingDeposits.ts @@ -3,6 +3,7 @@ import {PendingDeposit} from "@lodestar/types/lib/electra/types.js"; import {addValidatorToRegistry, isValidDepositSignature} from "../block/processDeposit.js"; import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; import {increaseBalance} from "../util/balance.js"; +import {hasCompoundingWithdrawalCredential} from "../util/electra.js"; import {computeStartSlotAtEpoch} from "../util/epoch.js"; import {getActivationExitChurnLimit} from "../util/validator.js"; @@ -106,6 +107,8 @@ function applyPendingDeposit( // Verify the deposit signature (proof of possession) which is not checked by the deposit contract if (isValidDepositSignature(state.config, pubkey, withdrawalCredentials, amount, signature)) { addValidatorToRegistry(ForkSeq.electra, state, pubkey, withdrawalCredentials, amount); + const newValidatorIndex = state.validators.length - 1; + cache.isCompoundingValidatorArr[newValidatorIndex] = hasCompoundingWithdrawalCredential(withdrawalCredentials); } } else { // Increase balance From 0c1ad93f8919c66abf0053ec3f9c2519623ec1b6 Mon Sep 17 00:00:00 2001 From: twoeths Date: Wed, 27 Nov 2024 17:01:15 +0700 Subject: [PATCH 206/259] fix: handle outOfRangeData when range sync Deneb (#7249) * fix: handle outOfRangeData for beaconBlocksMaybeBlobsByRange() * fix: lint * fix: archiveBlocks - handle deneb outOfRangeData block --- .../src/chain/archiver/archiveBlocks.ts | 44 ++++++++++++++----- .../reqresp/beaconBlocksMaybeBlobsByRange.ts | 8 ++-- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts index 69c7dedfc560..ad0ac0ff2c6b 100644 --- a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts +++ b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts @@ -59,8 +59,8 @@ export async function archiveBlocks( }); if (finalizedPostDeneb) { - await migrateBlobSidecarsFromHotToColdDb(config, db, finalizedCanonicalBlockRoots); - logger.verbose("Migrated blobSidecars from hot DB to cold DB"); + const migrate = await migrateBlobSidecarsFromHotToColdDb(config, db, finalizedCanonicalBlockRoots, currentEpoch); + logger.verbose(migrate ? "Migrated blobSidecars from hot DB to cold DB" : "Skip blobSidecars migration"); } } @@ -157,22 +157,36 @@ async function migrateBlocksFromHotToColdDb(db: IBeaconDb, blocks: BlockRootSlot } } +/** + * Migrate blobSidecars from hot db to cold db. + * @returns true if we do that, false if block is out of range data. + */ async function migrateBlobSidecarsFromHotToColdDb( config: ChainForkConfig, db: IBeaconDb, - blocks: BlockRootSlot[] -): Promise { + blocks: BlockRootSlot[], + currentEpoch: Epoch +): Promise { + let result = false; + for (let i = 0; i < blocks.length; i += BLOB_SIDECAR_BATCH_SIZE) { const toIdx = Math.min(i + BLOB_SIDECAR_BATCH_SIZE, blocks.length); const canonicalBlocks = blocks.slice(i, toIdx); // processCanonicalBlocks - if (canonicalBlocks.length === 0) return; + if (canonicalBlocks.length === 0) return false; // load Buffer instead of ssz deserialized to improve performance const canonicalBlobSidecarsEntries: KeyValue[] = await Promise.all( canonicalBlocks - .filter((block) => config.getForkSeq(block.slot) >= ForkSeq.deneb) + .filter((block) => { + const blockSlot = block.slot; + const blockEpoch = computeEpochAtSlot(blockSlot); + return ( + config.getForkSeq(blockSlot) >= ForkSeq.deneb && + blockEpoch >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS + ); + }) .map(async (block) => { const bytes = await db.blobSidecars.getBinary(block.root); if (!bytes) { @@ -182,12 +196,20 @@ async function migrateBlobSidecarsFromHotToColdDb( }) ); - // put to blockArchive db and delete block db - await Promise.all([ - db.blobSidecarsArchive.batchPutBinary(canonicalBlobSidecarsEntries), - db.blobSidecars.batchDelete(canonicalBlocks.map((block) => block.root)), - ]); + const migrate = canonicalBlobSidecarsEntries.length > 0; + + if (migrate) { + // put to blockArchive db and delete block db + await Promise.all([ + db.blobSidecarsArchive.batchPutBinary(canonicalBlobSidecarsEntries), + db.blobSidecars.batchDelete(canonicalBlocks.map((block) => block.root)), + ]); + } + + result = result || migrate; } + + return result; } /** diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts index 21d781f11437..d19a7867d873 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts @@ -36,8 +36,9 @@ export async function beaconBlocksMaybeBlobsByRange( return blocks.map((block) => getBlockInput.preData(config, block.data, BlockSource.byRange, block.bytes)); } + // From Deneb // Only request blobs if they are recent enough - if (computeEpochAtSlot(startSlot) >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) { + if (startEpoch >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) { const [allBlocks, allBlobSidecars] = await Promise.all([ network.sendBeaconBlocksByRange(peerId, request), network.sendBlobSidecarsByRange(peerId, request), @@ -46,8 +47,9 @@ export async function beaconBlocksMaybeBlobsByRange( return matchBlockWithBlobs(config, allBlocks, allBlobSidecars, endSlot, BlockSource.byRange, BlobsSource.byRange); } - // Post Deneb but old blobs - throw Error("Cannot sync blobs outside of blobs prune window"); + // Data is out of range, only request blocks + const blocks = await network.sendBeaconBlocksByRange(peerId, request); + return blocks.map((block) => getBlockInput.outOfRangeData(config, block.data, BlockSource.byRange, block.bytes)); } // Assumes that the blobs are in the same sequence as blocks, doesn't require block to be sorted From 48dea55f542b6356d301663ec7c36e5ab9412c1b Mon Sep 17 00:00:00 2001 From: twoeths Date: Thu, 28 Nov 2024 14:20:20 +0700 Subject: [PATCH 207/259] fix: sync cached balance when adding new validator to registry (#7255) * fix: sync cached balance when adding new validator to registry * chore: add more comments * fix: remove persisted checkpoint states from the previous run at startup --- .../chain/stateCache/persistentCheckpointsCache.ts | 11 +++++------ .../src/epoch/processPendingDeposits.ts | 6 ++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 7fb67a758673..d0540e507df3 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -151,12 +151,11 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { await this.datastore.init(); } const persistedKeys = await this.datastore.readKeys(); - for (const persistedKey of persistedKeys) { - const cp = datastoreKeyToCheckpoint(persistedKey); - this.cache.set(toCacheKey(cp), {type: CacheItemType.persisted, value: persistedKey}); - this.epochIndex.getOrDefault(cp.epoch).add(toRootHex(cp.root)); - } - this.logger.info("Loaded persisted checkpoint states from the last run", { + // all checkpoint states from the last run are not trusted, remove them + // otherwise if we have a bad checkpoint state from the last run, the node get stucked + // this was found during mekong devnet, see https://github.com/ChainSafe/lodestar/pull/7255 + await Promise.all(persistedKeys.map((key) => this.datastore.remove(key))); + this.logger.info("Removed persisted checkpoint states from the last run", { count: persistedKeys.length, maxEpochsInMemory: this.maxEpochsInMemory, }); diff --git a/packages/state-transition/src/epoch/processPendingDeposits.ts b/packages/state-transition/src/epoch/processPendingDeposits.ts index e00e1ef93c8c..d925aa1cc741 100644 --- a/packages/state-transition/src/epoch/processPendingDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingDeposits.ts @@ -109,6 +109,12 @@ function applyPendingDeposit( addValidatorToRegistry(ForkSeq.electra, state, pubkey, withdrawalCredentials, amount); const newValidatorIndex = state.validators.length - 1; cache.isCompoundingValidatorArr[newValidatorIndex] = hasCompoundingWithdrawalCredential(withdrawalCredentials); + // set balance, so that the next deposit of same pubkey will increase the balance correctly + // this is to fix the double deposit issue found in mekong + // see https://github.com/ChainSafe/lodestar/pull/7255 + if (cachedBalances) { + cachedBalances[newValidatorIndex] = amount; + } } } else { // Increase balance From 36be6b39d1c290dd2884887e37313a11792de19b Mon Sep 17 00:00:00 2001 From: Phil Ngo Date: Thu, 28 Nov 2024 12:54:20 -0500 Subject: [PATCH 208/259] chore: bump package versions to 1.23.1 --- lerna.json | 2 +- packages/api/package.json | 10 +++++----- packages/beacon-node/package.json | 26 +++++++++++++------------- packages/cli/package.json | 26 +++++++++++++------------- packages/config/package.json | 8 ++++---- packages/db/package.json | 8 ++++---- packages/flare/package.json | 14 +++++++------- packages/fork-choice/package.json | 12 ++++++------ packages/light-client/package.json | 12 ++++++------ packages/logger/package.json | 6 +++--- packages/params/package.json | 2 +- packages/prover/package.json | 18 +++++++++--------- packages/reqresp/package.json | 12 ++++++------ packages/spec-test-util/package.json | 4 ++-- packages/state-transition/package.json | 10 +++++----- packages/test-utils/package.json | 6 +++--- packages/types/package.json | 4 ++-- packages/utils/package.json | 2 +- packages/validator/package.json | 18 +++++++++--------- 19 files changed, 100 insertions(+), 100 deletions(-) diff --git a/lerna.json b/lerna.json index 6d76d7f4a488..cdd74f75b2cf 100644 --- a/lerna.json +++ b/lerna.json @@ -4,7 +4,7 @@ ], "npmClient": "yarn", "useNx": true, - "version": "1.23.0", + "version": "1.23.1", "stream": true, "command": { "version": { diff --git a/packages/api/package.json b/packages/api/package.json index a787147f6f07..1f4f3e7c3fdf 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.23.0", + "version": "1.23.1", "type": "module", "exports": { ".": { @@ -72,10 +72,10 @@ "dependencies": { "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/ssz": "^0.18.0", - "@lodestar/config": "^1.23.0", - "@lodestar/params": "^1.23.0", - "@lodestar/types": "^1.23.0", - "@lodestar/utils": "^1.23.0", + "@lodestar/config": "^1.23.1", + "@lodestar/params": "^1.23.1", + "@lodestar/types": "^1.23.1", + "@lodestar/utils": "^1.23.1", "eventsource": "^2.0.2", "qs": "^6.11.1" }, diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 87d80d27039c..ffce2f3eacfe 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.23.0", + "version": "1.23.1", "type": "module", "exports": { ".": { @@ -120,18 +120,18 @@ "@libp2p/peer-id-factory": "^4.1.0", "@libp2p/prometheus-metrics": "^3.0.21", "@libp2p/tcp": "9.0.23", - "@lodestar/api": "^1.23.0", - "@lodestar/config": "^1.23.0", - "@lodestar/db": "^1.23.0", - "@lodestar/fork-choice": "^1.23.0", - "@lodestar/light-client": "^1.23.0", - "@lodestar/logger": "^1.23.0", - "@lodestar/params": "^1.23.0", - "@lodestar/reqresp": "^1.23.0", - "@lodestar/state-transition": "^1.23.0", - "@lodestar/types": "^1.23.0", - "@lodestar/utils": "^1.23.0", - "@lodestar/validator": "^1.23.0", + "@lodestar/api": "^1.23.1", + "@lodestar/config": "^1.23.1", + "@lodestar/db": "^1.23.1", + "@lodestar/fork-choice": "^1.23.1", + "@lodestar/light-client": "^1.23.1", + "@lodestar/logger": "^1.23.1", + "@lodestar/params": "^1.23.1", + "@lodestar/reqresp": "^1.23.1", + "@lodestar/state-transition": "^1.23.1", + "@lodestar/types": "^1.23.1", + "@lodestar/utils": "^1.23.1", + "@lodestar/validator": "^1.23.1", "@multiformats/multiaddr": "^12.1.3", "c-kzg": "^2.1.2", "datastore-core": "^9.1.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 287300183a7f..e1b2134f5f82 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@chainsafe/lodestar", - "version": "1.23.0", + "version": "1.23.1", "description": "Command line interface for lodestar", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -62,17 +62,17 @@ "@libp2p/crypto": "^4.1.0", "@libp2p/peer-id": "^4.1.0", "@libp2p/peer-id-factory": "^4.1.0", - "@lodestar/api": "^1.23.0", - "@lodestar/beacon-node": "^1.23.0", - "@lodestar/config": "^1.23.0", - "@lodestar/db": "^1.23.0", - "@lodestar/light-client": "^1.23.0", - "@lodestar/logger": "^1.23.0", - "@lodestar/params": "^1.23.0", - "@lodestar/state-transition": "^1.23.0", - "@lodestar/types": "^1.23.0", - "@lodestar/utils": "^1.23.0", - "@lodestar/validator": "^1.23.0", + "@lodestar/api": "^1.23.1", + "@lodestar/beacon-node": "^1.23.1", + "@lodestar/config": "^1.23.1", + "@lodestar/db": "^1.23.1", + "@lodestar/light-client": "^1.23.1", + "@lodestar/logger": "^1.23.1", + "@lodestar/params": "^1.23.1", + "@lodestar/state-transition": "^1.23.1", + "@lodestar/types": "^1.23.1", + "@lodestar/utils": "^1.23.1", + "@lodestar/validator": "^1.23.1", "@multiformats/multiaddr": "^12.1.3", "deepmerge": "^4.3.1", "ethers": "^6.7.0", @@ -88,7 +88,7 @@ "yargs": "^17.7.1" }, "devDependencies": { - "@lodestar/test-utils": "^1.23.0", + "@lodestar/test-utils": "^1.23.1", "@types/debug": "^4.1.7", "@types/got": "^9.6.12", "@types/inquirer": "^9.0.3", diff --git a/packages/config/package.json b/packages/config/package.json index aadbf9e004b2..5a4edcf7879c 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/config", - "version": "1.23.0", + "version": "1.23.1", "description": "Chain configuration required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -65,8 +65,8 @@ ], "dependencies": { "@chainsafe/ssz": "^0.18.0", - "@lodestar/params": "^1.23.0", - "@lodestar/types": "^1.23.0", - "@lodestar/utils": "^1.23.0" + "@lodestar/params": "^1.23.1", + "@lodestar/types": "^1.23.1", + "@lodestar/utils": "^1.23.1" } } diff --git a/packages/db/package.json b/packages/db/package.json index 370caaa5f8c9..a332d316185b 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/db", - "version": "1.23.0", + "version": "1.23.1", "description": "DB modules of Lodestar", "author": "ChainSafe Systems", "homepage": "https://github.com/ChainSafe/lodestar#readme", @@ -36,12 +36,12 @@ }, "dependencies": { "@chainsafe/ssz": "^0.18.0", - "@lodestar/config": "^1.23.0", - "@lodestar/utils": "^1.23.0", + "@lodestar/config": "^1.23.1", + "@lodestar/utils": "^1.23.1", "classic-level": "^1.4.1", "it-all": "^3.0.4" }, "devDependencies": { - "@lodestar/logger": "^1.23.0" + "@lodestar/logger": "^1.23.1" } } diff --git a/packages/flare/package.json b/packages/flare/package.json index 1ec88f28ac4d..c3d262173321 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/flare", - "version": "1.23.0", + "version": "1.23.1", "description": "Beacon chain debugging tool", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -60,12 +60,12 @@ "dependencies": { "@chainsafe/bls-keygen": "^0.4.0", "@chainsafe/blst": "^2.1.0", - "@lodestar/api": "^1.23.0", - "@lodestar/config": "^1.23.0", - "@lodestar/params": "^1.23.0", - "@lodestar/state-transition": "^1.23.0", - "@lodestar/types": "^1.23.0", - "@lodestar/utils": "^1.23.0", + "@lodestar/api": "^1.23.1", + "@lodestar/config": "^1.23.1", + "@lodestar/params": "^1.23.1", + "@lodestar/state-transition": "^1.23.1", + "@lodestar/types": "^1.23.1", + "@lodestar/utils": "^1.23.1", "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 1ee9d043c925..cc86cd75b45f 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.23.0", + "version": "1.23.1", "type": "module", "exports": "./lib/index.js", "types": "./lib/index.d.ts", @@ -37,11 +37,11 @@ }, "dependencies": { "@chainsafe/ssz": "^0.18.0", - "@lodestar/config": "^1.23.0", - "@lodestar/params": "^1.23.0", - "@lodestar/state-transition": "^1.23.0", - "@lodestar/types": "^1.23.0", - "@lodestar/utils": "^1.23.0" + "@lodestar/config": "^1.23.1", + "@lodestar/params": "^1.23.1", + "@lodestar/state-transition": "^1.23.1", + "@lodestar/types": "^1.23.1", + "@lodestar/utils": "^1.23.1" }, "keywords": [ "ethereum", diff --git a/packages/light-client/package.json b/packages/light-client/package.json index c942ff07ed44..f972250937ae 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.23.0", + "version": "1.23.1", "type": "module", "exports": { ".": { @@ -77,11 +77,11 @@ "@chainsafe/blst": "^0.2.0", "@chainsafe/persistent-merkle-tree": "^0.8.0", "@chainsafe/ssz": "^0.18.0", - "@lodestar/api": "^1.23.0", - "@lodestar/config": "^1.23.0", - "@lodestar/params": "^1.23.0", - "@lodestar/types": "^1.23.0", - "@lodestar/utils": "^1.23.0", + "@lodestar/api": "^1.23.1", + "@lodestar/config": "^1.23.1", + "@lodestar/params": "^1.23.1", + "@lodestar/types": "^1.23.1", + "@lodestar/utils": "^1.23.1", "mitt": "^3.0.0" }, "devDependencies": { diff --git a/packages/logger/package.json b/packages/logger/package.json index b9e9beef39be..3e8d2095866b 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.23.0", + "version": "1.23.1", "type": "module", "exports": { ".": { @@ -66,14 +66,14 @@ }, "types": "lib/index.d.ts", "dependencies": { - "@lodestar/utils": "^1.23.0", + "@lodestar/utils": "^1.23.1", "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.23.0", + "@lodestar/test-utils": "^1.23.1", "@types/triple-beam": "^1.3.2", "triple-beam": "^1.3.0" }, diff --git a/packages/params/package.json b/packages/params/package.json index ce78e826ef18..203dd660571e 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/params", - "version": "1.23.0", + "version": "1.23.1", "description": "Chain parameters required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", diff --git a/packages/prover/package.json b/packages/prover/package.json index eee42f4226c2..cbaa7dabdbf3 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.23.0", + "version": "1.23.1", "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.23.0", - "@lodestar/config": "^1.23.0", - "@lodestar/light-client": "^1.23.0", - "@lodestar/logger": "^1.23.0", - "@lodestar/params": "^1.23.0", - "@lodestar/types": "^1.23.0", - "@lodestar/utils": "^1.23.0", + "@lodestar/api": "^1.23.1", + "@lodestar/config": "^1.23.1", + "@lodestar/light-client": "^1.23.1", + "@lodestar/logger": "^1.23.1", + "@lodestar/params": "^1.23.1", + "@lodestar/types": "^1.23.1", + "@lodestar/utils": "^1.23.1", "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.23.0", + "@lodestar/test-utils": "^1.23.1", "@types/http-proxy": "^1.17.10", "@types/yargs": "^17.0.24", "axios": "^1.3.4", diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index 981016a363df..c2280ee8fc37 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.23.0", + "version": "1.23.1", "type": "module", "exports": { ".": { @@ -54,9 +54,9 @@ "dependencies": { "@chainsafe/fast-crc32c": "^4.1.1", "@libp2p/interface": "^1.3.0", - "@lodestar/config": "^1.23.0", - "@lodestar/params": "^1.23.0", - "@lodestar/utils": "^1.23.0", + "@lodestar/config": "^1.23.1", + "@lodestar/params": "^1.23.1", + "@lodestar/utils": "^1.23.1", "it-all": "^3.0.4", "it-pipe": "^3.0.1", "snappy": "^7.2.2", @@ -65,8 +65,8 @@ "uint8arraylist": "^2.4.7" }, "devDependencies": { - "@lodestar/logger": "^1.23.0", - "@lodestar/types": "^1.23.0", + "@lodestar/logger": "^1.23.1", + "@lodestar/types": "^1.23.1", "libp2p": "1.4.3" }, "peerDependencies": { diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index 6f58e55d2201..c35814d8b57f 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.23.0", + "version": "1.23.1", "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.23.0", + "@lodestar/utils": "^1.23.1", "axios": "^1.3.4", "rimraf": "^4.4.1", "snappyjs": "^0.7.0", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 5dfecfa9bbf6..31d638bb0b7e 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.23.0", + "version": "1.23.1", "type": "module", "exports": { ".": { @@ -65,10 +65,10 @@ "@chainsafe/pubkey-index-map": "2.0.0", "@chainsafe/ssz": "^0.18.0", "@chainsafe/swap-or-not-shuffle": "^0.0.2", - "@lodestar/config": "^1.23.0", - "@lodestar/params": "^1.23.0", - "@lodestar/types": "^1.23.0", - "@lodestar/utils": "^1.23.0", + "@lodestar/config": "^1.23.1", + "@lodestar/params": "^1.23.1", + "@lodestar/types": "^1.23.1", + "@lodestar/utils": "^1.23.1", "bigint-buffer": "^1.1.5", "immutable": "^4.3.2" }, diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index c8fc5cd41c55..ff65198c3b35 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.23.0", + "version": "1.23.1", "description": "Test utilities reused across other packages", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -59,8 +59,8 @@ "dependencies": { "@chainsafe/bls-keystore": "^3.1.0", "@chainsafe/blst": "^2.1.0", - "@lodestar/params": "^1.23.0", - "@lodestar/utils": "^1.23.0", + "@lodestar/params": "^1.23.1", + "@lodestar/utils": "^1.23.1", "axios": "^1.3.4", "testcontainers": "^10.2.1", "tmp": "^0.2.1", diff --git a/packages/types/package.json b/packages/types/package.json index 9201ef2f4e88..fbaf060afbca 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.23.0", + "version": "1.23.1", "type": "module", "exports": { ".": { @@ -74,7 +74,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/ssz": "^0.18.0", - "@lodestar/params": "^1.23.0", + "@lodestar/params": "^1.23.1", "ethereum-cryptography": "^2.0.0" }, "keywords": [ diff --git a/packages/utils/package.json b/packages/utils/package.json index 9b6f5e797e68..babd09066e8c 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.23.0", + "version": "1.23.1", "type": "module", "exports": "./lib/index.js", "files": [ diff --git a/packages/validator/package.json b/packages/validator/package.json index 1566c08668b9..823d2dd86907 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/validator", - "version": "1.23.0", + "version": "1.23.1", "description": "A Typescript implementation of the validator client", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -47,17 +47,17 @@ "dependencies": { "@chainsafe/blst": "^2.1.0", "@chainsafe/ssz": "^0.18.0", - "@lodestar/api": "^1.23.0", - "@lodestar/config": "^1.23.0", - "@lodestar/db": "^1.23.0", - "@lodestar/params": "^1.23.0", - "@lodestar/state-transition": "^1.23.0", - "@lodestar/types": "^1.23.0", - "@lodestar/utils": "^1.23.0", + "@lodestar/api": "^1.23.1", + "@lodestar/config": "^1.23.1", + "@lodestar/db": "^1.23.1", + "@lodestar/params": "^1.23.1", + "@lodestar/state-transition": "^1.23.1", + "@lodestar/types": "^1.23.1", + "@lodestar/utils": "^1.23.1", "strict-event-emitter-types": "^2.0.0" }, "devDependencies": { - "@lodestar/test-utils": "^1.23.0", + "@lodestar/test-utils": "^1.23.1", "bigint-buffer": "^1.1.5", "rimraf": "^4.4.1" } From ffa4bb8cc1f34ac82ef0aa1248a359cdff47c7b8 Mon Sep 17 00:00:00 2001 From: twoeths Date: Wed, 27 Nov 2024 15:22:24 +0700 Subject: [PATCH 209/259] fix: prune checkpoint states at syncing time (#7241) * fix: prune checkpoint states at syncing time * fix: lint * fix: check-types in test --- packages/beacon-node/src/chain/chain.ts | 1 - .../stateCache/persistentCheckpointsCache.ts | 27 +++---------------- .../persistentCheckpointsCache.test.ts | 18 +++++-------- 3 files changed, 9 insertions(+), 37 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 144b73f0c01d..9141aa994224 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -293,7 +293,6 @@ export class BeaconChain implements IBeaconChain { metrics, logger, clock, - shufflingCache: this.shufflingCache, blockStateCache, bufferPool: this.bufferPool, datastore: fileDataStore diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 0719efcfd309..8663c0533ed8 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -6,7 +6,6 @@ import {loadCachedBeaconState} from "@lodestar/state-transition"; import {INTERVALS_PER_SLOT} from "@lodestar/params"; import {Metrics} from "../../metrics/index.js"; import {IClock} from "../../util/clock.js"; -import {ShufflingCache} from "../shufflingCache.js"; import {AllocSource, BufferPool, BufferWithKey} from "../../util/bufferPool.js"; import {StateCloneOpts} from "../regen/interface.js"; import {serializeState} from "../serializeState.js"; @@ -17,8 +16,6 @@ import {CheckpointHex, CacheItemType, CheckpointStateCache, BlockStateCache} fro export type PersistentCheckpointStateCacheOpts = { /** Keep max n states in memory, persist the rest to disk */ maxCPStateEpochsInMemory?: number; - /** for testing only */ - processLateBlock?: boolean; }; type PersistentCheckpointStateCacheModules = { @@ -26,7 +23,6 @@ type PersistentCheckpointStateCacheModules = { logger: Logger; clock?: IClock | null; signal?: AbortSignal; - shufflingCache: ShufflingCache; datastore: CPStateDatastore; blockStateCache: BlockStateCache; bufferPool?: BufferPool | null; @@ -102,24 +98,12 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { private preComputedCheckpoint: string | null = null; private preComputedCheckpointHits: number | null = null; private readonly maxEpochsInMemory: number; - // only for testing, default false for production - private readonly processLateBlock: boolean; private readonly datastore: CPStateDatastore; - private readonly shufflingCache: ShufflingCache; private readonly blockStateCache: BlockStateCache; private readonly bufferPool?: BufferPool | null; constructor( - { - metrics, - logger, - clock, - signal, - shufflingCache, - datastore, - blockStateCache, - bufferPool, - }: PersistentCheckpointStateCacheModules, + {metrics, logger, clock, signal, datastore, blockStateCache, bufferPool}: PersistentCheckpointStateCacheModules, opts: PersistentCheckpointStateCacheOpts ) { this.cache = new MapTracker(metrics?.cpStateCache); @@ -153,10 +137,8 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { throw new Error("maxEpochsInMemory must be >= 0"); } this.maxEpochsInMemory = opts.maxCPStateEpochsInMemory ?? DEFAULT_MAX_CP_STATE_EPOCHS_IN_MEMORY; - this.processLateBlock = opts.processLateBlock ?? false; // Specify different datastore for testing this.datastore = datastore; - this.shufflingCache = shufflingCache; this.blockStateCache = blockStateCache; this.bufferPool = bufferPool; } @@ -487,12 +469,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { // 2/3 of slot is the most free time of every slot, take that chance to persist checkpoint states // normally it should only persist checkpoint states at 2/3 of slot 0 of epoch await sleep(secToTwoThirdsSlot * 1000, this.signal); - } else if (!this.processLateBlock) { - // normally the block persist happens at 2/3 of slot 0 of epoch, if it's already late then just skip to allow other tasks to run - // there are plenty of chances in the same epoch to persist checkpoint states, also if block is late it could be reorged - this.logger.verbose("Skip persist checkpoint states", {blockSlot, root: blockRootHex}); - return 0; } + // at syncing time, it's critical to persist checkpoint states as soon as possible to avoid OOM during unfinality time + // if node is synced this is not a hot time because block comes late, we'll likely miss attestation already, or the block is orphaned const persistEpochs = sortedEpochs.slice(0, sortedEpochs.length - this.maxEpochsInMemory); for (const lowestEpoch of persistEpochs) { diff --git a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts index f98b180fa983..aecec564bd92 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts @@ -90,10 +90,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 2, processLateBlock: true} + {maxCPStateEpochsInMemory: 2} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -165,10 +164,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 2, processLateBlock: true} + {maxCPStateEpochsInMemory: 2} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -242,10 +240,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 2, processLateBlock: true} + {maxCPStateEpochsInMemory: 2} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -548,10 +545,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 1, processLateBlock: true} + {maxCPStateEpochsInMemory: 1} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -820,10 +816,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 0, processLateBlock: true} + {maxCPStateEpochsInMemory: 0} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -911,10 +906,9 @@ describe("PersistentCheckpointStateCache", () => { { datastore, logger: testLogger(), - shufflingCache: new ShufflingCache(), blockStateCache: new FIFOBlockStateCache({}, {}), }, - {maxCPStateEpochsInMemory: 0, processLateBlock: true} + {maxCPStateEpochsInMemory: 0} ); const root1a = Buffer.alloc(32, 100); From 2c2326f2debd6b181669967aff17ead5e5c02826 Mon Sep 17 00:00:00 2001 From: twoeths Date: Wed, 27 Nov 2024 15:52:43 +0700 Subject: [PATCH 210/259] fix: sync cached isCompoundingValidatorArr at epoch transition (#7247) --- .../src/cache/epochTransitionCache.ts | 47 ++++++++++++------- .../epoch/processEffectiveBalanceUpdates.ts | 7 +-- .../src/epoch/processPendingDeposits.ts | 5 +- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/packages/state-transition/src/cache/epochTransitionCache.ts b/packages/state-transition/src/cache/epochTransitionCache.ts index 2a35317fbc93..b21f940c28d5 100644 --- a/packages/state-transition/src/cache/epochTransitionCache.ts +++ b/packages/state-transition/src/cache/epochTransitionCache.ts @@ -1,27 +1,32 @@ -import {phase0, Epoch, RootHex, ValidatorIndex} from "@lodestar/types"; -import {intDiv, toRootHex} from "@lodestar/utils"; import { EPOCHS_PER_SLASHINGS_VECTOR, FAR_FUTURE_EPOCH, ForkSeq, - SLOTS_PER_HISTORICAL_ROOT, MIN_ACTIVATION_BALANCE, + SLOTS_PER_HISTORICAL_ROOT, } from "@lodestar/params"; +import {Epoch, RootHex, ValidatorIndex} from "@lodestar/types"; +import {intDiv, toRootHex} from "@lodestar/utils"; +import {processPendingAttestations} from "../epoch/processPendingAttestations.js"; import { - hasMarkers, - FLAG_UNSLASHED, + CachedBeaconStateAllForks, + CachedBeaconStateAltair, + CachedBeaconStatePhase0, + hasCompoundingWithdrawalCredential, +} from "../index.js"; +import {computeBaseRewardPerIncrement} from "../util/altair.js"; +import { + FLAG_CURR_HEAD_ATTESTER, + FLAG_CURR_SOURCE_ATTESTER, + FLAG_CURR_TARGET_ATTESTER, FLAG_ELIGIBLE_ATTESTER, + FLAG_PREV_HEAD_ATTESTER, FLAG_PREV_SOURCE_ATTESTER, FLAG_PREV_TARGET_ATTESTER, - FLAG_PREV_HEAD_ATTESTER, - FLAG_CURR_SOURCE_ATTESTER, - FLAG_CURR_TARGET_ATTESTER, - FLAG_CURR_HEAD_ATTESTER, + FLAG_UNSLASHED, + hasMarkers, } from "../util/attesterStatus.js"; -import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../index.js"; -import {computeBaseRewardPerIncrement} from "../util/altair.js"; -import {processPendingAttestations} from "../epoch/processPendingAttestations.js"; export type EpochTransitionCacheOpts = { /** @@ -133,11 +138,7 @@ export interface EpochTransitionCache { flags: number[]; - /** - * Validators in the current epoch, should use it for read-only value instead of accessing state.validators directly. - * Note that during epoch processing, validators could be updated so need to use it with care. - */ - validators: phase0.Validator[]; + isCompoundingValidatorArr: boolean[]; /** * balances array will be populated by processRewardsAndPenalties() and consumed by processEffectiveBalanceUpdates(). @@ -209,6 +210,8 @@ const inclusionDelays = new Array(); /** WARNING: reused, never gc'd */ const flags = new Array(); /** WARNING: reused, never gc'd */ +const isCompoundingValidatorArr = new Array(); +/** WARNING: reused, never gc'd */ const nextEpochShufflingActiveValidatorIndices = new Array(); export function beforeProcessEpoch( @@ -262,6 +265,10 @@ export function beforeProcessEpoch( // TODO: optimize by combining the two loops // likely will require splitting into phase0 and post-phase0 versions + if (forkSeq >= ForkSeq.electra) { + isCompoundingValidatorArr.length = validatorCount; + } + // Clone before being mutated in processEffectiveBalanceUpdates epochCtx.beforeEpochTransition(); @@ -298,6 +305,10 @@ export function beforeProcessEpoch( flags[i] = flag; + if (forkSeq >= ForkSeq.electra) { + isCompoundingValidatorArr[i] = hasCompoundingWithdrawalCredential(validator.withdrawalCredentials); + } + if (isActiveCurr) { totalActiveStakeByIncrement += effectiveBalancesByIncrements[i]; } else { @@ -511,7 +522,7 @@ export function beforeProcessEpoch( proposerIndices, inclusionDelays, flags, - validators, + isCompoundingValidatorArr, // Will be assigned in processRewardsAndPenalties() balances: undefined, }; diff --git a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts index 1fe5c92eea1a..6e71d8ccdc73 100644 --- a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts +++ b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts @@ -5,10 +5,11 @@ import { HYSTERESIS_QUOTIENT, HYSTERESIS_UPWARD_MULTIPLIER, MAX_EFFECTIVE_BALANCE, + MAX_EFFECTIVE_BALANCE_ELECTRA, + MIN_ACTIVATION_BALANCE, TIMELY_TARGET_FLAG_INDEX, } from "@lodestar/params"; import {EpochTransitionCache, CachedBeaconStateAllForks, BeaconStateAltair} from "../types.js"; -import {getMaxEffectiveBalance} from "../util/validator.js"; /** Same to https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/beacon-chain.md#has_flag */ const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX; @@ -43,7 +44,7 @@ export function processEffectiveBalanceUpdates( // and updated in processPendingDeposits() and processPendingConsolidations() // so it's recycled here for performance. const balances = cache.balances ?? state.balances.getAll(); - const currentEpochValidators = cache.validators; + const isCompoundingValidatorArr = cache.isCompoundingValidatorArr; let numUpdate = 0; for (let i = 0, len = balances.length; i < len; i++) { @@ -58,7 +59,7 @@ export function processEffectiveBalanceUpdates( effectiveBalanceLimit = MAX_EFFECTIVE_BALANCE; } else { // from electra, effectiveBalanceLimit is per validator - effectiveBalanceLimit = getMaxEffectiveBalance(currentEpochValidators[i].withdrawalCredentials); + effectiveBalanceLimit = isCompoundingValidatorArr[i] ? MAX_EFFECTIVE_BALANCE_ELECTRA : MIN_ACTIVATION_BALANCE; } if ( diff --git a/packages/state-transition/src/epoch/processPendingDeposits.ts b/packages/state-transition/src/epoch/processPendingDeposits.ts index 53af3ab38763..b25cf1d040a4 100644 --- a/packages/state-transition/src/epoch/processPendingDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingDeposits.ts @@ -2,8 +2,9 @@ import {FAR_FUTURE_EPOCH, ForkSeq, GENESIS_SLOT, MAX_PENDING_DEPOSITS_PER_EPOCH} import {PendingDeposit} from "@lodestar/types/lib/electra/types.js"; import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; import {increaseBalance} from "../util/balance.js"; -import {getActivationExitChurnLimit} from "../util/validator.js"; +import {hasCompoundingWithdrawalCredential} from "../util/electra.js"; import {computeStartSlotAtEpoch} from "../util/epoch.js"; +import {getActivationExitChurnLimit} from "../util/validator.js"; import {addValidatorToRegistry, isValidDepositSignature} from "../block/processDeposit.js"; /** @@ -106,6 +107,8 @@ function applyPendingDeposit( // Verify the deposit signature (proof of possession) which is not checked by the deposit contract if (isValidDepositSignature(state.config, pubkey, withdrawalCredentials, amount, signature)) { addValidatorToRegistry(ForkSeq.electra, state, pubkey, withdrawalCredentials, amount); + const newValidatorIndex = state.validators.length - 1; + cache.isCompoundingValidatorArr[newValidatorIndex] = hasCompoundingWithdrawalCredential(withdrawalCredentials); } } else { // Increase balance From f1e81982a3df27a88d107137e79556225db46015 Mon Sep 17 00:00:00 2001 From: twoeths Date: Wed, 27 Nov 2024 17:01:15 +0700 Subject: [PATCH 211/259] fix: handle outOfRangeData when range sync Deneb (#7249) * fix: handle outOfRangeData for beaconBlocksMaybeBlobsByRange() * fix: lint * fix: archiveBlocks - handle deneb outOfRangeData block --- .../src/chain/archiver/archiveBlocks.ts | 44 ++++++++++++++----- .../reqresp/beaconBlocksMaybeBlobsByRange.ts | 8 ++-- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts index 8e1ac456579a..320715f09dda 100644 --- a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts +++ b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts @@ -59,8 +59,8 @@ export async function archiveBlocks( }); if (finalizedPostDeneb) { - await migrateBlobSidecarsFromHotToColdDb(config, db, finalizedCanonicalBlockRoots); - logger.verbose("Migrated blobSidecars from hot DB to cold DB"); + const migrate = await migrateBlobSidecarsFromHotToColdDb(config, db, finalizedCanonicalBlockRoots, currentEpoch); + logger.verbose(migrate ? "Migrated blobSidecars from hot DB to cold DB" : "Skip blobSidecars migration"); } } @@ -157,22 +157,36 @@ async function migrateBlocksFromHotToColdDb(db: IBeaconDb, blocks: BlockRootSlot } } +/** + * Migrate blobSidecars from hot db to cold db. + * @returns true if we do that, false if block is out of range data. + */ async function migrateBlobSidecarsFromHotToColdDb( config: ChainForkConfig, db: IBeaconDb, - blocks: BlockRootSlot[] -): Promise { + blocks: BlockRootSlot[], + currentEpoch: Epoch +): Promise { + let result = false; + for (let i = 0; i < blocks.length; i += BLOB_SIDECAR_BATCH_SIZE) { const toIdx = Math.min(i + BLOB_SIDECAR_BATCH_SIZE, blocks.length); const canonicalBlocks = blocks.slice(i, toIdx); // processCanonicalBlocks - if (canonicalBlocks.length === 0) return; + if (canonicalBlocks.length === 0) return false; // load Buffer instead of ssz deserialized to improve performance const canonicalBlobSidecarsEntries: KeyValue[] = await Promise.all( canonicalBlocks - .filter((block) => config.getForkSeq(block.slot) >= ForkSeq.deneb) + .filter((block) => { + const blockSlot = block.slot; + const blockEpoch = computeEpochAtSlot(blockSlot); + return ( + config.getForkSeq(blockSlot) >= ForkSeq.deneb && + blockEpoch >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS + ); + }) .map(async (block) => { const bytes = await db.blobSidecars.getBinary(block.root); if (!bytes) { @@ -182,12 +196,20 @@ async function migrateBlobSidecarsFromHotToColdDb( }) ); - // put to blockArchive db and delete block db - await Promise.all([ - db.blobSidecarsArchive.batchPutBinary(canonicalBlobSidecarsEntries), - db.blobSidecars.batchDelete(canonicalBlocks.map((block) => block.root)), - ]); + const migrate = canonicalBlobSidecarsEntries.length > 0; + + if (migrate) { + // put to blockArchive db and delete block db + await Promise.all([ + db.blobSidecarsArchive.batchPutBinary(canonicalBlobSidecarsEntries), + db.blobSidecars.batchDelete(canonicalBlocks.map((block) => block.root)), + ]); + } + + result = result || migrate; } + + return result; } /** diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts index 3d71087c8fd8..041f1c59cc0a 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts @@ -36,8 +36,9 @@ export async function beaconBlocksMaybeBlobsByRange( return blocks.map((block) => getBlockInput.preData(config, block.data, BlockSource.byRange, block.bytes)); } + // From Deneb // Only request blobs if they are recent enough - if (computeEpochAtSlot(startSlot) >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) { + if (startEpoch >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) { const [allBlocks, allBlobSidecars] = await Promise.all([ network.sendBeaconBlocksByRange(peerId, request), network.sendBlobSidecarsByRange(peerId, request), @@ -46,8 +47,9 @@ export async function beaconBlocksMaybeBlobsByRange( return matchBlockWithBlobs(config, allBlocks, allBlobSidecars, endSlot, BlockSource.byRange, BlobsSource.byRange); } - // Post Deneb but old blobs - throw Error("Cannot sync blobs outside of blobs prune window"); + // Data is out of range, only request blocks + const blocks = await network.sendBeaconBlocksByRange(peerId, request); + return blocks.map((block) => getBlockInput.outOfRangeData(config, block.data, BlockSource.byRange, block.bytes)); } // Assumes that the blobs are in the same sequence as blocks, doesn't require block to be sorted From 7f96e709366cbcfe860d656ca5787328debc5b2d Mon Sep 17 00:00:00 2001 From: twoeths Date: Thu, 28 Nov 2024 14:20:20 +0700 Subject: [PATCH 212/259] fix: sync cached balance when adding new validator to registry (#7255) * fix: sync cached balance when adding new validator to registry * chore: add more comments * fix: remove persisted checkpoint states from the previous run at startup --- .../chain/stateCache/persistentCheckpointsCache.ts | 11 +++++------ .../src/epoch/processPendingDeposits.ts | 6 ++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 8663c0533ed8..5573366e3523 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -151,12 +151,11 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { await this.datastore.init(); } const persistedKeys = await this.datastore.readKeys(); - for (const persistedKey of persistedKeys) { - const cp = datastoreKeyToCheckpoint(persistedKey); - this.cache.set(toCacheKey(cp), {type: CacheItemType.persisted, value: persistedKey}); - this.epochIndex.getOrDefault(cp.epoch).add(toRootHex(cp.root)); - } - this.logger.info("Loaded persisted checkpoint states from the last run", { + // all checkpoint states from the last run are not trusted, remove them + // otherwise if we have a bad checkpoint state from the last run, the node get stucked + // this was found during mekong devnet, see https://github.com/ChainSafe/lodestar/pull/7255 + await Promise.all(persistedKeys.map((key) => this.datastore.remove(key))); + this.logger.info("Removed persisted checkpoint states from the last run", { count: persistedKeys.length, maxEpochsInMemory: this.maxEpochsInMemory, }); diff --git a/packages/state-transition/src/epoch/processPendingDeposits.ts b/packages/state-transition/src/epoch/processPendingDeposits.ts index b25cf1d040a4..8384295350f8 100644 --- a/packages/state-transition/src/epoch/processPendingDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingDeposits.ts @@ -109,6 +109,12 @@ function applyPendingDeposit( addValidatorToRegistry(ForkSeq.electra, state, pubkey, withdrawalCredentials, amount); const newValidatorIndex = state.validators.length - 1; cache.isCompoundingValidatorArr[newValidatorIndex] = hasCompoundingWithdrawalCredential(withdrawalCredentials); + // set balance, so that the next deposit of same pubkey will increase the balance correctly + // this is to fix the double deposit issue found in mekong + // see https://github.com/ChainSafe/lodestar/pull/7255 + if (cachedBalances) { + cachedBalances[newValidatorIndex] = amount; + } } } else { // Increase balance From 9f4e7e6703866721202c68a7c740fd59786c0b66 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 27 Nov 2024 07:46:14 +0100 Subject: [PATCH 213/259] chore: skip web3_provider unit tests (#7252) --- packages/prover/test/unit/web3_provider.node.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/prover/test/unit/web3_provider.node.test.ts b/packages/prover/test/unit/web3_provider.node.test.ts index d1f281175b56..896715699e95 100644 --- a/packages/prover/test/unit/web3_provider.node.test.ts +++ b/packages/prover/test/unit/web3_provider.node.test.ts @@ -7,7 +7,8 @@ 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", () => { +// https://github.com/ChainSafe/lodestar/issues/7250 +describe.skip("web3_provider", () => { afterEach(() => { vi.clearAllMocks(); }); From aaac34aeab632615ceb76ced2b89ca535371557a Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 29 Nov 2024 11:18:21 +0100 Subject: [PATCH 214/259] fix: do not throw error when trying to prune missing directory (#7257) --- packages/cli/src/util/pruneOldFilesInDir.ts | 4 ++++ packages/cli/test/unit/util/pruneOldFilesInDir.test.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/cli/src/util/pruneOldFilesInDir.ts b/packages/cli/src/util/pruneOldFilesInDir.ts index 3d5cc2b60bcb..8b8dfe754059 100644 --- a/packages/cli/src/util/pruneOldFilesInDir.ts +++ b/packages/cli/src/util/pruneOldFilesInDir.ts @@ -2,6 +2,10 @@ import fs from "node:fs"; import path from "node:path"; export function pruneOldFilesInDir(dirpath: string, maxAgeMs: number): number { + if (!fs.existsSync(dirpath)) { + return 0; // Nothing to prune + } + let deletedFileCount = 0; for (const entryName of fs.readdirSync(dirpath)) { const entryPath = path.join(dirpath, entryName); diff --git a/packages/cli/test/unit/util/pruneOldFilesInDir.test.ts b/packages/cli/test/unit/util/pruneOldFilesInDir.test.ts index a50c59547688..ee5532a358ee 100644 --- a/packages/cli/test/unit/util/pruneOldFilesInDir.test.ts +++ b/packages/cli/test/unit/util/pruneOldFilesInDir.test.ts @@ -55,6 +55,10 @@ describe("pruneOldFilesInDir", () => { expect(fs.existsSync(emptyDir)).toBe(false); }); + it("should handle missing directories", () => { + expect(() => pruneOldFilesInDir(path.join(dataDir, "does-not-exist"), DAYS_TO_MS)).not.toThrowError(); + }); + function createFileWithAge(path: string, ageInDays: number): void { // Create a new empty file fs.closeSync(fs.openSync(path, "w")); From c9af6c37f985928491ed1060c4fba453bc9dd0c3 Mon Sep 17 00:00:00 2001 From: Phil Ngo <58080811+philknows@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:17:43 -0500 Subject: [PATCH 215/259] docs: update documentation Oct 2024 (#7178) * docs update oct 2024 init * Reconfig quickstart nav and minor fixes * fix lint * spelling fixes * minor fixes and add to wordlist * prettier fix * add to wordlist * sort wordlist * modify dominance to include lighthouse * fix typescript casing and add recommendation * add selection and boost_factor with keymanager notice * update wordlist * remove builder enabled and add keymanager api * spelling --------- Co-authored-by: Nico Flaig --- .wordlist.txt | 26 + docs/docusaurus.config.ts | 32 +- docs/pages/google0c42298b7ec08b7e.html | 1 - docs/pages/index.md | 24 +- docs/pages/introduction.md | 24 +- .../run/beacon-management/starting-a-node.md | 126 +-- .../pages/run/getting-started/installation.md | 6 +- .../quick-start-custom-guide.md | 728 ++++++++++++++++++ docs/pages/run/getting-started/quick-start.md | 28 +- .../logging-and-metrics/client-monitoring.md | 2 +- .../run/logging-and-metrics/dashboards.md | 0 .../run/logging-and-metrics/log-management.md | 3 - .../logging-and-metrics/metrics-management.md | 0 .../logging-and-metrics/prometheus-grafana.md | 10 +- .../validator-management/proposer-config.md | 48 ++ .../validator-management/vc-configuration.md | 4 + docs/pages/supporting-libraries/libraries.md | 4 +- docs/pages/trouble-shooting.md | 1 - docs/sidebars.ts | 21 +- packages/light-client/README.md | 2 +- packages/prover/README.md | 2 +- 21 files changed, 954 insertions(+), 138 deletions(-) delete mode 100644 docs/pages/google0c42298b7ec08b7e.html create mode 100644 docs/pages/run/getting-started/quick-start-custom-guide.md delete mode 100644 docs/pages/run/logging-and-metrics/dashboards.md delete mode 100644 docs/pages/run/logging-and-metrics/log-management.md delete mode 100644 docs/pages/run/logging-and-metrics/metrics-management.md create mode 100644 docs/pages/run/validator-management/proposer-config.md delete mode 100644 docs/pages/trouble-shooting.md diff --git a/.wordlist.txt b/.wordlist.txt index a2e642a926a0..2c28fc784061 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -1,3 +1,4 @@ +API APIs Andreas Antonopoulos @@ -13,6 +14,7 @@ Casper Chai ChainSafe Codespaces +CoinCashew Corepack Customizations DPoS @@ -29,6 +31,7 @@ ENRs ETH Edgington Erigon +Esat EthStaker EtherScan Ethereum @@ -37,8 +40,11 @@ FINDNODE FX Flamegraph Flamegraphs +GPG Geth Github +Goerli +Golang Gossipsub Grafana Grandine @@ -46,6 +52,7 @@ HTTPS HackMD Hashicorp Homebrew +Hyperledger IPFS IPv Infura @@ -60,15 +67,18 @@ LGPLv LMD LPoS LTS +LVM Lerna MEV MacOS Metamask +MevBoost ModuleNotFoundError Monorepo NPM NVM Nethermind +Nim NodeJS NodeSource OSI @@ -81,9 +91,11 @@ Quickstart RPC Reth Ryzen +SFTP SHA SSD SSZ +Somer Stakehouse TOC TTD @@ -103,6 +115,7 @@ backfill beaconcha blockRoot blockchain +blockspace blst bootnode bootnodes @@ -110,6 +123,7 @@ bundlers chainConfig chainsafe chiado +chmod cli cmd codebase @@ -125,6 +139,8 @@ dApp dApps ddos decrypt +decrypted +derypted deserialization dev devcontainer @@ -139,30 +155,38 @@ env envs ephemery ethers +feeRecipient flamegraph flamegraphs floodsub +fsSL getNetworkIdentity gnosis +gpg heapdump heaptrack holesky interop js +keymanager keypair +keyrings keystore keystores libp lightclient linter +liveness lldb llnode lockfile mainnet malloc +mbps mdns merkle merkleization +misconfiguration mmeshsub monorepo multiaddr @@ -199,6 +223,7 @@ ssz stakers subnet subnets +sudo tcp testnet testnets @@ -215,6 +240,7 @@ vite vitest webpack wip +xRelayPubKey xcode yaml yamux diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index e37cee619e81..3e57867009f8 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -97,29 +97,23 @@ const config: Config = { style: "dark", links: [ { - title: "Docs", - items: [ - { - label: "Introduction", - to: "/introduction", - }, - ], + label: 'Lodestar Website', + href: 'https://lodestar.chainsafe.io', }, { - title: "Community", - items: [ - { - label: "Discord", - href: "https://discord.com/invite/yjyvFRP", - }, - { - label: "Twitter", - href: "https://twitter.com/lodestar_eth", - }, - ], + label: 'Discord', + href: 'https://discord.com/invite/yjyvFRP', + }, + { + label: 'Twitter/X', + href: 'https://x.com/lodestar_eth', + }, + { + label: 'Github', + href: 'https://github.com/ChainSafe/lodestar', }, ], - copyright: `Copyright © ${new Date().getFullYear()} ChainSafe, Inc.`, + copyright: `Copyright © ${new Date().getFullYear()} ChainSafe. Built with Docusaurus.` , }, colorMode: { respectPrefersColorScheme: false, diff --git a/docs/pages/google0c42298b7ec08b7e.html b/docs/pages/google0c42298b7ec08b7e.html deleted file mode 100644 index 7edebde149af..000000000000 --- a/docs/pages/google0c42298b7ec08b7e.html +++ /dev/null @@ -1 +0,0 @@ -google-site-verification: google0c42298b7ec08b7e.html \ No newline at end of file diff --git a/docs/pages/index.md b/docs/pages/index.md index c74ad6470d7d..2bca344b84cb 100644 --- a/docs/pages/index.md +++ b/docs/pages/index.md @@ -4,14 +4,14 @@ title: Home ![lodestar logo](../../assets/lodestar_icon_text_black_stroke.png) -## Welcome to the Lodestar documentation +## Welcome to the Lodestar Documentation -> **Lodestar is an open-source Ethereum Consensus client and Typescript ecosystem, maintained by ChainSafe Systems** +> **Lodestar is an open-source Ethereum Consensus client and TypeScript ecosystem, maintained by ChainSafe Systems** -### Getting started +### Getting Started - Follow the instructions for [build from source](./run/getting-started/installation#build-from-source), [binaries](./run/getting-started/installation#binaries), or [Docker](./run/getting-started/installation#docker-installation) to install Lodestar. Or use our [Lodestar Quickstart scripts](https://github.com/ChainSafe/lodestar-quickstart). -- Use [Lodestar libraries](./supporting-libraries/index.md) in your next Ethereum Typescript project. +- Use [Lodestar libraries](./supporting-libraries/index.md) in your next Ethereum TypeScript project. - Run a beacon node on [mainnet or a public testnet](./run/beacon-management/starting-a-node.md). - Utilize the whole stack by [starting a local testnet](./contribution/advanced-topics/setting-up-a-testnet.md). - View the Lodestar Beacon [CLI commands and options](./run/beacon-management/beacon-cli.md) @@ -26,14 +26,18 @@ Hardware specifications minimum / recommended, to run the Lodestar client. | | Minimum | Recommended | | --------- | -------------------------------------- | -------------------------------------- | | Processor | Intel Core i3–9100 or AMD Ryzen 5 3450 | Intel Core i7–9700 or AMD Ryzen 7 4700 | -| Memory | 16GB RAM | 32GB RAM | -| Storage | 100GB available space SSD | 1TB available space SSD | -| Internet | Broadband connection | Broadband connection | +| Memory | 8 GB RAM | 16 GB RAM | +| Storage | 130 GB available space SSD | 200 GB available space SSD | +| Internet | Reliable broadband with 10mbps upload | Reliable broadband with >10mbps upload | -## About these docs +### Execution Client -This documentation is open source, contribute at [Github Lodestar repository /docs](https://github.com/ChainSafe/lodestar/tree/unstable/docs). +If you run the [execution client](https://ethereum.org/en/developers/docs/nodes-and-clients/#execution-clients) on the same host, you will need to check their requirements and add them to the above requirements. Broadly, to run both an execution and a consensus client on the same machine, we recommend a 4 TB SSD and 32 GB RAM. -## Need assistance? +## About These Docs + +This documentation is open source, contribute on our [Github Lodestar repository /docs](https://github.com/ChainSafe/lodestar/tree/unstable/docs). + +## Need Assistance? If you have questions about this documentation, feel free to talk to us on our [ChainSafe Discord](https://discord.gg/yjyvFRP) or [open an issue](https://github.com/ChainSafe/lodestar/issues/new/choose) and a member of the team or our community will be happy to assist you. diff --git a/docs/pages/introduction.md b/docs/pages/introduction.md index ab864b8a9df8..f74d0b70768d 100644 --- a/docs/pages/introduction.md +++ b/docs/pages/introduction.md @@ -1,29 +1,29 @@ # Introduction -Ethereum is one of the most profoundly important inventions in recent history. It is a decentralized, open-source blockchain featuring smart contract functionality. It is the second-largest cryptocurrency by market capitalization, after Bitcoin, and is the most actively used blockchain. Ethereum was proposed in 2013 by programmer Vitalik Buterin. Development was crowdfunded in 2014, and the network went live on 30 July 2015, with 72 million coins premined. ChainSafe was founded not too long afterwards and has been actively working in the Ethereum space ever since. We are proud to develop Lodestar and to present this documentation as a resource for the Ethereum community. +Ethereum is one of the most profoundly important inventions in recent history. It is a decentralized, open-source blockchain featuring smart contract functionality. It is the second-largest cryptocurrency by market capitalization, after Bitcoin, and is the second largest blockchain by market capitalization. Ethereum was proposed in 2013 by programmer Vitalik Buterin. Development was crowdfunded in 2014, and the network went live on 30 July 2015, with 72 million coins premined. ChainSafe was founded not too long afterwards in 2017 and has been actively working in the Ethereum ecosystem ever since. We are proud to develop Lodestar, the only TypeScript based consensus client, and to present this documentation as a resource for the Ethereum community. ## Proof of Stake -In Ethereum's Proof of Stake (PoS) model, validators replace miners from the Proof of Work (PoW) system. Validators are Ethereum stakeholders who lock up a portion of their Ether as a stake. The protocol randomly selects these validators to propose new blocks. The chance of being chosen is tied to the size of their stake: the more Ether staked, the higher the probability of being selected to propose the block. Proposers receive transaction fees and block rewards as incentives. Validators are also responsible for voting on the validity of blocks proposed by other validators. However, they face penalties, known as slashing, for actions like double-signing, votes on a block that is not in the majority or going offline, ensuring network integrity and reliability. The PoS mechanism significantly reduces energy consumption compared to PoW, because it does not require extensive computational power. Moreover, PoS tends to facilitate faster transaction validations and block creations, enhancing the overall performance and scalability of the network. +In Ethereum's Proof of Stake (PoS) model, validators replace miners from the Proof of Work (PoW) system. Validators are Ethereum stakeholders who lock up a portion of their Ether as a stake. The protocol randomly selects these validators to propose new blocks. The chance of being chosen is tied to the size of their stake: the more Ether staked, the higher the probability of being selected to propose the block. Proposers receive transaction fees and block rewards as incentives. Validators are also responsible for voting on the validity of blocks proposed by other validators. However, they also face penalties, known as slashing, for actions like signing two different block proposals in the same slot or voting on two different attestations for the same target epoch, which creates conflicting states. The PoS mechanism significantly reduces energy consumption compared to PoW, because it does not require extensive computational power. Moreover, PoS tends to facilitate faster transaction validations and block creations, enhancing the overall performance and scalability of the network. ## Consensus Clients -In an effort to promote client diversity there are several beacon-nodes being developed. Each is programmed in a different language and by a different team. The following is a list of the current beacon-node clients: +In an effort to promote client diversity there are several consensus beacon nodes being developed. Each is programmed in a different language and by a different team. The following is a list of the current open source consensus clients in alphabetical order: -- [Lodestar](https://lodestar.chainsafe.io/) -- [Prysm](https://prysmaticlabs.com/) -- [Lighthouse](https://lighthouse.sigmaprime.io/) -- [Teku](https://consensys.net/knowledge-base/ethereum-2/teku/) -- [Nimbus](https://nimbus.team/) -- [Grandine](https://grandine.io) +- [Grandine (Rust)](https://grandine.io) +- [Lighthouse (Rust)](https://lighthouse.sigmaprime.io/) +- [Lodestar (TypeScript)](https://lodestar.chainsafe.io/) +- [Nimbus (Nim)](https://nimbus.team/) +- [Prysm (Golang)](https://prysmaticlabs.com/) +- [Teku (Java)](https://consensys.net/knowledge-base/ethereum-2/teku/) ## 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. +The Ethereum network's robustness is significantly enhanced by its client diversity, whereby multiple, independently-developed clients conforming to a common specification, facilitating seamless interaction and function equivalently across different 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, 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. +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 help to mitigate risks associated with potential bugs or attacks that could, in extreme cases, derail the consensus process (liveness failure) or lead to incorrect chain splits (forking), thereby jeopardizing the network's stability and trust. While the data suggests a [dominance of the Prysm and Lighthouse clients](https://clientdiversity.org) on the consensus layer, efforts are ongoing to promote a more even distribution among others clients. 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. -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. +The [non-finality event of May 2023](https://medium.com/offchainlabs/post-mortem-report-ethereum-mainnet-finality-05-11-2023-95e271dfd8b2) 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 from reaching finality. 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. ## Ethereum Reading List diff --git a/docs/pages/run/beacon-management/starting-a-node.md b/docs/pages/run/beacon-management/starting-a-node.md index 6838e14304d6..7aa0799b6e83 100644 --- a/docs/pages/run/beacon-management/starting-a-node.md +++ b/docs/pages/run/beacon-management/starting-a-node.md @@ -2,15 +2,13 @@ title: Starting a Node --- -# Beacon management +# Beacon Management -The following instructions are required to setup and run a Lodestar beacon node. +Running a Lodestar node on mainnet or a testnet only requires basic familiarity with the terminal. The following instructions are required to configure and run the Lodestar beacon node. This page assumes you have already setup an Ethereum execution client. -## Connect to mainnet or a public testnet +## Connect to Mainnet or a Public Testnet -Running a Lodestar node on mainnet or a testnet only requires basic familiarity with the terminal. - -Make sure Lodestar is installed in your local environment, following the chosen install method. The following command should return a non error message. +Make sure Lodestar is installed in your local environment, following the chosen [Installation](../getting-started/installation.md) method. The following command should return a non-error message. ```bash ./lodestar --help @@ -18,25 +16,21 @@ Make sure Lodestar is installed in your local environment, following the chosen For a complete list of beacon node CLI commands and options, see the [`beacon` CLI Command](../beacon-management/beacon-cli.md) section. -To select a known testnet or mainnet, use the `--network` flag. `mainnet` is selected by default, and a list of available networks is listed with the `--help` flag. Setting the `--network` flag will conveniently configure the beacon node or validator client for the selected network. For power users, any configuration option should be able to be overridden. +To select a known testnet or mainnet, use the `--network` flag. The option `mainnet` is selected by default, and a list of available networks is listed with the `--help` flag. Setting the `--network` flag will conveniently configure the beacon node for the selected network. For power users, any configuration option should be able to be overridden. -## Configure the Lodestar JWT authentication token +## Configure the Lodestar JWT Authentication Token -Post-Merge Ethereum will require [secure authentication with the Engine API](https://github.com/ethereum/execution-apis/blob/main/src/engine/authentication.md) connection on your chosen Execution node. +Ethereum requires a [secure authentication with the Engine API](https://github.com/ethereum/execution-apis/blob/main/src/engine/authentication.md) for connecting to your chosen execution client on port 8551. -:::info -Post-Merge Ethereum **requires** a secure, authenticated connection to the Execution client on port 8551. We recommend setting this up now to ensure a proper configuration before the Merge. -::: - -### Generate a secret key +### Generate a Secret Key You must generate a secret 32-byte (64 characters) hexadecimal string that will be used to authenticate with an execution node. You can use the following command in most terminals to generate a random secret: `openssl rand -hex 32`. Or you can use an [online generator](https://codebeautify.org/generate-random-hexadecimal-numbers). Save this secret key into a text file and note where you store this file. -### Configure Lodestar to locate the JWT secret +### Configure Lodestar to Locate the JWT Secret When starting up a Lodestar beacon node in any configuration, ensure you add the `--jwtSecret $JWT_SECRET_PATH` flag to point to the saved secret key file. -### Ensure JWT is configured with your execution node +### Configure the Execution Client with the JWT Secret **For Go Ethereum:** Use the `--authrpc.jwtsecret /path/to/jwtsecret.hex` flag to configure the secret. Use their documentation [here](https://geth.ethereum.org/docs/getting-started#start-geth). @@ -53,59 +47,68 @@ Use the `--authrpc.jwtsecret /path/to/jwtsecret.hex` flag to configure the secre **For Reth:** Use the `--authrpc.jwtsecret /path/to/jwtsecret.hex` flag to configure the secret. Use their documentation [here](https://reth.rs/run/mainnet.html?highlight=jwt#running-the-reth-node). -## Run a beacon node +## Run the Beacon Node -To start a Lodestar beacon run the command: +To start the Lodestar beacon, run the command: ```bash ./lodestar beacon --network $NETWORK_NAME --jwtSecret $JWT_SECRET_PATH ``` -This will assume an execution-layer client is available at the default -location of `https://localhost:8545`. +This will assume an execution client is available at the default location of `https://localhost:8545`. -In case execution-layer clients are available at different locations, use `--execution.urls` to specify these locations in the command: +If the execution clients are available at different locations, use the flag `--execution.urls` to specify these locations in the command: ```bash ./lodestar beacon --network $NETWORK_NAME --jwtSecret $JWT_SECRET_PATH --execution.urls $EL_URL1 $EL_URL2 ``` -Immediately you should see confirmation that the node has started +Your initial logs should confirm that the node has started. ```txt -Apr-20 15:12:45.274[] info: Lodestar network=mainnet, version=v1.7.2, commit= -Apr-20 15:12:45.327[] info: Connected to LevelDB database path=/data/mt1/chain-db -Apr-20 15:12:57.747[] info: Initializing beacon from a valid db state slot=6264480, epoch=195765, stateRoot=0x8133cd4d0be59c3e94405f902fe0ad68ffaa5013b525dddb6285b91ad79716f6, isWithinWeakSubjectivityPeriod=true -Apr-20 15:13:18.077[network] info: PeerId 16Uiu2HAmDsGet67va6VCnaW2Tu1Ae2yujiDMnmURMMWNvssER7ZQ, Multiaddrs /ip4/127.0.0.1/tcp/9000/p2p/16Uiu2HAmDsGet67va6VCnaW2Tu1Ae2yujiDMnmURMMWNvssER7ZQ,/ip4/10.244.0.199/tcp/9000/p2p/16Uiu2HAmDsGet67va6VCnaW2Tu1Ae2yujiDMnmURMMWNvssER7ZQ -Apr-20 15:13:18.270[rest] info: Started REST API server address=http://127.0.0.1:9596 -Apr-20 15:13:18.271[] warn: Low peer count peers=0 -Apr-20 15:13:18.280[] info: Searching peers - peers: 0 - slot: 6264964 - head: (slot - 484) 0x7ee6…2a15 - exec-block: syncing(17088043 0x9442…) - finalized: 0xe359…4d7e:195763 -Apr-20 15:13:23.009[chain] info: Validated transition configuration with execution client terminalTotalDifficulty=0xc70d808a128d7380000, terminalBlockHash=0x0000000000000000000000000000000000000000000000000000000000000000, terminalBlockNumber=0x0 -Apr-20 15:13:29.287[] info: Syncing - ? left - 0.00 slots/s - slot: 6264965 - head: (slot - 485) 0x7ee6…2a15 - exec-block: syncing(17088043 0x9442…) - finalized: 0xe359…4d7e:195763 - peers: 1 -Apr-20 15:14:41.003[] info: Syncing - 22 seconds left - 4.92 slots/s - slot: 6264971 - head: (slot - 108) 0xd15f…b605 - exec-block: valid(17088414 0x3dba…) - finalized: 0x70fd…5157:195775 - peers: 4 -Apr-20 15:14:53.001[] info: Syncing - 9 seconds left - 5.00 slots/s - slot: 6264972 - head: (slot - 45) 0x44e4…20a4 - exec-block: valid(17088475 0xca61…) - finalized: 0x9cbd…ba83:195776 - peers: 8 -Apr-20 15:15:01.443[network] info: Subscribed gossip core topics -Apr-20 15:15:01.446[sync] info: Subscribed gossip core topics -Apr-20 15:15:05.000[] info: Synced - slot: 6264973 - head: 0x90ea…c655 - exec-block: valid(17088521 0xca9b…) - finalized: 0x6981…682f:195778 - peers: 6 +Jul-31 13:35:27.967[] info: Lodestar network=mainnet, version=v1.21.0/ff35faa, commit=ff35faae4ad1697b86d708a0367a95a71648ab6e +Jul-31 13:35:28.344[] info: Connected to LevelDB database path=/data/lodestar/chain-db +Jul-31 13:35:49.828[] info: Initializing beacon from a valid db state slot=9633504, epoch=301047, stateRoot=0xfa2845a6877b98555906a1654941c97d9c05bdd41e61cc0870a967dc9030b156, isWithinWeakSubjectivityPeriod=true +Jul-31 13:35:51.955[chain] info: Historical state worker started +Jul-31 13:35:51.969[eth1] info: Eth1 provider urls=http://localhost:8551 +Jul-31 13:35:51.975[execution] info: Execution client urls=http://localhost:8551 +Jul-31 13:35:51.977[] info: External builder url=http://localhost:8661 +Jul-31 13:36:21.128[network] info: running libp2p instance in worker thread +Jul-31 13:36:21.727[network] info: libp2p worker started peer=15Uiu2HAmACcmCEXcgt3zCtJL2rqJZ2Mvdjh6U6fe26HgD2FoNRwW +Jul-31 13:36:27.677[network] info: discv5 worker started peerId=16Uiu2HAmACcmCEXcgt3zCtJL2rqJZ2Mvdjh6U6fe26HgD2FoNRwW, initialENR=enr:-IO4QHGTUd1Zg8LAhUAioOz_ySTKoJLIOa6zltSP_AvvhTFVYw6M6YB35IxsiKxQG7nUgCpUB5SIsNxMntCNlTK9sMEBgmlkgnY0iXNlY3AyNTZrMaEC24cdmzuGnWqSwF-8Hw2gbkAZDzMWW3LsHJfp_kDhy-GDdGNwgiMog3VkcIIeWH, bindAddr4=/ip4/0.0.0.0/udp/9000 +Jul-31 13:36:28.134[network] info: PeerId 16Uiu2HAmACcmCEXcgt3zCtJL2rqJZ2Mvdjh6U6fe26HgD2FoNRwW, Multiaddrs /ip4/0.0.0.0/tcp/9000 +Jul-31 13:36:28.137[metrics] info: Started metrics HTTP server address=http://127.0.0.1:8008 +Jul-31 13:36:28.256[rest] info: Started REST API server address=http://0.0.0.0:9596 +Jul-31 13:36:28.257[] info: Searching peers - peers: 0 - slot: 9634080 - head: (slot -576) 0x9d88…d02a - exec-block: syncing(20426302 0xcec4…) - finalized: 0x7feb…c130:301045 +Jul-31 13:36:36.461[execution] info: Execution client is synced oldState=ONLINE, newState=SYNCED +Jul-31 13:36:53.019[] info: Syncing - 3.7 minutes left - 2.32 slots/s - slot: 9634082 - head: (slot -515) 0x792f…f8aa - exec-block: valid(20426365 0x58b1…) - finalized: 0x9d88…d02a:301047 - peers: 11 +Jul-31 13:38:53.168[] info: Syncing - 11 seconds left - 4.01 slots/s - slot: 9634092 - head: (slot -44) 0x7491…f63e - exec-block: valid(20426841 0xd4b2…) - finalized: 0x1e00…6e6b:301062 - peers: 59 +Jul-31 13:38:58.051[network] info: Subscribed gossip core topics +Jul-31 13:38:58.132[sync] info: Subscribed gossip core topics +Jul-31 13:39:05.001[] info: Synced - slot: 9634093 - head: 0x35de…1f0e - exec-block: valid(20426886 0x10ff…) - finalized: 0x88f8…5375:301063 - peers: 70 +Jul-31 13:39:17.000[] info: Synced - slot: 9634094 - head: 0x7844…3b3e - exec-block: valid(20426887 0x67d1…) - finalized: 0x88f8…5375:301063 - peers: 69 +Jul-31 13:39:29.000[] info: Synced - slot: 9634095 - head: 0x5516…ba12 - exec-block: valid(20426888 0x4ceb…) - finalized: 0x88f8…5375:301063 - peers: 74 ``` :::info -If your node is stuck with `Searching for peers` review your network configuration to make sure your ports are open. +If your node is stuck with `Searching peers`, review your network configuration to make sure your ports are open and forwarded to your host machine. ::: By default, Lodestar stores all configuration and chain data at the path `$XDG_DATA_HOME/lodestar/$NETWORK_NAME`. -A young testnet should take a few hours to sync. If you see multiple or consistent errors in the logs, please open a [Github issue](https://github.com/ChainSafe/lodestar/issues/new/choose) or reach out to us in [Discord](https://discord.gg/yjyvFRP). Just by reporting anomalies you are helping accelerate the progress of Ethereum Consensus, thanks for contributing! +A young testnet should take a few hours to sync. If you see multiple or consistent errors in the logs, please open a [Github issue](https://github.com/ChainSafe/lodestar/issues/new/choose) or reach out to us in [Discord](https://discord.gg/yjyvFRP). By reporting anomalies, you are helping to accelerate the progress of Ethereum consensus and we thank you for contributing! :::warning -It is dangerous to expose your Beacon APIs publicly as there is no default authentication mechanism provided. Ensure your beacon node host is not exposing ports 8545 or 9596 outside of your internal network. +It is dangerous to expose your Beacon or Execution APIs publicly as there is no default authentication mechanism provided. Ensure your beacon node host is not exposing ports 8545 or 9596 outside of your internal network. ::: ### Checkpoint Sync -If you are starting your node from a blank db, like starting from genesis, or from the last saved state in db and the network is now far ahead, your node will be susceptible to "long range attacks." Ethereum's solution to this is via something called weak subjectivity. [Read Vitalik's illuminating post explaining weak subjectivity.](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/). +If you are starting your node from a blank database, or from a last saved database state that is too old (outside of the weak subjectivity period), your node will be susceptible to "long range attacks." Ethereum's solution to this attack is via something called weak subjectivity. [Read Vitalik's illuminating post explaining weak subjectivity.](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/). -If you have a synced beacon node available (e.g., your friend's node or an infrastructure provider) and a trusted checkpoint you can rely on, you can start off your beacon node in under a minute! And at the same time kicking the "long range attack" in its butt! +If you have a synced beacon node available (e.g., your friend's node or a trusted infrastructure provider) to serve a trusted checkpoint you can rely on, you can start syncing your beacon node from that available checkpoint with the flag `--checkpointSyncUrl` and passing in the URL of the checkpoint provider. This will allow your beacon node to sync within minutes rather than several days. + +The Ethereum community has maintained a set of [public beacon chain checkpoints](https://eth-clients.github.io/checkpoint-sync-endpoints/) that serve these sync endpoints to the larger community. You can correlate the state root and the block root with more than one provider to verify the checkpoints being served follow the same canonical chain. Just supply these **extra arguments** to your beacon node command: @@ -113,28 +116,27 @@ Just supply these **extra arguments** to your beacon node command: --checkpointSyncUrl [--wssCheckpoint ] ``` -In case you really trust `checkpointSyncUrl` then you may skip providing `wssCheckpoint`, which will then result into your beacon node syncing and starting off the recently finalized state from the trusted URL. +In case you really trust the `--checkpointSyncUrl` provider, then you may skip providing `--wssCheckpoint`, which will then result into your beacon node syncing and starting off the recently finalized state from the trusted URL. :::warning -Please use this option very carefully (and at your own risk), a malicious server URL can put you on the wrong chain with a danger of you losing your funds by social engineering. -If possible, validate your `wssCheckpoint` from multiple places (e.g. different client distributions) or from other trusted sources. This will highly reduce the risk of starting off on a malicious chain. -This list of [public endpoints](https://eth-clients.github.io/checkpoint-sync-endpoints/) maintained by the Ethereum community may be used for reference. +Please be aware that a malicious checkpoint sync server URL can put you on the wrong chain with a danger of you losing your funds by social engineering. +If possible, validate your `wssCheckpoint` state from multiple places (e.g. different client distributions) or from other trusted sources. This will highly reduce the risk of starting off on a malicious chain. This list of [public endpoints](https://eth-clients.github.io/checkpoint-sync-endpoints/) maintained by the Ethereum community may be used for reference. ::: -**Taking too long to sync?** +#### Still Taking Long to Sync? -After your node has been offline for a while, it might be the case that it takes a long time to sync even though a `checkpointSyncUrl` is specified. -This is due to the fact that the last db state is still within the weak subjectivity period (~15 days on mainnet) which causes the node -to sync from the db state instead of the checkpoint state. +After your node has been offline for a while, it might be the case that it takes a long time to sync even though a `--checkpointSyncUrl` is specified. +This is due to the fact that the last database state is still within the weak subjectivity period (~15 days on mainnet) which causes the node +to sync from the database state instead of the checkpoint state. -It is possible to force syncing from checkpoint state by supplying the `--forceCheckpointSync` flag. This option is only recommended if it is absolutely +It is possible to force syncing from a checkpoint state by supplying the `--forceCheckpointSync` flag. This option is only recommended if it is absolutely necessary for the node to be synced right away to fulfill its duties as there is an inherent risk each time the state is obtained from an external source. -### Guide to the sync logs +### Sync Log Guide -Lodestar beacon sync log aims to provide information of utmost importance about your node and yet be succinct at the same time. You may see the sync logs in the following format: +The Lodestar beacon sync log aims to provide information of utmost importance about the state of your node and be succinct at the same time. You may see the sync logs in the following format: -`[Sync status] - [ Slot info ] - [Head info] - [Exec block info] - [Finalized info] - [Peers info]` +`[Sync status] - [ Slot info ] - [Head info] - [Execution block info] - [Finalized info] - [Peers info]` See the following example of different kinds of sync log: @@ -171,16 +173,20 @@ Apr-20 15:16:05.000[] info: Synced - slot: 6264978 - head: 0xc9f Apr-20 15:16:17.017[] info: Synced - slot: 6264979 - head: 0xde91…d4cb - exec-block: valid(17088527 0xa488…) - finalized: 0x6981…682f:195778 - peers: 7 ``` -1. Sync status: Takes three values : `Synced` or `Syncing` (along with sync speed info) or `Searching` if node is is still looking for viable peers from where it can download blocks. +1. Sync status: This status takes three values: + +- `Synced`: The node is currently synced +- `Syncing` The node is currently in the syncing process +- `Searching`: The node is is still looking for viable peers from where it can download blocks -2. Slot (clock) info: What is the current ongoing slot as per the chain genesis +2. Slot (clock) info: The current ongoing slot as per the chain genesis -3. Head info: It specifies where the local chain head hash is. In case its far behind the Slot (clock) then it independently shows the head slot else it show how far behind from the Slot it is if difference < 1000. +3. Head info: Specifies where the local beacon chain head hash is. In case it's far behind the Slot (clock), then it independently shows the head slot. Else, it will show how far behind the node is from the Slot (if the difference is < 1000) -4. Execution block info: It provides the execution information about the head whether its confirmed `valid` or execution layer is still `syncing` to it, as well as its number and a short hash to easy identification. +4. Execution block info: Provides the information about the execution block head, whether its confirmed `valid` or still `syncing` to it. In parenthesis, it shows the current execution block number and a short hash for easy identification -5. Finalized info: What is the current local `finalized` checkpoint in the format of `[checkpoint root]:[checkpoint epoch]`, for e.g.: `0xd7ba…8386:189636` +5. Finalized info: Shows the current local `finalized` checkpoint in the format of `[checkpoint root]:[checkpoint epoch]`. For example: `0xd7ba…8386:189636` shows a checkpoint root of `0xd7ba…8386` in epoch `189636` -6. Peer info: Current total number of outbound or inbound peers, for e.g.: `peers: 27` +6. Peer info: Current total number of outbound and inbound peers -For more insight into how a Lodestar beacon node is functioning, you may setup lodestar metrics and use the prepared Grafana dashboards that are found in the repository. Check out our section on [Prometheus and Grafana](../logging-and-metrics/prometheus-grafana.md) for more details. +For more insight into how a Lodestar beacon node is functioning, you may setup Lodestar metrics with the `--metrics` flag and use the prepared Grafana dashboards that are found in the repository. Check out our section on [Prometheus and Grafana](../logging-and-metrics/prometheus-grafana.md) for more details. diff --git a/docs/pages/run/getting-started/installation.md b/docs/pages/run/getting-started/installation.md index 52cb2770725b..40c4865f7726 100644 --- a/docs/pages/run/getting-started/installation.md +++ b/docs/pages/run/getting-started/installation.md @@ -1,8 +1,8 @@ -# Installation +# Install Options ## Binaries -Binaries can be downloaded from [the release page](https://github.com/ChainSafe/lodestar/releases/latest) under the `Assets` section. +Binaries can be downloaded from the Lodestar [release page](https://github.com/ChainSafe/lodestar/releases/latest) under the `Assets` section. ## Docker Installation @@ -100,5 +100,5 @@ pip3 install setuptools --force-reinstall --user ## Install from NPM [not recommended] :::danger -For mainnet (production) usage, we only recommend installing with docker due to [NPM supply chain attacks](https://hackaday.com/2021/10/22/supply-chain-attack-npm-library-used-by-facebook-and-others-was-compromised/). Until a [safer installation method has been found](https://github.com/ChainSafe/lodestar/issues/3596), do not use this install method except for experimental purposes only. +For mainnet (production) usage, we only recommend installing with Docker, using binaries or building from source due to [NPM supply chain attacks](https://hackaday.com/2021/10/22/supply-chain-attack-npm-library-used-by-facebook-and-others-was-compromised/). Until a [safer installation method has been found](https://github.com/ChainSafe/lodestar/issues/3596), do not use this install method except for experimental purposes only. ::: diff --git a/docs/pages/run/getting-started/quick-start-custom-guide.md b/docs/pages/run/getting-started/quick-start-custom-guide.md new file mode 100644 index 000000000000..8afc11c00ebf --- /dev/null +++ b/docs/pages/run/getting-started/quick-start-custom-guide.md @@ -0,0 +1,728 @@ +# Quick Start Custom Setup Guide + +This is a step-by-step guide to utilize [@ChainSafe/lodestar-quickstart](https://github.com/ChainSafe/lodestar-quickstart) to setup a Ubuntu-based full Ethereum node using a local execution client and ChainSafe's Lodestar consensus client via Docker (the recommended method to use Lodestar for production environments). This is an adaptation of [Somer Esat's guides](https://someresat.medium.com/) for the Ethereum staking community. + +This guide will provide instructions which include running a local execution node. This guide uses Lodestar's `stable` release branch and supports **Holesky** testnet setups and **Mainnet**. + +:::info +This guide specifically focuses on using Lodestar's Quickstart scripts which allows for near instant setup with the following technologies: + +- [Ubuntu v22.04 (LTS) x64 server](https://releases.ubuntu.com/22.04/) +- Ethereum Execution (eth1) clients: + - [Erigon](https://github.com/ledgerwatch/erigon/releases) | [Github](https://github.com/ledgerwatch/erigon) + - [Go-Ethereum (Geth)](https://geth.ethereum.org/) | [Github](https://github.com/ethereum/go-ethereum/releases/) + - [Hyperledger Besu](https://www.hyperledger.org/) | [Github](https://github.com/hyperledger/besu) + - [Nethermind](https://nethermind.io/) | [Github](https://github.com/NethermindEth/nethermind) + - [Rust](https://reth.rs) | [Github](https://github.com/paradigmxyz/reth) +- [ChainSafe's Lodestar Ethereum Consensus Client](https://lodestar.chainsafe.io/) | [Github](https://github.com/ChainSafe/lodestar) +- [Docker Engine](https://docs.docker.com/engine/) + ::: + +:::danger +This guide **_does not_** assist with securing your server such as secure SSH logins or enabling firewalls. Ensure you have limited access to your server and blocked unused ports with guides such as [CoinCashew's Security Best Practices for your ETH staking validator node](https://www.coincashew.com/coins/overview-eth/guide-or-how-to-setup-a-validator-on-eth2-mainnet/part-i-installation/guide-or-security-best-practices-for-a-eth2-validator-beaconchain-node) before continuing with this guide. +::: + +:::warning +This guide is for informational purposes only and does not constitute professional advice. The author does not guarantee accuracy of the information in this article and the author is not responsible for any damages or losses incurred by following this article. A full disclaimer can be found at the bottom of this page — please read before continuing. +::: + +## Support + +For technical support please reach out to: + +- The Lodestar team actively develops and collaborates on the [ChainSafe Discord Server](https://discord.gg/642wB3XC3Q) under **_#:star2:-lodestar-general_** channel. +- Please subscribe to our Discord server announcements on the [ChainSafe Discord Server](https://discord.gg/642wB3XC3Q) under **_#lodestar-announcements_** channel. + +## Prerequisites + +This guide assumes knowledge of Ethereum (ETH), Docker, staking and Linux. + +You require the following before getting started: + +- [Ubuntu Server v22.04 (LTS) amd64](https://releases.ubuntu.com/22.04/) or newer, installed and running on a local machine or in the cloud. _A locally running machine is encouraged for greater decentralization — if the cloud provider goes down then all nodes hosted with that provider go down._ + +- 32 ETH to run a solo validator with Lodestar. If running on testnet, contact us in our [ChainSafe Discord Server](https://discord.gg/642wB3XC3Q) for testnet Ether. + +## Testnet to Mainnet + +If moving from a testnet setup to a mainnet setup it is strongly recommended that you start on a fresh (newly installed) server instance. This guide has not been tested for migration scenarios and does not guarantee success if you are using an existing instance with previously installed testnet software. + +## Hardware Requirements + +| | Minimum | Recommended | +| --------- | -------------------------------------- | -------------------------------------- | +| Processor | Intel Core i3–9100 or AMD Ryzen 5 3450 | Intel Core i7–9700 or AMD Ryzen 7 4700 | +| Memory | 8 GB RAM | 16 GB RAM | +| Storage | 130 GB available space SSD | 200 GB available space SSD | +| Internet | Reliable broadband with 10mbps upload | Reliable broadband with >10mbps upload | + +:::info +Check your available disk space. Even you have a large SSD there are cases where Ubuntu is reporting only 100GB free. If this applies to you then take a look at [**_Appendix A — Expanding the Logical Volume._**](#appendix-a---expanding-the-logical-volume) +::: + +--- + +## Setup Machine & Repository + +### Install Docker Engine & Docker Compose + +We must install Docker Engine to run the images on your local machine. + +#### Add Docker's GPG keyrings + +Run each line one at a time. + +```bash= +sudo apt-get update +sudo apt-get install ca-certificates curl gnupg +sudo install -m 0755 -d /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg +sudo chmod a+r /etc/apt/keyrings/docker.gpg +``` + +#### Add the repository to Apt sources + +Copy and paste the entire command below. + +```bash +echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +``` + +#### Update Ubuntu + +Ensure all updates to your Ubuntu Server are complete. + +```bash= +sudo apt-get update +sudo apt-get upgrade -y +``` + +Hit `Enter` if required to restart services. + +#### Install Docker Engine + +```bash +sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin +``` + +#### Test Docker + +```bash +sudo docker run hello-world +``` + +If you see the message `Hello from Docker! +This message shows that your installation appears to be working correctly.`, you can move on to the next step. + +#### Clone lodestar-quickstart repository + +Clone the [lodestar-quickstart](https://github.com/ChainSafe/lodestar-quickstart) from Github into your local server. + +```bash +cd ~ && git clone https://github.com/ChainSafe/lodestar-quickstart.git +``` + +## Configure Lodestar Quick Scripts + +### Navigate to the root directory + +The script and required files are located within the `lodestar-quickstart` folder. + +``` +cd lodestar-quickstart +``` + +### Create your own JWT Secret + +We will generate a JWT secret that is shared by the Execution client and Lodestar in order to have a required secure connection for the `Engine API` on port `8551`. + +``` +openssl rand -hex 32 | tr -d "\n" > "jwtsecret" +``` + +Confirm that your JWT token created. + +``` +cat jwtsecret ; echo +``` + +Your terminal should display the secret. Copy the token for the next step. Be careful to only copy the 64 characters corresponding to the secret and nothing else. + +:::danger +:rotating_light: **WARNING:** Do not share this secret as it protects your authenticated port 8551. +::: + +### Input your JWT Secret into the `import-args.sh` script + +Edit the `import-args.sh` file. + +```sh +nano import-args.sh +``` + +Replace the 64 characters after `0x` with your token. + +If you are not running validators, press `CTRL` + `x` then `y` then `Enter` to save and exit. Proceed to Configuring your Network. + +### Configure feeRecipient + +:::warning +If you are running validators, Ethereum requires validators to set a **Fee Recipient** which allows you to receive priority fees and MEV rewards when proposing blocks. If you do not set this address, your rewards will be sent to the [burn address by default](https://etherscan.io/address/0x0000000000000000000000000000000000000000). +::: + +Configure your validator client's feeRecipient address by changing the `FEE_RECIPIENT` line. Ensure you specify an Ethereum address you control. + +An example of a fee recipient set with the address `0xB7576e9d314Df41EC5506494293Afb1bd5D3f65d`, you would change the configuration to: + +``` +FEE_RECIPIENT="0xB7576e9d314Df41EC5506494293Afb1bd5D3f65d" +``` + +If you would like to run [MEV-Boost](https://boost.flashbots.net) with your validators, proceed to the next section. + +If you do not want to run MEV-Boost, press `CTRL` + `x` then `y` then `Enter` to save and exit. Proceed to [Configuring your Network](#configuring-your-network). + +### Set minimum bid for MEV-Boost validators + +:::info +(Optional): If you are running validators and would like to use MEV-Boost, follow this section. Otherwise, skip this section. +::: + +Validators running MEV-Boost maximize their staking reward by selling blockspace to an open market of builders. MEV-Boost v1.4+ allows you to set a minimum bid threshold to only use an externally built block if it meets or exceeds this parameter. + +The `min-bid` parameter is denominated in ETH. For example, if you want to set your threshold to 0.03 ETH, set your configuration to `MIN_BUILDERBID=0.03` + +When complete, press `CTRL` + `x` then `y` then `Enter` to save and exit. + +### Configuring your Network + +When using the quick scripts, each supported network has a `.vars` file to define the parameters required for configuring the clients to the specified network. + +To view the available files, use the command: + +``` +ls *.vars +``` + +### Select your Network + +Each network has specifics variables that you may want to setup for use. We will use `Holesky` to demonstrate connecting to a public testnet. + +Open the `holesky.vars` file. + +```bash +nano holesky.vars +``` + +### Configure MEV-boost relays + +:::info +(Optional): If you have validators you intend to use for MEV-boost, you can input the relays you want to connect here. Otherwise, skip this section. +::: + +You can list multiple relays simply by pasting the relay URL as a variable in this file. + +```shell= +RELAY_A=https://0xRelayPubKey@relay.com +RELAY_B=https://0xRelayPubKey@relay2.com +``` + +Make sure to identify the ones you want to use by editing the line: + +```shell= +RELAYS="$RELAY_A,$RELAY_B" +``` + +### Configure Lodestar version + +The lodestar-quickstart scripts currently defaults to using our `stable` release branch. To use our nightly `unstable` release instead, replace `LODESTAR_IMAGE=chainsafe/lodestar:latest` with `LODESTAR_IMAGE=chainsafe/lodestar:next` in the `import-images.sh` file. + +You may also choose to use a specific version release of Lodestar. To select a specific version, replace the image with `LODESTAR_IMAGE=chainsafe/lodestar:v1.x.x` + +:::warning +:warning: We do not recommend using the `unstable` branch or `@chainsafe/lodestar:next` docker versions of Lodestar for production related tasks. +::: + +### Modify your weak subjectivity (checkpoint sync) provider + +:::note +(Optional): We use ChainSafe's Lodestar checkpoints by default. You may choose to point your trusted checkpoint at another source or verify the checkpoints with other providers. If you would rather sync from genesis (not recommended), you can skip this step. +::: + +Weak subjectivity (checkpoint sync) allows your beacon node to sync within minutes by utilizing a trusted checkpoint from a trusted provider. + +**We highly recommend using this feature** so you do not need to wait days to sync from genesis and will mitigate your susceptibility to [long-range attacks](https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/). + +Minimize your risk of syncing a malicious chain from a malicious checkpoint by verifying the trusted checkpoint from multiple sources. + +1. View the community maintained list of [Beacon Chain checkpoint sync endpoints](https://eth-clients.github.io/checkpoint-sync-endpoints/) +2. Verify multiple endpoint links and ensure the latest finalized and latest justified block roots are the same +3. Choose one of those endpoint URLs +4. Replace the `--checkpointSyncUrl` address with your chosen provider. + +:::info +**NOTE**: Ensure you use checkpoint URLs from the list above corresponding to the network you are trying to sync or you **will** receive errors. +::: + +When complete, press `CTRL` + `x` then `y` then `Enter` to save and exit. + +## Modify other client parameters (For advanced users) + +:::info +(Optional): We have already set fixed parameters for a seamless setup. If you are looking to customize the default parameters of the clients you are using, follow this section. Otherwise, skip this section. +::: + +Fixed parameters for clients can be modified under the `fixed.vars` configuration file. + +Under the selected client, modify or add the custom arguments on their corresponding line. + +:::note +The following are links to client documentation for CLI commands: + +- [**Lodestar CLI Commands**](https://chainsafe.github.io/lodestar/reference/cli/) +- [**Nethermind CLI Commands**](https://docs.nethermind.io/fundamentals/configuration#command-line-options) +- [**Besu CLI Commands**](https://besu.hyperledger.org/en/stable/Reference/CLI/CLI-Syntax/) +- [**Go Ethereum CLI commands**](https://geth.ethereum.org/docs/interface/command-line-options) +- [**Erigon CLI commands**](https://github.com/ledgerwatch/erigon#beacon-chain) +- [**Reth CLI commands**](https://reth.rs/cli/reth.html) + ::: + +Once complete, press `CTRL` + `x` then `y` then `Enter` to save and exit. + +--- + +## Setup Validators + +:::info +Optional: Skip this entire section if you do not intend to run validators. +::: + +### Create validator keystore password + +Make sure you are in your main quickstart directory. Create the `pass.txt` file containing your validator's decryption password for use. + +``` +cd ~/lodestar-quickstart +``` + +``` +nano pass.txt +``` + +Enter the password for your validators. + +:::info +Once the validator container is running, you can delete this file from your server. Note that every time you restart this container, you will need this password to decrypt your keystore.json files. +::: + +Once complete, press `CTRL` + `x` then `y` then `Enter` to save and exit. + +### Option 1: Setup validators with keystores + +If you want to setup validators with your `keystores.json` files follow this section. Otherwise, skip this step. + +#### Copy/Move keystores to `lodestar-quickstart/keystores` directory + +Your `keystore.json` file(s) generated from the [`staking-deposit-cli`](https://github.com/ethereum/staking-deposit-cli) or similar generator for validator keys will be placed in the `lodestar-quickstart/keystores` directory using the `cp` command to copy or `mv` command to move the files. + +``` +mkdir keystores +``` + +:::info +You may choose to use your own method (e.g. SFTP) for copying/uploading keys to your server. This is only a guide. +::: + +The format of the command to use is below: + +``` +cp +``` + +An example usage of this command is: + +``` +cp /home/user/validator_keys/keystore-x.json ~/lodestar-quickstart/keystores +``` + +Ensure your `keystore.json` files are in the `lodestar-quickstart/keystores` directory using `ls` command. + +``` +ls -lsah ~/lodestar-quickstart/keystores/ +``` + +You should see the keystore files within the directory. + +:::info +Ensure the `/keystores` directory only has the `keystore-m_xxxxx.json` files and nothing else. If you copied in the `deposit_data-xxxxx.json` files, you can remove them by using the `sudo rm ` command. + +Example: + +``` +sudo rm deposit_data-1552658472.json +``` + +::: + +Continue to the [**Startup Quickstart Script**](#startup-quickstart-script) section. + +### Option 2: Setup multiple validator sets with keystores encrypted under different passwords + +Optional: If you want to setup validators with your `keystores.json` files but they are not encrypted with the same password, follow this section. Otherwise, skip this step. + +This option will allow you to run multiple validator clients corresponding to each validator keystore set encrypted with the same password. Therefore, we will setup `validatorset1` with one decryption password and `validatorset2` with another decryption password. You can repeat these steps to create subsequent validator sets with different keystore decryption passwords. + +#### Create validator keystore set directory + +Ensure you are in the `lodestar-quickstart` directory and create a folder for your first validator keystore set. + +``` +cd ~/lodestar-quickstart +``` + +Make the new directory for set one. + +``` +mkdir validatorset1 +``` + +Navigate into the directory. + +``` +cd validatorset1 +``` + +#### Create validator keystore password + +Create the `pass.txt` file containing your validator's decryption password for use. + +``` +nano pass.txt +``` + +Enter the password for your validators. + +:::info +Once the validator container is running, you can delete this file from your server. Note that every time you restart this container, you will need this password to decrypt your keystore.json files. +::: + +Once complete, press `CTRL` + `x` then `y` then `Enter` to save and exit. + +#### Copy/Move keystores to `lodestar-quickstart/validatorset1/keystores` directory + +Your `keystore.json` file(s) generated from the [`staking-deposit-cli`](https://github.com/ethereum/staking-deposit-cli) or similar generator for validator keys will be placed in the `lodestar-quickstart/validatorset1/keystores` directory using the `sudo cp` command to copy or `sudo mv` command to move the files. + +``` +mkdir keystores +``` + +The format of the command to use is below: + +``` +cp +``` + +An example usage of this command is: + +``` +cp /home/user/validator_keys/keystore-x.json ~/lodestar-quickstart/validatorset1/keystores +``` + +Ensure your `keystore.json` files are in the `lodestar-quickstart/validatorset1/keystores` directory using `ls` command. + +``` +ls -lsah ~/lodestar-quickstart/validatorset1/keystores/ +``` + +You should see the keystore files within the directory. + +:::info +Ensure the `/keystores` directory only has the `keystore-m_xxxxx.json` files and nothing else. If you copied in the `deposit_data-xxxxx.json` files, you can remove them by using the `sudo rm ` command. + +Example: + +``` +sudo rm deposit_data-1552658472.json +``` + +::: + +Repeat the same steps above for `validatorset2` and any subsequent sets of validators you require. When complete you should have a similar looking directory tree such as the one below: + +Then, continue to the [**Startup Quickstart Script**](#startup-quickstart-script) section. Pay particular attention to startup script example five (5) and (6). + +### Option 3: Setup validators with mnemonic + +:::warning +**TESTNET USE ONLY:** Do not use this method unless you're validating on a testnet. Your mnemonic will be stored in plaintext on your server, which is unsafe. +::: + +Optional: If you want to setup validators with your mnemonic. Otherwise, skip this step. + +#### Setup Mnemonic + +Select the `.vars` file corresponding to the network you want to run. For Holesky, select `holesky.vars`. Open the file with the `nano` text editor and edit the configuration: + +``` +nano holesky.vars +``` + +We will modify the `LODESTAR_VALIDATOR_MNEMONIC_ARGS=`. Specifically, the mnemonic located after the `--fromMnemonic` flag. + +- Replace the default mnemonic with your mnemonic. Ensure it is between the quotations + +- Indicate which indexes of the mnemonic you wish Lodestar to run. Specify a specific index number `--mnemonicIndexes 0` or a range of numbers `--mnemonicIndexes 0..5` + +:::info +If you created your mnemonic with one key, it is likely located in index 0. If you've added to it, the generated keys are likely the subsequent indexes. + +Therefore, if you generated one key, it is likely in index 0, so you would use `--mnemonicIndexes 0`. If you generated five keys, it is likely in index 0 to 4, so you would use `--mnemonicIndexes 0..4` +::: + +Once complete, press `CTRL` + `x` then `y` then `Enter` to save and exit. + +Continue to the [**Startup Quickstart Script**](#startup-quickstart-script) section. + +--- + +## Startup Quickstart Script + +Ensure you are in the `~/lodestar-quickstart folder. + +``` +cd ~/lodestar-quickstart +``` + +The following are **_example commands_** as a template for initiating the quickstart script: + +1. Startup a Sepolia beacon node with no validators and Go Ethereum (Geth) execution client with terminals attached: + +``` +./setup.sh --dataDir sepolia-data --elClient geth --network sepolia --dockerWithSudo --withTerminal "gnome-terminal --disable-factory --" +``` + +2. Startup Mainnet beacon node with no validators and Nethermind execution client detached from containers (Recommended only when you've verified the setup has initiated properly with terminals attached): + +``` +./setup.sh --dataDir mainnet-data --elClient nethermind --network mainnet --dockerWithSudo --detached +``` + +3. Startup Holesky beacon node with validator client (using mnemonic in /keystores) and Erigon execution client detached from containers: + +``` +./setup.sh --dataDir holesky-data --elClient erigon --network holesky --dockerWithSudo --detached --withValidatorMnemonic ~/lodestar-quickstart/ +``` + +4. Startup Mainnet beacon node with validator client (using keystores) with MEV-Boost and Hyperledger Besu execution client detached from containers: + +``` +./setup.sh --dataDir mainnet-data --elClient besu --network mainnet --dockerWithSudo --detached --withValidatorKeystore ~/lodestar-quickstart/ --withMevBoost +``` + +5. Startup Holesky beacon node with validator client set one (using keystores) and execution client Geth detached from containers: + +``` +./setup.sh --dataDir holesky-data --elClient geth --network holesky --dockerWithSudo --detached --withValidatorKeystore ~/lodestar-quickstart/validatorset1 +``` + +:::warning +You can only start up one set of validator keystores per validator client on the same command. Use the below command (#6) to startup another validator client for another set of validator keys. +::: + +6. Startup validator client only with validator client set two (using keystores) and execution client Geth detached from containers: + +``` +./setup.sh --dataDir holesky-data --elClient geth --network holesky --dockerWithSudo --detached --withValidatorKeystore ~/lodestar-quickstart/validatorset2 --justVC +``` + +:::info +The script will standardize naming your containers so running the `setup.sh` twice, will not create two instances of the same containers. The script will standardize naming your containers so running the `./setup.sh ` a second time, will not create two instances of the same containers. +::: + +Configure the above commands with what you intend to run using the Quickstart Script Help table below. + +## Quickstart Script Help + +| Command | Required/Optional | Description | +| ------------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `dataDir` | Required | File location (volume) of the configuration & data for setup. This directory should be non-existent for the first run. If the directory exists, it will skip fetching the configuration, assuming it has been done previously. You can also clean individual directors of CL/EL between the re-runs. | +| `elClient` | Required | The selected EL client you want to run with Lodestar. Options are `nethermind`, `besu`, `erigon` or `geth`. | +| `network` | Required | The network/chain you want to load, reads the corresponding `.vars` (for e.g. `holesky.vars`) network configuration , like images, or urls for EL/CL to interact. Example: Default for Holesky is `--network holesky` using `holesky.vars`. | +| `dockerWithSudo` | Optional | Provide this argument if your Docker needs a `sudo` prefix. | +| `--withTerminal` | Optional\* | Provide the terminal command prefix for CL and EL processes to run in your favourite terminal. You may use an alias or a terminal launching script as long as it waits for the command it runs till ends and then closes. If not provided, it will launch the docker processes in in-terminal mode. | +| `--detached` | Optional\* | By default the script will wait for processes and use user input (ctrl +c) to end the processes, however you can pass this option to skip this behavior and just return, for e.g. in case you just want to leave it running. | +| `--withValidatorKeystore` | Optional\*\* | Launch a validator client using `LODESTAR_VALIDATOR_MNEMONIC_ARGS` (`--withValidatorMnemonic`) or using a folder (`--withValidatorKeystore --justVC` connecting to same beacon node. | +| `--withValidatorMnemonic` | Optional\*\* | Launch a validator client using mnemonic method.(`LODESTAR_VALIDATOR_MNEMONIC_ARGS`) as set in the network vars file. | +| `--withMevBoost` | Optional | Launch a MEV-Boost container to interface with multiple relays picked for the corresponding network vars file. When paired with `--justCL` or `--justVC` this only activates the builder arguments in the beacon/validator and use the builder url set in MEVBOOST_URL variable in fixed.vars | +| `--justEL` | Optional | Launch only the Execution Layer client. | +| `--justCL` | Optional | Launch only the Lodestar beacon node. | +| `--justVC` | Optional | Launch only the Lodestar validator. | +| `--skipImagePull` | Optional | Launch with only the local Docker images. Do not update them on this run. | + +:::note +`*` : Only one of the two options should be provided. +`**` : Only one of the two options should be provided. +::: + +### Check Containers + +You can check the status and get the name of your containers by using the `docker ps` command: + +``` +sudo docker ps +``` + +The containers should not constantly restart. If they restart, likely a misconfiguration occurred. + +### Check Container Logs + +You can check the status of what your container is logging to diagnose a problem or follow along the status of your container output. + +Check the logs by using the `docker logs` command: + +``` +sudo docker logs +``` + +Follow along the logs by adding the `-f` flag: + +``` +sudo docker logs -f +``` + +Limit the fetched logs by indicating the latest container out puts by number of lines using the `-n ` flag. For the last 10 lines: + +``` +sudo docker logs -n 10 +``` + +### Check beacon node is progressing + +Your beacon node should initialize and you should see something similar to: + +``` +Jul-31 13:35:27.967[] info: Lodestar network=mainnet, version=v1.21.0/ff35faa, commit=ff35faae4ad1697b86d708a0367a95a71648ab6e +Jul-31 13:35:28.344[] info: Connected to LevelDB database path=/data/lodestar/chain-db +Jul-31 13:35:49.828[] info: Initializing beacon from a valid db state slot=9633504, epoch=301047, stateRoot=0xfa2845a6877b98555906a1654941c97d9c05bdd41e61cc0870a967dc9030b156, isWithinWeakSubjectivityPeriod=true +Jul-31 13:35:51.955[chain] info: Historical state worker started +Jul-31 13:35:51.969[eth1] info: Eth1 provider urls=http://localhost:8551 +Jul-31 13:35:51.975[execution] info: Execution client urls=http://localhost:8551 +Jul-31 13:35:51.977[] info: External builder url=http://localhost:8661 +Jul-31 13:36:21.128[network] info: running libp2p instance in worker thread +Jul-31 13:36:21.727[network] info: libp2p worker started peer=15Uiu2HAmACcmCEXcgt3zCtJL2rqJZ2Mvdjh6U6fe26HgD2FoNRwW +Jul-31 13:36:27.677[network] info: discv5 worker started peerId=16Uiu2HAmACcmCEXcgt3zCtJL2rqJZ2Mvdjh6U6fe26HgD2FoNRwW, initialENR=enr:-IO4QHGTUd1Zg8LAhUAioOz_ySTKoJLIOa6zltSP_AvvhTFVYw6M6YB35IxsiKxQG7nUgCpUB5SIsNxMntCNlTK9sMEBgmlkgnY0iXNlY3AyNTZrMaEC24cdmzuGnWqSwF-8Hw2gbkAZDzMWW3LsHJfp_kDhy-GDdGNwgiMog3VkcIIeWH, bindAddr4=/ip4/0.0.0.0/udp/9000 +Jul-31 13:36:28.134[network] info: PeerId 16Uiu2HAmACcmCEXcgt3zCtJL2rqJZ2Mvdjh6U6fe26HgD2FoNRwW, Multiaddrs /ip4/0.0.0.0/tcp/9000 +Jul-31 13:36:28.137[metrics] info: Started metrics HTTP server address=http://127.0.0.1:8008 +Jul-31 13:36:28.256[rest] info: Started REST API server address=http://0.0.0.0:9596 +Jul-31 13:36:28.257[] info: Searching peers - peers: 0 - slot: 9634080 - head: (slot -576) 0x9d88…d02a - exec-block: syncing(20426302 0xcec4…) - finalized: 0x7feb…c130:301045 +Jul-31 13:36:36.461[execution] info: Execution client is synced oldState=ONLINE, newState=SYNCED +Jul-31 13:36:53.019[] info: Syncing - 3.7 minutes left - 2.32 slots/s - slot: 9634082 - head: (slot -515) 0x792f…f8aa - exec-block: valid(20426365 0x58b1…) - finalized: 0x9d88…d02a:301047 - peers: 11 +Jul-31 13:38:53.168[] info: Syncing - 11 seconds left - 4.01 slots/s - slot: 9634092 - head: (slot -44) 0x7491…f63e - exec-block: valid(20426841 0xd4b2…) - finalized: 0x1e00…6e6b:301062 - peers: 59 +Jul-31 13:38:58.051[network] info: Subscribed gossip core topics +Jul-31 13:38:58.132[sync] info: Subscribed gossip core topics +Jul-31 13:39:05.001[] info: Synced - slot: 9634093 - head: 0x35de…1f0e - exec-block: valid(20426886 0x10ff…) - finalized: 0x88f8…5375:301063 - peers: 70 +Jul-31 13:39:17.000[] info: Synced - slot: 9634094 - head: 0x7844…3b3e - exec-block: valid(20426887 0x67d1…) - finalized: 0x88f8…5375:301063 - peers: 69 +Jul-31 13:39:29.000[] info: Synced - slot: 9634095 - head: 0x5516…ba12 - exec-block: valid(20426888 0x4ceb…) - finalized: 0x88f8…5375:301063 - peers: 74 +``` + +### Check validators are detected and decrypted + +> OPTIONAL: If you are running validators, you can check the validator client logs to ensure the validator keys exist, has been detected and decrypted. + +Here is an example command if you are running validators on Goerli with the lodestar-quickstart script: + +``` +sudo docker logs goerli-validator +``` + +You should see something similar to: + +``` +Mar-01 03:06:35.048[] info: Lodestar network=holesky, version=v1.16.0/6ad9740, commit=6ad9740a085574306cf46c7642e749d6ec9a4264 +Mar-01 03:06:35.050[] info: Connecting to LevelDB database path=/keystoresDir/validator-db-holesky +Mar-01 03:06:35.697[] info: 100% of keystores imported. current=2 total=2 rate=1318.68keys/m +Mar-01 03:06:35.698[] info: 2 local keystores +Mar-01 03:06:35.698[] info: 0xa6fcfca12e1db6c7341d82327010cd57224dc239d1c5e4fb18286cc32edb877d813c5af1c870d474aef7b3ff7ab927ea +Mar-01 03:06:35.698[] info: 0x8f868e53bbe1451bcf6d42c9ab6d292cbd7fbfa09c59b6b99c1dd6a4977e2e7b4b752c328784ca2788dd6f63ffcbdb7e +Mar-01 03:06:35.732[] info: Beacon node urls=http://127.0.0.1:9596 +Mar-01 03:09:23.813[] info: Genesis fetched from the beacon node +Mar-01 03:09:23.816[] info: Verified connected beacon node and validator have same the config +Mar-01 03:09:23.818[] info: Verified connected beacon node and validator have the same genesisValidatorRoot +Mar-01 03:09:23.818[] info: Initializing validator useProduceBlockV3=deneb+, broadcastValidation=gossip, defaultBuilderSelection=executiononly, suggestedFeeRecipient=0xeeef273281fB83F56182eE960aA4bAfe7fE075DE, strictFeeRecipientCheck=false +Mar-01 03:09:23.830[] info: Validator seen on beacon chain validatorIndex=1234567, pubKey=0xa6fcfca12e1db6c7341d82327010cd57224dc239d1c5e4fb18286cc32edb877d813c5af1c870d474aef7b3ff7ab927ea +Mar-01 03:09:23.830[] info: Validator seen on beacon chain validatorIndex=1234568, pubKey=0x8f868e53bbe1451bcf6d42c9ab6d292cbd7fbfa09c59b6b99c1dd6a4977e2e7b4b752c328784ca2788dd6f63ffcbdb7e +Mar-01 03:09:23.830[] info: Validator statuses active=2, total=2 +Mar-01 03:15:50.191[] info: Published attestations slot=1113379, count=1 +Mar-01 03:16:02.728[] info: Published attestations slot=1113380, count=1 +``` + +:::info +It is normal to see `Error on getProposerDuties` in your validator logs as your beacon node and execution node sync up. Give it time. +::: + +## Stop Containers + +You can stop the running containers by using the `docker stop` command and apply it to more than one container if necessary. + +``` +sudo docker stop +``` + +Ensure to remove the container if you don't plan to restart it with the same parameters. + +``` +sudo docker rm +``` + +--- + +# Appendix + +## Appendix A - Expanding the Logical Volume + +There are cases where Ubuntu is provisioning only 200GB of a larger SSD causing users to run out of disk space when syncing their Eth1 node. The error message is similar to: + +`Fatal: Failed to register the Ethereum service: write /var/lib/goethereum/geth/chaindata/383234.ldb: no space left on device` + +To address this issue, assuming you have a SSD that is larger than 200GB, expand the space allocation for the LVM by following these steps: + +``` +sudo lvdisplay <-- Check your logical volume size +sudo lvm +lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv +lvextend -l +100%FREE -r /dev/ubuntu-vg/ubuntu-lv +exit +sudo resize2fs /dev/ubuntu-vg/ubuntu-lv +df -h <-- Check results +``` + +That should resize your disk to the maximum available space. + +If you need support, please check with the [ChainSafe Discord](https://discord.gg/642wB3XC3Q) under the #:star2:-lodestar-general channel. + +## Appendix B - Update client images + +To update client images, you just need to stop all the containers, remove them and restart the lodestar-quickstart script to automatically check for new images. + +You can stop the running containers by using the `docker stop` command with the container names. + +``` +sudo docker stop +``` + +Remove the containers by using the `docker rm` command. + +``` +sudo docker rm +``` + +Restart your containers using your [Startup Quickstart Script](#startup-quickstart-script) command. + +--- + +## Full Disclaimer + +This article (the guide) is for informational purposes only and does not constitute professional advice. The author does not warrant or guarantee the accuracy, integrity, quality, completeness, currency, or validity of any information in this article. All information herein is provided “as is” without warranty of any kind and is subject to change at any time without notice. The author disclaims all express, implied, and statutory warranties of any kind, including warranties as to accuracy, timeliness, completeness, or fitness of the information in this article for any particular purpose. The author is not responsible for any direct, indirect, incidental, consequential or any other damages arising out of or in connection with the use of this article or in reliance on the information available on this article. This includes any personal injury, business interruption, loss of use, lost data, lost profits, or any other pecuniary loss, whether in an action of contract, negligence, or other misuse, even if the author has been informed of the possibility. diff --git a/docs/pages/run/getting-started/quick-start.md b/docs/pages/run/getting-started/quick-start.md index a28de8014b6a..e1a77face695 100644 --- a/docs/pages/run/getting-started/quick-start.md +++ b/docs/pages/run/getting-started/quick-start.md @@ -1,26 +1,20 @@ --- -title: Quick Start +title: Lodestar Quick Start Scripts --- -## Lodestar Quickstart +In order to make things easier and quicker for all types of users to bootstrap the Lodestar consensus client with a variety of execution clients, we have come up with [Lodestar Quickstart](https://github.com/ChainSafe/lodestar-quickstart) Docker scripts! -In order to make things easy for users to onboard and try the Ethereum **Proof of Stake** we have come up with [Lodestar quick start](https://github.com/ChainSafe/lodestar-quickstart) scripts! +- ✅ Zero configuration +- ✅ Single command startup +- ✅ All testnets supported along with mainnet +- ✅ All mainstream execution clients integrated -✅ Zero Configuration -✅ All testnets supported along with `mainnet` -✅ All mainstream Execution Clients integrated - -With just single command you can run lodestar with various execution engines, switch them up to see the Optimistic sync work its magic and eventually brings lodestar and the execution engine in sync - -### Customizations - -You can adapt them to your production setups with ease! Here is a simple guide for you to follow along: +### Support -👉 [Lodestar Quick Setup Guide](https://hackmd.io/@philknows/rJegZyH9q) +We actively maintain and update the configurations of running Lodestar with the most commonly used execution clients for various test/production networks so there is minimal configuration required for a standard setup. -### Support +If you have questions about these scripts, documentation or repository, feel free to talk to us on our [ChainSafe Discord](https://discord.gg/yjyvFRP) or [open an issue](https://github.com/ChainSafe/lodestar-quickstart/issues/new) and a member of the team or our community will be happy to assist you. -We actively maintain and update the configurations of running lodestar with the top of the line execution engines for various PoS networks so you have the minimum possible figuring out to do. +### Customizations (Optional) -In case you are facing any issues with the quick start guide, do reach us out on lodestar discord! -Happy to help! 🙏🙏🙏 +You can further adapt our Quickstart Docker scripts to your node setups with ease! Use our [Quickstart Custom Setup Guide](./quick-start-custom-guide.md)! diff --git a/docs/pages/run/logging-and-metrics/client-monitoring.md b/docs/pages/run/logging-and-metrics/client-monitoring.md index dc707f2b31d0..3d9ede1d8464 100644 --- a/docs/pages/run/logging-and-metrics/client-monitoring.md +++ b/docs/pages/run/logging-and-metrics/client-monitoring.md @@ -1,4 +1,4 @@ -# Client monitoring +# Client Monitoring Lodestar has the ability to send client stats to a remote service for collection. At the moment, the main service offering remote monitoring is [beaconcha.in](https://beaconcha.in/). diff --git a/docs/pages/run/logging-and-metrics/dashboards.md b/docs/pages/run/logging-and-metrics/dashboards.md deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/docs/pages/run/logging-and-metrics/log-management.md b/docs/pages/run/logging-and-metrics/log-management.md deleted file mode 100644 index a0ee1d5fec07..000000000000 --- a/docs/pages/run/logging-and-metrics/log-management.md +++ /dev/null @@ -1,3 +0,0 @@ -# Log Management - -Check back soon for more information!! diff --git a/docs/pages/run/logging-and-metrics/metrics-management.md b/docs/pages/run/logging-and-metrics/metrics-management.md deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/docs/pages/run/logging-and-metrics/prometheus-grafana.md b/docs/pages/run/logging-and-metrics/prometheus-grafana.md index f49a44f37209..c36c52a72a0c 100644 --- a/docs/pages/run/logging-and-metrics/prometheus-grafana.md +++ b/docs/pages/run/logging-and-metrics/prometheus-grafana.md @@ -1,8 +1,12 @@ -# Prometheus and Grafana +# Prometheus and Grafana Setup Prometheus is an open-source monitoring system with efficient time series database and a modern alerting approach. Together with Grafana it's the recommended way to make sure that your node and validator(s) are performing correctly. -## Prometheus +## Localized Docker Metrics Script + +The Lodestar team has setup a script which will copy the latest dashboards compiled by our team for development purposes. By utilizing the script located in `/docker/docker-compose.local_dev.sh`, you can instantly setup the latest dockerized metrics alongside your local beacon node. + +## Prometheus Setup To start, download Prometheus from https://prometheus.io/download/. Unzip the downloaded .zip file and run Prometheus from its installed location with the lodestar `prometheus.yml` passed in as the configuration file @@ -23,7 +27,7 @@ lodestar --metrics=true --metrics.port=8008 Navigate to http://localhost:9090/ in your browser to verify that Prometheus is monitoring Lodestar -## Grafana +## Grafana Setup Download and install Grafana from its official repository https://grafana.com/docs/grafana/latest/installation/debian/ diff --git a/docs/pages/run/validator-management/proposer-config.md b/docs/pages/run/validator-management/proposer-config.md new file mode 100644 index 000000000000..444789a9f8b0 --- /dev/null +++ b/docs/pages/run/validator-management/proposer-config.md @@ -0,0 +1,48 @@ +# Proposer Configuration + +:::warning +This is an alpha feature. The feature and its format are subject to change. +::: + +With Lodestar's validator client, you can assign specific metadata for each proposer/public key using a proposer configuration file written in YAML file. This will allow you to set specific graffiti, fee recipients and builder settings per validator key. + +### Example proposer_config.yaml + +```yaml +proposer_config: + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c": + graffiti: "graffiti" + strict_fee_recipient_check: false + fee_recipient: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + builder: + gas_limit: "30000000" + selection: "executionalways" + boost_factor: "0" + "0xa4855c83d868f772a579133d9f23818008417b743e8447e235d8eb78b1d8f8a9f63f98c551beb7de254400f89592314d": + fee_recipient: "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + builder: + gas_limit: "3000000" + selection: "maxprofit" + boost_factor: "100" +default_config: + graffiti: "default graffiti" + strict_fee_recipient_check: true + fee_recipient: "0xcccccccccccccccccccccccccccccccccccccccc" + builder: + gas_limit: "30000000" + selection: "default" + boost_factor: "90" +``` + +### Enable Proposer Configuration + +After you have configured your proposer configuration YAML file, you can start Lodestar with an additional CLI flag option pointing to the file: `--proposerSettingsFile /path/to/proposer_config.yaml`. + +:::info +The proposer configuration can also be retrieved via the keymanager API endpoint: + +``` +GET /eth/v0/validator/{pubkey}/proposer_config +``` + +::: diff --git a/docs/pages/run/validator-management/vc-configuration.md b/docs/pages/run/validator-management/vc-configuration.md index ce6db52b3a66..a51791eff494 100644 --- a/docs/pages/run/validator-management/vc-configuration.md +++ b/docs/pages/run/validator-management/vc-configuration.md @@ -74,6 +74,10 @@ Configure your validator client's fee recipient address by using the [`--suggest You may choose to use the [`--strictFeeRecipientCheck`](./validator-cli.md#--strictfeerecipientcheck) flag to enable a strict check of the fee recipient address with the one returned by the beacon node for added reassurance. +:::note +If you would like to set unique proposer metadata (e.g. fee recipient address) for each validator you are running, see the [Proposer Configuration](./proposer-config.md) feature. This feature is also available via the keymanager API. +::: + ### Configure your builder selection and/or builder boost factor If you are running a beacon node with connected builder relays, you may use these validator configurations to signal which block (builder vs. local execution) the beacon node should produce. diff --git a/docs/pages/supporting-libraries/libraries.md b/docs/pages/supporting-libraries/libraries.md index e76ccc2f9ec7..58796e56cd15 100644 --- a/docs/pages/supporting-libraries/libraries.md +++ b/docs/pages/supporting-libraries/libraries.md @@ -1,13 +1,13 @@ # Lodestar libraries -The Lodestar project is divided into Typescript packages that can be used independently of the CLI. These packages span the breadth of the Ethereum Consensus layer, and are perfect for Typescript developers looking to build around Ethereum. +The Lodestar project is divided into TypeScript packages that can be used independently of the CLI. These packages span the breadth of the Ethereum Consensus layer, and are perfect for TypeScript developers looking to build around Ethereum. ## Monorepo libraries Several useful Ethereum consensus libraries are developed as part of the [Lodestar monorepo](https://github.com/ChainSafe/lodestar) and may be useful when used individually. - [`params`](https://github.com/ChainSafe/lodestar/tree/unstable/packages/params) - Ethereum consensus constants and fork names -- [`types`](https://github.com/ChainSafe/lodestar/tree/unstable/packages/types) - Ethereum consensus types, Typescript interfaces and SSZ type objects +- [`types`](https://github.com/ChainSafe/lodestar/tree/unstable/packages/types) - Ethereum consensus types, TypeScript interfaces and SSZ type objects - [`config`](https://github.com/ChainSafe/lodestar/tree/unstable/packages/config) - Ethereum consensus run-time network configuration - [`api`](https://github.com/ChainSafe/lodestar/tree/unstable/packages/api) - Ethereum consensus REST API client - [`flare`](https://github.com/ChainSafe/lodestar/tree/unstable/packages/flare) - Beacon chain multi-purpose and debugging tool diff --git a/docs/pages/trouble-shooting.md b/docs/pages/trouble-shooting.md deleted file mode 100644 index 144aeb90ce20..000000000000 --- a/docs/pages/trouble-shooting.md +++ /dev/null @@ -1 +0,0 @@ -# Trouble Shooting diff --git a/docs/sidebars.ts b/docs/sidebars.ts index d9a4839a90c4..1b6eb1ac055d 100644 --- a/docs/sidebars.ts +++ b/docs/sidebars.ts @@ -10,11 +10,18 @@ const sidebars: SidebarsConfig = { label: "Run A Node", collapsed: false, items: [ - "run/getting-started/quick-start", "run/getting-started/installation", { type: "category", - label: "Beacon node", + label: "Quick Start", + items: [ + "run/getting-started/quick-start", + "run/getting-started/quick-start-custom-guide", + ], + }, + { + type: "category", + label: "Beacon Node", items: [ "run/beacon-management/starting-a-node", "run/beacon-management/beacon-cli", @@ -31,17 +38,23 @@ const sidebars: SidebarsConfig = { "run/validator-management/vc-configuration", "run/validator-management/validator-cli", "run/validator-management/external-signer", + "run/validator-management/proposer-config", ], }, { type: "category", label: "Logging and Metrics", - items: ["run/logging-and-metrics/prometheus-grafana", "run/logging-and-metrics/client-monitoring"], + items: [ + "run/logging-and-metrics/prometheus-grafana", + "run/logging-and-metrics/client-monitoring", + ], }, { type: "category", label: "Discv5 Bootnode", - items: ["run/bootnode/bootnode-cli"], + items: [ + "run/bootnode/bootnode-cli", + ], }, ], }, diff --git a/packages/light-client/README.md b/packages/light-client/README.md index 0323e8fc4326..3cab0c12f13b 100644 --- a/packages/light-client/README.md +++ b/packages/light-client/README.md @@ -31,7 +31,7 @@ You can find more information about the light-client protocol in the [specificat ## Getting started -- Follow the [installation guide](https://chainsafe.github.io/lodestar/getting-started/installation) or [Docker install](https://chainsafe.github.io/lodestar/getting-started/installation/#docker-installation) to install Lodestar. +- Follow the [installation guide](https://chainsafe.github.io/lodestar/run/getting-started/installation) to install Lodestar. - Quickly try out the whole stack by [starting a local testnet](https://chainsafe.github.io/lodestar/advanced-topics/setting-up-a-testnet). ## Light-Client CLI Example diff --git a/packages/prover/README.md b/packages/prover/README.md index ce1f33dd8efb..477da5140c4b 100644 --- a/packages/prover/README.md +++ b/packages/prover/README.md @@ -152,7 +152,7 @@ You will need to go over the [specification](https://github.com/ethereum/beacon- ## Getting started -- Follow the [installation guide](https://chainsafe.github.io/lodestar/getting-started/installation) to install Lodestar. +- Follow the [installation guide](https://chainsafe.github.io/lodestar/run/getting-started/installation) to install Lodestar. - Quickly try out the whole stack by [starting a local testnet](https://chainsafe.github.io/lodestar/advanced-topics/setting-up-a-testnet). ## Contributors From 8922d55a236db211a56fe6a74d8b19d315da8b08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 20:59:19 +0100 Subject: [PATCH 216/259] chore(deps): bump cross-spawn from 7.0.3 to 7.0.6 in /docs (#7268) Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6. - [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md) - [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6) --- updated-dependencies: - dependency-name: cross-spawn dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/yarn.lock b/docs/yarn.lock index 046829e3530b..80cd3a321a5a 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -3684,9 +3684,9 @@ cosmiconfig@^8.3.5: path-type "^4.0.0" cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" From 64eb0153dd97b7525cb61625b102a6a521869c05 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 2 Dec 2024 17:11:28 +0100 Subject: [PATCH 217/259] feat: add error log to notifier if execution client auth failed (#7239) * feat: add error log to notifier if execution client auth failed * Update packages/beacon-node/src/node/notifier.ts --------- Co-authored-by: NC <17676176+ensi321@users.noreply.github.com> --- packages/beacon-node/src/node/notifier.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/src/node/notifier.ts b/packages/beacon-node/src/node/notifier.ts index c0d9354197ae..cd316516259b 100644 --- a/packages/beacon-node/src/node/notifier.ts +++ b/packages/beacon-node/src/node/notifier.ts @@ -54,12 +54,12 @@ export async function runNodeNotifier(modules: NodeNotifierModules): Promise= config.BELLATRIX_FORK_EPOCH && - computeStartSlotAtEpoch(clockEpoch) === clockSlot && - chain.executionEngine.state === ExecutionEngineState.OFFLINE - ) { - logger.warn("Execution client is offline"); + if (clockEpoch >= config.BELLATRIX_FORK_EPOCH && computeStartSlotAtEpoch(clockEpoch) === clockSlot) { + if (chain.executionEngine.state === ExecutionEngineState.OFFLINE) { + logger.warn("Execution client is offline"); + } else if (chain.executionEngine.state === ExecutionEngineState.AUTH_FAILED) { + logger.error("Execution client authentication failed. Verify if the JWT secret matches on both clients"); + } } const headInfo = chain.forkChoice.getHead(); From 84e069930156b1fabb2e2cd9261d58fcd6eff6b1 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 3 Dec 2024 15:44:29 +0100 Subject: [PATCH 218/259] docs: display rcConfig flag on CLI reference page (#7270) * docs: display rcConfig flag on CLI reference page * Update word list --- .wordlist.txt | 2 ++ packages/cli/src/options/globalOptions.ts | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.wordlist.txt b/.wordlist.txt index 2c28fc784061..5070aafcf9a5 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -110,6 +110,7 @@ Vitalik Vitest Wagyu api +args async backfill beaconcha @@ -244,3 +245,4 @@ xRelayPubKey xcode yaml yamux +yml diff --git a/packages/cli/src/options/globalOptions.ts b/packages/cli/src/options/globalOptions.ts index 58ae396b67d1..6a6998dc76cc 100644 --- a/packages/cli/src/options/globalOptions.ts +++ b/packages/cli/src/options/globalOptions.ts @@ -10,6 +10,7 @@ type GlobalSingleArgs = { paramsFile?: string; preset: string; presetFile?: string; + rcConfig?: string; }; export const defaultNetwork: NetworkName = "mainnet"; @@ -44,11 +45,16 @@ const globalSingleOptions: CliCommandOptions = { description: "Preset configuration file to override the active preset with custom values", type: "string", }, + + rcConfig: { + description: "RC file to supplement command line args, accepted formats: .yml, .yaml, .json", + type: "string", + }, }; export const rcConfigOption: [string, string, (configPath: string) => Record] = [ "rcConfig", - "RC file to supplement command line args, accepted formats: .yml, .yaml, .json", + globalSingleOptions.rcConfig.description as string, (configPath: string): Record => readFile(configPath, ["json", "yml", "yaml"]), ]; From 376fe2a3c37823c93cdab70fda11c859280e72a2 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 3 Dec 2024 18:04:26 +0100 Subject: [PATCH 219/259] chore: remove prettier as default formatter for all file types (#7275) --- .vscode/settings.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index fbc0552fe61c..d36535917835 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,5 @@ { "window.title": "${activeEditorShort}${separator}${rootName}${separator}${profileName}${separator}[${activeRepositoryBranchName}]", - "editor.defaultFormatter": "esbenp.prettier-vscode", // For `sysoev.vscode-open-in-github` extension "openInGitHub.defaultBranch": "unstable", "editor.formatOnSave": true, @@ -18,5 +17,11 @@ }, "[jsonc]": { "editor.defaultFormatter": "biomejs.biome" - } + }, + "[yaml]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[markdown]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, } From 37c42875390f8fd8a0c2d872e160709eb5e8858f Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 3 Dec 2024 21:22:02 +0100 Subject: [PATCH 220/259] chore: unhide flags relevant for devnets / testing (#7271) --- packages/cli/src/cmds/beacon/options.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/cli/src/cmds/beacon/options.ts b/packages/cli/src/cmds/beacon/options.ts index a623ca99512c..7f2cdddfc4ff 100644 --- a/packages/cli/src/cmds/beacon/options.ts +++ b/packages/cli/src/cmds/beacon/options.ts @@ -33,7 +33,6 @@ export const beaconExtraOptions: CliCommandOptions = { }, genesisStateFile: { - hidden: true, description: "Path or URL to download a genesis state file in ssz-encoded format", type: "string", }, @@ -80,7 +79,6 @@ export const beaconExtraOptions: CliCommandOptions = { ignoreWeakSubjectivityCheck: { description: "Ignore the checkpoint sync state failing the weak subjectivity check. This is relevant in testnets where the weak subjectivity period is too small for even few epochs of non finalization causing last finalized to be out of range. This flag is not recommended for mainnet use.", - hidden: true, type: "boolean", group: "weak subjectivity", }, @@ -120,7 +118,6 @@ export const beaconExtraOptions: CliCommandOptions = { }, persistNetworkIdentity: { - hidden: true, description: "Whether to reuse the same peer-id across restarts", type: "boolean", }, From dbe2188a37135b2ec34b0322459cdd012395dcc9 Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Wed, 4 Dec 2024 01:50:26 -0500 Subject: [PATCH 221/259] feat: debug too many shuffling promises (#7251) * feat: add asyncShufflingCalculation to StateTransitionOpts * feat: add asyncShufflingCalculation to all regen / processSlots consumers * fix: default to false for async shuffling and remove unnecessary props * fix: remove unnecessary flags from stateTransition * feat: implement conditional build of shuffling for prepareNextSlot * fix: spec test bug where shufflingCache is present from BeaconChain constructor * feat: sync build next shuffling if not queued async * fix: use getSync to pull next shuffling correctly * docs: add comment to prepareNextSlot * refactor: rename StateCloneOpts to StateRegenerationOpts * feat: pass asyncShufflingCalculation through to afterProcessEpoch and refactor conditional to run purely sync * docs: add issue number to comment * chore: lint --- .../beacon-node/src/chain/prepareNextSlot.ts | 7 ++- .../beacon-node/src/chain/regen/interface.ts | 18 ++++-- .../beacon-node/src/chain/regen/queued.ts | 18 ++++-- packages/beacon-node/src/chain/regen/regen.ts | 14 ++--- .../chain/stateCache/blockStateCacheImpl.ts | 4 +- .../chain/stateCache/fifoBlockStateCache.ts | 4 +- .../stateCache/inMemoryCheckpointsCache.ts | 10 ++-- .../stateCache/persistentCheckpointsCache.ts | 12 ++-- .../beacon-node/src/chain/stateCache/types.ts | 12 ++-- .../state-transition/src/cache/epochCache.ts | 59 ++++++++++--------- .../src/cache/epochTransitionCache.ts | 17 +++++- 11 files changed, 105 insertions(+), 70 deletions(-) diff --git a/packages/beacon-node/src/chain/prepareNextSlot.ts b/packages/beacon-node/src/chain/prepareNextSlot.ts index 40cadb3774c7..f78c1842bd78 100644 --- a/packages/beacon-node/src/chain/prepareNextSlot.ts +++ b/packages/beacon-node/src/chain/prepareNextSlot.ts @@ -114,7 +114,12 @@ export class PrepareNextSlotScheduler { // the slot 0 of next epoch will likely use this Previous Root Checkpoint state for state transition so we transfer cache here // the resulting state with cache will be cached in Checkpoint State Cache which is used for the upcoming block processing // for other slots dontTransferCached=true because we don't run state transition on this state - {dontTransferCache: !isEpochTransition}, + // + // Shuffling calculation will be done asynchronously when passing asyncShufflingCalculation=true. Shuffling will be queued in + // beforeProcessEpoch and should theoretically be ready immediately after the synchronous epoch transition finished and the + // event loop is free. In long periods of non-finality too many forks will cause the shufflingCache to throw an error for + // too many queued shufflings so only run async during normal epoch transition. See issue ChainSafe/lodestar#7244 + {dontTransferCache: !isEpochTransition, asyncShufflingCalculation: true}, RegenCaller.precomputeEpoch ); diff --git a/packages/beacon-node/src/chain/regen/interface.ts b/packages/beacon-node/src/chain/regen/interface.ts index b70fbc059875..b9a4e38b5b68 100644 --- a/packages/beacon-node/src/chain/regen/interface.ts +++ b/packages/beacon-node/src/chain/regen/interface.ts @@ -28,8 +28,12 @@ export enum RegenFnName { getCheckpointState = "getCheckpointState", } -export type StateCloneOpts = { +export type StateRegenerationOpts = { dontTransferCache: boolean; + /** + * Do not queue shuffling calculation async. Forces sync JIT calculation in afterProcessEpoch if not passed as `true` + */ + asyncShufflingCalculation?: boolean; }; export interface IStateRegenerator extends IStateRegeneratorInternal { @@ -56,7 +60,11 @@ export interface IStateRegeneratorInternal { * Return a valid pre-state for a beacon block * This will always return a state in the latest viable epoch */ - getPreState(block: BeaconBlock, opts: StateCloneOpts, rCaller: RegenCaller): Promise; + getPreState( + block: BeaconBlock, + opts: StateRegenerationOpts, + rCaller: RegenCaller + ): Promise; /** * Return a valid checkpoint state @@ -64,7 +72,7 @@ export interface IStateRegeneratorInternal { */ getCheckpointState( cp: phase0.Checkpoint, - opts: StateCloneOpts, + opts: StateRegenerationOpts, rCaller: RegenCaller ): Promise; @@ -74,12 +82,12 @@ export interface IStateRegeneratorInternal { getBlockSlotState( blockRoot: RootHex, slot: Slot, - opts: StateCloneOpts, + opts: StateRegenerationOpts, rCaller: RegenCaller ): Promise; /** * Return the exact state with `stateRoot` */ - getState(stateRoot: RootHex, rCaller: RegenCaller, opts?: StateCloneOpts): Promise; + getState(stateRoot: RootHex, rCaller: RegenCaller, opts?: StateRegenerationOpts): Promise; } diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index b5084d593356..9069b384fd58 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -8,7 +8,13 @@ import {JobItemQueue} from "../../util/queue/index.js"; import {CheckpointHex, toCheckpointHex} from "../stateCache/index.js"; import {BlockStateCache, CheckpointStateCache} from "../stateCache/types.js"; import {RegenError, RegenErrorCode} from "./errors.js"; -import {IStateRegenerator, IStateRegeneratorInternal, RegenCaller, RegenFnName, StateCloneOpts} from "./interface.js"; +import { + IStateRegenerator, + IStateRegeneratorInternal, + RegenCaller, + RegenFnName, + StateRegenerationOpts, +} from "./interface.js"; import {RegenModules, StateRegenerator} from "./regen.js"; const REGEN_QUEUE_MAX_LEN = 256; @@ -86,7 +92,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { */ getPreStateSync( block: BeaconBlock, - opts: StateCloneOpts = {dontTransferCache: true} + opts: StateRegenerationOpts = {dontTransferCache: true} ): CachedBeaconStateAllForks | null { const parentRoot = toRootHex(block.parentRoot); const parentBlock = this.forkChoice.getBlockHex(parentRoot); @@ -212,7 +218,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { */ async getPreState( block: BeaconBlock, - opts: StateCloneOpts, + opts: StateRegenerationOpts, rCaller: RegenCaller ): Promise { this.metrics?.regenFnCallTotal.inc({caller: rCaller, entrypoint: RegenFnName.getPreState}); @@ -231,7 +237,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { async getCheckpointState( cp: phase0.Checkpoint, - opts: StateCloneOpts, + opts: StateRegenerationOpts, rCaller: RegenCaller ): Promise { this.metrics?.regenFnCallTotal.inc({caller: rCaller, entrypoint: RegenFnName.getCheckpointState}); @@ -256,7 +262,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { async getBlockSlotState( blockRoot: RootHex, slot: Slot, - opts: StateCloneOpts, + opts: StateRegenerationOpts, rCaller: RegenCaller ): Promise { this.metrics?.regenFnCallTotal.inc({caller: rCaller, entrypoint: RegenFnName.getBlockSlotState}); @@ -268,7 +274,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { async getState( stateRoot: RootHex, rCaller: RegenCaller, - opts: StateCloneOpts = {dontTransferCache: true} + opts: StateRegenerationOpts = {dontTransferCache: true} ): Promise { this.metrics?.regenFnCallTotal.inc({caller: rCaller, entrypoint: RegenFnName.getState}); diff --git a/packages/beacon-node/src/chain/regen/regen.ts b/packages/beacon-node/src/chain/regen/regen.ts index 073556d8162f..06d1cee71332 100644 --- a/packages/beacon-node/src/chain/regen/regen.ts +++ b/packages/beacon-node/src/chain/regen/regen.ts @@ -20,7 +20,7 @@ import {getCheckpointFromState} from "../blocks/utils/checkpoint.js"; import {ChainEvent, ChainEventEmitter} from "../emitter.js"; import {BlockStateCache, CheckpointStateCache} from "../stateCache/types.js"; import {RegenError, RegenErrorCode} from "./errors.js"; -import {IStateRegeneratorInternal, RegenCaller, StateCloneOpts} from "./interface.js"; +import {IStateRegeneratorInternal, RegenCaller, StateRegenerationOpts} from "./interface.js"; export type RegenModules = { db: IBeaconDb; @@ -51,7 +51,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { */ async getPreState( block: BeaconBlock, - opts: StateCloneOpts, + opts: StateRegenerationOpts, regenCaller: RegenCaller ): Promise { const parentBlock = this.modules.forkChoice.getBlock(block.parentRoot); @@ -84,7 +84,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { */ async getCheckpointState( cp: phase0.Checkpoint, - opts: StateCloneOpts, + opts: StateRegenerationOpts, regenCaller: RegenCaller, allowDiskReload = false ): Promise { @@ -99,7 +99,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { async getBlockSlotState( blockRoot: RootHex, slot: Slot, - opts: StateCloneOpts, + opts: StateRegenerationOpts, regenCaller: RegenCaller, allowDiskReload = false ): Promise { @@ -146,7 +146,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { async getState( stateRoot: RootHex, caller: RegenCaller, - opts?: StateCloneOpts, + opts?: StateRegenerationOpts, // internal option, don't want to expose to external caller allowDiskReload = false ): Promise { @@ -322,7 +322,7 @@ async function processSlotsByCheckpoint( preState: CachedBeaconStateAllForks, slot: Slot, regenCaller: RegenCaller, - opts: StateCloneOpts + opts: StateRegenerationOpts ): Promise { let postState = await processSlotsToNearestCheckpoint(modules, preState, slot, regenCaller, opts); if (postState.slot < slot) { @@ -343,7 +343,7 @@ async function processSlotsToNearestCheckpoint( preState: CachedBeaconStateAllForks, slot: Slot, regenCaller: RegenCaller, - opts: StateCloneOpts + opts: StateRegenerationOpts ): Promise { const preSlot = preState.slot; const postSlot = slot; diff --git a/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts index f57c9a411923..7d87675b7bbc 100644 --- a/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts +++ b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts @@ -3,7 +3,7 @@ import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {Epoch, RootHex} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; -import {StateCloneOpts} from "../regen/interface.js"; +import {StateRegenerationOpts} from "../regen/interface.js"; import {MapTracker} from "./mapMetrics.js"; import {BlockStateCache} from "./types.js"; @@ -39,7 +39,7 @@ export class BlockStateCacheImpl implements BlockStateCache { } } - get(rootHex: RootHex, opts?: StateCloneOpts): CachedBeaconStateAllForks | null { + get(rootHex: RootHex, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null { this.metrics?.lookups.inc(); const item = this.head?.stateRoot === rootHex ? this.head.state : this.cache.get(rootHex); if (!item) { diff --git a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts index eec1fce5d6c2..a119efe66887 100644 --- a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts +++ b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts @@ -4,7 +4,7 @@ import {RootHex} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; import {LinkedList} from "../../util/array.js"; -import {StateCloneOpts} from "../regen/interface.js"; +import {StateRegenerationOpts} from "../regen/interface.js"; import {MapTracker} from "./mapMetrics.js"; import {BlockStateCache} from "./types.js"; @@ -93,7 +93,7 @@ export class FIFOBlockStateCache implements BlockStateCache { /** * Get a state from this cache given a state root hex. */ - get(rootHex: RootHex, opts?: StateCloneOpts): CachedBeaconStateAllForks | null { + get(rootHex: RootHex, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null { this.metrics?.lookups.inc(); const item = this.cache.get(rootHex); if (!item) { diff --git a/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts index 4caa6779f697..81562d669365 100644 --- a/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/inMemoryCheckpointsCache.ts @@ -3,7 +3,7 @@ import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {Epoch, RootHex, phase0} from "@lodestar/types"; import {MapDef, toRootHex} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; -import {StateCloneOpts} from "../regen/interface.js"; +import {StateRegenerationOpts} from "../regen/interface.js"; import {MapTracker} from "./mapMetrics.js"; import {CacheItemType, CheckpointStateCache} from "./types.js"; @@ -42,7 +42,7 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache { this.maxEpochs = maxEpochs; } - async getOrReload(cp: CheckpointHex, opts?: StateCloneOpts): Promise { + async getOrReload(cp: CheckpointHex, opts?: StateRegenerationOpts): Promise { return this.get(cp, opts); } @@ -54,7 +54,7 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache { async getOrReloadLatest( rootHex: string, maxEpoch: number, - opts?: StateCloneOpts + opts?: StateRegenerationOpts ): Promise { return this.getLatest(rootHex, maxEpoch, opts); } @@ -64,7 +64,7 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache { return 0; } - get(cp: CheckpointHex, opts?: StateCloneOpts): CachedBeaconStateAllForks | null { + get(cp: CheckpointHex, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null { this.metrics?.lookups.inc(); const cpKey = toCheckpointKey(cp); const item = this.cache.get(cpKey); @@ -98,7 +98,7 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache { /** * Searches for the latest cached state with a `root`, starting with `epoch` and descending */ - getLatest(rootHex: RootHex, maxEpoch: Epoch, opts?: StateCloneOpts): CachedBeaconStateAllForks | null { + getLatest(rootHex: RootHex, maxEpoch: Epoch, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null { // sort epochs in descending order, only consider epochs lte `epoch` const epochs = Array.from(this.epochIndex.keys()) .sort((a, b) => b - a) diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index a7e0a7cdecfe..9a08aaa75461 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -7,7 +7,7 @@ import {Logger, MapDef, fromHex, sleep, toHex, toRootHex} from "@lodestar/utils" import {Metrics} from "../../metrics/index.js"; import {AllocSource, BufferPool, BufferWithKey} from "../../util/bufferPool.js"; import {IClock} from "../../util/clock.js"; -import {StateCloneOpts} from "../regen/interface.js"; +import {StateRegenerationOpts} from "../regen/interface.js"; import {serializeState} from "../serializeState.js"; import {CPStateDatastore, DatastoreKey} from "./datastore/index.js"; import {MapTracker} from "./mapMetrics.js"; @@ -168,7 +168,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { * - Get block for processing * - Regen head state */ - async getOrReload(cp: CheckpointHex, opts?: StateCloneOpts): Promise { + async getOrReload(cp: CheckpointHex, opts?: StateRegenerationOpts): Promise { const stateOrStateBytesData = await this.getStateOrLoadDb(cp, opts); if (stateOrStateBytesData === null || isCachedBeaconState(stateOrStateBytesData)) { return stateOrStateBytesData?.clone(opts?.dontTransferCache) ?? null; @@ -240,7 +240,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { */ async getStateOrLoadDb( cp: CheckpointHex, - opts?: StateCloneOpts + opts?: StateRegenerationOpts ): Promise { const cpKey = toCacheKey(cp); const inMemoryState = this.get(cpKey, opts); @@ -272,7 +272,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { /** * Similar to get() api without reloading from disk */ - get(cpOrKey: CheckpointHex | string, opts?: StateCloneOpts): CachedBeaconStateAllForks | null { + get(cpOrKey: CheckpointHex | string, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null { this.metrics?.cpStateCache.lookups.inc(); const cpKey = typeof cpOrKey === "string" ? cpOrKey : toCacheKey(cpOrKey); const cacheItem = this.cache.get(cpKey); @@ -323,7 +323,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { /** * Searches in-memory state for the latest cached state with a `root` without reload, starting with `epoch` and descending */ - getLatest(rootHex: RootHex, maxEpoch: Epoch, opts?: StateCloneOpts): CachedBeaconStateAllForks | null { + getLatest(rootHex: RootHex, maxEpoch: Epoch, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null { // sort epochs in descending order, only consider epochs lte `epoch` const epochs = Array.from(this.epochIndex.keys()) .sort((a, b) => b - a) @@ -349,7 +349,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { async getOrReloadLatest( rootHex: RootHex, maxEpoch: Epoch, - opts?: StateCloneOpts + opts?: StateRegenerationOpts ): Promise { // sort epochs in descending order, only consider epochs lte `epoch` const epochs = Array.from(this.epochIndex.keys()) diff --git a/packages/beacon-node/src/chain/stateCache/types.ts b/packages/beacon-node/src/chain/stateCache/types.ts index 403b469dd352..19f05c23ee35 100644 --- a/packages/beacon-node/src/chain/stateCache/types.ts +++ b/packages/beacon-node/src/chain/stateCache/types.ts @@ -1,7 +1,7 @@ import {routes} from "@lodestar/api"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {Epoch, RootHex, phase0} from "@lodestar/types"; -import {StateCloneOpts} from "../regen/interface.js"; +import {StateRegenerationOpts} from "../regen/interface.js"; export type CheckpointHex = {epoch: Epoch; rootHex: RootHex}; @@ -21,7 +21,7 @@ export type CheckpointHex = {epoch: Epoch; rootHex: RootHex}; * The cache key is state root */ export interface BlockStateCache { - get(rootHex: RootHex, opts?: StateCloneOpts): CachedBeaconStateAllForks | null; + get(rootHex: RootHex, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null; add(item: CachedBeaconStateAllForks): void; setHeadState(item: CachedBeaconStateAllForks | null): void; /** @@ -60,15 +60,15 @@ export interface BlockStateCache { */ export interface CheckpointStateCache { init?: () => Promise; - getOrReload(cp: CheckpointHex, opts?: StateCloneOpts): Promise; + getOrReload(cp: CheckpointHex, opts?: StateRegenerationOpts): Promise; getStateOrBytes(cp: CheckpointHex): Promise; - get(cpOrKey: CheckpointHex | string, opts?: StateCloneOpts): CachedBeaconStateAllForks | null; + get(cpOrKey: CheckpointHex | string, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null; add(cp: phase0.Checkpoint, state: CachedBeaconStateAllForks): void; - getLatest(rootHex: RootHex, maxEpoch: Epoch, opts?: StateCloneOpts): CachedBeaconStateAllForks | null; + getLatest(rootHex: RootHex, maxEpoch: Epoch, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null; getOrReloadLatest( rootHex: RootHex, maxEpoch: Epoch, - opts?: StateCloneOpts + opts?: StateRegenerationOpts ): Promise; updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null; prune(finalizedEpoch: Epoch, justifiedEpoch: Epoch): void; diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 86e63c672024..af9e79bc831c 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -49,6 +49,7 @@ import { import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; +import {EpochTransitionCache} from "./epochTransitionCache.js"; import {Index2PubkeyCache, syncPubkeys} from "./pubkeyCache.js"; import {CachedBeaconStateAllForks} from "./stateCache.js"; import { @@ -605,14 +606,7 @@ export class EpochCache { * Steps for afterProcessEpoch * 1) update previous/current/next values of cached items */ - afterProcessEpoch( - state: CachedBeaconStateAllForks, - epochTransitionCache: { - nextShufflingDecisionRoot: RootHex; - nextShufflingActiveIndices: Uint32Array; - nextEpochTotalActiveBalanceByIncrement: number; - } - ): void { + afterProcessEpoch(state: CachedBeaconStateAllForks, epochTransitionCache: EpochTransitionCache): void { // Because the slot was incremented before entering this function the "next epoch" is actually the "current epoch" // in this context but that is not actually true because the state transition happens in the last 4 seconds of the // epoch. For the context of this function "upcoming epoch" is used to denote the epoch that will begin after this @@ -657,28 +651,35 @@ export class EpochCache { this.nextDecisionRoot = epochTransitionCache.nextShufflingDecisionRoot; this.nextActiveIndices = epochTransitionCache.nextShufflingActiveIndices; if (this.shufflingCache) { - this.nextShuffling = null; - // This promise will resolve immediately after the synchronous code of the state-transition runs. Until - // the build is done on a worker thread it will be calculated immediately after the epoch transition - // completes. Once the work is done concurrently it should be ready by time this get runs so the promise - // will resolve directly on the next spin of the event loop because the epoch transition and shuffling take - // about the same time to calculate so theoretically its ready now. Do not await here though in case it - // is not ready yet as the transition must not be asynchronous. - this.shufflingCache - .get(epochAfterUpcoming, this.nextDecisionRoot) - .then((shuffling) => { - if (!shuffling) { - throw new Error("EpochShuffling not returned from get in afterProcessEpoch"); - } - this.nextShuffling = shuffling; - }) - .catch((err) => { - this.shufflingCache?.logger?.error( - "EPOCH_CONTEXT_SHUFFLING_BUILD_ERROR", - {epoch: epochAfterUpcoming, decisionRoot: epochTransitionCache.nextShufflingDecisionRoot}, - err - ); + if (!epochTransitionCache.asyncShufflingCalculation) { + this.nextShuffling = this.shufflingCache.getSync(epochAfterUpcoming, this.nextDecisionRoot, { + state, + activeIndices: this.nextActiveIndices, }); + } else { + this.nextShuffling = null; + // This promise will resolve immediately after the synchronous code of the state-transition runs. Until + // the build is done on a worker thread it will be calculated immediately after the epoch transition + // completes. Once the work is done concurrently it should be ready by time this get runs so the promise + // will resolve directly on the next spin of the event loop because the epoch transition and shuffling take + // about the same time to calculate so theoretically its ready now. Do not await here though in case it + // is not ready yet as the transition must not be asynchronous. + this.shufflingCache + .get(epochAfterUpcoming, this.nextDecisionRoot) + .then((shuffling) => { + if (!shuffling) { + throw new Error("EpochShuffling not returned from get in afterProcessEpoch"); + } + this.nextShuffling = shuffling; + }) + .catch((err) => { + this.shufflingCache?.logger?.error( + "EPOCH_CONTEXT_SHUFFLING_BUILD_ERROR", + {epoch: epochAfterUpcoming, decisionRoot: epochTransitionCache.nextShufflingDecisionRoot}, + err + ); + }); + } } else { // Only for testing. shufflingCache should always be available in prod this.nextShuffling = computeEpochShuffling(state, this.nextActiveIndices, epochAfterUpcoming); diff --git a/packages/state-transition/src/cache/epochTransitionCache.ts b/packages/state-transition/src/cache/epochTransitionCache.ts index b21f940c28d5..d159ca5f3763 100644 --- a/packages/state-transition/src/cache/epochTransitionCache.ts +++ b/packages/state-transition/src/cache/epochTransitionCache.ts @@ -33,6 +33,10 @@ export type EpochTransitionCacheOpts = { * Assert progressive balances the same to EpochTransitionCache */ assertCorrectProgressiveBalances?: boolean; + /** + * Do not queue shuffling calculation async. Forces sync JIT calculation in afterProcessEpoch + */ + asyncShufflingCalculation?: boolean; }; /** @@ -176,6 +180,12 @@ export interface EpochTransitionCache { */ nextEpochTotalActiveBalanceByIncrement: number; + /** + * Compute the shuffling sync or async. Defaults to synchronous. Need to pass `true` with the + * `EpochTransitionCacheOpts` + */ + asyncShufflingCalculation: boolean; + /** * Track by validator index if it's active in the prev epoch. * Used in metrics @@ -387,7 +397,11 @@ export function beforeProcessEpoch( for (let i = 0; i < nextEpochShufflingActiveIndicesLength; i++) { nextShufflingActiveIndices[i] = nextEpochShufflingActiveValidatorIndices[i]; } - state.epochCtx.shufflingCache?.build(epochAfterNext, nextShufflingDecisionRoot, state, nextShufflingActiveIndices); + + const asyncShufflingCalculation = opts?.asyncShufflingCalculation ?? false; + if (asyncShufflingCalculation) { + state.epochCtx.shufflingCache?.build(epochAfterNext, nextShufflingDecisionRoot, state, nextShufflingActiveIndices); + } if (totalActiveStakeByIncrement < 1) { totalActiveStakeByIncrement = 1; @@ -514,6 +528,7 @@ export function beforeProcessEpoch( indicesToEject, nextShufflingDecisionRoot, nextShufflingActiveIndices, + asyncShufflingCalculation, // to be updated in processEffectiveBalanceUpdates nextEpochTotalActiveBalanceByIncrement: 0, isActivePrevEpoch, From 69ae688bed4b17f93801494aa16919888935c780 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Wed, 4 Dec 2024 14:11:06 +0100 Subject: [PATCH 222/259] chore: unpin nodejs version from 22.4 (#6982) * Revert "chore: pin nodejs version to 22.4 (#6964)" This reverts commit f20484bb4b6b5f3a27c624556d1e6fb9f448b969. * Don't revert formatting changes --------- Co-authored-by: Nico Flaig Co-authored-by: Cayman --- .github/workflows/benchmark.yml | 2 +- .github/workflows/binaries.yml | 2 +- .github/workflows/docs-check.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/publish-dev.yml | 2 +- .github/workflows/publish-rc.yml | 2 +- .github/workflows/publish-stable.yml | 2 +- .github/workflows/test-sim-merge.yml | 2 +- .github/workflows/test-sim.yml | 12 ++++++------ .github/workflows/test.yml | 14 +++++++------- Dockerfile | 6 +++--- 11 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 671434fe19ad..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: 22.4 + node-version: 22 check-latest: true cache: yarn - name: Node.js version diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 722894424b91..469b0803c378 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -42,7 +42,7 @@ jobs: sudo apt-get install -y build-essential python3 - uses: "./.github/actions/setup-and-build" with: - node: 22.4 + node: 22 - run: | mkdir -p dist yarn global add caxa@3.0.1 diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml index bd7310995d62..180f1c16fdaa 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: 22.4 + node-version: 22 cache: yarn - name: Node.js version id: node diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a4c0f18cdbe3..cec2bca86b4b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 22.4 + node-version: 22 check-latest: true cache: yarn diff --git a/.github/workflows/publish-dev.yml b/.github/workflows/publish-dev.yml index 4e8c76e0dfdd..cb08c5c8fae0 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: 22.4 + 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 936072de42c9..e16cbce814dc 100644 --- a/.github/workflows/publish-rc.yml +++ b/.github/workflows/publish-rc.yml @@ -61,7 +61,7 @@ jobs: - uses: "./.github/actions/setup-and-build" with: - node: 22.4 + node: 22 - name: Generate changelog run: node scripts/generate_changelog.mjs ${{ needs.tag.outputs.prev_tag }} ${{ needs.tag.outputs.tag }} CHANGELOG.md diff --git a/.github/workflows/publish-stable.yml b/.github/workflows/publish-stable.yml index c2909a7e4e24..26fee0ba6052 100644 --- a/.github/workflows/publish-stable.yml +++ b/.github/workflows/publish-stable.yml @@ -67,7 +67,7 @@ jobs: - uses: "./.github/actions/setup-and-build" with: - node: 22.4 + node: 22 - name: Generate changelog run: node scripts/generate_changelog.mjs ${{ needs.tag.outputs.prev_tag }} ${{ needs.tag.outputs.tag }} CHANGELOG.md diff --git a/.github/workflows/test-sim-merge.yml b/.github/workflows/test-sim-merge.yml index 0042a9337bc3..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: 22.4 + 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 fbe2691da637..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: 22.4 + 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: 22.4 + 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: 22.4 + 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: 22.4 + 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: 22.4 + 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: 22.4 + 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 5514f6e896b7..47e17c56f042 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22.4] + node: [22] steps: # - Uses YAML anchors in the future - uses: actions/checkout@v4 @@ -42,7 +42,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22.4] + node: [22] steps: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" @@ -71,7 +71,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22.4] + node: [22] steps: - uses: actions/checkout@v4 @@ -92,7 +92,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22.4] + node: [22] steps: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" @@ -131,7 +131,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22.4] + node: [22] steps: # - Uses YAML anchors in the future - uses: actions/checkout@v4 @@ -168,7 +168,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22.4] + node: [22] steps: # - Uses YAML anchors in the future - uses: actions/checkout@v4 @@ -192,7 +192,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22.4] + node: [22] steps: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" diff --git a/Dockerfile b/Dockerfile index 0ee8083c85e2..5a1f51bfcee6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # --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:22.4-slim AS build_src +FROM --platform=${BUILDPLATFORM:-amd64} node:22-slim AS build_src ARG COMMIT WORKDIR /usr/app RUN apt-get update && apt-get install -y g++ make python3 python3-setuptools && apt-get clean && rm -rf /var/lib/apt/lists/* @@ -21,7 +21,7 @@ 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:22.4-slim AS build_deps +FROM node:22-slim AS build_deps WORKDIR /usr/app RUN apt-get update && apt-get install -y g++ make python3 python3-setuptools && apt-get clean && rm -rf /var/lib/apt/lists/* @@ -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:22.4-slim +FROM node:22-slim WORKDIR /usr/app COPY --from=build_deps /usr/app . From b5fb76c8e65c59397f34e1ba6b06d618b6845f38 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 5 Dec 2024 20:23:19 +0100 Subject: [PATCH 223/259] chore: update bootnodes file url for holesky and sepolia (#7276) --- packages/cli/src/networks/holesky.ts | 2 +- packages/cli/src/networks/sepolia.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/networks/holesky.ts b/packages/cli/src/networks/holesky.ts index 63bc6e07f8f2..ed1dd7c78462 100644 --- a/packages/cli/src/networks/holesky.ts +++ b/packages/cli/src/networks/holesky.ts @@ -3,7 +3,7 @@ export {holeskyChainConfig as chainConfig} from "@lodestar/config/networks"; export const depositContractDeployBlock = 0; export const genesisFileUrl = "https://media.githubusercontent.com/media/eth-clients/holesky/main/metadata/genesis.ssz"; export const bootnodesFileUrl = - "https://raw.githubusercontent.com/eth-clients/holesky/main/metadata/bootstrap_nodes.txt"; + "https://raw.githubusercontent.com/eth-clients/holesky/main/metadata/bootstrap_nodes.yaml"; export const bootEnrs = [ "enr:-Ku4QFo-9q73SspYI8cac_4kTX7yF800VXqJW4Lj3HkIkb5CMqFLxciNHePmMt4XdJzHvhrCC5ADI4D_GkAsxGJRLnQBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpAhnTT-AQFwAP__________gmlkgnY0gmlwhLKAiOmJc2VjcDI1NmsxoQORcM6e19T1T9gi7jxEZjk_sjVLGFscUNqAY9obgZaxbIN1ZHCCIyk", diff --git a/packages/cli/src/networks/sepolia.ts b/packages/cli/src/networks/sepolia.ts index 9dfd5dc20a0f..6900ca493057 100644 --- a/packages/cli/src/networks/sepolia.ts +++ b/packages/cli/src/networks/sepolia.ts @@ -3,7 +3,7 @@ export {sepoliaChainConfig as chainConfig} from "@lodestar/config/networks"; export const depositContractDeployBlock = 1273020; export const genesisFileUrl = "https://github.com/eth-clients/sepolia/raw/main/metadata/genesis.ssz"; export const bootnodesFileUrl = - "https://raw.githubusercontent.com/eth-clients/sepolia/main/metadata/bootstrap_nodes.txt"; + "https://raw.githubusercontent.com/eth-clients/sepolia/main/metadata/bootstrap_nodes.yaml"; export const bootEnrs = [ "enr:-KO4QP7MmB3juk8rUjJHcUoxZDU9Np4FlW0HyDEGIjSO7GD9PbSsabu7713cWSUWKDkxIypIXg1A-6lG7ySRGOMZHeGCAmuEZXRoMpDTH2GRkAAAc___________gmlkgnY0gmlwhBSoyGOJc2VjcDI1NmsxoQNta5b_bexSSwwrGW2Re24MjfMntzFd0f2SAxQtMj3ueYN0Y3CCIyiDdWRwgiMo", From d55bb2da72533e5ce01b29620ad9cf7d923abc74 Mon Sep 17 00:00:00 2001 From: acolytec3 <17355484+acolytec3@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:24:31 -0500 Subject: [PATCH 224/259] feat: add `debug_getHistoricalSummaries` endpoint (#7245) * feat: add new getHistoricalSummaries endpoint to debug namespace * Add JSON response * Restructure to use stateId and add proof to response * add test scaffolding * Address feedback * Move getHistoricalSummaries to lodestar namespace * add lodestar namespace unit test * update route name to lodestar namespace * cast state object as Capella state * Lint * json properties need to be lower case * Make it v1 since it's now part of lodestar namespace * Group with other /lodestar endpoints * Simplify beacon node impl * Rename return type * Update test description * Fix variable name --------- Co-authored-by: Nico Flaig --- packages/api/src/beacon/routes/lodestar.ts | 41 +++++++++++++- .../beacon/genericServerTest/lodestar.test.ts | 53 +++++++++++++++++++ .../beacon-node/src/api/impl/debug/index.ts | 2 +- .../src/api/impl/lodestar/index.ts | 29 +++++++++- packages/types/src/capella/sszTypes.ts | 6 ++- 5 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 packages/api/test/unit/beacon/genericServerTest/lodestar.test.ts diff --git a/packages/api/src/beacon/routes/lodestar.ts b/packages/api/src/beacon/routes/lodestar.ts index 81191efd2696..de05b7f2bb44 100644 --- a/packages/api/src/beacon/routes/lodestar.ts +++ b/packages/api/src/beacon/routes/lodestar.ts @@ -1,8 +1,11 @@ +import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; -import {Epoch, RootHex, Slot} from "@lodestar/types"; +import {Epoch, RootHex, Slot, ssz} from "@lodestar/types"; import { + ArrayOf, EmptyArgs, EmptyMeta, + EmptyMetaCodec, EmptyRequest, EmptyRequestCodec, EmptyResponseCodec, @@ -10,6 +13,7 @@ import { JsonOnlyResponseCodec, } from "../../utils/codecs.js"; import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; +import {StateArgs} from "./beacon/state.js"; import {FilterGetPeers, NodePeer, PeerDirection, PeerState} from "./node.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes @@ -75,6 +79,16 @@ export type LodestarNodePeer = NodePeer & { export type LodestarThreadType = "main" | "network" | "discv5"; +const HistoricalSummariesResponseType = new ContainerType( + { + historicalSummaries: ssz.capella.HistoricalSummaries, + proof: ArrayOf(ssz.Bytes8), + }, + {jsonCase: "eth2"} +); + +export type HistoricalSummariesResponse = ValueOf; + export type Endpoints = { /** Trigger to write a heapdump to disk at `dirpath`. May take > 1min */ writeHeapdump: Endpoint< @@ -214,6 +228,16 @@ export type Endpoints = { {count: number} >; + /** Returns historical summaries and proof for a given state ID */ + getHistoricalSummaries: Endpoint< + // ⏎ + "GET", + StateArgs, + {params: {state_id: string}}, + HistoricalSummariesResponse, + EmptyMeta + >; + /** Dump Discv5 Kad values */ discv5GetKadValues: Endpoint< // ⏎ @@ -365,6 +389,21 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions ({params: {state_id: stateId.toString()}}), + parseReq: ({params}) => ({stateId: params.state_id}), + schema: { + params: {state_id: Schema.StringRequired}, + }, + }, + resp: { + data: HistoricalSummariesResponseType, + meta: EmptyMetaCodec, + }, + }, discv5GetKadValues: { url: "/eth/v1/debug/discv5_kad_values", method: "GET", diff --git a/packages/api/test/unit/beacon/genericServerTest/lodestar.test.ts b/packages/api/test/unit/beacon/genericServerTest/lodestar.test.ts new file mode 100644 index 000000000000..b0f78f4bd62c --- /dev/null +++ b/packages/api/test/unit/beacon/genericServerTest/lodestar.test.ts @@ -0,0 +1,53 @@ +import {config} from "@lodestar/config/default"; +import {FastifyInstance} from "fastify"; +import {afterAll, beforeAll, describe, expect, it, vi} from "vitest"; +import {getClient} from "../../../../src/beacon/client/lodestar.js"; +import {Endpoints, getDefinitions} from "../../../../src/beacon/routes/lodestar.js"; +import {getRoutes} from "../../../../src/beacon/server/lodestar.js"; +import {HttpClient} from "../../../../src/utils/client/httpClient.js"; +import {AnyEndpoint} from "../../../../src/utils/codecs.js"; +import {FastifyRoute} from "../../../../src/utils/server/index.js"; +import {WireFormat} from "../../../../src/utils/wireFormat.js"; +import {getMockApi, getTestServer} from "../../../utils/utils.js"; + +describe("beacon / lodestar", () => { + describe("get HistoricalSummaries as json", () => { + const mockApi = getMockApi(getDefinitions(config)); + let baseUrl: string; + let server: FastifyInstance; + + beforeAll(async () => { + const res = getTestServer(); + server = res.server; + for (const route of Object.values(getRoutes(config, mockApi))) { + server.route(route as FastifyRoute); + } + baseUrl = await res.start(); + }); + + afterAll(async () => { + if (server !== undefined) await server.close(); + }); + + it("getHistoricalSummaries", async () => { + mockApi.getHistoricalSummaries.mockResolvedValue({ + data: { + historicalSummaries: [], + proof: [], + }, + }); + + const httpClient = new HttpClient({baseUrl}); + const client = getClient(config, httpClient); + + const res = await client.getHistoricalSummaries({stateId: "head"}, {responseWireFormat: WireFormat.json}); + + expect(res.ok).toBe(true); + expect(res.wireFormat()).toBe(WireFormat.json); + expect(res.json().data).toStrictEqual({ + historical_summaries: [], + proof: [], + }); + }); + }); +}); diff --git a/packages/beacon-node/src/api/impl/debug/index.ts b/packages/beacon-node/src/api/impl/debug/index.ts index e6c104272237..a004bd80e8f2 100644 --- a/packages/beacon-node/src/api/impl/debug/index.ts +++ b/packages/beacon-node/src/api/impl/debug/index.ts @@ -2,7 +2,7 @@ import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; import {ExecutionStatus} from "@lodestar/fork-choice"; import {ZERO_HASH_HEX} from "@lodestar/params"; -import {BeaconState} from "@lodestar/types"; +import {BeaconState, ssz} from "@lodestar/types"; import {isOptimisticBlock} from "../../../util/forkChoice.js"; import {getStateSlotFromBytes} from "../../../util/multifork.js"; import {getStateResponseWithRegen} from "../beacon/state/utils.js"; diff --git a/packages/beacon-node/src/api/impl/lodestar/index.ts b/packages/beacon-node/src/api/impl/lodestar/index.ts index 10787194f5f5..aeef2e11a83e 100644 --- a/packages/beacon-node/src/api/impl/lodestar/index.ts +++ b/packages/beacon-node/src/api/impl/lodestar/index.ts @@ -1,11 +1,12 @@ import fs from "node:fs"; import path from "node:path"; +import {Tree} from "@chainsafe/persistent-merkle-tree"; import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; import {ChainForkConfig} from "@lodestar/config"; import {Repository} from "@lodestar/db"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {getLatestWeakSubjectivityCheckpointEpoch} from "@lodestar/state-transition"; +import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {BeaconStateCapella, getLatestWeakSubjectivityCheckpointEpoch, loadState} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; import {toHex, toRootHex} from "@lodestar/utils"; import {BeaconChain} from "../../../chain/index.js"; @@ -13,6 +14,7 @@ import {QueuedStateRegenerator, RegenRequest} from "../../../chain/regen/index.j import {IBeaconDb} from "../../../db/interface.js"; import {GossipType} from "../../../network/index.js"; import {profileNodeJS, writeHeapSnapshot} from "../../../util/profile.js"; +import {getStateResponseWithRegen} from "../beacon/state/utils.js"; import {ApiModules} from "../types.js"; export function getLodestarApi({ @@ -187,6 +189,29 @@ export function getLodestarApi({ async dumpDbStateIndex() { return {data: await db.stateArchive.dumpRootIndexEntries()}; }, + + async getHistoricalSummaries({stateId}) { + const {state} = await getStateResponseWithRegen(chain, stateId); + + const stateView = ( + state instanceof Uint8Array ? loadState(config, chain.getHeadState(), state).state : state.clone() + ) as BeaconStateCapella; + + const fork = config.getForkName(stateView.slot); + if (ForkSeq[fork] < ForkSeq.capella) { + throw new Error("Historical summaries are not supported before Capella"); + } + + const {gindex} = ssz[fork].BeaconState.getPathInfo(["historicalSummaries"]); + const proof = new Tree(stateView.node).getSingleProof(gindex); + + return { + data: { + historicalSummaries: stateView.historicalSummaries.toValue(), + proof: proof, + }, + }; + }, }; } diff --git a/packages/types/src/capella/sszTypes.ts b/packages/types/src/capella/sszTypes.ts index 3110e59111d9..057bf97650fe 100644 --- a/packages/types/src/capella/sszTypes.ts +++ b/packages/types/src/capella/sszTypes.ts @@ -125,6 +125,10 @@ export const HistoricalSummary = new ContainerType( {typeName: "HistoricalSummary", jsonCase: "eth2"} ); +export const HistoricalSummaries = new ListCompositeType(HistoricalSummary, HISTORICAL_ROOTS_LIMIT, { + typeName: "HistoricalSummaries", +}); + // we don't reuse bellatrix.BeaconState fields since we need to replace some keys // and we cannot keep order doing that export const BeaconState = new ContainerType( @@ -168,7 +172,7 @@ export const BeaconState = new ContainerType( nextWithdrawalIndex: WithdrawalIndex, // [New in Capella] nextWithdrawalValidatorIndex: ValidatorIndex, // [New in Capella] // Deep history valid from Capella onwards - historicalSummaries: new ListCompositeType(HistoricalSummary, HISTORICAL_ROOTS_LIMIT), // [New in Capella] + historicalSummaries: HistoricalSummaries, // [New in Capella] }, {typeName: "BeaconState", jsonCase: "eth2"} ); From 86ed6f45d548f00ef54a1d35ac20387923762563 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 6 Dec 2024 09:38:42 +0100 Subject: [PATCH 225/259] chore: log sync committee signature errors as `error` (#7283) --- packages/beacon-node/src/api/impl/beacon/pool/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index 45fb763d9540..c283d6d3214c 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -257,7 +257,7 @@ export function getBeaconPoolApi({ } failures.push({index: i, message: (e as Error).message}); - logger.debug( + logger.error( `Error on submitPoolSyncCommitteeSignatures [${i}]`, {slot: signature.slot, validatorIndex: signature.validatorIndex}, e as Error From cd1211fef36976f459097ac6765b7822d5a86595 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 6 Dec 2024 09:56:25 +0100 Subject: [PATCH 226/259] fix: update engine_getClientVersionV1 commit encoding (#7282) --- packages/beacon-node/src/execution/engine/http.ts | 5 +++-- packages/beacon-node/src/util/kzg.ts | 9 +-------- packages/config/src/genesisConfig/index.ts | 6 +----- packages/utils/src/format.ts | 7 +++++++ 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index ea064d2fe816..0d2656ae46e2 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -2,6 +2,7 @@ import {Logger} from "@lodestar/logger"; import {ForkName, ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ExecutionPayload, ExecutionRequests, Root, RootHex, Wei} from "@lodestar/types"; import {BlobAndProof} from "@lodestar/types/deneb"; +import {strip0xPrefix} from "@lodestar/utils"; import { ErrorJsonRpcResponse, HttpRpcError, @@ -522,11 +523,11 @@ export class ExecutionEngineHttp implements IExecutionEngine { const response = await this.rpc.fetchWithRetries< EngineApiRpcReturnTypes[typeof method], EngineApiRpcParamTypes[typeof method] - >({method, params: [clientVersion]}); + >({method, params: [{...clientVersion, commit: `0x${clientVersion.commit}`}]}); const clientVersions = response.map((cv) => { const code = cv.code in ClientCode ? ClientCode[cv.code as keyof typeof ClientCode] : ClientCode.XX; - return {code, name: cv.name, version: cv.version, commit: cv.commit}; + return {code, name: cv.name, version: cv.version, commit: strip0xPrefix(cv.commit)}; }); if (clientVersions.length === 0) { diff --git a/packages/beacon-node/src/util/kzg.ts b/packages/beacon-node/src/util/kzg.ts index 36a7d19f8d2b..696eeae73370 100644 --- a/packages/beacon-node/src/util/kzg.ts +++ b/packages/beacon-node/src/util/kzg.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; import {fileURLToPath} from "node:url"; -import {fromHex, toHex} from "@lodestar/utils"; +import {fromHex, strip0xPrefix, toHex} from "@lodestar/utils"; // "c-kzg" has hardcoded the mainnet value, do not use params export const FIELD_ELEMENTS_PER_BLOB_MAINNET = 4096; @@ -154,10 +154,3 @@ export function trustedSetupJsonToTxt(data: TrustedSetupJSON): TrustedSetupTXT { ...data.setup_G2.map(strip0xPrefix), ].join("\n"); } - -function strip0xPrefix(hex: string): string { - if (hex.startsWith("0x")) { - return hex.slice(2); - } - return hex; -} diff --git a/packages/config/src/genesisConfig/index.ts b/packages/config/src/genesisConfig/index.ts index dad79df1a98d..992185461b58 100644 --- a/packages/config/src/genesisConfig/index.ts +++ b/packages/config/src/genesisConfig/index.ts @@ -1,6 +1,6 @@ import {DOMAIN_VOLUNTARY_EXIT, ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {DomainType, ForkDigest, Root, Slot, Version, phase0, ssz} from "@lodestar/types"; -import {toHex} from "@lodestar/utils"; +import {strip0xPrefix, toHex} from "@lodestar/utils"; import {ChainForkConfig} from "../beaconConfig.js"; import {CachedGenesis, ForkDigestHex} from "./types.js"; export type {ForkDigestContext} from "./types.js"; @@ -142,10 +142,6 @@ function toHexStringNoPrefix(hex: string | Uint8Array): string { return strip0xPrefix(typeof hex === "string" ? hex : toHex(hex)); } -function strip0xPrefix(hex: string): string { - return hex.startsWith("0x") ? hex.slice(2) : hex; -} - function computeForkDigest(currentVersion: Version, genesisValidatorsRoot: Root): ForkDigest { return computeForkDataRoot(currentVersion, genesisValidatorsRoot).slice(0, 4); } diff --git a/packages/utils/src/format.ts b/packages/utils/src/format.ts index b36412072720..94bf0d635ced 100644 --- a/packages/utils/src/format.ts +++ b/packages/utils/src/format.ts @@ -65,3 +65,10 @@ export function prettyMsToTime(timeMs: number): string { const date = new Date(0, 0, 0, 0, 0, 0, timeMs); return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}.${date.getMilliseconds()}`; } + +/** + * Remove 0x prefix from a string + */ +export function strip0xPrefix(hex: string): string { + return hex.startsWith("0x") ? hex.slice(2) : hex; +} From e353f67426581e622c6df83c30992b4a28dcb617 Mon Sep 17 00:00:00 2001 From: twoeths Date: Fri, 6 Dec 2024 16:30:33 +0700 Subject: [PATCH 227/259] fix: check pubkey or validator index known to a state (#7284) * fix: check pubkey or validator index known to a state * chore: add more comments --- .../src/block/processConsolidationRequest.ts | 7 ++++++- .../src/epoch/processPendingDeposits.ts | 6 +++--- packages/state-transition/src/util/electra.ts | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/state-transition/src/block/processConsolidationRequest.ts b/packages/state-transition/src/block/processConsolidationRequest.ts index d0650135d0c6..1a1d83eee0be 100644 --- a/packages/state-transition/src/block/processConsolidationRequest.ts +++ b/packages/state-transition/src/block/processConsolidationRequest.ts @@ -3,7 +3,7 @@ import {electra, ssz} from "@lodestar/types"; import {CachedBeaconStateElectra} from "../types.js"; import {hasEth1WithdrawalCredential} from "../util/capella.js"; -import {hasExecutionWithdrawalCredential, switchToCompoundingValidator} from "../util/electra.js"; +import {hasExecutionWithdrawalCredential, isPubkeyKnown, switchToCompoundingValidator} from "../util/electra.js"; import {computeConsolidationEpochAndUpdateChurn} from "../util/epoch.js"; import {getConsolidationChurnLimit, isActiveValidator} from "../util/validator.js"; @@ -13,6 +13,10 @@ export function processConsolidationRequest( consolidationRequest: electra.ConsolidationRequest ): void { const {sourcePubkey, targetPubkey, sourceAddress} = consolidationRequest; + if (!isPubkeyKnown(state, sourcePubkey) || !isPubkeyKnown(state, targetPubkey)) { + return; + } + const sourceIndex = state.epochCtx.getValidatorIndex(sourcePubkey); const targetIndex = state.epochCtx.getValidatorIndex(targetPubkey); @@ -97,6 +101,7 @@ function isValidSwitchToCompoundRequest( // Verify pubkey exists if (sourceIndex === null) { + // this check is mainly to make the compiler happy, pubkey is checked by the consumer already return false; } diff --git a/packages/state-transition/src/epoch/processPendingDeposits.ts b/packages/state-transition/src/epoch/processPendingDeposits.ts index d925aa1cc741..441d5601a380 100644 --- a/packages/state-transition/src/epoch/processPendingDeposits.ts +++ b/packages/state-transition/src/epoch/processPendingDeposits.ts @@ -3,7 +3,7 @@ import {PendingDeposit} from "@lodestar/types/lib/electra/types.js"; import {addValidatorToRegistry, isValidDepositSignature} from "../block/processDeposit.js"; import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; import {increaseBalance} from "../util/balance.js"; -import {hasCompoundingWithdrawalCredential} from "../util/electra.js"; +import {hasCompoundingWithdrawalCredential, isValidatorKnown} from "../util/electra.js"; import {computeStartSlotAtEpoch} from "../util/epoch.js"; import {getActivationExitChurnLimit} from "../util/validator.js"; @@ -51,7 +51,7 @@ export function processPendingDeposits(state: CachedBeaconStateElectra, cache: E let isValidatorWithdrawn = false; const validatorIndex = state.epochCtx.getValidatorIndex(deposit.pubkey); - if (validatorIndex !== null) { + if (isValidatorKnown(state, validatorIndex)) { const validator = state.validators.getReadonly(validatorIndex); isValidatorExited = validator.exitEpoch < FAR_FUTURE_EPOCH; isValidatorWithdrawn = validator.withdrawableEpoch < nextEpoch; @@ -103,7 +103,7 @@ function applyPendingDeposit( const {pubkey, withdrawalCredentials, amount, signature} = deposit; const cachedBalances = cache.balances; - if (validatorIndex === null) { + if (!isValidatorKnown(state, validatorIndex)) { // Verify the deposit signature (proof of possession) which is not checked by the deposit contract if (isValidDepositSignature(state.config, pubkey, withdrawalCredentials, amount, signature)) { addValidatorToRegistry(ForkSeq.electra, state, pubkey, withdrawalCredentials, amount); diff --git a/packages/state-transition/src/util/electra.ts b/packages/state-transition/src/util/electra.ts index f5b899eadcab..a9736dc8161e 100644 --- a/packages/state-transition/src/util/electra.ts +++ b/packages/state-transition/src/util/electra.ts @@ -45,3 +45,20 @@ export function queueExcessActiveBalance(state: CachedBeaconStateElectra, index: state.pendingDeposits.push(pendingDeposit); } } + +/** + * Since we share pubkey2index, pubkey maybe added by other epoch transition but we don't have that validator in this state + */ +export function isPubkeyKnown(state: CachedBeaconStateElectra, pubkey: Uint8Array): boolean { + return isValidatorKnown(state, state.epochCtx.getValidatorIndex(pubkey)); +} + +/** + * Since we share pubkey2index, validatorIndex maybe not null but we don't have that validator in this state + */ +export function isValidatorKnown( + state: CachedBeaconStateElectra, + index: ValidatorIndex | null +): index is ValidatorIndex { + return index !== null && index < state.validators.length; +} From f87eb0b2c74e42ea72324392380f28c5047477a1 Mon Sep 17 00:00:00 2001 From: Varun Guleria <152203177+varunguleriaCodes@users.noreply.github.com> Date: Fri, 6 Dec 2024 20:19:45 +0530 Subject: [PATCH 228/259] feat: lodestar script setup (#7254) * feat: lodestar_setup * feat: script_updates + docs * feat: script_addition_in_docs + command_update * Remove duplicate script from docs folder * Minor script updates * Update script to prepare docs and ignore copied file * Update installation page * Wording --------- Co-authored-by: Nico Flaig --- .gitignore | 1 + .../pages/run/getting-started/installation.md | 6 ++ scripts/install-binary.sh | 91 +++++++++++++++++++ scripts/prepare-docs.sh | 3 + 4 files changed, 101 insertions(+) create mode 100755 scripts/install-binary.sh diff --git a/.gitignore b/.gitignore index 52d9bc66e5b6..e54f7440864d 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ docs/pages/libraries/lightclient-prover/lightclient.md docs/pages/libraries/lightclient-prover/prover.md docs/pages/api/api-reference.md docs/pages/contribution/getting-started.md +docs/static/install ## Docusaurus docs/.docusaurus/ docs/build/ diff --git a/docs/pages/run/getting-started/installation.md b/docs/pages/run/getting-started/installation.md index 40c4865f7726..b2b4003f90a5 100644 --- a/docs/pages/run/getting-started/installation.md +++ b/docs/pages/run/getting-started/installation.md @@ -4,6 +4,12 @@ Binaries can be downloaded from the Lodestar [release page](https://github.com/ChainSafe/lodestar/releases/latest) under the `Assets` section. +Run the following command to install the latest version + +```bash +curl -fsSL https://chainsafe.github.io/lodestar/install | bash +``` + ## Docker Installation The [`chainsafe/lodestar`](https://hub.docker.com/r/chainsafe/lodestar) Docker Hub repository is maintained actively. It contains the `lodestar` CLI preinstalled. diff --git a/scripts/install-binary.sh b/scripts/install-binary.sh new file mode 100755 index 000000000000..f6db9948eeda --- /dev/null +++ b/scripts/install-binary.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +# ASCII art +echo " _ _ _ " +echo " | | | | | | " +echo " | | ___ __| | ___ ___| |_ __ _ _ __ " +echo " | |/ _ \ / _ |/ _ \/ __| __/ _ | __|" +echo " | | (_) | (_| | __/\__ \ || (_| | | " +echo " |_|\___/ \__ _|\___||___/\__\__ _|_| " +echo "" + +# Declare directories +TEMP_DIR=$(mktemp -d) +LOCAL_BIN="$HOME/.local/bin" + +# Ensure ~/.local/bin exists +mkdir -p "$LOCAL_BIN" + +# Inform the user about temporary directory usage +echo "Using temporary directory: $TEMP_DIR" + +# Fetch the latest release tag from GitHub +echo "Fetching the latest version information..." +VERSION=$(curl -s "https://api.github.com/repos/ChainSafe/lodestar/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + +# Check if VERSION is empty +if [ -z "$VERSION" ]; then + echo "Failed to fetch the latest version. Exiting." + exit 1 +fi + +echo "Latest version detected: $VERSION" + +# Detect the operating system and architecture +OS=$(uname -s) +ARCH=$(uname -m) + +# Translate architecture to expected format +case $ARCH in + x86_64) ARCH="amd64" ;; + aarch64|arm64) ARCH="arm64" ;; + *) + echo "Unsupported architecture: $ARCH. Exiting." + exit 1 + ;; +esac + +# Translate OS to expected format +case $OS in + Linux) PLATFORM="linux-$ARCH" ;; + *) + echo "Unsupported operating system: $OS. Exiting." + exit 1 + ;; +esac + +# Construct the download URL +URL="https://github.com/ChainSafe/lodestar/releases/download/$VERSION/lodestar-$VERSION-$PLATFORM.tar.gz" +echo "Downloading from: $URL" + +# Download the tarball +if ! wget "$URL" -O "$TEMP_DIR/lodestar-$VERSION-$PLATFORM.tar.gz"; then + echo "Download failed. Exiting." + exit 1 +fi + +# Extract the tarball +echo "Extracting the binary..." +if ! tar -xzf "$TEMP_DIR/lodestar-$VERSION-$PLATFORM.tar.gz" -C "$TEMP_DIR"; then + echo "Extraction failed. Exiting." + exit 1 +fi + +# Move the binary to ~/.local/bin +echo "Moving the binary to $LOCAL_BIN..." +mv "$TEMP_DIR/lodestar" "$LOCAL_BIN/" +chmod +x "$LOCAL_BIN/lodestar" + +# Verify if ~/.local/bin is in PATH +if [[ ":$PATH:" != *":$LOCAL_BIN:"* ]]; then + echo "Adding $LOCAL_BIN to PATH..." + echo 'export PATH="$PATH:$HOME/.local/bin"' >> "$HOME/.bashrc" + echo "Run 'source ~/.bashrc' to apply changes to your shell." +fi + +# Clean up the temporary directory +rm -rf "$TEMP_DIR" + +# Inform the user of successful installation +echo "Installation complete!" +echo "Run 'lodestar --help' to get started." diff --git a/scripts/prepare-docs.sh b/scripts/prepare-docs.sh index d2bac519a7f2..2fa16a7cc759 100755 --- a/scripts/prepare-docs.sh +++ b/scripts/prepare-docs.sh @@ -17,3 +17,6 @@ cp -r packages/prover/README.md $DOCS_DIR/pages/libraries/lightclient-prover/pro # Copy visual assets rm -rf $DOCS_DIR/pages/assets $DOCS_DIR/pages/images cp -r $ASSETS_DIR $DOCS_DIR/pages/assets + +# Copy binary install script to docs +cp scripts/install-binary.sh $DOCS_DIR/static/install From dad9037e7739d5bcbccfe627e715ef40e9ba935b Mon Sep 17 00:00:00 2001 From: ClockworkYuzu Date: Fri, 6 Dec 2024 13:00:13 -0800 Subject: [PATCH 229/259] feat: add terminal-sized Electra giraffe banner (#7286) * Create giraffeBanners.ts * Wire in banner * Fix file name * lint * Address @nflaig's comment --------- Co-authored-by: NC <17676176+ensi321@users.noreply.github.com> --- .../src/chain/blocks/utils/giraffeBanner.ts | 27 +++++++++++++++++++ .../src/chain/blocks/verifyBlock.ts | 6 +++++ 2 files changed, 33 insertions(+) create mode 100644 packages/beacon-node/src/chain/blocks/utils/giraffeBanner.ts diff --git a/packages/beacon-node/src/chain/blocks/utils/giraffeBanner.ts b/packages/beacon-node/src/chain/blocks/utils/giraffeBanner.ts new file mode 100644 index 000000000000..d3987831a064 --- /dev/null +++ b/packages/beacon-node/src/chain/blocks/utils/giraffeBanner.ts @@ -0,0 +1,27 @@ +export const ELECTRA_GIRAFFE_BANNER = String.raw` + 2048 + :--: + :-@==+-: + :-=++#+#++#> + :-=+=#+: + ::+*--@-*: + :-+=%*#%@-: + MAXEB**=+%*+: + :-*###+*#*=-: + :--=+*+==#*=-: + :-*=+#*=*-#*+%@%%%#*+: + -=+-+**#+#%%%*#@@+%%#=#% + 32 -*=*+#+=%*#%*#%#+*##***-: + : #+**+*+=*+*%*%%*==++@**=: + =++++=: ::----:: +=-@*: + +++=- -++ =+: + -=@ :+- -+ + :-: :+: :- + :+ := -= + := - @ + - @ : + -: -: - + *: :- =- + :- --: =: + ::*-: :::: :-: +`; diff --git a/packages/beacon-node/src/chain/blocks/verifyBlock.ts b/packages/beacon-node/src/chain/blocks/verifyBlock.ts index 5ead67a720f7..2ce78eb5f3f1 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlock.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlock.ts @@ -15,6 +15,7 @@ import {BlockProcessOpts} from "../options.js"; import {RegenCaller} from "../regen/index.js"; import {BlockInput, BlockInputType, ImportBlockOpts} from "./types.js"; import {DENEB_BLOWFISH_BANNER} from "./utils/blowfishBanner.js"; +import {ELECTRA_GIRAFFE_BANNER} from "./utils/giraffeBanner.js"; import {CAPELLA_OWL_BANNER} from "./utils/ownBanner.js"; import {POS_PANDA_MERGE_TRANSITION_BANNER} from "./utils/pandaMergeTransitionBanner.js"; import {verifyBlocksDataAvailability} from "./verifyBlocksDataAvailability.js"; @@ -157,6 +158,11 @@ export async function verifyBlocksInEpoch( this.logger.info("Activating blobs", {epoch: this.config.DENEB_FORK_EPOCH}); break; + case ForkName.electra: + this.logger.info(ELECTRA_GIRAFFE_BANNER); + this.logger.info("Activating maxEB", {epoch: this.config.ELECTRA_FORK_EPOCH}); + break; + default: } } From 99794d3b261bb50f9a6c7d9f6ca19291b3f30911 Mon Sep 17 00:00:00 2001 From: Cayman Date: Thu, 12 Dec 2024 13:16:55 -0500 Subject: [PATCH 230/259] chore: pin nodejs version to 22.4 (#7291) Revert "chore: unpin nodejs version from 22.4 (#6982)" This reverts commit 69ae688bed4b17f93801494aa16919888935c780. --- .github/workflows/benchmark.yml | 2 +- .github/workflows/binaries.yml | 2 +- .github/workflows/docs-check.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/publish-dev.yml | 2 +- .github/workflows/publish-rc.yml | 2 +- .github/workflows/publish-stable.yml | 2 +- .github/workflows/test-sim-merge.yml | 2 +- .github/workflows/test-sim.yml | 12 ++++++------ .github/workflows/test.yml | 14 +++++++------- Dockerfile | 6 +++--- 11 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index e515bef7f92a..671434fe19ad 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: 22 + node-version: 22.4 check-latest: true cache: yarn - name: Node.js version diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 469b0803c378..722894424b91 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -42,7 +42,7 @@ jobs: sudo apt-get install -y build-essential python3 - uses: "./.github/actions/setup-and-build" with: - node: 22 + node: 22.4 - run: | mkdir -p dist yarn global add caxa@3.0.1 diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml index 180f1c16fdaa..bd7310995d62 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: 22 + node-version: 22.4 cache: yarn - name: Node.js version id: node diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index cec2bca86b4b..a4c0f18cdbe3 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 22 + node-version: 22.4 check-latest: true cache: yarn diff --git a/.github/workflows/publish-dev.yml b/.github/workflows/publish-dev.yml index cb08c5c8fae0..4e8c76e0dfdd 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: 22 + node-version: 22.4 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 e16cbce814dc..936072de42c9 100644 --- a/.github/workflows/publish-rc.yml +++ b/.github/workflows/publish-rc.yml @@ -61,7 +61,7 @@ jobs: - uses: "./.github/actions/setup-and-build" with: - node: 22 + node: 22.4 - name: Generate changelog run: node scripts/generate_changelog.mjs ${{ needs.tag.outputs.prev_tag }} ${{ needs.tag.outputs.tag }} CHANGELOG.md diff --git a/.github/workflows/publish-stable.yml b/.github/workflows/publish-stable.yml index 26fee0ba6052..c2909a7e4e24 100644 --- a/.github/workflows/publish-stable.yml +++ b/.github/workflows/publish-stable.yml @@ -67,7 +67,7 @@ jobs: - uses: "./.github/actions/setup-and-build" with: - node: 22 + node: 22.4 - name: Generate changelog run: node scripts/generate_changelog.mjs ${{ needs.tag.outputs.prev_tag }} ${{ needs.tag.outputs.tag }} CHANGELOG.md diff --git a/.github/workflows/test-sim-merge.yml b/.github/workflows/test-sim-merge.yml index ad79bc2c0035..0042a9337bc3 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: 22 + node-version: 22.4 check-latest: true cache: yarn - name: Node.js version diff --git a/.github/workflows/test-sim.yml b/.github/workflows/test-sim.yml index ff28149537d3..fbe2691da637 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: 22 + node: 22.4 sim-test-multifork: name: Multifork sim test @@ -42,7 +42,7 @@ jobs: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" with: - node: 22 + node: 22.4 - 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: 22 + node: 22.4 - 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: 22 + node: 22.4 - 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: 22 + node: 22.4 - 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: 22 + node: 22.4 - 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 47e17c56f042..5514f6e896b7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22] + node: [22.4] steps: # - Uses YAML anchors in the future - uses: actions/checkout@v4 @@ -42,7 +42,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22] + node: [22.4] steps: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" @@ -71,7 +71,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22] + node: [22.4] steps: - uses: actions/checkout@v4 @@ -92,7 +92,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22] + node: [22.4] steps: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" @@ -131,7 +131,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22] + node: [22.4] steps: # - Uses YAML anchors in the future - uses: actions/checkout@v4 @@ -168,7 +168,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22] + node: [22.4] steps: # - Uses YAML anchors in the future - uses: actions/checkout@v4 @@ -192,7 +192,7 @@ jobs: strategy: fail-fast: false matrix: - node: [22] + node: [22.4] steps: - uses: actions/checkout@v4 - uses: "./.github/actions/setup-and-build" diff --git a/Dockerfile b/Dockerfile index 5a1f51bfcee6..0ee8083c85e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # --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:22-slim AS build_src +FROM --platform=${BUILDPLATFORM:-amd64} node:22.4-slim AS build_src ARG COMMIT WORKDIR /usr/app RUN apt-get update && apt-get install -y g++ make python3 python3-setuptools && apt-get clean && rm -rf /var/lib/apt/lists/* @@ -21,7 +21,7 @@ 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:22-slim AS build_deps +FROM node:22.4-slim AS build_deps WORKDIR /usr/app RUN apt-get update && apt-get install -y g++ make python3 python3-setuptools && apt-get clean && rm -rf /var/lib/apt/lists/* @@ -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:22-slim +FROM node:22.4-slim WORKDIR /usr/app COPY --from=build_deps /usr/app . From 879f99bf87b7826bad8c2530a42f5ed16cf340b7 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 13 Dec 2024 21:29:10 +0100 Subject: [PATCH 231/259] feat: expose `DOMAIN_APPLICATION_MASK` in config/spec api (#7296) * feat: expose DOMAIN_APPLICATION_MASK in config/spec api * Lint --- packages/beacon-node/src/api/impl/config/constants.ts | 2 ++ packages/beacon-node/test/e2e/api/impl/config.test.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/api/impl/config/constants.ts b/packages/beacon-node/src/api/impl/config/constants.ts index c55cfe7008f4..6b390727cec3 100644 --- a/packages/beacon-node/src/api/impl/config/constants.ts +++ b/packages/beacon-node/src/api/impl/config/constants.ts @@ -7,6 +7,7 @@ import { DEPOSIT_CONTRACT_TREE_DEPTH, DOMAIN_AGGREGATE_AND_PROOF, DOMAIN_APPLICATION_BUILDER, + DOMAIN_APPLICATION_MASK, DOMAIN_BEACON_ATTESTER, DOMAIN_BEACON_PROPOSER, DOMAIN_BLS_TO_EXECUTION_CHANGE, @@ -67,6 +68,7 @@ export const specConstants = { DOMAIN_VOLUNTARY_EXIT, DOMAIN_SELECTION_PROOF, DOMAIN_AGGREGATE_AND_PROOF, + DOMAIN_APPLICATION_MASK, DOMAIN_APPLICATION_BUILDER, // phase0/validator.md diff --git a/packages/beacon-node/test/e2e/api/impl/config.test.ts b/packages/beacon-node/test/e2e/api/impl/config.test.ts index a878d41a36f0..474826050a3a 100644 --- a/packages/beacon-node/test/e2e/api/impl/config.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/config.test.ts @@ -60,7 +60,7 @@ async function downloadRemoteConstants(commit: string): Promise { const constantNames: string[] = []; for (const spec of await Promise.all(downloadedSpecs)) { - const matches = spec.matchAll(/\|\s`*([A-Z_]+)`\s\|/g); + const matches = spec.matchAll(/\|\s`*([A-Z_]+)`\s+\|/g); for (const match of matches) { constantNames.push(match[1]); } From 30c669b1f58d029e4ff821264796f041a45a55d9 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:51:29 -0800 Subject: [PATCH 232/259] feat: make `MAX_REQUEST_BLOB_SIDECARS` and `MAX_BLOBS_PER_BLOCK` configurable (#7294) * Init commit * Fix check-types * Add comment on how MAX_REQUEST_BLOB_SIDECARS is calculated * Ensure proper config object is passed * Address comment --------- Co-authored-by: Nico Flaig --- .../src/network/core/networkCore.ts | 16 +++++----- .../src/network/gossip/gossipsub.ts | 2 +- .../beacon-node/src/network/gossip/topic.ts | 6 ++-- packages/beacon-node/src/network/interface.ts | 3 +- packages/beacon-node/src/network/network.ts | 12 ++++---- .../src/network/reqresp/ReqRespBeaconNode.ts | 6 ++-- .../reqresp/handlers/blobSidecarsByRoot.ts | 5 ++-- .../src/network/reqresp/handlers/index.ts | 3 +- .../src/network/reqresp/protocols.ts | 8 ++--- .../src/network/reqresp/rateLimit.ts | 29 +++++++++---------- .../beacon-node/src/network/reqresp/types.ts | 12 ++++---- packages/beacon-node/src/util/types.ts | 7 ++++- .../config/src/chainConfig/configs/mainnet.ts | 3 ++ .../config/src/chainConfig/configs/minimal.ts | 3 ++ packages/config/src/chainConfig/types.ts | 4 +++ packages/params/src/index.ts | 2 -- packages/params/src/presets/mainnet.ts | 1 - packages/params/src/presets/minimal.ts | 1 - packages/params/src/types.ts | 2 -- .../test/e2e/ensure-config-is-synced.test.ts | 3 +- .../src/block/processExecutionPayload.ts | 6 ++-- packages/types/src/deneb/sszTypes.ts | 3 -- packages/types/src/deneb/types.ts | 1 - packages/validator/src/util/params.ts | 3 +- 24 files changed, 74 insertions(+), 67 deletions(-) diff --git a/packages/beacon-node/src/network/core/networkCore.ts b/packages/beacon-node/src/network/core/networkCore.ts index 718b7c92df7f..beda73b62a94 100644 --- a/packages/beacon-node/src/network/core/networkCore.ts +++ b/packages/beacon-node/src/network/core/networkCore.ts @@ -316,7 +316,7 @@ export class NetworkCore implements INetworkCore { } for (const fork of getActiveForks(this.config, this.clock.currentEpoch)) { - this.subscribeCoreTopicsAtFork(fork); + this.subscribeCoreTopicsAtFork(this.config, fork); } } @@ -325,7 +325,7 @@ export class NetworkCore implements INetworkCore { */ async unsubscribeGossipCoreTopics(): Promise { for (const fork of this.subscribedForks.values()) { - this.unsubscribeCoreTopicsAtFork(fork); + this.unsubscribeCoreTopicsAtFork(this.config, fork); } } @@ -456,7 +456,7 @@ export class NetworkCore implements INetworkCore { if (epoch === forkEpoch - FORK_EPOCH_LOOKAHEAD) { // Don't subscribe to new fork if the node is not subscribed to any topic if (await this.isSubscribedToGossipCoreTopics()) { - this.subscribeCoreTopicsAtFork(nextFork); + this.subscribeCoreTopicsAtFork(this.config, nextFork); this.logger.info("Subscribing gossip topics before fork", {nextFork}); } else { this.logger.info("Skipping subscribing gossip topics before fork", {nextFork}); @@ -475,7 +475,7 @@ export class NetworkCore implements INetworkCore { // After fork transition if (epoch === forkEpoch + FORK_EPOCH_LOOKAHEAD) { this.logger.info("Unsubscribing gossip topics from prev fork", {prevFork}); - this.unsubscribeCoreTopicsAtFork(prevFork); + this.unsubscribeCoreTopicsAtFork(this.config, prevFork); this.attnetsService.unsubscribeSubnetsFromPrevFork(prevFork); this.syncnetsService.unsubscribeSubnetsFromPrevFork(prevFork); } @@ -501,12 +501,12 @@ export class NetworkCore implements INetworkCore { } }; - private subscribeCoreTopicsAtFork(fork: ForkName): void { + private subscribeCoreTopicsAtFork(config: BeaconConfig, fork: ForkName): void { if (this.subscribedForks.has(fork)) return; this.subscribedForks.add(fork); const {subscribeAllSubnets, disableLightClientServer} = this.opts; - for (const topic of getCoreTopicsAtFork(fork, { + for (const topic of getCoreTopicsAtFork(config, fork, { subscribeAllSubnets, disableLightClientServer, })) { @@ -514,12 +514,12 @@ export class NetworkCore implements INetworkCore { } } - private unsubscribeCoreTopicsAtFork(fork: ForkName): void { + private unsubscribeCoreTopicsAtFork(config: BeaconConfig, fork: ForkName): void { if (!this.subscribedForks.has(fork)) return; this.subscribedForks.delete(fork); const {subscribeAllSubnets, disableLightClientServer} = this.opts; - for (const topic of getCoreTopicsAtFork(fork, { + for (const topic of getCoreTopicsAtFork(config, fork, { subscribeAllSubnets, disableLightClientServer, })) { diff --git a/packages/beacon-node/src/network/gossip/gossipsub.ts b/packages/beacon-node/src/network/gossip/gossipsub.ts index 42f8ba8b114c..9f2b47e21c6f 100644 --- a/packages/beacon-node/src/network/gossip/gossipsub.ts +++ b/packages/beacon-node/src/network/gossip/gossipsub.ts @@ -329,7 +329,7 @@ function getMetricsTopicStrToLabel(config: BeaconConfig, opts: {disableLightClie const metricsTopicStrToLabel = new Map(); for (const {name: fork} of config.forksAscendingEpochOrder) { - const topics = getCoreTopicsAtFork(fork, { + const topics = getCoreTopicsAtFork(config, fork, { subscribeAllSubnets: true, disableLightClientServer: opts.disableLightClientServer, }); diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index de52860605a9..1c34440df2b8 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -1,9 +1,8 @@ -import {ForkDigestContext} from "@lodestar/config"; +import {ChainConfig, ForkDigestContext} from "@lodestar/config"; import { ATTESTATION_SUBNET_COUNT, ForkName, ForkSeq, - MAX_BLOBS_PER_BLOCK, SYNC_COMMITTEE_SUBNET_COUNT, isForkLightClient, } from "@lodestar/params"; @@ -199,6 +198,7 @@ export function parseGossipTopic(forkDigestContext: ForkDigestContext, topicStr: * De-duplicate logic to pick fork topics between subscribeCoreTopicsAtFork and unsubscribeCoreTopicsAtFork */ export function getCoreTopicsAtFork( + config: ChainConfig, fork: ForkName, opts: {subscribeAllSubnets?: boolean; disableLightClientServer?: boolean} ): GossipTopicTypeMap[keyof GossipTopicTypeMap][] { @@ -213,7 +213,7 @@ export function getCoreTopicsAtFork( // After Deneb also track blob_sidecar_{index} if (ForkSeq[fork] >= ForkSeq.deneb) { - for (let index = 0; index < MAX_BLOBS_PER_BLOCK; index++) { + for (let index = 0; index < config.MAX_BLOBS_PER_BLOCK; index++) { topics.push({type: GossipType.blob_sidecar, index}); } } diff --git a/packages/beacon-node/src/network/interface.ts b/packages/beacon-node/src/network/interface.ts index bf117cc8a743..edcf35878420 100644 --- a/packages/beacon-node/src/network/interface.ts +++ b/packages/beacon-node/src/network/interface.ts @@ -30,6 +30,7 @@ import { import type {Datastore} from "interface-datastore"; import {Libp2p as ILibp2p} from "libp2p"; import {PeerIdStr} from "../util/peerId.js"; +import {BlobSidecarsByRootRequest} from "../util/types.js"; import {INetworkCorePublic} from "./core/types.js"; import {INetworkEventBus} from "./events.js"; import {GossipType} from "./gossip/interface.js"; @@ -66,7 +67,7 @@ export interface INetwork extends INetworkCorePublic { request: phase0.BeaconBlocksByRootRequest ): Promise[]>; sendBlobSidecarsByRange(peerId: PeerIdStr, request: deneb.BlobSidecarsByRangeRequest): Promise; - sendBlobSidecarsByRoot(peerId: PeerIdStr, request: deneb.BlobSidecarsByRootRequest): Promise; + sendBlobSidecarsByRoot(peerId: PeerIdStr, request: BlobSidecarsByRootRequest): Promise; // Gossip publishBeaconBlock(signedBlock: SignedBeaconBlock): Promise; diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 2181e21744da..870fbf303ff4 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -4,7 +4,7 @@ import {PeerId} from "@libp2p/interface"; import {routes} from "@lodestar/api"; import {BeaconConfig} from "@lodestar/config"; import {LoggerNode} from "@lodestar/logger/node"; -import {ForkSeq, MAX_BLOBS_PER_BLOCK} from "@lodestar/params"; +import {ForkSeq} from "@lodestar/params"; import {ResponseIncoming} from "@lodestar/reqresp"; import {computeStartSlotAtEpoch, computeTimeAtSlot} from "@lodestar/state-transition"; import { @@ -28,6 +28,7 @@ import {IBeaconDb} from "../db/interface.js"; import {Metrics, RegistryMetricCreator} from "../metrics/index.js"; import {IClock} from "../util/clock.js"; import {PeerIdStr, peerIdToString} from "../util/peerId.js"; +import {BlobSidecarsByRootRequest} from "../util/types.js"; import {INetworkCore, NetworkCore, WorkerNetworkCore} from "./core/index.js"; import {INetworkEventBus, NetworkEvent, NetworkEventBus, NetworkEventData} from "./events.js"; import {getActiveForks} from "./forks.js"; @@ -502,15 +503,12 @@ export class Network implements INetwork { return collectMaxResponseTyped( this.sendReqRespRequest(peerId, ReqRespMethod.BlobSidecarsByRange, [Version.V1], request), // request's count represent the slots, so the actual max count received could be slots * blobs per slot - request.count * MAX_BLOBS_PER_BLOCK, + request.count * this.config.MAX_BLOBS_PER_BLOCK, responseSszTypeByMethod[ReqRespMethod.BlobSidecarsByRange] ); } - async sendBlobSidecarsByRoot( - peerId: PeerIdStr, - request: deneb.BlobSidecarsByRootRequest - ): Promise { + async sendBlobSidecarsByRoot(peerId: PeerIdStr, request: BlobSidecarsByRootRequest): Promise { return collectMaxResponseTyped( this.sendReqRespRequest(peerId, ReqRespMethod.BlobSidecarsByRoot, [Version.V1], request), request.length, @@ -524,7 +522,7 @@ export class Network implements INetwork { versions: number[], request: Req ): AsyncIterable { - const requestType = requestSszTypeByMethod[method]; + const requestType = requestSszTypeByMethod(this.config)[method]; const requestData = requestType ? requestType.serialize(request as never) : new Uint8Array(); // ReqResp outgoing request, emit from main thread to worker diff --git a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts index a2a2ebd657ab..96b5c6c0a776 100644 --- a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts +++ b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts @@ -156,7 +156,9 @@ export class ReqRespBeaconNode extends ReqResp { // Overwrite placeholder requestData from main thread with correct sequenceNumber if (method === ReqRespMethod.Ping) { - requestData = requestSszTypeByMethod[ReqRespMethod.Ping].serialize(this.metadataController.seqNumber); + requestData = requestSszTypeByMethod(this.config)[ReqRespMethod.Ping].serialize( + this.metadataController.seqNumber + ); } // ReqResp outgoing request, emit from main thread to worker @@ -205,7 +207,7 @@ export class ReqRespBeaconNode extends ReqResp { versions: number[], request: Req ): AsyncIterable { - const requestType = requestSszTypeByMethod[method]; + const requestType = requestSszTypeByMethod(this.config)[method]; const requestData = requestType ? requestType.serialize(request as never) : new Uint8Array(); return this.sendRequestWithoutEncoding(peerId, method, versions, requestData); } diff --git a/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts b/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts index f44f9482eeb6..951a39cff564 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRoot.ts @@ -1,13 +1,14 @@ import {BLOBSIDECAR_FIXED_SIZE} from "@lodestar/params"; import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp"; -import {RootHex, deneb} from "@lodestar/types"; +import {RootHex} from "@lodestar/types"; import {fromHex, toRootHex} from "@lodestar/utils"; import {IBeaconChain} from "../../../chain/index.js"; import {IBeaconDb} from "../../../db/index.js"; import {BLOB_SIDECARS_IN_WRAPPER_INDEX} from "../../../db/repositories/blobSidecars.js"; +import {BlobSidecarsByRootRequest} from "../../../util/types.js"; export async function* onBlobSidecarsByRoot( - requestBody: deneb.BlobSidecarsByRootRequest, + requestBody: BlobSidecarsByRootRequest, chain: IBeaconChain, db: IBeaconDb ): AsyncIterable { diff --git a/packages/beacon-node/src/network/reqresp/handlers/index.ts b/packages/beacon-node/src/network/reqresp/handlers/index.ts index a836cbc47769..83f6620dbbd4 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/index.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/index.ts @@ -2,6 +2,7 @@ import {ProtocolHandler} from "@lodestar/reqresp"; import {ssz} from "@lodestar/types"; import {IBeaconChain} from "../../../chain/index.js"; import {IBeaconDb} from "../../../db/index.js"; +import {BlobSidecarsByRootRequestType} from "../../../util/types.js"; import {GetReqRespHandlerFn, ReqRespMethod} from "../types.js"; import {onBeaconBlocksByRange} from "./beaconBlocksByRange.js"; import {onBeaconBlocksByRoot} from "./beaconBlocksByRoot.js"; @@ -37,7 +38,7 @@ export function getReqRespHandlers({db, chain}: {db: IBeaconDb; chain: IBeaconCh return onBeaconBlocksByRoot(body, chain, db); }, [ReqRespMethod.BlobSidecarsByRoot]: (req) => { - const body = ssz.deneb.BlobSidecarsByRootRequest.deserialize(req.data); + const body = BlobSidecarsByRootRequestType(chain.config).deserialize(req.data); return onBlobSidecarsByRoot(body, chain, db); }, [ReqRespMethod.BlobSidecarsByRange]: (req) => { diff --git a/packages/beacon-node/src/network/reqresp/protocols.ts b/packages/beacon-node/src/network/reqresp/protocols.ts index b6b9c6c48967..b254db022101 100644 --- a/packages/beacon-node/src/network/reqresp/protocols.ts +++ b/packages/beacon-node/src/network/reqresp/protocols.ts @@ -1,4 +1,4 @@ -import {ForkDigestContext} from "@lodestar/config"; +import {BeaconConfig, ForkDigestContext} from "@lodestar/config"; import {ContextBytesFactory, ContextBytesType, Encoding} from "@lodestar/reqresp"; import {rateLimitQuotas} from "./rateLimit.js"; import {ProtocolNoHandler, ReqRespMethod, Version, requestSszTypeByMethod, responseSszTypeByMethod} from "./types.js"; @@ -100,13 +100,13 @@ type ProtocolSummary = { }; function toProtocol(protocol: ProtocolSummary) { - return (config: ForkDigestContext): ProtocolNoHandler => ({ + return (config: BeaconConfig): ProtocolNoHandler => ({ method: protocol.method, version: protocol.version, encoding: Encoding.SSZ_SNAPPY, contextBytes: toContextBytes(protocol.contextBytesType, config), - inboundRateLimits: rateLimitQuotas[protocol.method], - requestSizes: requestSszTypeByMethod[protocol.method], + inboundRateLimits: rateLimitQuotas(config)[protocol.method], + requestSizes: requestSszTypeByMethod(config)[protocol.method], responseSizes: (fork) => responseSszTypeByMethod[protocol.method](fork, protocol.version), }); } diff --git a/packages/beacon-node/src/network/reqresp/rateLimit.ts b/packages/beacon-node/src/network/reqresp/rateLimit.ts index 5830b48d2eab..771d01f6c339 100644 --- a/packages/beacon-node/src/network/reqresp/rateLimit.ts +++ b/packages/beacon-node/src/network/reqresp/rateLimit.ts @@ -1,14 +1,10 @@ -import { - MAX_BLOBS_PER_BLOCK, - MAX_REQUEST_BLOB_SIDECARS, - MAX_REQUEST_BLOCKS, - MAX_REQUEST_LIGHT_CLIENT_UPDATES, -} from "@lodestar/params"; +import {ChainConfig} from "@lodestar/config"; +import {MAX_REQUEST_BLOCKS, MAX_REQUEST_LIGHT_CLIENT_UPDATES} from "@lodestar/params"; import {InboundRateLimitQuota} from "@lodestar/reqresp"; import {ReqRespMethod, RequestBodyByMethod} from "./types.js"; import {requestSszTypeByMethod} from "./types.js"; -export const rateLimitQuotas: Record = { +export const rateLimitQuotas: (config: ChainConfig) => Record = (config) => ({ [ReqRespMethod.Status]: { // Rationale: https://github.com/sigp/lighthouse/blob/bf533c8e42cc73c35730e285c21df8add0195369/beacon_node/lighthouse_network/src/rpc/mod.rs#L118-L130 byPeer: {quota: 5, quotaTimeMs: 15_000}, @@ -29,22 +25,22 @@ export const rateLimitQuotas: Record = { [ReqRespMethod.BeaconBlocksByRange]: { // Rationale: https://github.com/sigp/lighthouse/blob/bf533c8e42cc73c35730e285c21df8add0195369/beacon_node/lighthouse_network/src/rpc/mod.rs#L118-L130 byPeer: {quota: MAX_REQUEST_BLOCKS, quotaTimeMs: 10_000}, - getRequestCount: getRequestCountFn(ReqRespMethod.BeaconBlocksByRange, (req) => req.count), + getRequestCount: getRequestCountFn(config, ReqRespMethod.BeaconBlocksByRange, (req) => req.count), }, [ReqRespMethod.BeaconBlocksByRoot]: { // Rationale: https://github.com/sigp/lighthouse/blob/bf533c8e42cc73c35730e285c21df8add0195369/beacon_node/lighthouse_network/src/rpc/mod.rs#L118-L130 byPeer: {quota: 128, quotaTimeMs: 10_000}, - getRequestCount: getRequestCountFn(ReqRespMethod.BeaconBlocksByRoot, (req) => req.length), + getRequestCount: getRequestCountFn(config, ReqRespMethod.BeaconBlocksByRoot, (req) => req.length), }, [ReqRespMethod.BlobSidecarsByRange]: { // Rationale: MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK - byPeer: {quota: MAX_REQUEST_BLOB_SIDECARS, quotaTimeMs: 10_000}, - getRequestCount: getRequestCountFn(ReqRespMethod.BlobSidecarsByRange, (req) => req.count), + byPeer: {quota: config.MAX_REQUEST_BLOB_SIDECARS, quotaTimeMs: 10_000}, + getRequestCount: getRequestCountFn(config, ReqRespMethod.BlobSidecarsByRange, (req) => req.count), }, [ReqRespMethod.BlobSidecarsByRoot]: { // Rationale: quota of BeaconBlocksByRoot * MAX_BLOBS_PER_BLOCK - byPeer: {quota: 128 * MAX_BLOBS_PER_BLOCK, quotaTimeMs: 10_000}, - getRequestCount: getRequestCountFn(ReqRespMethod.BlobSidecarsByRoot, (req) => req.length), + byPeer: {quota: config.MAX_REQUEST_BLOB_SIDECARS, quotaTimeMs: 10_000}, + getRequestCount: getRequestCountFn(config, ReqRespMethod.BlobSidecarsByRoot, (req) => req.length), }, [ReqRespMethod.LightClientBootstrap]: { // As similar in the nature of `Status` protocol so we use the same rate limits. @@ -53,7 +49,7 @@ export const rateLimitQuotas: Record = { [ReqRespMethod.LightClientUpdatesByRange]: { // Same rationale as for BeaconBlocksByRange byPeer: {quota: MAX_REQUEST_LIGHT_CLIENT_UPDATES, quotaTimeMs: 10_000}, - getRequestCount: getRequestCountFn(ReqRespMethod.LightClientUpdatesByRange, (req) => req.count), + getRequestCount: getRequestCountFn(config, ReqRespMethod.LightClientUpdatesByRange, (req) => req.count), }, [ReqRespMethod.LightClientFinalityUpdate]: { // Finality updates should not be requested more than once per epoch. @@ -65,14 +61,15 @@ export const rateLimitQuotas: Record = { // Allow 2 per slot and a very safe bound until there's more testing of real usage. byPeer: {quota: 2, quotaTimeMs: 12_000}, }, -}; +}); // Helper to produce a getRequestCount function function getRequestCountFn( + config: ChainConfig, method: T, fn: (req: RequestBodyByMethod[T]) => number ): (reqData: Uint8Array) => number { - const type = requestSszTypeByMethod[method]; + const type = requestSszTypeByMethod(config)[method]; return (reqData: Uint8Array) => { try { return (type && fn(type.deserialize(reqData))) ?? 1; diff --git a/packages/beacon-node/src/network/reqresp/types.ts b/packages/beacon-node/src/network/reqresp/types.ts index 96ae1558ec07..b7c18ebdfeb5 100644 --- a/packages/beacon-node/src/network/reqresp/types.ts +++ b/packages/beacon-node/src/network/reqresp/types.ts @@ -1,4 +1,5 @@ import {Type} from "@chainsafe/ssz"; +import {ChainConfig} from "@lodestar/config"; import {ForkLightClient, ForkName, isForkLightClient} from "@lodestar/params"; import {Protocol, ProtocolHandler, ReqRespRequest} from "@lodestar/reqresp"; import { @@ -15,6 +16,7 @@ import { ssz, sszTypesFor, } from "@lodestar/types"; +import {BlobSidecarsByRootRequest, BlobSidecarsByRootRequestType} from "../../util/types.js"; export type ProtocolNoHandler = Omit; @@ -44,7 +46,7 @@ export type RequestBodyByMethod = { [ReqRespMethod.BeaconBlocksByRange]: phase0.BeaconBlocksByRangeRequest; [ReqRespMethod.BeaconBlocksByRoot]: phase0.BeaconBlocksByRootRequest; [ReqRespMethod.BlobSidecarsByRange]: deneb.BlobSidecarsByRangeRequest; - [ReqRespMethod.BlobSidecarsByRoot]: deneb.BlobSidecarsByRootRequest; + [ReqRespMethod.BlobSidecarsByRoot]: BlobSidecarsByRootRequest; [ReqRespMethod.LightClientBootstrap]: Root; [ReqRespMethod.LightClientUpdatesByRange]: altair.LightClientUpdatesByRange; [ReqRespMethod.LightClientFinalityUpdate]: null; @@ -68,9 +70,9 @@ type ResponseBodyByMethod = { }; /** Request SSZ type for each method and ForkName */ -export const requestSszTypeByMethod: { +export const requestSszTypeByMethod: (config: ChainConfig) => { [K in ReqRespMethod]: RequestBodyByMethod[K] extends null ? null : Type; -} = { +} = (config) => ({ [ReqRespMethod.Status]: ssz.phase0.Status, [ReqRespMethod.Goodbye]: ssz.phase0.Goodbye, [ReqRespMethod.Ping]: ssz.phase0.Ping, @@ -78,12 +80,12 @@ export const requestSszTypeByMethod: { [ReqRespMethod.BeaconBlocksByRange]: ssz.phase0.BeaconBlocksByRangeRequest, [ReqRespMethod.BeaconBlocksByRoot]: ssz.phase0.BeaconBlocksByRootRequest, [ReqRespMethod.BlobSidecarsByRange]: ssz.deneb.BlobSidecarsByRangeRequest, - [ReqRespMethod.BlobSidecarsByRoot]: ssz.deneb.BlobSidecarsByRootRequest, + [ReqRespMethod.BlobSidecarsByRoot]: BlobSidecarsByRootRequestType(config), [ReqRespMethod.LightClientBootstrap]: ssz.Root, [ReqRespMethod.LightClientUpdatesByRange]: ssz.altair.LightClientUpdatesByRange, [ReqRespMethod.LightClientFinalityUpdate]: null, [ReqRespMethod.LightClientOptimisticUpdate]: null, -}; +}); export type ResponseTypeGetter = (fork: ForkName, version: number) => Type; diff --git a/packages/beacon-node/src/util/types.ts b/packages/beacon-node/src/util/types.ts index 545a706c7511..5b9c7a784277 100644 --- a/packages/beacon-node/src/util/types.ts +++ b/packages/beacon-node/src/util/types.ts @@ -1,4 +1,5 @@ -import {ContainerType, ValueOf} from "@chainsafe/ssz"; +import {ContainerType, ListCompositeType, ValueOf} from "@chainsafe/ssz"; +import {ChainConfig} from "@lodestar/config"; import {ssz} from "@lodestar/types"; // Misc SSZ types used only in the beacon-node package, no need to upstream to types @@ -12,3 +13,7 @@ export const signedBLSToExecutionChangeVersionedType = new ContainerType( {jsonCase: "eth2", typeName: "SignedBLSToExecutionChangeVersionedType"} ); export type SignedBLSToExecutionChangeVersioned = ValueOf; + +export const BlobSidecarsByRootRequestType = (config: ChainConfig) => + new ListCompositeType(ssz.deneb.BlobIdentifier, config.MAX_REQUEST_BLOB_SIDECARS); +export type BlobSidecarsByRootRequest = ValueOf>; diff --git a/packages/config/src/chainConfig/configs/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts index 4a01d9d062b1..ae9a2ec74d1f 100644 --- a/packages/config/src/chainConfig/configs/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -101,6 +101,9 @@ export const chainConfig: ChainConfig = { // Deneb // `2**12` (= 4096 epochs, ~18 days) MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096, + MAX_BLOBS_PER_BLOCK: 6, + // MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK + MAX_REQUEST_BLOB_SIDECARS: 768, // Electra // 2**8 * 10**9 (= 256,000,000,000) diff --git a/packages/config/src/chainConfig/configs/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts index f0e116a553ab..6f536bc7732c 100644 --- a/packages/config/src/chainConfig/configs/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -98,6 +98,9 @@ export const chainConfig: ChainConfig = { // Deneb // `2**12` (= 4096 epochs, ~18 days) MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096, + MAX_BLOBS_PER_BLOCK: 6, + // MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK + MAX_REQUEST_BLOB_SIDECARS: 768, // Electra // 2**7 * 10**9 (= 128,000,000,000) diff --git a/packages/config/src/chainConfig/types.ts b/packages/config/src/chainConfig/types.ts index 5c06b205c2f6..513324bdbcb8 100644 --- a/packages/config/src/chainConfig/types.ts +++ b/packages/config/src/chainConfig/types.ts @@ -72,6 +72,8 @@ export type ChainConfig = { // Networking MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: number; + MAX_BLOBS_PER_BLOCK: number; + MAX_REQUEST_BLOB_SIDECARS: number; }; export const chainConfigTypes: SpecTypes = { @@ -136,6 +138,8 @@ export const chainConfigTypes: SpecTypes = { // Networking MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: "number", + MAX_BLOBS_PER_BLOCK: "number", + MAX_REQUEST_BLOB_SIDECARS: "number", }; /** Allows values in a Spec file */ diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 82ffa491daa3..64d3b64dbd60 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -91,7 +91,6 @@ export const { FIELD_ELEMENTS_PER_BLOB, MAX_BLOB_COMMITMENTS_PER_BLOCK, - MAX_BLOBS_PER_BLOCK, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, MAX_EFFECTIVE_BALANCE_ELECTRA, @@ -198,7 +197,6 @@ export const SYNC_COMMITTEE_SUBNET_SIZE = Math.floor(SYNC_COMMITTEE_SIZE / SYNC_ export const MAX_REQUEST_BLOCKS = 2 ** 10; // 1024 export const MAX_REQUEST_BLOCKS_DENEB = 2 ** 7; // 128 -export const MAX_REQUEST_BLOB_SIDECARS = MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK; // Lightclient pre-computed /** diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 9a03001375f2..afbfd78eba95 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -115,7 +115,6 @@ export const mainnetPreset: BeaconPreset = { /////////// FIELD_ELEMENTS_PER_BLOB: 4096, MAX_BLOB_COMMITMENTS_PER_BLOCK: 4096, - MAX_BLOBS_PER_BLOCK: 6, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 17, // ELECTRA diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 6edd7e2858f1..d9be1b1468ab 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -116,7 +116,6 @@ export const minimalPreset: BeaconPreset = { /////////// FIELD_ELEMENTS_PER_BLOB: 4096, MAX_BLOB_COMMITMENTS_PER_BLOCK: 16, - MAX_BLOBS_PER_BLOCK: 6, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 9, // ELECTRA diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index 5e17adaace12..e641e0f05286 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -78,7 +78,6 @@ export type BeaconPreset = { /////////// FIELD_ELEMENTS_PER_BLOB: number; MAX_BLOB_COMMITMENTS_PER_BLOCK: number; - MAX_BLOBS_PER_BLOCK: number; KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: number; // ELECTRA @@ -179,7 +178,6 @@ export const beaconPresetTypes: BeaconPresetTypes = { /////////// FIELD_ELEMENTS_PER_BLOB: "number", MAX_BLOB_COMMITMENTS_PER_BLOCK: "number", - MAX_BLOBS_PER_BLOCK: "number", KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: "number", // ELECTRA diff --git a/packages/params/test/e2e/ensure-config-is-synced.test.ts b/packages/params/test/e2e/ensure-config-is-synced.test.ts index ab34c16201c8..b1d9c05a54b1 100644 --- a/packages/params/test/e2e/ensure-config-is-synced.test.ts +++ b/packages/params/test/e2e/ensure-config-is-synced.test.ts @@ -12,9 +12,8 @@ const specConfigCommit = "v1.5.0-alpha.8"; /** * Fields that we filter from local config when doing comparison. * Ideally this should be empty as it is not spec compliant - * For `MAX_BLOBS_PER_BLOCK`, see https://github.com/ChainSafe/lodestar/issues/7172 */ -const ignoredLocalPresetFields: (keyof BeaconPreset)[] = ["MAX_BLOBS_PER_BLOCK"]; +const ignoredLocalPresetFields: (keyof BeaconPreset)[] = []; describe("Ensure config is synced", () => { vi.setConfig({testTimeout: 60 * 1000}); diff --git a/packages/state-transition/src/block/processExecutionPayload.ts b/packages/state-transition/src/block/processExecutionPayload.ts index 3900583956ba..0ea2fc7a16f7 100644 --- a/packages/state-transition/src/block/processExecutionPayload.ts +++ b/packages/state-transition/src/block/processExecutionPayload.ts @@ -1,5 +1,5 @@ import {byteArrayEquals} from "@chainsafe/ssz"; -import {ForkSeq, MAX_BLOBS_PER_BLOCK} from "@lodestar/params"; +import {ForkSeq} from "@lodestar/params"; import {BeaconBlockBody, BlindedBeaconBlockBody, deneb, isExecutionPayload} from "@lodestar/types"; import {toHex, toRootHex} from "@lodestar/utils"; import {CachedBeaconStateBellatrix, CachedBeaconStateCapella} from "../types.js"; @@ -49,8 +49,8 @@ export function processExecutionPayload( if (fork >= ForkSeq.deneb) { const blobKzgCommitmentsLen = (body as deneb.BeaconBlockBody).blobKzgCommitments?.length ?? 0; - if (blobKzgCommitmentsLen > MAX_BLOBS_PER_BLOCK) { - throw Error(`blobKzgCommitmentsLen exceeds limit=${MAX_BLOBS_PER_BLOCK}`); + if (blobKzgCommitmentsLen > state.config.MAX_BLOBS_PER_BLOCK) { + throw Error(`blobKzgCommitmentsLen exceeds limit=${state.config.MAX_BLOBS_PER_BLOCK}`); } } diff --git a/packages/types/src/deneb/sszTypes.ts b/packages/types/src/deneb/sszTypes.ts index 6dc18c8f8b02..9275ac4c4da5 100644 --- a/packages/types/src/deneb/sszTypes.ts +++ b/packages/types/src/deneb/sszTypes.ts @@ -6,7 +6,6 @@ import { HISTORICAL_ROOTS_LIMIT, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, MAX_BLOB_COMMITMENTS_PER_BLOCK, - MAX_REQUEST_BLOB_SIDECARS, SLOTS_PER_EPOCH, } from "@lodestar/params"; import {ssz as altairSsz} from "../altair/index.js"; @@ -62,8 +61,6 @@ export const BlobIdentifier = new ContainerType( {typeName: "BlobIdentifier", jsonCase: "eth2"} ); -export const BlobSidecarsByRootRequest = new ListCompositeType(BlobIdentifier, MAX_REQUEST_BLOB_SIDECARS); - // Beacon Chain types // https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/beacon-chain.md#containers diff --git a/packages/types/src/deneb/types.ts b/packages/types/src/deneb/types.ts index 1bbabd0e4285..c1c973d4d5be 100644 --- a/packages/types/src/deneb/types.ts +++ b/packages/types/src/deneb/types.ts @@ -18,7 +18,6 @@ export type BLSFieldElement = ValueOf; export type BlobIdentifier = ValueOf; export type BlobSidecarsByRangeRequest = ValueOf; -export type BlobSidecarsByRootRequest = ValueOf; export type ExecutionPayload = ValueOf; export type ExecutionPayloadHeader = ValueOf; diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 53ccd759a5c1..e8fd1a1e6dc4 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -136,6 +136,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Sat, 14 Dec 2024 01:23:31 +0100 Subject: [PATCH 233/259] feat: use `BLOB_SIDECAR_SUBNET_COUNT` to configure blob subnets (#7297) feat: use BLOB_SIDECAR_SUBNET_COUNT to configure blob subnets --- .../src/chain/errors/blobSidecarError.ts | 2 +- .../src/chain/validation/blobSidecar.ts | 15 ++++++++++----- .../beacon-node/src/network/gossip/interface.ts | 2 +- packages/beacon-node/src/network/gossip/topic.ts | 16 ++++++++-------- packages/beacon-node/src/network/network.ts | 4 ++-- .../src/network/processor/gossipHandlers.ts | 10 +++++----- .../beacon-node/test/e2e/api/impl/config.test.ts | 2 -- .../test/unit/network/gossip/topic.test.ts | 2 +- .../config/src/chainConfig/configs/mainnet.ts | 1 + .../config/src/chainConfig/configs/minimal.ts | 1 + packages/config/src/chainConfig/types.ts | 2 ++ packages/validator/src/util/params.ts | 1 + 12 files changed, 33 insertions(+), 25 deletions(-) diff --git a/packages/beacon-node/src/chain/errors/blobSidecarError.ts b/packages/beacon-node/src/chain/errors/blobSidecarError.ts index 410574594911..71118d8b8f9d 100644 --- a/packages/beacon-node/src/chain/errors/blobSidecarError.ts +++ b/packages/beacon-node/src/chain/errors/blobSidecarError.ts @@ -26,7 +26,7 @@ export enum BlobSidecarErrorCode { } export type BlobSidecarErrorType = - | {code: BlobSidecarErrorCode.INVALID_INDEX; blobIdx: number; gossipIndex: number} + | {code: BlobSidecarErrorCode.INVALID_INDEX; blobIdx: number; subnet: number} | {code: BlobSidecarErrorCode.INVALID_KZG; blobIdx: number} | {code: BlobSidecarErrorCode.INVALID_KZG_TXS} | {code: BlobSidecarErrorCode.INCORRECT_SLOT; blockSlot: Slot; blobSlot: Slot; blobIdx: number} diff --git a/packages/beacon-node/src/chain/validation/blobSidecar.ts b/packages/beacon-node/src/chain/validation/blobSidecar.ts index 3b90972f62b1..e2f4ed267d01 100644 --- a/packages/beacon-node/src/chain/validation/blobSidecar.ts +++ b/packages/beacon-node/src/chain/validation/blobSidecar.ts @@ -1,6 +1,7 @@ +import {ChainConfig} from "@lodestar/config"; import {KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, KZG_COMMITMENT_SUBTREE_INDEX0} from "@lodestar/params"; import {computeStartSlotAtEpoch, getBlockHeaderProposerSignatureSet} from "@lodestar/state-transition"; -import {Root, Slot, deneb, ssz} from "@lodestar/types"; +import {BlobIndex, Root, Slot, deneb, ssz} from "@lodestar/types"; import {toRootHex, verifyMerkleBranch} from "@lodestar/utils"; import {byteArrayEquals} from "../../util/bytes.js"; @@ -13,16 +14,16 @@ import {RegenCaller} from "../regen/index.js"; export async function validateGossipBlobSidecar( chain: IBeaconChain, blobSidecar: deneb.BlobSidecar, - gossipIndex: number + subnet: number ): Promise { const blobSlot = blobSidecar.signedBlockHeader.message.slot; - // [REJECT] The sidecar is for the correct topic -- i.e. sidecar.index matches the topic {index}. - if (blobSidecar.index !== gossipIndex) { + // [REJECT] The sidecar is for the correct subnet -- i.e. `compute_subnet_for_blob_sidecar(sidecar.index) == subnet_id`. + if (computeSubnetForBlobSidecar(blobSidecar.index, chain.config) !== subnet) { throw new BlobSidecarGossipError(GossipAction.REJECT, { code: BlobSidecarErrorCode.INVALID_INDEX, blobIdx: blobSidecar.index, - gossipIndex, + subnet, }); } @@ -225,3 +226,7 @@ function validateInclusionProof(blobSidecar: deneb.BlobSidecar): boolean { blobSidecar.signedBlockHeader.message.bodyRoot ); } + +function computeSubnetForBlobSidecar(blobIndex: BlobIndex, config: ChainConfig): number { + return blobIndex % config.BLOB_SIDECAR_SUBNET_COUNT; +} diff --git a/packages/beacon-node/src/network/gossip/interface.ts b/packages/beacon-node/src/network/gossip/interface.ts index 9939ed5af657..be7293524ce9 100644 --- a/packages/beacon-node/src/network/gossip/interface.ts +++ b/packages/beacon-node/src/network/gossip/interface.ts @@ -54,7 +54,7 @@ export interface IGossipTopic { export type GossipTopicTypeMap = { [GossipType.beacon_block]: {type: GossipType.beacon_block}; - [GossipType.blob_sidecar]: {type: GossipType.blob_sidecar; index: number}; + [GossipType.blob_sidecar]: {type: GossipType.blob_sidecar; subnet: number}; [GossipType.beacon_aggregate_and_proof]: {type: GossipType.beacon_aggregate_and_proof}; [GossipType.beacon_attestation]: {type: GossipType.beacon_attestation; subnet: number}; [GossipType.voluntary_exit]: {type: GossipType.voluntary_exit}; diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index 1c34440df2b8..88ef4143f8ff 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -73,7 +73,7 @@ function stringifyGossipTopicType(topic: GossipTopic): string { case GossipType.sync_committee: return `${topic.type}_${topic.subnet}`; case GossipType.blob_sidecar: - return `${topic.type}_${topic.index}`; + return `${topic.type}_${topic.subnet}`; } } @@ -181,10 +181,10 @@ export function parseGossipTopic(forkDigestContext: ForkDigestContext, topicStr: } if (gossipTypeStr.startsWith(GossipType.blob_sidecar)) { - const indexStr = gossipTypeStr.slice(GossipType.blob_sidecar.length + 1); // +1 for '_' concatenating the topic name and the index - const index = parseInt(indexStr, 10); - if (Number.isNaN(index)) throw Error(`index ${indexStr} is not a number`); - return {type: GossipType.blob_sidecar, index, fork, encoding}; + const subnetStr = gossipTypeStr.slice(GossipType.blob_sidecar.length + 1); // +1 for '_' concatenating the topic name and the subnet + const subnet = parseInt(subnetStr, 10); + if (Number.isNaN(subnet)) throw Error(`subnet ${subnetStr} is not a number`); + return {type: GossipType.blob_sidecar, subnet, fork, encoding}; } throw Error(`Unknown gossip type ${gossipTypeStr}`); @@ -211,10 +211,10 @@ export function getCoreTopicsAtFork( {type: GossipType.attester_slashing}, ]; - // After Deneb also track blob_sidecar_{index} + // After Deneb also track blob_sidecar_{subnet_id} if (ForkSeq[fork] >= ForkSeq.deneb) { - for (let index = 0; index < config.MAX_BLOBS_PER_BLOCK; index++) { - topics.push({type: GossipType.blob_sidecar, index}); + for (let subnet = 0; subnet < config.BLOB_SIDECAR_SUBNET_COUNT; subnet++) { + topics.push({type: GossipType.blob_sidecar, subnet}); } } diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 870fbf303ff4..d8370fc22b5f 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -312,9 +312,9 @@ export class Network implements INetwork { async publishBlobSidecar(blobSidecar: deneb.BlobSidecar): Promise { const slot = blobSidecar.signedBlockHeader.message.slot; const fork = this.config.getForkName(slot); - const index = blobSidecar.index; + const subnet = blobSidecar.index; - return this.publishGossip({type: GossipType.blob_sidecar, fork, index}, blobSidecar, { + return this.publishGossip({type: GossipType.blob_sidecar, fork, subnet}, blobSidecar, { ignoreDuplicatePublishError: true, }); } diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index 029e7ae4db42..3fb7b06e700a 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -179,7 +179,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand async function validateBeaconBlob( blobSidecar: deneb.BlobSidecar, blobBytes: Uint8Array, - gossipIndex: number, + subnet: number, peerIdStr: string, seenTimestampSec: number ): Promise { @@ -202,7 +202,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand ); try { - await validateGossipBlobSidecar(chain, blobSidecar, gossipIndex); + await validateGossipBlobSidecar(chain, blobSidecar, subnet); const recvToValidation = Date.now() / 1000 - seenTimestampSec; const validationTime = recvToValidation - recvToValLatency; @@ -212,10 +212,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand logger.debug("Received gossip blob", { slot: slot, root: blockHex, - curentSlot: chain.clock.currentSlot, + currentSlot: chain.clock.currentSlot, peerId: peerIdStr, delaySec, - gossipIndex, + subnet, ...blockInputMeta, recvToValLatency, recvToValidation, @@ -363,7 +363,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand const blockInput = await validateBeaconBlob( blobSidecar, serializedData, - topic.index, + topic.subnet, peerIdStr, seenTimestampSec ); diff --git a/packages/beacon-node/test/e2e/api/impl/config.test.ts b/packages/beacon-node/test/e2e/api/impl/config.test.ts index 474826050a3a..078e210cb0cc 100644 --- a/packages/beacon-node/test/e2e/api/impl/config.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/config.test.ts @@ -10,8 +10,6 @@ const CONSTANT_NAMES_SKIP_LIST = new Set([ // This constant can also be derived from existing constants so it's not critical. // PARTICIPATION_FLAG_WEIGHTS = [TIMELY_SOURCE_WEIGHT, TIMELY_TARGET_WEIGHT, TIMELY_HEAD_WEIGHT] "PARTICIPATION_FLAG_WEIGHTS", - // TODO DENEB: Configure the blob subnets in a followup PR - "BLOB_SIDECAR_SUBNET_COUNT", ]); describe("api / impl / config", () => { diff --git a/packages/beacon-node/test/unit/network/gossip/topic.test.ts b/packages/beacon-node/test/unit/network/gossip/topic.test.ts index f68c2d737fd6..4b323865061e 100644 --- a/packages/beacon-node/test/unit/network/gossip/topic.test.ts +++ b/packages/beacon-node/test/unit/network/gossip/topic.test.ts @@ -17,7 +17,7 @@ describe("network / gossip / topic", () => { ], [GossipType.blob_sidecar]: [ { - topic: {type: GossipType.blob_sidecar, index: 1, fork: ForkName.deneb, encoding}, + topic: {type: GossipType.blob_sidecar, subnet: 1, fork: ForkName.deneb, encoding}, topicStr: "/eth2/46acb19a/blob_sidecar_1/ssz_snappy", }, ], diff --git a/packages/config/src/chainConfig/configs/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts index ae9a2ec74d1f..a4adc04a1756 100644 --- a/packages/config/src/chainConfig/configs/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -101,6 +101,7 @@ export const chainConfig: ChainConfig = { // Deneb // `2**12` (= 4096 epochs, ~18 days) MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096, + BLOB_SIDECAR_SUBNET_COUNT: 6, MAX_BLOBS_PER_BLOCK: 6, // MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK MAX_REQUEST_BLOB_SIDECARS: 768, diff --git a/packages/config/src/chainConfig/configs/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts index 6f536bc7732c..d16b03e82c28 100644 --- a/packages/config/src/chainConfig/configs/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -98,6 +98,7 @@ export const chainConfig: ChainConfig = { // Deneb // `2**12` (= 4096 epochs, ~18 days) MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096, + BLOB_SIDECAR_SUBNET_COUNT: 6, MAX_BLOBS_PER_BLOCK: 6, // MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK MAX_REQUEST_BLOB_SIDECARS: 768, diff --git a/packages/config/src/chainConfig/types.ts b/packages/config/src/chainConfig/types.ts index 513324bdbcb8..291dcc8601a7 100644 --- a/packages/config/src/chainConfig/types.ts +++ b/packages/config/src/chainConfig/types.ts @@ -72,6 +72,7 @@ export type ChainConfig = { // Networking MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: number; + BLOB_SIDECAR_SUBNET_COUNT: number; MAX_BLOBS_PER_BLOCK: number; MAX_REQUEST_BLOB_SIDECARS: number; }; @@ -138,6 +139,7 @@ export const chainConfigTypes: SpecTypes = { // Networking MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: "number", + BLOB_SIDECAR_SUBNET_COUNT: "number", MAX_BLOBS_PER_BLOCK: "number", MAX_REQUEST_BLOB_SIDECARS: "number", }; diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index e8fd1a1e6dc4..825f60e8c7fa 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -136,6 +136,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Sun, 15 Dec 2024 12:34:56 +0100 Subject: [PATCH 234/259] chore: log sync aggregate participants when producing beacon block body (#7300) * chore: log sync aggregate participants when producing beacon block body * Use isForkLightClient instead of ForkSeq * Fix produce block unit tests --- .../chain/produceBlock/produceBlockBody.ts | 23 ++++++++++++++----- .../test/mocks/mockedBeaconChain.ts | 11 ++++++++- .../api/impl/validator/produceBlockV2.test.ts | 6 ++++- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index d26703050070..e4c86b78907c 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -1,11 +1,10 @@ import {ChainForkConfig} from "@lodestar/config"; -import {ForkExecution, ForkSeq, isForkExecution} from "@lodestar/params"; +import {ForkExecution, ForkSeq, isForkExecution, isForkLightClient} from "@lodestar/params"; import { CachedBeaconStateAllForks, CachedBeaconStateBellatrix, CachedBeaconStateCapella, CachedBeaconStateExecutions, - computeEpochAtSlot, computeTimeAtSlot, getCurrentEpoch, getExpectedWithdrawals, @@ -143,8 +142,15 @@ export async function produceBlockBody( ? Object.assign({}, commonBlockBody) : await produceCommonBlockBody.call(this, blockType, currentState, blockAttr); - const {attestations, deposits, voluntaryExits, attesterSlashings, proposerSlashings, blsToExecutionChanges} = - blockBody; + const { + attestations, + deposits, + voluntaryExits, + attesterSlashings, + proposerSlashings, + syncAggregate, + blsToExecutionChanges, + } = blockBody; Object.assign(logMeta, { attestations: attestations.length, @@ -154,6 +160,12 @@ export async function produceBlockBody( proposerSlashings: proposerSlashings.length, }); + if (isForkLightClient(fork)) { + Object.assign(logMeta, { + syncAggregateParticipants: syncAggregate.syncCommitteeBits.getTrueBitIndexes().length, + }); + } + const endExecutionPayload = stepsMetrics?.startTimer(); if (isForkExecution(fork)) { const safeBlockHash = this.forkChoice.getJustifiedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX; @@ -608,7 +620,6 @@ export async function produceCommonBlockBody( ? this.metrics?.executionBlockProductionTimeSteps : this.metrics?.builderBlockProductionTimeSteps; - const blockEpoch = computeEpochAtSlot(slot); const fork = currentState.config.getForkName(slot); // TODO: @@ -653,7 +664,7 @@ export async function produceCommonBlockBody( } const endSyncAggregate = stepsMetrics?.startTimer(); - if (blockEpoch >= this.config.ALTAIR_FORK_EPOCH) { + if (ForkSeq[fork] >= ForkSeq.altair) { const syncAggregate = this.syncContributionAndProofPool.getAggregate(parentSlot, parentBlockRoot); this.metrics?.production.producedSyncAggregateParticipants.observe( syncAggregate.syncCommitteeBits.getTrueBitIndexes().length diff --git a/packages/beacon-node/test/mocks/mockedBeaconChain.ts b/packages/beacon-node/test/mocks/mockedBeaconChain.ts index b274284e3ab1..36d6fb27c53a 100644 --- a/packages/beacon-node/test/mocks/mockedBeaconChain.ts +++ b/packages/beacon-node/test/mocks/mockedBeaconChain.ts @@ -8,7 +8,7 @@ import {BeaconProposerCache} from "../../src/chain/beaconProposerCache.js"; import {BeaconChain} from "../../src/chain/chain.js"; import {ChainEventEmitter} from "../../src/chain/emitter.js"; import {LightClientServer} from "../../src/chain/lightClient/index.js"; -import {AggregatedAttestationPool, OpPool} from "../../src/chain/opPools/index.js"; +import {AggregatedAttestationPool, OpPool, SyncContributionAndProofPool} from "../../src/chain/opPools/index.js"; import {QueuedStateRegenerator} from "../../src/chain/regen/index.js"; import {ShufflingCache} from "../../src/chain/shufflingCache.js"; import {Eth1ForBlockProduction} from "../../src/eth1/index.js"; @@ -27,6 +27,7 @@ export type MockedBeaconChain = Mocked & { eth1: Mocked; opPool: Mocked; aggregatedAttestationPool: Mocked; + syncContributionAndProofPool: Mocked; beaconProposerCache: Mocked; shufflingCache: Mocked; regen: Mocked; @@ -94,10 +95,17 @@ vi.mock("../../src/chain/opPools/index.js", async (importActual) => { }; }); + const SyncContributionAndProofPool = vi.fn().mockImplementation(() => { + return { + getAggregate: vi.fn(), + }; + }); + return { ...mod, OpPool, AggregatedAttestationPool, + SyncContributionAndProofPool, }; }); @@ -124,6 +132,7 @@ vi.mock("../../src/chain/chain.js", async (importActual) => { eth1: new Eth1ForBlockProduction(), opPool: new OpPool(), aggregatedAttestationPool: new AggregatedAttestationPool(config), + syncContributionAndProofPool: new SyncContributionAndProofPool(), // @ts-expect-error beaconProposerCache: new BeaconProposerCache(), shufflingCache: new ShufflingCache(), diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts index 52f600b7174c..418dd2e56d8d 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts @@ -1,7 +1,7 @@ import {fromHexString, toHexString} from "@chainsafe/ssz"; import {ProtoBlock} from "@lodestar/fork-choice"; import {ForkName} from "@lodestar/params"; -import {CachedBeaconStateBellatrix, computeTimeAtSlot} from "@lodestar/state-transition"; +import {CachedBeaconStateBellatrix, G2_POINT_AT_INFINITY, computeTimeAtSlot} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {getValidatorApi} from "../../../../../src/api/impl/validator/index.js"; @@ -99,6 +99,10 @@ describe("api/validator - produceBlockV2", () => { eth1Data: ssz.phase0.Eth1Data.defaultValue(), deposits: [], }); + modules.chain["syncContributionAndProofPool"].getAggregate.mockReturnValue({ + syncCommitteeBits: ssz.altair.SyncCommitteeBits.defaultValue(), + syncCommitteeSignature: G2_POINT_AT_INFINITY, + }); modules.forkChoice.getJustifiedBlock.mockReturnValue({} as ProtoBlock); modules.forkChoice.getFinalizedBlock.mockReturnValue({} as ProtoBlock); From 3f3c7fcb3476d66550515958a4b80e81b07ea87b Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 16 Dec 2024 17:25:19 +0000 Subject: [PATCH 235/259] chore: print graffiti when producing beacon block body (#7303) --- packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index e4c86b78907c..0b7797828c98 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -143,6 +143,7 @@ export async function produceBlockBody( : await produceCommonBlockBody.call(this, blockType, currentState, blockAttr); const { + graffiti, attestations, deposits, voluntaryExits, @@ -153,6 +154,7 @@ export async function produceBlockBody( } = blockBody; Object.assign(logMeta, { + graffiti, attestations: attestations.length, deposits: deposits.length, voluntaryExits: voluntaryExits.length, From c290469e9069aec2ff1654018d8967b8b82f6106 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 17 Dec 2024 01:24:44 +0000 Subject: [PATCH 236/259] fix: warn if engine / builder failed to produce block within cutoff time (#7305) --- .../src/api/impl/validator/index.ts | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index b15644a8087e..fe26c559661c 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -695,32 +695,46 @@ export function getValidatorApi( throw Error("Builder and engine both failed to produce the block within timeout"); } - if (engine.status === "rejected" && isEngineEnabled) { - logger.warn( - "Engine failed to produce the block", - { - ...loggerContext, - durationMs: engine.durationMs, - }, - engine.reason - ); - } - - if (builder.status === "rejected" && isBuilderEnabled) { - if (builder.reason instanceof NoBidReceived) { - logger.info("Builder did not provide a bid", { - ...loggerContext, - durationMs: builder.durationMs, - }); - } else { + if (isEngineEnabled) { + if (engine.status === "rejected") { logger.warn( - "Builder failed to produce the block", + "Engine failed to produce the block", { ...loggerContext, - durationMs: builder.durationMs, + durationMs: engine.durationMs, }, - builder.reason + engine.reason ); + } else if (engine.status === "pending") { + logger.warn("Engine failed to produce the block within cutoff time", { + ...loggerContext, + cutoffMs, + }); + } + } + + if (isBuilderEnabled) { + if (builder.status === "rejected") { + if (builder.reason instanceof NoBidReceived) { + logger.info("Builder did not provide a bid", { + ...loggerContext, + durationMs: builder.durationMs, + }); + } else { + logger.warn( + "Builder failed to produce the block", + { + ...loggerContext, + durationMs: builder.durationMs, + }, + builder.reason + ); + } + } else if (builder.status === "pending") { + logger.warn("Builder failed to produce the block within cutoff time", { + ...loggerContext, + cutoffMs, + }); } } From 7cd296b0466f75136cbf544aaec5ce000c89a8ed Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Mon, 16 Dec 2024 19:21:22 -0800 Subject: [PATCH 237/259] feat: add kzg commitment length check when validating gossip blocks (#7302) --- .../src/chain/errors/blockError.ts | 5 +- .../beacon-node/src/chain/validation/block.ts | 16 ++++++- .../test/unit/chain/validation/block.test.ts | 47 +++++++++++++++++-- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/src/chain/errors/blockError.ts b/packages/beacon-node/src/chain/errors/blockError.ts index bc5dd6c33956..1dc5b08ccc20 100644 --- a/packages/beacon-node/src/chain/errors/blockError.ts +++ b/packages/beacon-node/src/chain/errors/blockError.ts @@ -64,6 +64,8 @@ export enum BlockErrorCode { TOO_MANY_SKIPPED_SLOTS = "TOO_MANY_SKIPPED_SLOTS", /** The blobs are unavailable */ DATA_UNAVAILABLE = "BLOCK_ERROR_DATA_UNAVAILABLE", + /** Block contains too many kzg commitments */ + TOO_MANY_KZG_COMMITMENTS = "BLOCK_ERROR_TOO_MANY_KZG_COMMITMENTS", } type ExecutionErrorStatus = Exclude< @@ -105,7 +107,8 @@ export type BlockErrorType = | {code: BlockErrorCode.SAME_PARENT_HASH; blockHash: RootHex} | {code: BlockErrorCode.TRANSACTIONS_TOO_BIG; size: number; max: number} | {code: BlockErrorCode.EXECUTION_ENGINE_ERROR; execStatus: ExecutionErrorStatus; errorMessage: string} - | {code: BlockErrorCode.DATA_UNAVAILABLE}; + | {code: BlockErrorCode.DATA_UNAVAILABLE} + | {code: BlockErrorCode.TOO_MANY_KZG_COMMITMENTS; blobKzgCommitmentsLen: number; commitmentLimit: number}; export class BlockGossipError extends GossipActionError {} diff --git a/packages/beacon-node/src/chain/validation/block.ts b/packages/beacon-node/src/chain/validation/block.ts index 1b5251f77809..b2623aa4f79d 100644 --- a/packages/beacon-node/src/chain/validation/block.ts +++ b/packages/beacon-node/src/chain/validation/block.ts @@ -1,5 +1,5 @@ import {ChainForkConfig} from "@lodestar/config"; -import {ForkName} from "@lodestar/params"; +import {ForkName, isForkBlobs} from "@lodestar/params"; import { computeStartSlotAtEpoch, computeTimeAtSlot, @@ -8,7 +8,7 @@ import { isExecutionEnabled, isExecutionStateType, } from "@lodestar/state-transition"; -import {SignedBeaconBlock} from "@lodestar/types"; +import {SignedBeaconBlock, deneb} from "@lodestar/types"; import {sleep, toRootHex} from "@lodestar/utils"; import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../../constants/index.js"; import {BlockErrorCode, BlockGossipError, GossipAction} from "../errors/index.js"; @@ -110,6 +110,18 @@ export async function validateGossipBlock( }); } + // [REJECT] The length of KZG commitments is less than or equal to the limitation defined in Consensus Layer -- i.e. validate that len(body.signed_beacon_block.message.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK + if (isForkBlobs(fork)) { + const blobKzgCommitmentsLen = (block as deneb.BeaconBlock).body.blobKzgCommitments.length; + if (blobKzgCommitmentsLen > chain.config.MAX_BLOBS_PER_BLOCK) { + throw new BlockGossipError(GossipAction.REJECT, { + code: BlockErrorCode.TOO_MANY_KZG_COMMITMENTS, + blobKzgCommitmentsLen, + commitmentLimit: chain.config.MAX_BLOBS_PER_BLOCK, + }); + } + } + // use getPreState to reload state if needed. It also checks for whether the current finalized checkpoint is an ancestor of the block. // As a result, we throw an IGNORE (whereas the spec says we should REJECT for this scenario). // this is something we should change this in the future to make the code airtight to the spec. diff --git a/packages/beacon-node/test/unit/chain/validation/block.test.ts b/packages/beacon-node/test/unit/chain/validation/block.test.ts index 4b236181b038..5e3faf794453 100644 --- a/packages/beacon-node/test/unit/chain/validation/block.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/block.test.ts @@ -1,6 +1,6 @@ import {config} from "@lodestar/config/default"; import {ProtoBlock} from "@lodestar/fork-choice"; -import {ForkName} from "@lodestar/params"; +import {ForkBlobs, ForkName} from "@lodestar/params"; import {SignedBeaconBlock, ssz} from "@lodestar/types"; import {Mock, Mocked, beforeEach, describe, it, vi} from "vitest"; import {BlockErrorCode} from "../../../../src/chain/errors/index.js"; @@ -20,12 +20,15 @@ describe("gossip block validation", () => { let job: SignedBeaconBlock; const proposerIndex = 0; const clockSlot = 32; - const block = ssz.phase0.BeaconBlock.defaultValue(); + const block = ssz.deneb.BeaconBlock.defaultValue(); block.slot = clockSlot; const signature = EMPTY_SIGNATURE; const maxSkipSlots = 10; beforeEach(() => { + // Fill up with kzg commitments + block.body.blobKzgCommitments = Array.from({length: config.MAX_BLOBS_PER_BLOCK}, () => new Uint8Array([0])); + chain = getMockedBeaconChain(); vi.spyOn(chain.clock, "currentSlotWithGossipDisparity", "get").mockReturnValue(clockSlot); forkChoice = chain.forkChoice; @@ -184,9 +187,47 @@ describe("gossip block validation", () => { regen.getPreState.mockResolvedValue(state); // BLS signature verifier returns valid verifySignature.mockResolvedValue(true); - // Force proposer shuffling cache to return wrong value + // Force proposer shuffling cache to return correct value vi.spyOn(state.epochCtx, "getBeaconProposer").mockReturnValue(proposerIndex); await validateGossipBlock(config, chain, job, ForkName.phase0); }); + + it("deneb - TOO_MANY_KZG_COMMITMENTS", async () => { + // Return not known for proposed block + forkChoice.getBlockHex.mockReturnValueOnce(null); + // Returned parent block is latter than proposed block + forkChoice.getBlockHex.mockReturnValueOnce({slot: clockSlot - 1} as ProtoBlock); + // Regen returns some state + const state = generateCachedState(); + regen.getPreState.mockResolvedValue(state); + // BLS signature verifier returns valid + verifySignature.mockResolvedValue(true); + // Force proposer shuffling cache to return correct value + vi.spyOn(state.epochCtx, "getBeaconProposer").mockReturnValue(proposerIndex + 1); + // Add one extra kzg commitment in the block so it goes over the limit + (job as SignedBeaconBlock).message.body.blobKzgCommitments.push(new Uint8Array([0])); + + await expectRejectedWithLodestarError( + validateGossipBlock(config, chain, job, ForkName.deneb), + BlockErrorCode.TOO_MANY_KZG_COMMITMENTS + ); + }); + + it("deneb - valid", async () => { + // Return not known for proposed block + forkChoice.getBlockHex.mockReturnValueOnce(null); + // Returned parent block is latter than proposed block + forkChoice.getBlockHex.mockReturnValueOnce({slot: clockSlot - 1} as ProtoBlock); + // Regen returns some state + const state = generateCachedState(); + regen.getPreState.mockResolvedValue(state); + // BLS signature verifier returns valid + verifySignature.mockResolvedValue(true); + // Force proposer shuffling cache to return correct value + vi.spyOn(state.epochCtx, "getBeaconProposer").mockReturnValue(proposerIndex); + // Keep number of kzg commitments as is so it stays within the limit + + await validateGossipBlock(config, chain, job, ForkName.deneb); + }); }); From bfe54d25def3e72705c6fa027549878d7e69f996 Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:45:51 -0800 Subject: [PATCH 238/259] feat: add blob sidecar index check (#7313) Validate blobSidecar index --- .../beacon-node/src/chain/errors/blobSidecarError.ts | 2 ++ packages/beacon-node/src/chain/validation/blobSidecar.ts | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/packages/beacon-node/src/chain/errors/blobSidecarError.ts b/packages/beacon-node/src/chain/errors/blobSidecarError.ts index 71118d8b8f9d..216ad9206db4 100644 --- a/packages/beacon-node/src/chain/errors/blobSidecarError.ts +++ b/packages/beacon-node/src/chain/errors/blobSidecarError.ts @@ -2,6 +2,7 @@ import {RootHex, Slot, ValidatorIndex} from "@lodestar/types"; import {GossipActionError} from "./gossipValidation.js"; export enum BlobSidecarErrorCode { + INDEX_TOO_LARGE = "BLOB_SIDECAR_ERROR_INDEX_TOO_LARGE", INVALID_INDEX = "BLOB_SIDECAR_ERROR_INVALID_INDEX", /** !bls.KeyValidate(block.body.blob_kzg_commitments[i]) */ INVALID_KZG = "BLOB_SIDECAR_ERROR_INVALID_KZG", @@ -26,6 +27,7 @@ export enum BlobSidecarErrorCode { } export type BlobSidecarErrorType = + | {code: BlobSidecarErrorCode.INDEX_TOO_LARGE; blobIdx: number; maxBlobsPerBlock: number} | {code: BlobSidecarErrorCode.INVALID_INDEX; blobIdx: number; subnet: number} | {code: BlobSidecarErrorCode.INVALID_KZG; blobIdx: number} | {code: BlobSidecarErrorCode.INVALID_KZG_TXS} diff --git a/packages/beacon-node/src/chain/validation/blobSidecar.ts b/packages/beacon-node/src/chain/validation/blobSidecar.ts index e2f4ed267d01..4aeff0f23ff1 100644 --- a/packages/beacon-node/src/chain/validation/blobSidecar.ts +++ b/packages/beacon-node/src/chain/validation/blobSidecar.ts @@ -18,6 +18,15 @@ export async function validateGossipBlobSidecar( ): Promise { const blobSlot = blobSidecar.signedBlockHeader.message.slot; + // [REJECT] The sidecar's index is consistent with `MAX_BLOBS_PER_BLOCK` -- i.e. `blob_sidecar.index < MAX_BLOBS_PER_BLOCK`. + if (blobSidecar.index < chain.config.MAX_BLOBS_PER_BLOCK) { + throw new BlobSidecarGossipError(GossipAction.REJECT, { + code: BlobSidecarErrorCode.INDEX_TOO_LARGE, + blobIdx: blobSidecar.index, + maxBlobsPerBlock: chain.config.MAX_BLOBS_PER_BLOCK, + }); + } + // [REJECT] The sidecar is for the correct subnet -- i.e. `compute_subnet_for_blob_sidecar(sidecar.index) == subnet_id`. if (computeSubnetForBlobSidecar(blobSidecar.index, chain.config) !== subnet) { throw new BlobSidecarGossipError(GossipAction.REJECT, { From 1f38c8b1751c810e267ceab4d56d06735ac3445c Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Wed, 18 Dec 2024 17:31:22 -0800 Subject: [PATCH 239/259] fix: fix blob sidecar index check (#7315) Fix index check --- packages/beacon-node/src/chain/validation/blobSidecar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/src/chain/validation/blobSidecar.ts b/packages/beacon-node/src/chain/validation/blobSidecar.ts index 4aeff0f23ff1..b79db77e3931 100644 --- a/packages/beacon-node/src/chain/validation/blobSidecar.ts +++ b/packages/beacon-node/src/chain/validation/blobSidecar.ts @@ -19,7 +19,7 @@ export async function validateGossipBlobSidecar( const blobSlot = blobSidecar.signedBlockHeader.message.slot; // [REJECT] The sidecar's index is consistent with `MAX_BLOBS_PER_BLOCK` -- i.e. `blob_sidecar.index < MAX_BLOBS_PER_BLOCK`. - if (blobSidecar.index < chain.config.MAX_BLOBS_PER_BLOCK) { + if (blobSidecar.index >= chain.config.MAX_BLOBS_PER_BLOCK) { throw new BlobSidecarGossipError(GossipAction.REJECT, { code: BlobSidecarErrorCode.INDEX_TOO_LARGE, blobIdx: blobSidecar.index, From 8c7eaf8c57b56aa9294dcb8607f334b5500de237 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 19 Dec 2024 09:35:23 +0000 Subject: [PATCH 240/259] chore: fix format of printed graffiti from hex to utf-8 (#7306) * chore: fix format of printed graffiti from hex to utf-8 * Use Buffer.from no copy with offset --- .../beacon-node/src/chain/produceBlock/produceBlockBody.ts | 3 ++- packages/beacon-node/src/util/graffiti.ts | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index 0b7797828c98..d7b36e06abc4 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -37,6 +37,7 @@ import {ZERO_HASH, ZERO_HASH_HEX} from "../../constants/index.js"; import {IEth1ForBlockProduction} from "../../eth1/index.js"; import {numToQuantity} from "../../eth1/provider/utils.js"; import {IExecutionBuilder, IExecutionEngine, PayloadAttributes, PayloadId} from "../../execution/index.js"; +import {fromGraffitiBuffer} from "../../util/graffiti.js"; import type {BeaconChain} from "../chain.js"; import {CommonBlockBody} from "../interface.js"; import {validateBlobsAndKzgCommitments} from "./validateBlobsAndKzgCommitments.js"; @@ -154,7 +155,7 @@ export async function produceBlockBody( } = blockBody; Object.assign(logMeta, { - graffiti, + graffiti: fromGraffitiBuffer(graffiti), attestations: attestations.length, deposits: deposits.length, voluntaryExits: voluntaryExits.length, diff --git a/packages/beacon-node/src/util/graffiti.ts b/packages/beacon-node/src/util/graffiti.ts index 9a4bc3d9689b..fb5c30aca3d3 100644 --- a/packages/beacon-node/src/util/graffiti.ts +++ b/packages/beacon-node/src/util/graffiti.ts @@ -8,6 +8,13 @@ export function toGraffitiBuffer(graffiti: string): Buffer { return Buffer.concat([Buffer.from(graffiti, "utf8"), Buffer.alloc(GRAFFITI_SIZE, 0)], GRAFFITI_SIZE); } +/** + * Converts a graffiti from 32 bytes buffer back to a UTF-8 string + */ +export function fromGraffitiBuffer(graffiti: Uint8Array): string { + return Buffer.from(graffiti.buffer, graffiti.byteOffset, graffiti.byteLength).toString("utf8"); +} + export function getDefaultGraffiti( consensusClientVersion: ClientVersion, executionClientVersion: ClientVersion | null | undefined, From ffdfb2e51704456ffb49214b5aba9bd7a2360051 Mon Sep 17 00:00:00 2001 From: Phil Ngo <58080811+philknows@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:44:42 -0500 Subject: [PATCH 241/259] docs: batch commit typos and update contributor readme (#7312) * batch commit typos and update contributor readme * update donation text Co-authored-by: Nico Flaig * correct spelling Co-authored-by: Nico Flaig --------- Co-authored-by: Nico Flaig --- .wordlist.txt | 1 - CONTRIBUTING.md | 2 ++ README.md | 4 ++-- RELEASE.md | 2 +- docs/pages/contribution/testing/index.md | 4 ++-- docs/pages/contribution/tools/heap-dumps.md | 4 ++-- docs/pages/faqs.md | 2 +- docs/pages/introduction.md | 2 +- docs/pages/run/logging-and-metrics/client-monitoring.md | 2 +- packages/light-client/README.md | 6 +++--- packages/params/README.md | 2 +- packages/prover/README.md | 2 +- packages/utils/src/yaml/int.ts | 2 +- scripts/await-release.sh | 2 +- 14 files changed, 19 insertions(+), 18 deletions(-) diff --git a/.wordlist.txt b/.wordlist.txt index 5070aafcf9a5..d74291a2fb0c 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -198,7 +198,6 @@ namespaces nodemodule orchestrator osx -overriden params performant pid diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 24d087810980..ca5a28442fd8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -126,6 +126,8 @@ Unsure where to begin contributing to Lodestar? Here are some ideas! 5. Make an open pull request when you're ready for it to be reviewed. We review PRs on a regular basis. See Pull request etiquette for more information. 6. You may be asked to sign a Contributor License Agreement (CLA). We make it relatively painless with CLA-bot. +Please note that trivial, non-code contributions such as spelling, grammar, typos, corrections, comments and link fixes are not acceptable pull requests. Although we appreciate the effort to fix these valid concerns, it is not practical for us to run our CI systems to accommodate minor external contributions which generate minimal value for the purpose of contribution/airdrop farming. It would be appreciated for you to open up an issue instead for our team to aggregate these types of contributions into a batch commit. + ## Github Style Guide **Branch Naming** diff --git a/README.md b/README.md index e03de683a9de..53c53cee8621 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,9 @@ Read our [contributors document](/CONTRIBUTING.md), [submit an issue](https://gi ## Meetings -Weekly contributor meetings are public and announced on Discord. Feel free to check out our meeting notes and documents on [HackMD](https://hackmd.io/@wemeetagain/rJTEOdqPS/%2FXBzvaQgMTyyMJuToWAEDjw). Post-September 2021, meeting notes can be found on the [Lodestar Wiki Page](https://github.com/ChainSafe/lodestar/wiki). +Weekly contributor meetings are posted under [Discussions](https://github.com/ChainSafe/lodestar/discussions) and topics are welcomed by any participant in the relevant meeting thread. Feel free to check out our meeting notes and documents on [HackMD](https://hackmd.io/@wemeetagain/rJTEOdqPS/%2FXBzvaQgMTyyMJuToWAEDjw). Post-September 2021, meeting notes can be found on the [Lodestar Wiki Page](https://github.com/ChainSafe/lodestar/wiki). ## Donations We are a local group of Toronto open-source developers. As such, all of our open-source work is funded by grants. We all take the time out of our hectic lives to contribute to the Ethereum ecosystem. -If you want to donate, you can send us ETH at the following address: `lodestar.chainsafe.eth` +If you want to donate, you can find the ETH address under "Sponsor this project" on this repository. diff --git a/RELEASE.md b/RELEASE.md index bb40b611ebe5..6d831ddb3bd4 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -69,7 +69,7 @@ Tagging a release candidate will trigger CI to publish to NPM, dockerhub, and Gi Once a release candidate is created, the Lodestar team begins a testing period. -If there is a bug discovered during the testing period which significantly impacts performance, security, or stability, and it is determined that it is no longer prudent to promote the `rc.x` candidate to `stable`, then it will await a bug fix by the team. The fix will be committed to `unstable` first, then cherrypicked into the `rc/v1.1.0` branch. Then we publish and promote the new commit to `rc.x+1`. The 3 day testing period will reset. +If there is a bug discovered during the testing period which significantly impacts performance, security, or stability, and it is determined that it is no longer prudent to promote the `rc.x` candidate to `stable`, then it will await a bug fix by the team. The fix will be committed to `unstable` first, then cherrypicked into the `rc/v1.1.0` branch. Then we publish and promote the new commit to `rc.x+1`. The 3-day testing period will reset. For example: After 3-5 days of testing, is performance equal to or better than latest stable? diff --git a/docs/pages/contribution/testing/index.md b/docs/pages/contribution/testing/index.md index ecef1ef22c56..a9795670fa82 100644 --- a/docs/pages/contribution/testing/index.md +++ b/docs/pages/contribution/testing/index.md @@ -2,7 +2,7 @@ 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. +There are a few flags you can set through env variables to override behavior of testing and its output. | ENV variable | Effect | Impact | | ------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------- | @@ -24,7 +24,7 @@ Node.js is an unforgiving virtual machine when it comes to high performance, mul ### End-To-End Tests -E2E test are where Lodestar is run in its full form, often from the CLI as a user would to check that the system as a whole works as expected. These tests are meant to exercise the entire system in isolation and there is no network interaction, nor interaction with any other code outside of Lodestar. See the [End-To-End Testing](./end-to-end-tests.md) page for more information. +E2E tests are where Lodestar is run in its full form, often from the CLI as a user would to check that the system as a whole works as expected. These tests are meant to exercise the entire system in isolation and there is no network interaction, nor interaction with any other code outside of Lodestar. See the [End-To-End Testing](./end-to-end-tests.md) page for more information. ### Integration Tests diff --git a/docs/pages/contribution/tools/heap-dumps.md b/docs/pages/contribution/tools/heap-dumps.md index 97f2be51dfac..612dfebc3f83 100644 --- a/docs/pages/contribution/tools/heap-dumps.md +++ b/docs/pages/contribution/tools/heap-dumps.md @@ -40,7 +40,7 @@ Click on the `Open dedicated DevTools for Node` link to open the node specific w ![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 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) @@ -70,7 +70,7 @@ Having a good understanding of the codebase will help to narrow down where to lo _**note: collecting a native heap dump is only supported on linux, analysis can be done from linux or Mac**_ -There are several tools that can be used to do native heap dump analysis. The most common are [`massif`](https://valgrind.org/docs/manual/ms-manual.html) from the [`Valgrind`](https://valgrind.org/) suite, google's [`gperftools`](https://github.com/gperftools/gperftools) and `heaptrack` from [KDE](https://community.kde.org/Main_Page). Of the three, `heaptrack` is the most user friendly tool, and it is specifically designed for the task. It is much faster than `Valgrind`, easier to integrate than `gperftools` and also includes a gui for result analysis. Often times there are also memory allocations that are not related to memory leaks, and tools like `Valgrind` and `gperftools` become less useful. This is why `heaptrack` is the recommended tool for heap dump analysis on Lodestar. +There are several tools that can be used to do native heap dump analysis. The most common are [`massif`](https://valgrind.org/docs/manual/ms-manual.html) from the [`Valgrind`](https://valgrind.org/) suite, google's [`gperftools`](https://github.com/gperftools/gperftools) and `heaptrack` from [KDE](https://community.kde.org/Main_Page). Of the three, `heaptrack` is the most user-friendly tool, and it is specifically designed for the task. It is much faster than `Valgrind`, easier to integrate than `gperftools` and also includes a gui for result analysis. Often times there are also memory allocations that are not related to memory leaks, and tools like `Valgrind` and `gperftools` become less useful. This is why `heaptrack` is the recommended tool for heap dump analysis on Lodestar. There are a few things that will make the results with `heaptrack` far better. The most important is using debug builds of all libraries included in a binary, including the application itself. This will make the results usable. Not to say that they will be useless without debug symbols but it will be kinda tough to optimize functions without knowing the function names nor the file and line numbers. diff --git a/docs/pages/faqs.md b/docs/pages/faqs.md index e7ac490bf9b9..ebe2a2158a2d 100644 --- a/docs/pages/faqs.md +++ b/docs/pages/faqs.md @@ -1,6 +1,6 @@ # Frequently Asked Questions -This section of the documentation will cover common questions and encounters often asked by users and developers. +This section of the documentation will cover common questions and common encounters by users and developers. ## Tooling diff --git a/docs/pages/introduction.md b/docs/pages/introduction.md index f74d0b70768d..5633131dd600 100644 --- a/docs/pages/introduction.md +++ b/docs/pages/introduction.md @@ -1,6 +1,6 @@ # Introduction -Ethereum is one of the most profoundly important inventions in recent history. It is a decentralized, open-source blockchain featuring smart contract functionality. It is the second-largest cryptocurrency by market capitalization, after Bitcoin, and is the second largest blockchain by market capitalization. Ethereum was proposed in 2013 by programmer Vitalik Buterin. Development was crowdfunded in 2014, and the network went live on 30 July 2015, with 72 million coins premined. ChainSafe was founded not too long afterwards in 2017 and has been actively working in the Ethereum ecosystem ever since. We are proud to develop Lodestar, the only TypeScript based consensus client, and to present this documentation as a resource for the Ethereum community. +Ethereum is one of the most profoundly important inventions in recent history. It is a decentralized, open-source blockchain featuring smart contract functionality. It is the second-largest cryptocurrency by market capitalization, after Bitcoin, and is the second-largest blockchain by market capitalization. Ethereum was proposed in 2013 by programmer Vitalik Buterin. Development was crowdfunded in 2014, and the network went live on 30 July 2015, with 72 million coins premined. ChainSafe was founded not too long afterwards in 2017 and has been actively working in the Ethereum ecosystem ever since. We are proud to develop Lodestar, the only TypeScript based consensus client, and to present this documentation as a resource for the Ethereum community. ## Proof of Stake diff --git a/docs/pages/run/logging-and-metrics/client-monitoring.md b/docs/pages/run/logging-and-metrics/client-monitoring.md index 3d9ede1d8464..31a20600ecf3 100644 --- a/docs/pages/run/logging-and-metrics/client-monitoring.md +++ b/docs/pages/run/logging-and-metrics/client-monitoring.md @@ -27,7 +27,7 @@ When sending data to a remote service you should be conscious about security: - Only use a service that you trust as this will send information which may identify you and associate your validators, IP address and other personal information. -- Always use a HTTPS connection (i.e. a URL starting with `https://`) to prevent the traffic +- Always use an HTTPS connection (i.e. a URL starting with `https://`) to prevent the traffic from being intercepted in transit and leaking information. ::: diff --git a/packages/light-client/README.md b/packages/light-client/README.md index 3cab0c12f13b..f9af65f23f98 100644 --- a/packages/light-client/README.md +++ b/packages/light-client/README.md @@ -18,7 +18,7 @@ The evolution of light clients is emblematic of the broader trajectory of Ethere ## Requirements for Running a Light-Client -Access to an beacon node that supports the light client specification is necessary. The client must support the following routes from the [consensus API spec](https://github.com/ethereum/beacon-APIs/tree/v2.5.0/apis/beacon/light_client): +Access to a beacon node that supports the light client specification is necessary. The client must support the following routes from the [consensus API spec](https://github.com/ethereum/beacon-APIs/tree/v2.5.0/apis/beacon/light_client): - [`GET /eth/v1/beacon/light_client/updates`](https://ethereum.github.io/beacon-APIs/?urls.primaryName=v2.5.0#/Beacon/getLightClientUpdatesByRange) - [`GET /eth/v1/beacon/light_client/optimistic_update`](https://ethereum.github.io/beacon-APIs/?urls.primaryName=v2.5.0#/Beacon/getLightClientOptimisticUpdate) @@ -32,7 +32,7 @@ You can find more information about the light-client protocol in the [specificat ## Getting started - Follow the [installation guide](https://chainsafe.github.io/lodestar/run/getting-started/installation) to install Lodestar. -- Quickly try out the whole stack by [starting a local testnet](https://chainsafe.github.io/lodestar/advanced-topics/setting-up-a-testnet). +- Quickly try out the whole stack by [starting a local testnet](https://chainsafe.github.io/lodestar/contribution/advanced-topics/setting-up-a-testnet). ## Light-Client CLI Example @@ -92,7 +92,7 @@ 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.20.0` version. +If you want to use Lightclient in browser and are facing some issues in building it with bundlers like webpack, vite. We suggest using our distribution build. The support for single distribution build is started from `1.20.0` version. Directly link the dist build with the `