diff --git a/packages/beacon-node/src/api/impl/validator/utils.ts b/packages/beacon-node/src/api/impl/validator/utils.ts index b8e5aa525f25..f7d69ec97847 100644 --- a/packages/beacon-node/src/api/impl/validator/utils.ts +++ b/packages/beacon-node/src/api/impl/validator/utils.ts @@ -1,7 +1,7 @@ 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 {BLSPubkey, CommitteeIndex, ProducedBlockSource, Slot, SubnetID, ValidatorIndex} from "@lodestar/types"; import {MAX_BUILDER_BOOST_FACTOR} from "@lodestar/validator"; import {BlockSelectionResult, BuilderBlockSelectionReason, EngineBlockSelectionReason} from "./index.js"; @@ -9,7 +9,7 @@ export function computeSubnetForCommitteesAtSlot( slot: Slot, committeesAtSlot: number, committeeIndex: CommitteeIndex -): number { +): SubnetID { const slotsSinceEpochStart = computeSlotsSinceEpochStart(slot); const committeesSinceEpochStart = committeesAtSlot * slotsSinceEpochStart; return (committeesSinceEpochStart + committeeIndex) % ATTESTATION_SUBNET_COUNT; diff --git a/packages/beacon-node/src/chain/errors/blobSidecarError.ts b/packages/beacon-node/src/chain/errors/blobSidecarError.ts index 71118d8b8f9d..0f31e587e647 100644 --- a/packages/beacon-node/src/chain/errors/blobSidecarError.ts +++ b/packages/beacon-node/src/chain/errors/blobSidecarError.ts @@ -1,4 +1,4 @@ -import {RootHex, Slot, ValidatorIndex} from "@lodestar/types"; +import {RootHex, Slot, SubnetID, ValidatorIndex} from "@lodestar/types"; import {GossipActionError} from "./gossipValidation.js"; export enum BlobSidecarErrorCode { @@ -26,7 +26,7 @@ export enum BlobSidecarErrorCode { } export type BlobSidecarErrorType = - | {code: BlobSidecarErrorCode.INVALID_INDEX; blobIdx: number; subnet: number} + | {code: BlobSidecarErrorCode.INVALID_INDEX; blobIdx: number; subnet: SubnetID} | {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/opPools/syncCommitteeMessagePool.ts b/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts index 6551ee625491..fd7b9bd3a235 100644 --- a/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts +++ b/packages/beacon-node/src/chain/opPools/syncCommitteeMessagePool.ts @@ -146,7 +146,7 @@ function aggregateSignatureInto( * Format `signature` into an efficient `contribution` to add more signatures in with aggregateSignatureInto() */ function signatureToAggregate( - subnet: number, + subnet: Subnet, signature: altair.SyncCommitteeMessage, indexInSubcommittee: number ): ContributionFast { diff --git a/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts b/packages/beacon-node/src/chain/seenCache/seenAttestationData.ts index 8e0dfcb3bd96..8c5df69e783b 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, RootHex, Slot, phase0} from "@lodestar/types"; +import {CommitteeIndex, RootHex, Slot, SubnetID, phase0} from "@lodestar/types"; import {MapDef} from "@lodestar/utils"; import {Metrics} from "../../metrics/metrics.js"; import {InsertOutcome} from "../opPools/types.js"; @@ -23,7 +23,7 @@ export type AttestationDataCacheEntry = { // caching this for 3 slots take 600 instances max, this is nothing compared to attestations processed per slot // for example in a mainnet node subscribing to all subnets, attestations are processed up to 20k per slot attestationData: phase0.AttestationData; - subnet: number; + subnet: SubnetID; }; export enum RejectReason { diff --git a/packages/beacon-node/src/chain/seenCache/seenCommittee.ts b/packages/beacon-node/src/chain/seenCache/seenCommittee.ts index 9d7e930c94d7..44411eaf2115 100644 --- a/packages/beacon-node/src/chain/seenCache/seenCommittee.ts +++ b/packages/beacon-node/src/chain/seenCache/seenCommittee.ts @@ -38,6 +38,6 @@ export class SeenSyncCommitteeMessages { } } -function seenCacheKey(subnet: number, validatorIndex: ValidatorIndex): ValidatorSubnetKey { +function seenCacheKey(subnet: SubcommitteeIndex, validatorIndex: ValidatorIndex): ValidatorSubnetKey { return `${subnet}-${validatorIndex}`; } diff --git a/packages/beacon-node/src/chain/validation/attestation.ts b/packages/beacon-node/src/chain/validation/attestation.ts index e49a3f79450c..05f3faeaebd6 100644 --- a/packages/beacon-node/src/chain/validation/attestation.ts +++ b/packages/beacon-node/src/chain/validation/attestation.ts @@ -27,6 +27,7 @@ import { Root, RootHex, Slot, + SubnetID, electra, isElectraAttestation, phase0, @@ -58,7 +59,7 @@ export type BatchResult = { export type AttestationValidationResult = { attestation: Attestation; indexedAttestation: IndexedAttestation; - subnet: number; + subnet: SubnetID; attDataRootHex: RootHex; committeeIndex: CommitteeIndex; }; @@ -93,7 +94,7 @@ export async function validateGossipAttestationsSameAttData( fork: ForkName, chain: IBeaconChain, attestationOrBytesArr: GossipAttestation[], - subnet: number, + subnet: SubnetID, // for unit test, consumers do not need to pass this step0ValidationFn = validateAttestationNoSignatureCheck ): Promise { @@ -232,7 +233,7 @@ async function validateAttestationNoSignatureCheck( chain: IBeaconChain, attestationOrBytes: AttestationOrBytes, /** Optional, to allow verifying attestations through API with unknown subnet */ - subnet: number | null + subnet: SubnetID | null ): Promise { // Do checks in this order: // - do early checks (w/o indexed attestation) @@ -342,7 +343,7 @@ async function validateAttestationNoSignatureCheck( let committeeValidatorIndices: Uint32Array; let getSigningRoot: () => Uint8Array; - let expectedSubnet: number; + let expectedSubnet: SubnetID; if (attestationOrCache.cache) { committeeValidatorIndices = attestationOrCache.cache.committeeValidatorIndices; const signingRoot = attestationOrCache.cache.signingRoot; @@ -762,7 +763,7 @@ export function getCommitteeIndices( /** * Compute the correct subnet for a slot/committee index */ -export function computeSubnetForSlot(shuffling: EpochShuffling, slot: number, committeeIndex: number): number { +export function computeSubnetForSlot(shuffling: EpochShuffling, slot: number, committeeIndex: number): SubnetID { const slotsSinceEpochStart = slot % SLOTS_PER_EPOCH; const committeesSinceEpochStart = shuffling.committeesPerSlot * slotsSinceEpochStart; return (committeesSinceEpochStart + committeeIndex) % ATTESTATION_SUBNET_COUNT; diff --git a/packages/beacon-node/src/chain/validation/blobSidecar.ts b/packages/beacon-node/src/chain/validation/blobSidecar.ts index e2f4ed267d01..71fdbbf3bc90 100644 --- a/packages/beacon-node/src/chain/validation/blobSidecar.ts +++ b/packages/beacon-node/src/chain/validation/blobSidecar.ts @@ -1,7 +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 {BlobIndex, Root, Slot, deneb, ssz} from "@lodestar/types"; +import {BlobIndex, Root, Slot, SubnetID, deneb, ssz} from "@lodestar/types"; import {toRootHex, verifyMerkleBranch} from "@lodestar/utils"; import {byteArrayEquals} from "../../util/bytes.js"; @@ -14,7 +14,7 @@ import {RegenCaller} from "../regen/index.js"; export async function validateGossipBlobSidecar( chain: IBeaconChain, blobSidecar: deneb.BlobSidecar, - subnet: number + subnet: SubnetID ): Promise { const blobSlot = blobSidecar.signedBlockHeader.message.slot; @@ -227,6 +227,6 @@ function validateInclusionProof(blobSidecar: deneb.BlobSidecar): boolean { ); } -function computeSubnetForBlobSidecar(blobIndex: BlobIndex, config: ChainConfig): number { +function computeSubnetForBlobSidecar(blobIndex: BlobIndex, config: ChainConfig): SubnetID { return blobIndex % config.BLOB_SIDECAR_SUBNET_COUNT; } diff --git a/packages/beacon-node/src/chain/validation/syncCommittee.ts b/packages/beacon-node/src/chain/validation/syncCommittee.ts index c563bf7cf6be..fb4b7741b4fd 100644 --- a/packages/beacon-node/src/chain/validation/syncCommittee.ts +++ b/packages/beacon-node/src/chain/validation/syncCommittee.ts @@ -1,6 +1,6 @@ import {SYNC_COMMITTEE_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; -import {altair} from "@lodestar/types"; +import {SubnetID, altair} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {GossipAction, SyncCommitteeError, SyncCommitteeErrorCode} from "../errors/index.js"; import {IBeaconChain} from "../interface.js"; @@ -14,7 +14,7 @@ type IndexInSubcommittee = number; export async function validateGossipSyncCommittee( chain: IBeaconChain, syncCommittee: altair.SyncCommitteeMessage, - subnet: number + subnet: SubnetID ): Promise<{indexInSubcommittee: IndexInSubcommittee}> { const {slot, validatorIndex, beaconBlockRoot} = syncCommittee; const messageRoot = toRootHex(beaconBlockRoot); @@ -103,7 +103,7 @@ async function validateSyncCommitteeSigOnly( export function validateGossipSyncCommitteeExceptSig( chain: IBeaconChain, headState: CachedBeaconStateAllForks, - subnet: number, + subnet: SubnetID, data: Pick ): IndexInSubcommittee { const {slot, validatorIndex} = data; @@ -144,7 +144,7 @@ export function validateGossipSyncCommitteeExceptSig( */ function getIndexInSubcommittee( headState: CachedBeaconStateAllForks, - subnet: number, + subnet: SubnetID, data: Pick ): IndexInSubcommittee | null { const syncCommittee = headState.epochCtx.getIndexedSyncCommittee(data.slot); diff --git a/packages/beacon-node/src/metrics/validatorMonitor.ts b/packages/beacon-node/src/metrics/validatorMonitor.ts index 401d58af57ff..1c9a093656ce 100644 --- a/packages/beacon-node/src/metrics/validatorMonitor.ts +++ b/packages/beacon-node/src/metrics/validatorMonitor.ts @@ -10,7 +10,7 @@ import { parseAttesterFlags, parseParticipationFlags, } from "@lodestar/state-transition"; -import {BeaconBlock, RootHex, altair, deneb} from "@lodestar/types"; +import {BeaconBlock, RootHex, SubnetID, altair, deneb} from "@lodestar/types"; import {Epoch, Slot, ValidatorIndex} from "@lodestar/types"; import {IndexedAttestation, SignedAggregateAndProof} from "@lodestar/types"; import {LogData, LogHandler, LogLevel, Logger, MapDef, MapDefMax, toRootHex} from "@lodestar/utils"; @@ -52,7 +52,7 @@ export type ValidatorMonitor = { onPoolSubmitUnaggregatedAttestation( seenTimestampSec: number, indexedAttestation: IndexedAttestation, - subnet: number, + subnet: SubnetID, sentPeers: number ): void; onPoolSubmitAggregatedAttestation( diff --git a/packages/beacon-node/src/network/core/metrics.ts b/packages/beacon-node/src/network/core/metrics.ts index 7d0ef47d84af..0c9155893ced 100644 --- a/packages/beacon-node/src/network/core/metrics.ts +++ b/packages/beacon-node/src/network/core/metrics.ts @@ -1,3 +1,4 @@ +import {SubnetID} from "@lodestar/types"; import {RegistryMetricCreator} from "../../metrics/utils/registryMetricCreator.js"; import {SubnetType} from "../metadata.js"; import {DiscoveredPeerStatus} from "../peers/discover.js"; @@ -194,14 +195,14 @@ export function createNetworkCoreMetrics(register: RegistryMetricCreator) { name: "lodestar_attnets_service_committee_subscriptions_total", help: "Count of committee subscriptions", }), - subscriptionsCommitteeMeshPeers: register.histogram<{subnet: number}>({ + subscriptionsCommitteeMeshPeers: register.histogram<{subnet: SubnetID}>({ name: "lodestar_attnets_service_committee_subscriptions_mesh_peers", help: "Histogram of mesh peers per committee subscription", labelNames: ["subnet"], // Dlow = 6, D = 8, DHi = 12 plus 2 more buckets buckets: [0, 4, 6, 8, 12], }), - subscriptionsCommitteeTimeToStableMesh: register.histogram<{subnet: number}>({ + subscriptionsCommitteeTimeToStableMesh: register.histogram<{subnet: SubnetID}>({ name: "lodestar_attnets_service_committee_subscriptions_time_to_stable_mesh_seconds", help: "Histogram of time until committee subscription is considered healthy (>= 6 mesh peers)", labelNames: ["subnet"], @@ -216,12 +217,12 @@ export function createNetworkCoreMetrics(register: RegistryMetricCreator) { name: "lodestar_attnets_service_long_lived_subscriptions_total", help: "Count of long lived subscriptions", }), - subscribeSubnets: register.gauge<{subnet: number; src: SubnetSource}>({ + subscribeSubnets: register.gauge<{subnet: SubnetID; src: SubnetSource}>({ name: "lodestar_attnets_service_subscribe_subnets_total", help: "Count of subscribe_subnets calls", labelNames: ["subnet", "src"], }), - unsubscribeSubnets: register.gauge<{subnet: number; src: SubnetSource}>({ + unsubscribeSubnets: register.gauge<{subnet: SubnetID; src: SubnetSource}>({ name: "lodestar_attnets_service_unsubscribe_subnets_total", help: "Count of unsubscribe_subnets calls", labelNames: ["subnet", "src"], @@ -237,12 +238,12 @@ export function createNetworkCoreMetrics(register: RegistryMetricCreator) { name: "lodestar_syncnets_service_committee_subscriptions_total", help: "Count of syncnet committee subscriptions", }), - subscribeSubnets: register.gauge<{subnet: number}>({ + subscribeSubnets: register.gauge<{subnet: SubnetID}>({ name: "lodestar_syncnets_service_subscribe_subnets_total", help: "Count of syncnet subscribe_subnets calls", labelNames: ["subnet"], }), - unsubscribeSubnets: register.gauge<{subnet: number}>({ + unsubscribeSubnets: register.gauge<{subnet: SubnetID}>({ name: "lodestar_syncnets_service_unsubscribe_subnets_total", help: "Count of syncnet unsubscribe_subnets calls", labelNames: ["subnet"], diff --git a/packages/beacon-node/src/network/gossip/gossipsub.ts b/packages/beacon-node/src/network/gossip/gossipsub.ts index 9f2b47e21c6f..236cc40a8d05 100644 --- a/packages/beacon-node/src/network/gossip/gossipsub.ts +++ b/packages/beacon-node/src/network/gossip/gossipsub.ts @@ -4,6 +4,7 @@ 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 {SubnetID} from "@lodestar/types"; import {Logger, Map2d, Map2dArr} from "@lodestar/utils"; import {GOSSIP_MAX_SIZE, GOSSIP_MAX_SIZE_BELLATRIX} from "../../constants/network.js"; @@ -319,7 +320,7 @@ export class Eth2Gossipsub extends GossipSub { * Left pad subnets to two characters. Assumes ATTESTATION_SUBNET_COUNT < 99 * Otherwise grafana sorts the mesh peers chart as: [1,11,12,13,...] */ -function attSubnetLabel(subnet: number): string { +function attSubnetLabel(subnet: SubnetID): string { if (subnet > 9) return String(subnet); return `0${subnet}`; diff --git a/packages/beacon-node/src/network/gossip/interface.ts b/packages/beacon-node/src/network/gossip/interface.ts index be7293524ce9..1a91a5bc6598 100644 --- a/packages/beacon-node/src/network/gossip/interface.ts +++ b/packages/beacon-node/src/network/gossip/interface.ts @@ -9,6 +9,7 @@ import { SignedAggregateAndProof, SignedBeaconBlock, Slot, + SubnetID, altair, capella, deneb, @@ -54,16 +55,16 @@ export interface IGossipTopic { export type GossipTopicTypeMap = { [GossipType.beacon_block]: {type: GossipType.beacon_block}; - [GossipType.blob_sidecar]: {type: GossipType.blob_sidecar; subnet: number}; + [GossipType.blob_sidecar]: {type: GossipType.blob_sidecar; subnet: SubnetID}; [GossipType.beacon_aggregate_and_proof]: {type: GossipType.beacon_aggregate_and_proof}; - [GossipType.beacon_attestation]: {type: GossipType.beacon_attestation; subnet: number}; + [GossipType.beacon_attestation]: {type: GossipType.beacon_attestation; subnet: SubnetID}; [GossipType.voluntary_exit]: {type: GossipType.voluntary_exit}; [GossipType.proposer_slashing]: {type: GossipType.proposer_slashing}; [GossipType.attester_slashing]: {type: GossipType.attester_slashing}; [GossipType.sync_committee_contribution_and_proof]: { type: GossipType.sync_committee_contribution_and_proof; }; - [GossipType.sync_committee]: {type: GossipType.sync_committee; subnet: number}; + [GossipType.sync_committee]: {type: GossipType.sync_committee; subnet: SubnetID}; [GossipType.light_client_finality_update]: {type: GossipType.light_client_finality_update}; [GossipType.light_client_optimistic_update]: {type: GossipType.light_client_optimistic_update}; [GossipType.bls_to_execution_change]: {type: GossipType.bls_to_execution_change}; diff --git a/packages/beacon-node/src/network/gossip/metrics.ts b/packages/beacon-node/src/network/gossip/metrics.ts index 5ca5d22154c2..3e11615b44b5 100644 --- a/packages/beacon-node/src/network/gossip/metrics.ts +++ b/packages/beacon-node/src/network/gossip/metrics.ts @@ -1,4 +1,5 @@ import {ForkName} from "@lodestar/params"; +import {SubnetID} from "@lodestar/types"; import {RegistryMetricCreator} from "../../metrics/index.js"; import {GossipType} from "./interface.js"; @@ -33,7 +34,7 @@ export function createEth2GossipsubMetrics(register: RegistryMetricCreator) { help: "Number of connected mesh peers per beacon attestation subnet", labelNames: ["subnet", "fork"], }), - peersBySyncCommitteeSubnet: register.gauge<{subnet: number; fork: ForkName}>({ + peersBySyncCommitteeSubnet: register.gauge<{subnet: SubnetID; fork: ForkName}>({ name: "lodestar_gossip_mesh_peers_by_sync_committee_subnet_count", help: "Number of connected mesh peers per sync committee subnet", labelNames: ["subnet", "fork"], @@ -50,7 +51,7 @@ export function createEth2GossipsubMetrics(register: RegistryMetricCreator) { help: "Number of connected topic peers per beacon attestation subnet", labelNames: ["subnet", "fork"], }), - peersBySyncCommitteeSubnet: register.gauge<{subnet: number; fork: ForkName}>({ + peersBySyncCommitteeSubnet: register.gauge<{subnet: SubnetID; fork: ForkName}>({ name: "lodestar_gossip_topic_peers_by_sync_committee_subnet_count", help: "Number of connected topic peers per sync committee subnet", labelNames: ["subnet", "fork"], diff --git a/packages/beacon-node/src/network/interface.ts b/packages/beacon-node/src/network/interface.ts index edcf35878420..87cf535d9d97 100644 --- a/packages/beacon-node/src/network/interface.ts +++ b/packages/beacon-node/src/network/interface.ts @@ -21,6 +21,7 @@ import { SignedBeaconBlock, Slot, SlotRootHex, + SubnetID, WithBytes, altair, capella, @@ -54,7 +55,7 @@ export interface INetwork extends INetworkCorePublic { getConnectedPeerCount(): number; isSubscribedToGossipCoreTopics(): boolean; reportPeer(peer: PeerIdStr, action: PeerAction, actionName: string): void; - shouldAggregate(subnet: number, slot: Slot): boolean; + shouldAggregate(subnet: SubnetID, slot: Slot): boolean; reStatusPeers(peers: PeerIdStr[]): Promise; searchUnknownSlotRoot(slotRoot: SlotRootHex, peer?: PeerIdStr): void; // ReqResp @@ -73,12 +74,12 @@ export interface INetwork extends INetworkCorePublic { publishBeaconBlock(signedBlock: SignedBeaconBlock): Promise; publishBlobSidecar(blobSidecar: deneb.BlobSidecar): Promise; publishBeaconAggregateAndProof(aggregateAndProof: SignedAggregateAndProof): Promise; - publishBeaconAttestation(attestation: phase0.Attestation, subnet: number): Promise; + publishBeaconAttestation(attestation: phase0.Attestation, subnet: SubnetID): Promise; publishVoluntaryExit(voluntaryExit: phase0.SignedVoluntaryExit): Promise; publishBlsToExecutionChange(blsToExecutionChange: capella.SignedBLSToExecutionChange): Promise; publishProposerSlashing(proposerSlashing: phase0.ProposerSlashing): Promise; publishAttesterSlashing(attesterSlashing: phase0.AttesterSlashing): Promise; - publishSyncCommitteeSignature(signature: altair.SyncCommitteeMessage, subnet: number): Promise; + publishSyncCommitteeSignature(signature: altair.SyncCommitteeMessage, subnet: SubnetID): Promise; publishContributionAndProof(contributionAndProof: altair.SignedContributionAndProof): Promise; publishLightClientFinalityUpdate(update: LightClientFinalityUpdate): Promise; publishLightClientOptimisticUpdate(update: LightClientOptimisticUpdate): Promise; diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index d8370fc22b5f..93e5af0265bb 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -16,6 +16,7 @@ import { SignedAggregateAndProof, SignedBeaconBlock, SlotRootHex, + SubnetID, WithBytes, altair, capella, @@ -296,7 +297,7 @@ export class Network implements INetwork { return this.subscribedToCoreTopics; } - shouldAggregate(subnet: number, slot: number): boolean { + shouldAggregate(subnet: SubnetID, slot: number): boolean { return this.aggregatorTracker.shouldAggregate(subnet, slot); } @@ -328,7 +329,7 @@ export class Network implements INetwork { ); } - async publishBeaconAttestation(attestation: phase0.Attestation, subnet: number): Promise { + async publishBeaconAttestation(attestation: phase0.Attestation, subnet: SubnetID): Promise { const fork = this.config.getForkName(attestation.data.slot); return this.publishGossip( {type: GossipType.beacon_attestation, fork, subnet}, @@ -379,7 +380,7 @@ export class Network implements INetwork { ); } - async publishSyncCommitteeSignature(signature: altair.SyncCommitteeMessage, subnet: number): Promise { + async publishSyncCommitteeSignature(signature: altair.SyncCommitteeMessage, subnet: SubnetID): Promise { const fork = this.config.getForkName(signature.slot); return this.publishGossip({type: GossipType.sync_committee, fork, subnet}, signature, { ignoreDuplicatePublishError: true, diff --git a/packages/beacon-node/src/network/peers/discover.ts b/packages/beacon-node/src/network/peers/discover.ts index e658fd6378bf..55fef17bbb21 100644 --- a/packages/beacon-node/src/network/peers/discover.ts +++ b/packages/beacon-node/src/network/peers/discover.ts @@ -3,6 +3,7 @@ import type {PeerId, PeerInfo} from "@libp2p/interface"; import {BeaconConfig} from "@lodestar/config"; import {LoggerNode} from "@lodestar/logger/node"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; +import {SubnetID} from "@lodestar/types"; import {pruneSetToMax, sleep} from "@lodestar/utils"; import {Multiaddr} from "@multiformats/multiaddr"; import {NetworkCoreMetrics} from "../core/metrics.js"; @@ -65,7 +66,7 @@ type SubnetRequestInfo = { }; export type SubnetDiscvQueryMs = { - subnet: number; + subnet: SubnetID; type: SubnetType; toUnixMs: UnixMs; maxPeersToDiscover: number; diff --git a/packages/beacon-node/src/network/peers/utils/prioritizePeers.ts b/packages/beacon-node/src/network/peers/utils/prioritizePeers.ts index 545d8a6ca8b0..9aa95e8af645 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 {BitArray} from "@chainsafe/ssz"; import {Direction, PeerId} from "@libp2p/interface"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; -import {altair, phase0} from "@lodestar/types"; +import {SubnetID, altair, phase0} from "@lodestar/types"; import {MapDef} from "@lodestar/utils"; import {shuffle} from "../../../util/shuffle.js"; import {sortBy} from "../../../util/sortBy.js"; @@ -38,7 +38,7 @@ const OUTBOUND_PEERS_RATIO = 0.1; const attnetsZero = BitArray.fromBitLen(ATTESTATION_SUBNET_COUNT); const syncnetsZero = BitArray.fromBitLen(SYNC_COMMITTEE_SUBNET_COUNT); -type SubnetDiscvQuery = {subnet: number; toSlot: number; maxPeersToDiscover: number}; +type SubnetDiscvQuery = {subnet: SubnetID; toSlot: number; maxPeersToDiscover: number}; type PeerInfo = { id: PeerId; @@ -412,8 +412,8 @@ export function sortPeersToPrune(connectedPeers: PeerInfo[], dutiesByPeer: Map

TARGET_SUBNET_PEERS, return null if peers are not grouped * to any subnets. */ -function findMaxPeersSubnet(subnetToPeers: Map, targetSubnetPeers: number): number | null { - let maxPeersSubnet: number | null = null; +function findMaxPeersSubnet(subnetToPeers: Map, targetSubnetPeers: number): SubnetID | null { + let maxPeersSubnet: SubnetID | null = null; let maxPeerCountPerSubnet = -1; for (const [subnet, peers] of subnetToPeers) { diff --git a/packages/beacon-node/src/network/peers/utils/subnetMap.ts b/packages/beacon-node/src/network/peers/utils/subnetMap.ts index 97985b3d8da0..a815bafc4cbf 100644 --- a/packages/beacon-node/src/network/peers/utils/subnetMap.ts +++ b/packages/beacon-node/src/network/peers/utils/subnetMap.ts @@ -1,7 +1,7 @@ -import {Slot} from "@lodestar/types"; +import {Slot, SubnetID} from "@lodestar/types"; export type RequestedSubnet = { - subnet: number; + subnet: SubnetID; /** * Slot after which the network will stop maintaining a min number of peers * connected to `subnetId`RequestedSubnet @@ -14,13 +14,13 @@ export type RequestedSubnet = { */ export class SubnetMap { /** Map of subnets and the slot until they are needed */ - private subnets = new Map(); + private subnets = new Map(); get size(): number { return this.subnets.size; } - has(subnet: number): boolean { + has(subnet: SubnetID): boolean { return this.subnets.has(subnet); } @@ -35,18 +35,18 @@ export class SubnetMap { /** * Get last active slot of a subnet. */ - getToSlot(subnet: number): number | undefined { + getToSlot(subnet: SubnetID): Slot | undefined { return this.subnets.get(subnet); } - isActiveAtSlot(subnet: number, slot: Slot): boolean { + isActiveAtSlot(subnet: SubnetID, slot: Slot): boolean { const toSlot = this.subnets.get(subnet); return toSlot !== undefined && toSlot >= slot; // ACTIVE: >= } /** Return subnetIds with a `toSlot` equal greater than `currentSlot` */ - getActive(currentSlot: Slot): number[] { - const subnetIds: number[] = []; + getActive(currentSlot: Slot): SubnetID[] { + const subnetIds: SubnetID[] = []; for (const [subnet, toSlot] of this.subnets.entries()) { if (toSlot >= currentSlot) { subnetIds.push(subnet); @@ -67,8 +67,8 @@ export class SubnetMap { } /** Return subnetIds with a `toSlot` less than `currentSlot`. Also deletes expired entries */ - getExpired(currentSlot: Slot): number[] { - const subnetIds: number[] = []; + getExpired(currentSlot: Slot): SubnetID[] { + const subnetIds: SubnetID[] = []; for (const [subnet, toSlot] of this.subnets.entries()) { if (toSlot < currentSlot) { subnetIds.push(subnet); @@ -78,11 +78,11 @@ export class SubnetMap { return subnetIds; } - getAll(): number[] { + getAll(): SubnetID[] { return Array.from(this.subnets.keys()); } - delete(subnet: number): void { + delete(subnet: SubnetID): void { this.subnets.delete(subnet); } } diff --git a/packages/beacon-node/src/network/processor/aggregatorTracker.ts b/packages/beacon-node/src/network/processor/aggregatorTracker.ts index 634e809ae61f..0cd9d3e843b8 100644 --- a/packages/beacon-node/src/network/processor/aggregatorTracker.ts +++ b/packages/beacon-node/src/network/processor/aggregatorTracker.ts @@ -1,9 +1,7 @@ import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {Slot} from "@lodestar/types"; +import {Slot, SubnetID} from "@lodestar/types"; import {MapDef, pruneSetToMax} from "@lodestar/utils"; -type SubnetId = number; - // Subscriptions are submitted max two epochs in advance const MAX_SLOTS_CACHED = SLOTS_PER_EPOCH * 2; @@ -12,17 +10,17 @@ const MAX_SLOTS_CACHED = SLOTS_PER_EPOCH * 2; * to only then insert attestations into the op pool */ export class AggregatorTracker { - private subnetAggregatorsBySlot = new MapDef>(() => new Set()); + private subnetAggregatorsBySlot = new MapDef>(() => new Set()); get maxSlotsCached(): number { return MAX_SLOTS_CACHED; } - addAggregator(subnet: SubnetId, slot: Slot): void { + addAggregator(subnet: SubnetID, slot: Slot): void { this.subnetAggregatorsBySlot.getOrDefault(slot).add(subnet); } - shouldAggregate(subnet: SubnetId, slot: Slot): boolean { + shouldAggregate(subnet: SubnetID, slot: Slot): boolean { return this.subnetAggregatorsBySlot.get(slot)?.has(subnet) === true; } diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index 3fb7b06e700a..7ef32ffc32b1 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -2,7 +2,7 @@ import {routes} from "@lodestar/api"; import {BeaconConfig, ChainForkConfig} from "@lodestar/config"; import {ForkName, ForkSeq} from "@lodestar/params"; import {computeTimeAtSlot} from "@lodestar/state-transition"; -import {Root, SignedBeaconBlock, Slot, UintNum64, deneb, ssz, sszTypesFor} from "@lodestar/types"; +import {Root, SignedBeaconBlock, Slot, SubnetID, UintNum64, deneb, ssz, sszTypesFor} from "@lodestar/types"; import {LogLevel, Logger, prettyBytes, toRootHex} from "@lodestar/utils"; import { BlobSidecarValidation, @@ -179,7 +179,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand async function validateBeaconBlob( blobSidecar: deneb.BlobSidecar, blobBytes: Uint8Array, - subnet: number, + subnet: SubnetID, peerIdStr: string, seenTimestampSec: number ): Promise { diff --git a/packages/beacon-node/src/network/subnets/attnetsService.ts b/packages/beacon-node/src/network/subnets/attnetsService.ts index ed2f94bd56d8..aa97746bee00 100644 --- a/packages/beacon-node/src/network/subnets/attnetsService.ts +++ b/packages/beacon-node/src/network/subnets/attnetsService.ts @@ -5,7 +5,7 @@ import { ForkName, SLOTS_PER_EPOCH, } from "@lodestar/params"; -import {Epoch, Slot, ssz} from "@lodestar/types"; +import {Epoch, Slot, SubnetID, ssz} from "@lodestar/types"; import {Logger, MapDef} from "@lodestar/utils"; import {ClockEvent, IClock} from "../../util/clock.js"; import {NetworkCoreMetrics} from "../core/metrics.js"; @@ -126,7 +126,7 @@ export class AttnetsService implements IAttnetsService { /** * Check if a subscription is still active before handling a gossip object */ - shouldProcess(subnet: number, slot: Slot): boolean { + shouldProcess(subnet: SubnetID, slot: Slot): boolean { if (!this.aggregatorSlotSubnet.has(slot)) { return false; } diff --git a/packages/beacon-node/src/network/subnets/interface.ts b/packages/beacon-node/src/network/subnets/interface.ts index e3b1e2513818..fe9f1e6172cf 100644 --- a/packages/beacon-node/src/network/subnets/interface.ts +++ b/packages/beacon-node/src/network/subnets/interface.ts @@ -1,12 +1,12 @@ import {ForkName} from "@lodestar/params"; -import {Bytes32, Slot, ValidatorIndex} from "@lodestar/types"; +import {Bytes32, Slot, SubnetID, ValidatorIndex} from "@lodestar/types"; 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 = { validatorIndex: ValidatorIndex; - subnet: number; + subnet: SubnetID; slot: Slot; isAggregator: boolean; }; @@ -20,7 +20,7 @@ export type SubnetsService = { }; export interface IAttnetsService extends SubnetsService { - shouldProcess(subnet: number, slot: Slot): boolean; + shouldProcess(subnet: SubnetID, slot: Slot): boolean; } export type RandBetweenFn = (min: number, max: number) => number; 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 1ffbf7696111..228f705355ad 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 {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {ssz} from "@lodestar/types"; +import {SubnetID, ssz} from "@lodestar/types"; import {LodestarError} from "@lodestar/utils"; import {describe, expect, it} from "vitest"; import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../../state-transition/test/perf/util.js"; @@ -309,7 +309,7 @@ describe("validateAttestation", () => { async function expectGossipError( chain: IBeaconChain, attestationOrBytes: GossipAttestation, - subnet: number, + subnet: SubnetID, errorCode: string ): Promise { const fork = chain.config.getForkName(stateSlot); 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 5e7149f4d7f8..f679532bb09a 100644 --- a/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts +++ b/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts @@ -8,6 +8,7 @@ import { } from "@lodestar/params"; import {ZERO_HASH} from "@lodestar/state-transition"; import {getCurrentSlot} from "@lodestar/state-transition"; +import {SubnetID} from "@lodestar/types"; import {bigIntToBytes} from "@lodestar/utils"; import {MockedObject, afterEach, beforeEach, describe, expect, it, vi} from "vitest"; import {Eth2Gossipsub} from "../../../../src/network/gossip/gossipsub.js"; @@ -77,8 +78,8 @@ describe("AttnetsService", () => { expect(gossipStub.subscribeTopic).toBeCalledWith(expect.objectContaining({fork: ForkName.phase0})); expect(gossipStub.subscribeTopic).not.toBeCalledWith({fork: ForkName.altair}); expect(gossipStub.subscribeTopic).toBeCalledTimes(2); - const firstSubnet = (gossipStub.subscribeTopic.mock.calls[0][0] as unknown as {subnet: number}).subnet; - const secondSubnet = (gossipStub.subscribeTopic.mock.calls[1][0] as unknown as {subnet: number}).subnet; + const firstSubnet = (gossipStub.subscribeTopic.mock.calls[0][0] as unknown as {subnet: SubnetID}).subnet; + const secondSubnet = (gossipStub.subscribeTopic.mock.calls[1][0] as unknown as {subnet: SubnetID}).subnet; expect(gossipStub.subscribeTopic).toBeCalledTimes(SUBNETS_PER_NODE); vi.advanceTimersByTime(config.SECONDS_PER_SLOT * SLOTS_PER_EPOCH * (ALTAIR_FORK_EPOCH - 2) * 1000); service.subscribeSubnetsToNextFork(ForkName.altair); @@ -105,8 +106,8 @@ describe("AttnetsService", () => { it("should not subscribe to new short lived subnet if not aggregator", () => { expect(gossipStub.subscribeTopic).toBeCalledTimes(SUBNETS_PER_NODE); - const firstSubnet = (gossipStub.subscribeTopic.mock.calls[0][0] as unknown as {subnet: number}).subnet; - const secondSubnet = (gossipStub.subscribeTopic.mock.calls[1][0] as unknown as {subnet: number}).subnet; + const firstSubnet = (gossipStub.subscribeTopic.mock.calls[0][0] as unknown as {subnet: SubnetID}).subnet; + const secondSubnet = (gossipStub.subscribeTopic.mock.calls[1][0] as unknown as {subnet: SubnetID}).subnet; // should subscribe to new short lived subnet const newSubnet = 63; expect(newSubnet).not.toBe(firstSubnet); @@ -124,8 +125,8 @@ describe("AttnetsService", () => { it("should subscribe to new short lived subnet if aggregator", () => { expect(gossipStub.subscribeTopic).toBeCalledTimes(SUBNETS_PER_NODE); - const firstSubnet = (gossipStub.subscribeTopic.mock.calls[0][0] as unknown as {subnet: number}).subnet; - const secondSubnet = (gossipStub.subscribeTopic.mock.calls[1][0] as unknown as {subnet: number}).subnet; + const firstSubnet = (gossipStub.subscribeTopic.mock.calls[0][0] as unknown as {subnet: SubnetID}).subnet; + const secondSubnet = (gossipStub.subscribeTopic.mock.calls[1][0] as unknown as {subnet: SubnetID}).subnet; // should subscribe to new short lived subnet const newSubnet = 63; expect(newSubnet).not.toBe(firstSubnet); @@ -149,7 +150,7 @@ describe("AttnetsService", () => { it("should not subscribe to existing short lived subnet if aggregator", () => { expect(gossipStub.subscribeTopic).toBeCalledTimes(SUBNETS_PER_NODE); - const firstSubnet = (gossipStub.subscribeTopic.mock.calls[0][0] as unknown as {subnet: number}).subnet; + const firstSubnet = (gossipStub.subscribeTopic.mock.calls[0][0] as unknown as {subnet: SubnetID}).subnet; // should not subscribe to existing short lived subnet const subscription: CommitteeSubscription = { validatorIndex: 2023, diff --git a/packages/beacon-node/test/utils/network.ts b/packages/beacon-node/test/utils/network.ts index 56c831b269f5..d64249d3a130 100644 --- a/packages/beacon-node/test/utils/network.ts +++ b/packages/beacon-node/test/utils/network.ts @@ -2,6 +2,7 @@ import {BitArray} from "@chainsafe/ssz"; import {PeerId} from "@libp2p/interface"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; +import {SubnetID} from "@lodestar/types"; import {INetwork, Network, NetworkEvent} from "../../src/network/index.js"; import {Libp2p} from "../../src/network/interface.js"; import {createNodeJsLibp2p} from "../../src/network/libp2p/index.js"; @@ -55,7 +56,7 @@ export function onPeerDisconnect(network: Network): Promise { /** * Generate valid filled attnets BitVector */ -export function getAttnets(subnetIds: number[] = []): BitArray { +export function getAttnets(subnetIds: SubnetID[] = []): BitArray { const attnets = BitArray.fromBitLen(ATTESTATION_SUBNET_COUNT); for (const subnetId of subnetIds) { attnets.set(subnetId, true); @@ -66,7 +67,7 @@ export function getAttnets(subnetIds: number[] = []): BitArray { /** * Generate valid filled syncnets BitVector */ -export function getSyncnets(subnetIds: number[] = []): BitArray { +export function getSyncnets(subnetIds: SubnetID[] = []): BitArray { const syncnets = BitArray.fromBitLen(SYNC_COMMITTEE_SUBNET_COUNT); for (const subnetId of subnetIds) { syncnets.set(subnetId, true); diff --git a/packages/beacon-node/test/utils/validationData/attestation.ts b/packages/beacon-node/test/utils/validationData/attestation.ts index 40dccbd77f18..e8f0fca632eb 100644 --- a/packages/beacon-node/test/utils/validationData/attestation.ts +++ b/packages/beacon-node/test/utils/validationData/attestation.ts @@ -2,7 +2,7 @@ import {BitArray, toHexString} from "@chainsafe/ssz"; import {DataAvailabilityStatus, ExecutionStatus, IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; import {computeEpochAtSlot, computeSigningRoot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {Slot, phase0, ssz} from "@lodestar/types"; +import {Slot, SubnetID, phase0, ssz} from "@lodestar/types"; import { generateTestCachedBeaconStateOnlyValidators, getSecretKeyFromIndexCached, @@ -37,7 +37,7 @@ export type AttestationValidDataOpts = { export function getAttestationValidData(opts: AttestationValidDataOpts): { chain: IBeaconChain; attestation: phase0.Attestation; - subnet: number; + subnet: SubnetID; validatorIndex: number; } { const currentSlot = opts.currentSlot ?? 100; diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index af9e79bc831c..4714d6169204 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -20,6 +20,7 @@ import { IndexedAttestation, RootHex, Slot, + SubnetID, SyncPeriod, ValidatorIndex, electra, @@ -798,7 +799,7 @@ export class EpochCache { /** * Compute the correct subnet for a slot/committee index */ - computeSubnetForSlot(slot: number, committeeIndex: number): number { + computeSubnetForSlot(slot: number, committeeIndex: number): SubnetID { const slotsSinceEpochStart = slot % SLOTS_PER_EPOCH; const committeesPerSlot = this.getCommitteeCountPerSlot(computeEpochAtSlot(slot)); const committeesSinceEpochStart = committeesPerSlot * slotsSinceEpochStart; diff --git a/packages/types/src/primitive/types.ts b/packages/types/src/primitive/types.ts index 53422cc9b995..d0eef619840a 100644 --- a/packages/types/src/primitive/types.ts +++ b/packages/types/src/primitive/types.ts @@ -30,6 +30,7 @@ export type SubcommitteeIndex = UintNum64; export type ValidatorIndex = UintNum64; export type WithdrawalIndex = UintNum64; export type BlobIndex = UintNum64; +export type SubnetID = UintNum64; export type Gwei = UintBn64; export type Wei = UintBn256; export type Root = Bytes32;