diff --git a/packages/api/src/beacon/routes/beacon/pool.ts b/packages/api/src/beacon/routes/beacon/pool.ts index ee43280d73bb..a5b6d3cd6fdb 100644 --- a/packages/api/src/beacon/routes/beacon/pool.ts +++ b/packages/api/src/beacon/routes/beacon/pool.ts @@ -26,6 +26,7 @@ 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"; +import {bigintToNumber} from "@lodestar/utils"; const SingleAttestationListTypePhase0 = ArrayOf(ssz.phase0.Attestation); const SingleAttestationListTypeElectra = ArrayOf(ssz.electra.SingleAttestation); @@ -399,7 +400,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { - const fork = config.getForkName(Number(attesterSlashing.attestation1.data.slot)); + const fork = config.getForkName(bigintToNumber(attesterSlashing.attestation1.data.slot)); return { body: isForkPostElectra(fork) ? ssz.electra.AttesterSlashing.toJson(attesterSlashing) @@ -416,7 +417,7 @@ export function getDefinitions(config: ChainForkConfig): RouteDefinitions { - const fork = config.getForkName(Number(attesterSlashing.attestation1.data.slot)); + const fork = config.getForkName(bigintToNumber(attesterSlashing.attestation1.data.slot)); return { body: isForkPostElectra(fork) ? ssz.electra.AttesterSlashing.serialize(attesterSlashing as electra.AttesterSlashing) diff --git a/packages/api/src/beacon/routes/events.ts b/packages/api/src/beacon/routes/events.ts index 4b1dfbe33d60..bb85fb04c79a 100644 --- a/packages/api/src/beacon/routes/events.ts +++ b/packages/api/src/beacon/routes/events.ts @@ -23,6 +23,7 @@ import {EmptyMeta, EmptyResponseCodec, EmptyResponseData} from "../../utils/code import {getPostAltairForkTypes, getPostBellatrixForkTypes} from "../../utils/fork.js"; import {Endpoint, RouteDefinitions, Schema} from "../../utils/index.js"; import {VersionType} from "../../utils/metadata.js"; +import {bigintToNumber} from "@lodestar/utils"; const stringType = new StringType(); export const blobSidecarSSE = new ContainerType( @@ -273,11 +274,11 @@ export function getTypeByEvent(config: ChainForkConfig): {[K in EventType]: Type [EventType.proposerSlashing]: ssz.phase0.ProposerSlashing, [EventType.attesterSlashing]: { toJson: (attesterSlashing) => { - const fork = config.getForkName(Number(attesterSlashing.attestation1.data.slot)); + const fork = config.getForkName(bigintToNumber(attesterSlashing.attestation1.data.slot)); return sszTypesFor(fork).AttesterSlashing.toJson(attesterSlashing); }, fromJson: (attesterSlashing) => { - const fork = config.getForkName(Number((attesterSlashing as AttesterSlashing).attestation1.data.slot)); + const fork = config.getForkName(bigintToNumber((attesterSlashing as AttesterSlashing).attestation1.data.slot)); return sszTypesFor(fork).AttesterSlashing.fromJson(attesterSlashing); }, }, diff --git a/packages/api/src/keymanager/routes.ts b/packages/api/src/keymanager/routes.ts index 05eddeefd604..6e3f80142d6c 100644 --- a/packages/api/src/keymanager/routes.ts +++ b/packages/api/src/keymanager/routes.ts @@ -691,7 +691,7 @@ function parseGasLimit(gasLimitInput: string | number): number { if ((typeof gasLimitInput !== "string" && typeof gasLimitInput !== "number") || `${gasLimitInput}`.trim() === "") { throw Error("Not valid Gas Limit"); } - const gasLimit = Number(gasLimitInput); + const gasLimit = typeof gasLimitInput === "string" ? parseInt(gasLimitInput, 10) : gasLimitInput; if (Number.isNaN(gasLimit) || gasLimit === 0) { throw Error(`Gas Limit is not valid gasLimit=${gasLimit}`); } 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 80a5895afb54..5063aff88b35 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -17,6 +17,8 @@ import {validateApiVoluntaryExit} from "../../../../chain/validation/voluntaryEx import {validateGossipFnRetryUnknownRoot} from "../../../../network/processor/gossipHandlers.js"; import {ApiError, FailureList, IndexedError} from "../../errors.js"; import {ApiModules} from "../../types.js"; +import {bigintToNumber} from "@lodestar/utils" + export function getBeaconPoolApi({ chain, @@ -180,7 +182,7 @@ export function getBeaconPoolApi({ async submitPoolAttesterSlashingsV2({attesterSlashing}) { await validateApiAttesterSlashing(chain, attesterSlashing); - const fork = chain.config.getForkName(Number(attesterSlashing.attestation1.data.slot)); + const fork = chain.config.getForkName(bigintToNumber(attesterSlashing.attestation1.data.slot)); chain.opPool.insertAttesterSlashing(fork, attesterSlashing); await network.publishAttesterSlashing(attesterSlashing); }, 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 b7af79f2d73d..04490df71504 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -161,7 +161,7 @@ export function getStateValidatorIndex( return {valid: false, code: 400, reason: "Invalid pubkey hex encoding"}; } } else { - id = Number(id); + id = parseInt(id, 10); } } diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index f61d686aec24..d79e32e8122c 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -50,8 +50,8 @@ import { } from "@lodestar/types"; import { TimeoutError, + bigintToNumber, defer, - formatWeiToEth, fromHex, prettyWeiToEth, resolveOrRacePromises, @@ -455,8 +455,8 @@ export function getValidatorApi( metrics?.blockProductionSuccess.inc({source}); metrics?.blockProductionNumAggregated.observe({source}, block.body.attestations.length); - metrics?.blockProductionConsensusBlockValue.observe({source}, Number(formatWeiToEth(consensusBlockValue))); - metrics?.blockProductionExecutionPayloadValue.observe({source}, Number(formatWeiToEth(executionPayloadValue))); + metrics?.blockProductionConsensusBlockValue.observe({source}, bigintToNumber(consensusBlockValue)); + metrics?.blockProductionExecutionPayloadValue.observe({source}, bigintToNumber(executionPayloadValue)); logger.verbose("Produced blinded block", { slot, executionPayloadValue, @@ -512,8 +512,8 @@ export function getValidatorApi( metrics?.blockProductionSuccess.inc({source}); metrics?.blockProductionNumAggregated.observe({source}, block.body.attestations.length); - metrics?.blockProductionConsensusBlockValue.observe({source}, Number(formatWeiToEth(consensusBlockValue))); - metrics?.blockProductionExecutionPayloadValue.observe({source}, Number(formatWeiToEth(executionPayloadValue))); + metrics?.blockProductionConsensusBlockValue.observe({source}, bigintToNumber(consensusBlockValue)); + metrics?.blockProductionExecutionPayloadValue.observe({source}, bigintToNumber(executionPayloadValue)); const blockRoot = toRootHex(config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block)); logger.verbose("Produced execution block", { diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 091739b7d3da..48df5b7a998c 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -104,6 +104,7 @@ import {InMemoryCheckpointStateCache} from "./stateCache/inMemoryCheckpointsCach import {PersistentCheckpointStateCache} from "./stateCache/persistentCheckpointsCache.js"; import {CheckpointStateCache} from "./stateCache/types.js"; import {ValidatorMonitor} from "./validatorMonitor.js"; +import {bigintToNumber} from "@lodestar/utils" /** * The maximum number of cached produced results to keep in memory. @@ -421,7 +422,7 @@ export class BeaconChain implements IBeaconChain { const anchorStateFork = this.config.getForkName(anchorState.slot); if (isForkPostElectra(anchorStateFork)) { const {eth1DepositIndex, depositRequestsStartIndex} = anchorState as BeaconStateElectra; - if (eth1DepositIndex === Number(depositRequestsStartIndex)) { + if (eth1DepositIndex === bigintToNumber(depositRequestsStartIndex)) { this.eth1.stopPollingEth1Data(); } } diff --git a/packages/beacon-node/src/chain/prepareNextSlot.ts b/packages/beacon-node/src/chain/prepareNextSlot.ts index 62698a8a8a05..a384c2883307 100644 --- a/packages/beacon-node/src/chain/prepareNextSlot.ts +++ b/packages/beacon-node/src/chain/prepareNextSlot.ts @@ -11,7 +11,7 @@ import { isExecutionStateType, } from "@lodestar/state-transition"; import {Slot} from "@lodestar/types"; -import {Logger, fromHex, isErrorAborted, sleep} from "@lodestar/utils"; +import {Logger, bigintToNumber, fromHex, isErrorAborted, sleep} from "@lodestar/utils"; import {GENESIS_SLOT, ZERO_HASH_HEX} from "../constants/constants.js"; import {BuilderStatus} from "../execution/builder/http.js"; import {Metrics} from "../metrics/index.js"; @@ -266,7 +266,7 @@ export class PrepareNextSlotScheduler { if ( finalizedState !== undefined && - finalizedState.eth1DepositIndex === Number((finalizedState as BeaconStateElectra).depositRequestsStartIndex) + finalizedState.eth1DepositIndex === bigintToNumber((finalizedState as BeaconStateElectra).depositRequestsStartIndex) ) { // Signal eth1 to stop polling eth1Data this.chain.eth1.stopPollingEth1Data(); diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index b10841413b99..6d372fd9f0cf 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -857,7 +857,7 @@ function fromCacheKey(key: CacheKey): CheckpointHex { const [rootHex, epoch] = key.split("_"); return { rootHex, - epoch: Number(epoch), + epoch: parseInt(epoch), }; } diff --git a/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts b/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts index ea2d134fe4dd..26783e07915f 100644 --- a/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts +++ b/packages/beacon-node/src/eth1/eth1MergeBlockTracker.ts @@ -1,6 +1,6 @@ import {ChainConfig} from "@lodestar/config"; import {RootHex} from "@lodestar/types"; -import {Logger, pruneSetToMax, toRootHex} from "@lodestar/utils"; +import {bigintToNumber, Logger, pruneSetToMax, toRootHex} from "@lodestar/utils"; import {ZERO_HASH_HEX} from "../constants/index.js"; import {Metrics} from "../metrics/index.js"; import {enumToIndexMap} from "../util/enum.js"; @@ -75,8 +75,8 @@ export class Eth1MergeBlockTracker { // Only run metrics if necessary if (metrics) { // TTD can't be dynamically changed during execution, register metric once - metrics.eth1.eth1MergeTTD.set(Number(scaledTTD as bigint)); - metrics.eth1.eth1MergeTDFactor.set(Number(this.safeTDFactor as bigint)); + metrics.eth1.eth1MergeTTD.set(bigintToNumber(scaledTTD as bigint)); + metrics.eth1.eth1MergeTDFactor.set(bigintToNumber(this.safeTDFactor as bigint)); metrics.eth1.eth1MergeStatus.addCollect(() => { // Set merge ttd, merge status and merge block status @@ -85,7 +85,7 @@ export class Eth1MergeBlockTracker { if (this.latestEth1Block !== null) { // Set latestBlock stats metrics.eth1.eth1LatestBlockNumber.set(this.latestEth1Block.number); - metrics.eth1.eth1LatestBlockTD.set(Number(this.latestEth1Block.totalDifficulty / this.safeTDFactor)); + metrics.eth1.eth1LatestBlockTD.set(bigintToNumber(this.latestEth1Block.totalDifficulty / this.safeTDFactor)); metrics.eth1.eth1LatestBlockTimestamp.set(this.latestEth1Block.timestamp); } }); @@ -121,7 +121,7 @@ export class Eth1MergeBlockTracker { return { ttdHit: false, tdFactor: this.safeTDFactor, - tdDiffScaled: Number((tdDiff / this.safeTDFactor) as bigint), + tdDiffScaled: bigintToNumber((tdDiff / this.safeTDFactor) as bigint), ttd: this.config.TERMINAL_TOTAL_DIFFICULTY, td: this.latestEth1Block.totalDifficulty, timestamp: this.latestEth1Block.timestamp, diff --git a/packages/beacon-node/src/eth1/utils/eth1Vote.ts b/packages/beacon-node/src/eth1/utils/eth1Vote.ts index a101907b4977..78c2e7db12e4 100644 --- a/packages/beacon-node/src/eth1/utils/eth1Vote.ts +++ b/packages/beacon-node/src/eth1/utils/eth1Vote.ts @@ -2,7 +2,7 @@ import {ChainForkConfig} from "@lodestar/config"; import {EPOCHS_PER_ETH1_VOTING_PERIOD, SLOTS_PER_EPOCH, isForkPostElectra} from "@lodestar/params"; import {BeaconStateAllForks, BeaconStateElectra, computeTimeAtSlot} from "@lodestar/state-transition"; import {RootHex, phase0} from "@lodestar/types"; -import {toRootHex} from "@lodestar/utils"; +import { bigintToNumber, toRootHex} from "@lodestar/utils"; export type Eth1DataGetter = ({ timestampRange, @@ -18,7 +18,7 @@ export async function getEth1VotesToConsider( const fork = config.getForkName(state.slot); if (isForkPostElectra(fork)) { const {eth1DepositIndex, depositRequestsStartIndex} = state as BeaconStateElectra; - if (eth1DepositIndex === Number(depositRequestsStartIndex)) { + if (eth1DepositIndex === bigintToNumber(depositRequestsStartIndex)) { return state.eth1DataVotes.getAllReadonly(); } } diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index d28632d07a13..808447f8122d 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -414,7 +414,7 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { ): EngineApiRpcReturnTypes["engine_getPayloadV5"] { // 1. Given the payloadId client software MUST return the most recent version of the payload that is available in // the corresponding build process at the time of receiving the call. - const payloadIdNbr = Number(payloadId); + const payloadIdNbr = parseInt(payloadId, 10); const payload = this.preparingPayloads.get(payloadIdNbr); // 2. The call MUST return -38001: Unknown payload error if the build process identified by the payloadId does not diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 4694ce093aa1..63ad96204db5 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -27,7 +27,7 @@ import { fulu, phase0, } from "@lodestar/types"; -import {prettyPrintIndices, sleep} from "@lodestar/utils"; +import {bigintToNumber, prettyPrintIndices, sleep} from "@lodestar/utils"; import {BlockInputSource} from "../chain/blocks/blockInput/types.js"; import {ChainEvent, IBeaconChain} from "../chain/index.js"; import {computeSubnetForDataColumnSidecar} from "../chain/validation/dataColumnSidecar.js"; @@ -427,7 +427,7 @@ export class Network implements INetwork { } async publishProposerSlashing(proposerSlashing: phase0.ProposerSlashing): Promise { - const epoch = computeEpochAtSlot(Number(proposerSlashing.signedHeader1.message.slot as bigint)); + const epoch = computeEpochAtSlot(bigintToNumber(proposerSlashing.signedHeader1.message.slot as bigint)); const boundary = this.config.getForkBoundaryAtEpoch(epoch); return this.publishGossip( @@ -437,7 +437,7 @@ export class Network implements INetwork { } async publishAttesterSlashing(attesterSlashing: AttesterSlashing): Promise { - const epoch = computeEpochAtSlot(Number(attesterSlashing.attestation1.data.slot as bigint)); + const epoch = computeEpochAtSlot(bigintToNumber(attesterSlashing.attestation1.data.slot as bigint)); const boundary = this.config.getForkBoundaryAtEpoch(epoch); return this.publishGossip( 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 3b788fecd4e8..f5f595fbefe2 100644 --- a/packages/beacon-node/test/spec/presets/light_client/sync.ts +++ b/packages/beacon-node/test/spec/presets/light_client/sync.ts @@ -5,7 +5,7 @@ import {isForkPostAltair} from "@lodestar/params"; import {InputType} from "@lodestar/spec-test-util"; import {computeSyncPeriodAtSlot} from "@lodestar/state-transition"; import {RootHex, Slot, altair, phase0, ssz, sszTypesFor} from "@lodestar/types"; -import {fromHex, toHex} from "@lodestar/utils"; +import {bigintToNumber, fromHex, toHex} from "@lodestar/utils"; import {testLogger} from "../../../utils/logger.js"; import {TestRunnerFn} from "../../utils/types.js"; @@ -98,7 +98,7 @@ export const sync: TestRunnerFn = (fork) => { function assertHeader(actualHeader: phase0.BeaconBlockHeader, expectedHeader: CheckHeader, msg: string): void { expect(toHeaderSummary(actualHeader)).deep.equals( - {root: expectedHeader.beacon_root, slot: Number(expectedHeader.slot as bigint)}, + {root: expectedHeader.beacon_root, slot: bigintToNumber(expectedHeader.slot as bigint)}, msg ); } @@ -119,7 +119,7 @@ export const sync: TestRunnerFn = (fork) => { for (const [i, step] of testcase.steps.entries()) { try { if (isProcessUpdateStep(step)) { - const currentSlot = Number(step.process_update.current_slot as bigint); + const currentSlot = bigintToNumber(step.process_update.current_slot as bigint); logger.debug(`Step ${i}/${stepsLen} process_update`, renderSlot(currentSlot)); const updateBytes = testcase.updates.get(step.process_update.update); @@ -127,7 +127,7 @@ export const sync: TestRunnerFn = (fork) => { throw Error(`update ${step.process_update.update} not found`); } - const headerSlot = Number(step.process_update.checks.optimistic_header.slot); + const headerSlot = bigintToNumber(step.process_update.checks.optimistic_header.slot); const update = config.getPostAltairForkTypes(headerSlot).LightClientUpdate.deserialize(updateBytes); logger.debug(`LightclientUpdateSummary: ${JSON.stringify(toLightClientUpdateSummary(update))}`); @@ -138,7 +138,7 @@ export const sync: TestRunnerFn = (fork) => { // force_update step else if (isForceUpdateStep(step)) { - const currentSlot = Number(step.force_update.current_slot as bigint); + const currentSlot = bigintToNumber(step.force_update.current_slot as bigint); logger.debug(`Step ${i}/${stepsLen} force_update`, renderSlot(currentSlot)); // Simulate force_update() @@ -201,7 +201,7 @@ function pickConfigForkEpochs(config: Partial): Partial BigInt(Number.MAX_SAFE_INTEGER)) { configOnlyFork[key] = Infinity; } else { - configOnlyFork[key] = Number(value); + configOnlyFork[key] = typeof value === "bigint" ? bigintToNumber(value) : Number(value); } } } 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 e8a16cf021a3..ecaa9f421516 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 @@ -4,6 +4,8 @@ import {isForkPostAltair} from "@lodestar/params"; import {InputType} from "@lodestar/spec-test-util"; import {LightClientUpdate, altair, ssz, sszTypesFor} from "@lodestar/types"; import {TestRunnerFn} from "../../utils/types.js"; +import {bigintToNumber} from "@lodestar/utils"; + // https://github.com/ethereum/consensus-specs/blob/da3f5af919be4abb5a6db5a80b235deb8b4b5cba/tests/formats/light_client/update_ranking.md type UpdateRankingTestCase = { @@ -19,7 +21,7 @@ export const updateRanking: TestRunnerFn = (fork) = return { testFunction: (testcase) => { // Parse update files - const updatesCount = Number(testcase.meta.updates_count as bigint); + const updatesCount = bigintToNumber(testcase.meta.updates_count as bigint); const updates: LightClientUpdate[] = []; for (let i = 0; i < updatesCount; i++) { diff --git a/packages/beacon-node/test/unit/execution/engine/types.test.ts b/packages/beacon-node/test/unit/execution/engine/types.test.ts index 171a2f4b01e5..6993f9f79ba9 100644 --- a/packages/beacon-node/test/unit/execution/engine/types.test.ts +++ b/packages/beacon-node/test/unit/execution/engine/types.test.ts @@ -17,9 +17,9 @@ describe("execution / engine / types", () => { // Assert 1-byte request_type prefix is set correctly expect(serialized.length).toBe(3); - expect(Number(serialized[0].substring(0, 2))).toBe(DEPOSIT_REQUEST_TYPE); - expect(Number(serialized[1].substring(0, 2))).toBe(WITHDRAWAL_REQUEST_TYPE); - expect(Number(serialized[2].substring(0, 2))).toBe(CONSOLIDATION_REQUEST_TYPE); + expect(parseInt(serialized[0].substring(0, 2), 16)).toBe(DEPOSIT_REQUEST_TYPE); + expect(parseInt(serialized[1].substring(0, 2), 16)).toBe(WITHDRAWAL_REQUEST_TYPE); + expect(parseInt(serialized[2].substring(0, 2), 16)).toBe(CONSOLIDATION_REQUEST_TYPE); // Assert execution requests can be deserialized expect(ssz.electra.DepositRequests.deserialize(fromHex(serialized[0].slice(2)))).toEqual( @@ -44,8 +44,8 @@ describe("execution / engine / types", () => { // Assert withdrawals are omitted expect(serialized.length).toBe(2); - expect(Number(serialized[0].substring(0, 2))).toBe(DEPOSIT_REQUEST_TYPE); - expect(Number(serialized[1].substring(0, 2))).toBe(CONSOLIDATION_REQUEST_TYPE); + expect(parseInt(serialized[0].substring(0, 2), 16)).toBe(DEPOSIT_REQUEST_TYPE); + expect(parseInt(serialized[1].substring(0, 2), 16)).toBe(CONSOLIDATION_REQUEST_TYPE); // Assert execution requests can be deserialized expect(ssz.electra.DepositRequests.deserialize(fromHex(serialized[0].slice(2)))).toEqual( diff --git a/packages/beacon-node/test/unit/monitoring/service.test.ts b/packages/beacon-node/test/unit/monitoring/service.test.ts index bdcc0680c134..b1e0b1257ca9 100644 --- a/packages/beacon-node/test/unit/monitoring/service.test.ts +++ b/packages/beacon-node/test/unit/monitoring/service.test.ts @@ -193,7 +193,7 @@ describe("monitoring / service", () => { }); it("should properly handle errors if remote service is unreachable", async () => { - const differentPort = Number(remoteServiceUrl.port) - 1; + const differentPort = parseInt(remoteServiceUrl.port, 10) - 1; const endpoint = `http://127.0.0.1:${differentPort}/`; service = new MonitoringService("beacon", {endpoint}, {register, logger}); 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 b64049c73298..5a4cccaf58ae 100644 --- a/packages/beacon-node/test/unit/network/subnets/util.test.ts +++ b/packages/beacon-node/test/unit/network/subnets/util.test.ts @@ -1,7 +1,7 @@ import {describe, expect, it} from "vitest"; import {config} from "@lodestar/config/default"; import {ATTESTATION_SUBNET_PREFIX_BITS, NODE_ID_BITS} from "@lodestar/params"; -import {bigIntToBytes} from "@lodestar/utils"; +import {bigIntToBytes, bigintToNumber} from "@lodestar/utils"; import {computeSubscribedSubnet, getNodeIdPrefix, getNodeOffset} from "../../../../src/network/subnets/util.js"; const nodeIds: string[] = [ @@ -24,7 +24,7 @@ describe("getNodeIdPrefix", () => { // nodeId is of type uint256, which is 32 bytes const nodeIdBytes = bigIntToBytes(nodeIdBigInt, 32, "be"); expect(getNodeIdPrefix(nodeIdBytes)).toBe( - Number(nodeIdBigInt >> BigInt(NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS)) + bigintToNumber(nodeIdBigInt >> BigInt(NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS)) ); }); } @@ -36,7 +36,7 @@ describe("getNodeOffset", () => { const nodeIdBigInt = BigInt(nodeId); // nodeId is of type uint256, which is 32 bytes const nodeIdBytes = bigIntToBytes(nodeIdBigInt, 32, "be"); - expect(getNodeOffset(nodeIdBytes)).toBe(Number(nodeIdBigInt % BigInt(256))); + expect(getNodeOffset(nodeIdBytes)).toBe(bigintToNumber(nodeIdBigInt % BigInt(256))); }); } }); diff --git a/packages/cli/package.json b/packages/cli/package.json index a614b841f6c1..950b7caa9117 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -29,9 +29,7 @@ ".git-data.json", "!**/*.tsbuildinfo" ], - "bin": { - "lodestar": "lib/index.js" - }, + "bin": "lib/index.js", "scripts": { "clean": "rm -rf lib && rm -f *.tsbuildinfo", "build": "tsc -p tsconfig.build.json && yarn write-git-data", diff --git a/packages/cli/src/util/proposerConfig.ts b/packages/cli/src/util/proposerConfig.ts index a346aa9acf96..c883e4b11f8e 100644 --- a/packages/cli/src/util/proposerConfig.ts +++ b/packages/cli/src/util/proposerConfig.ts @@ -89,7 +89,7 @@ function parseProposerConfigSection( builder: overrideConfig?.builder || builder ? { - gasLimit: overrideConfig?.builder?.gasLimit ?? (gas_limit !== undefined ? Number(gas_limit) : undefined), + gasLimit: overrideConfig?.builder?.gasLimit ?? (gas_limit !== undefined ? parseInt(gas_limit, 10) : undefined), selection: overrideConfig?.builder?.selection ?? parseBuilderSelection(builderSelection), boostFactor: overrideConfig?.builder?.boostFactor ?? parseBuilderBoostFactor(boost_factor), } diff --git a/packages/cli/test/utils/crucible/utils/executionGenesis.ts b/packages/cli/test/utils/crucible/utils/executionGenesis.ts index 7250c147e2c1..44d7c721dfc0 100644 --- a/packages/cli/test/utils/crucible/utils/executionGenesis.ts +++ b/packages/cli/test/utils/crucible/utils/executionGenesis.ts @@ -1,5 +1,7 @@ import {SIM_ENV_CHAIN_ID, SIM_ENV_NETWORK_ID} from "../constants.js"; import {Eth1GenesisBlock, ExecutionGenesisOptions, ExecutionStartMode} from "../interfaces.js"; +import {bigintToNumber} from "@lodestar/utils"; + export const getGethGenesisBlock = ( mode: ExecutionStartMode, @@ -35,7 +37,7 @@ export const getGethGenesisBlock = ( prague: {target: 6, max: 9, baseFeeUpdateFraction: 5007716}, // "osaka": { "target": 6, "max": 9, "updateFraction": 5007716 } }, - terminalTotalDifficulty: Number(ttd as bigint), + terminalTotalDifficulty: bigintToNumber(ttd as bigint), clique: {period: cliqueSealingPeriod, epoch: 30000}, }, nonce: "0x0", @@ -113,7 +115,7 @@ export const getNethermindChainSpec = ( eip3198Transition: "0x0", eip3529Transition: "0x0", eip3541Transition: "0x0", - terminalTotalDifficulty: Number(ttd as bigint), + terminalTotalDifficulty: bigintToNumber(ttd as bigint), gasLimitBoundDivisor: "0x400", maxCodeSize: "0x6000", maxCodeSizeTransition: "0x0", diff --git a/packages/flare/package.json b/packages/flare/package.json index 9cb04c31a2cd..46cba62534d5 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -21,9 +21,7 @@ "lib", "!**/*.tsbuildinfo" ], - "bin": { - "flare": "lib/index.js" - }, + "bin": "lib/index.js", "scripts": { "clean": "rm -rf lib && rm -f *.tsbuildinfo", "build": "tsc -p tsconfig.build.json", diff --git a/packages/flare/src/cmds/selfSlashAttester.ts b/packages/flare/src/cmds/selfSlashAttester.ts index 46ae8fdb4cd0..437ef5fbe26a 100644 --- a/packages/flare/src/cmds/selfSlashAttester.ts +++ b/packages/flare/src/cmds/selfSlashAttester.ts @@ -5,7 +5,7 @@ import {config as chainConfig} from "@lodestar/config/default"; import {DOMAIN_BEACON_ATTESTER, MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; import {computeSigningRoot} from "@lodestar/state-transition"; import {AttesterSlashing, phase0, ssz} from "@lodestar/types"; -import {CliCommand, toPubkeyHex} from "@lodestar/utils"; +import {CliCommand,bigintToNumber, toPubkeyHex} from "@lodestar/utils"; import {SecretKeysArgs, deriveSecretKeys, secretKeysOptions} from "../util/deriveSecretKeys.js"; type SelfSlashArgs = SecretKeysArgs & { @@ -141,7 +141,7 @@ function signAttestationDataBigint( sks: SecretKey[], data: phase0.AttestationDataBigint ): Uint8Array { - const slot = Number(data.slot as bigint); + const slot = bigintToNumber(data.slot as bigint); const proposerDomain = config.getDomain(slot, DOMAIN_BEACON_ATTESTER); const signingRoot = computeSigningRoot(ssz.phase0.AttestationDataBigint, data, proposerDomain); diff --git a/packages/flare/src/cmds/selfSlashProposer.ts b/packages/flare/src/cmds/selfSlashProposer.ts index 9d6d5dfea595..b33981904328 100644 --- a/packages/flare/src/cmds/selfSlashProposer.ts +++ b/packages/flare/src/cmds/selfSlashProposer.ts @@ -5,7 +5,7 @@ import {config as chainConfig} from "@lodestar/config/default"; import {DOMAIN_BEACON_PROPOSER} from "@lodestar/params"; import {computeSigningRoot} from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; -import {CliCommand, toPubkeyHex} from "@lodestar/utils"; +import {CliCommand,bigintToNumber, toPubkeyHex} from "@lodestar/utils"; import {SecretKeysArgs, deriveSecretKeys, secretKeysOptions} from "../util/deriveSecretKeys.js"; type SelfSlashArgs = SecretKeysArgs & { @@ -131,7 +131,7 @@ export async function selfSlashProposerHandler(args: SelfSlashArgs): Promise= ForkSeq.electra) { @@ -141,7 +141,7 @@ export function getExpectedWithdrawals( amount: withdrawableBalance, }); withdrawalIndex++; - withdrawnBalances.set(withdrawal.validatorIndex, totalWithdrawn + Number(withdrawableBalance)); + withdrawnBalances.set(withdrawal.validatorIndex, totalWithdrawn + bigintToNumber(withdrawableBalance)); } processedPartialWithdrawalsCount++; } diff --git a/packages/state-transition/src/signatureSets/attesterSlashings.ts b/packages/state-transition/src/signatureSets/attesterSlashings.ts index b053bb497805..f7f9677e8653 100644 --- a/packages/state-transition/src/signatureSets/attesterSlashings.ts +++ b/packages/state-transition/src/signatureSets/attesterSlashings.ts @@ -2,6 +2,8 @@ import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; import {AttesterSlashing, IndexedAttestationBigint, SignedBeaconBlock, ssz} from "@lodestar/types"; import {CachedBeaconStateAllForks} from "../types.js"; import {ISignatureSet, SignatureSetType, computeSigningRoot, computeStartSlotAtEpoch} from "../util/index.js"; +import {bigintToNumber} from "@lodestar/utils"; + /** Get signature sets from all AttesterSlashing objects in a block */ export function getAttesterSlashingsSignatureSets( @@ -27,7 +29,7 @@ export function getIndexedAttestationBigintSignatureSet( state: CachedBeaconStateAllForks, indexedAttestation: IndexedAttestationBigint ): ISignatureSet { - const slot = computeStartSlotAtEpoch(Number(indexedAttestation.data.target.epoch as bigint)); + const slot = computeStartSlotAtEpoch(bigintToNumber(indexedAttestation.data.target.epoch as bigint)); const domain = state.config.getDomain(state.slot, DOMAIN_BEACON_ATTESTER, slot); return { diff --git a/packages/state-transition/src/signatureSets/proposerSlashings.ts b/packages/state-transition/src/signatureSets/proposerSlashings.ts index d21c0906c511..6bf843d37025 100644 --- a/packages/state-transition/src/signatureSets/proposerSlashings.ts +++ b/packages/state-transition/src/signatureSets/proposerSlashings.ts @@ -2,6 +2,8 @@ import {DOMAIN_BEACON_PROPOSER} from "@lodestar/params"; import {SignedBeaconBlock, phase0, ssz} from "@lodestar/types"; import {CachedBeaconStateAllForks} from "../types.js"; import {ISignatureSet, SignatureSetType, computeSigningRoot} from "../util/index.js"; +import {bigintToNumber} from "@lodestar/utils"; + /** * Extract signatures to allow validating all block signatures at once @@ -19,7 +21,7 @@ export function getProposerSlashingSignatureSets( const domain = state.config.getDomain( state.slot, DOMAIN_BEACON_PROPOSER, - Number(signedHeader.message.slot as bigint) + bigintToNumber(signedHeader.message.slot as bigint) ); return { diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index 4370a13c783c..ca9175857143 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -1,6 +1,7 @@ import {ForkSeq, MAX_DEPOSITS} from "@lodestar/params"; import {UintNum64, phase0} from "@lodestar/types"; import {CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; +import {bigintToNumber} from "@lodestar/utils"; export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: phase0.Eth1Data): UintNum64 { const eth1DataToUse = eth1Data ?? state.eth1Data; @@ -11,7 +12,7 @@ export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: const eth1DataIndexLimit: UintNum64 = eth1DataToUse.depositCount < electraState.depositRequestsStartIndex ? eth1DataToUse.depositCount - : Number(electraState.depositRequestsStartIndex); + : bigintToNumber(electraState.depositRequestsStartIndex); if (state.eth1DepositIndex < eth1DataIndexLimit) { return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); diff --git a/packages/state-transition/src/util/epoch.ts b/packages/state-transition/src/util/epoch.ts index cc95d0d192f6..ce349cab9c3b 100644 --- a/packages/state-transition/src/util/epoch.ts +++ b/packages/state-transition/src/util/epoch.ts @@ -1,5 +1,6 @@ import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, GENESIS_EPOCH, MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params"; import {BeaconState, Epoch, Gwei, Slot, SyncPeriod} from "@lodestar/types"; +import {bigintToNumber} from "@lodestar/utils"; import {CachedBeaconStateElectra} from "../types.js"; import {getActivationExitChurnLimit, getConsolidationChurnLimit} from "./validator.js"; @@ -47,11 +48,11 @@ export function computeExitEpochAndUpdateChurn(state: CachedBeaconStateElectra, // New epoch for exits. let exitBalanceToConsume = - state.earliestExitEpoch < earliestExitEpoch ? perEpochChurn : Number(state.exitBalanceToConsume); + state.earliestExitEpoch < earliestExitEpoch ? perEpochChurn : bigintToNumber(state.exitBalanceToConsume); // Exit doesn't fit in the current earliest epoch. if (exitBalance > exitBalanceToConsume) { - const balanceToProcess = Number(exitBalance) - exitBalanceToConsume; + const balanceToProcess = bigintToNumber(exitBalance) - exitBalanceToConsume; const additionalEpochs = Math.floor((balanceToProcess - 1) / perEpochChurn) + 1; earliestExitEpoch += additionalEpochs; exitBalanceToConsume += additionalEpochs * perEpochChurn; @@ -78,11 +79,11 @@ export function computeConsolidationEpochAndUpdateChurn( let consolidationBalanceToConsume = state.earliestConsolidationEpoch < earliestConsolidationEpoch ? perEpochConsolidationChurn - : Number(state.consolidationBalanceToConsume); + : bigintToNumber(state.consolidationBalanceToConsume); // Consolidation doesn't fit in the current earliest epoch. if (consolidationBalance > consolidationBalanceToConsume) { - const balanceToProcess = Number(consolidationBalance) - consolidationBalanceToConsume; + const balanceToProcess = bigintToNumber(consolidationBalance) - consolidationBalanceToConsume; const additionalEpochs = Math.floor((balanceToProcess - 1) / perEpochConsolidationChurn) + 1; earliestConsolidationEpoch += additionalEpochs; consolidationBalanceToConsume += additionalEpochs * perEpochConsolidationChurn; diff --git a/packages/state-transition/src/util/seed.ts b/packages/state-transition/src/util/seed.ts index 3953df0b9b48..7627802288de 100644 --- a/packages/state-transition/src/util/seed.ts +++ b/packages/state-transition/src/util/seed.ts @@ -17,7 +17,7 @@ import { SYNC_COMMITTEE_SIZE, } from "@lodestar/params"; import {Bytes32, DomainType, Epoch, ValidatorIndex} from "@lodestar/types"; -import {assert, bytesToBigInt, bytesToInt, intToBytes} from "@lodestar/utils"; +import {assert, bigintToNumber, bytesToBigInt, bytesToInt, intToBytes} from "@lodestar/utils"; import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js"; import {BeaconStateAllForks, CachedBeaconStateAllForks} from "../types.js"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "./epoch.js"; @@ -282,7 +282,7 @@ export function computeShuffledIndex(index: number, indexCount: number, seed: By assert.lte(indexCount, 2 ** 40, "indexCount too big"); const _seed = seed; for (let i = 0; i < SHUFFLE_ROUND_COUNT; i++) { - const pivot = Number( + const pivot = bigintToNumber( bytesToBigInt(digest(Buffer.concat([_seed, intToBytes(i, 1)])).slice(0, 8)) % BigInt(indexCount) ); const flip = (pivot + indexCount - permuted) % indexCount; @@ -332,7 +332,7 @@ export function getComputeShuffledIndexFn(indexCount: number, seed: Bytes32): Co // bytesToBigInt(digest(Buffer.concat([_seed, intToBytes(i, 1)])).slice(0, 8)) % BigInt(indexCount) // ); pivotBuffer[32] = i % 256; - pivot = Number(bytesToBigInt(digest(pivotBuffer).subarray(0, 8)) % BigInt(indexCount)); + pivot = bigintToNumber(bytesToBigInt(digest(pivotBuffer).subarray(0, 8)) % BigInt(indexCount)); pivotByIndex.set(i, pivot); } diff --git a/packages/state-transition/src/util/syncCommittee.ts b/packages/state-transition/src/util/syncCommittee.ts index c776fd42b8e8..59ac6d892a85 100644 --- a/packages/state-transition/src/util/syncCommittee.ts +++ b/packages/state-transition/src/util/syncCommittee.ts @@ -9,7 +9,7 @@ import { WEIGHT_DENOMINATOR, } from "@lodestar/params"; import {altair} from "@lodestar/types"; -import {bigIntSqrt} from "@lodestar/utils"; +import {bigIntSqrt, bigintToNumber} from "@lodestar/utils"; import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js"; import {BeaconStateAllForks} from "../types.js"; import {getNextSyncCommitteeIndices} from "./seed.js"; @@ -48,7 +48,7 @@ export function getNextSyncCommittee( export function computeSyncParticipantReward(totalActiveBalanceIncrements: number): number { const totalActiveBalance = BigInt(totalActiveBalanceIncrements) * BigInt(EFFECTIVE_BALANCE_INCREMENT); const baseRewardPerIncrement = Math.floor( - (EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR) / Number(bigIntSqrt(totalActiveBalance)) + (EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR) / bigintToNumber(bigIntSqrt(totalActiveBalance)) ); const totalBaseRewards = baseRewardPerIncrement * totalActiveBalanceIncrements; const maxParticipantRewards = Math.floor( @@ -64,6 +64,6 @@ export function computeSyncParticipantReward(totalActiveBalanceIncrements: numbe export function computeBaseRewardPerIncrement(totalActiveStakeByIncrement: number): number { return Math.floor( (EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR) / - Number(bigIntSqrt(BigInt(totalActiveStakeByIncrement) * BigInt(EFFECTIVE_BALANCE_INCREMENT))) + bigintToNumber(bigIntSqrt(BigInt(totalActiveStakeByIncrement) * BigInt(EFFECTIVE_BALANCE_INCREMENT))) ); } diff --git a/packages/state-transition/src/util/validator.ts b/packages/state-transition/src/util/validator.ts index 0d7c011b99d7..4bbc840e278e 100644 --- a/packages/state-transition/src/util/validator.ts +++ b/packages/state-transition/src/util/validator.ts @@ -6,7 +6,7 @@ import { MIN_ACTIVATION_BALANCE, } from "@lodestar/params"; import {Epoch, ValidatorIndex, phase0} from "@lodestar/types"; -import {intDiv} from "@lodestar/utils"; +import {bigintToNumber, intDiv} from "@lodestar/utils"; import {BeaconStateAllForks, CachedBeaconStateElectra, EpochCache} from "../types.js"; import {hasCompoundingWithdrawalCredential} from "./electra.js"; @@ -98,7 +98,7 @@ export function getPendingBalanceToWithdraw(state: CachedBeaconStateElectra, val let total = 0; for (const item of state.pendingPartialWithdrawals.getAllReadonly()) { if (item.validatorIndex === validatorIndex) { - total += Number(item.amount); + total += bigintToNumber(item.amount); } } return total; diff --git a/packages/state-transition/test/perf/misc/arrayCreation.test.ts b/packages/state-transition/test/perf/misc/arrayCreation.test.ts index 59eeb418993d..c588f39f7f89 100644 --- a/packages/state-transition/test/perf/misc/arrayCreation.test.ts +++ b/packages/state-transition/test/perf/misc/arrayCreation.test.ts @@ -1,4 +1,5 @@ import {bench, describe} from "@chainsafe/benchmark"; +import { bigintToNumber } from "@lodestar/utils"; describe.skip("array creation", () => { const testCases: {id: string; fn: (n: number) => void}[] = [ @@ -37,7 +38,7 @@ describe.skip("array creation", () => { fn(elem); } const to = process.hrtime.bigint(); - const diffMs = Number(to - from) / 1e6; + const diffMs = bigintToNumber(to - from) / 1e6; 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 fa3690c8318f..da2c13cefc08 100644 --- a/packages/state-transition/test/perf/misc/bitopts.test.ts +++ b/packages/state-transition/test/perf/misc/bitopts.test.ts @@ -1,5 +1,6 @@ import {bench, describe} from "@chainsafe/benchmark"; import {FLAG_PREV_SOURCE_ATTESTER, FLAG_UNSLASHED} from "../../../src/index.js"; +import { bigintToNumber } from "@lodestar/utils"; describe.skip("bit opts", () => { bench("Benchmark bitshift", () => { @@ -12,7 +13,7 @@ describe.skip("bit opts", () => { FLAG_PREV_SOURCE_ATTESTER | FLAG_UNSLASHED; } const to = process.hrtime.bigint(); - const diffMs = Number(to - from) / 1e6; + const diffMs = bigintToNumber(to - from) / 1e6; console.log(`Time spent on OR in getAttestationDeltas: ${diffMs * ((orOptsPerRun * validators) / opsRun)} ms`); }); }); diff --git a/packages/types/test/unit/constants/blobs.test.ts b/packages/types/test/unit/constants/blobs.test.ts index 17075f5e5346..c564f854ecea 100644 --- a/packages/types/test/unit/constants/blobs.test.ts +++ b/packages/types/test/unit/constants/blobs.test.ts @@ -1,6 +1,7 @@ import {describe, expect, it} from "vitest"; import * as constants from "@lodestar/params"; import {ssz} from "../../../src/index.js"; +import {bigintToNumber} from "@lodestar/utils"; // NOTE: This test is here and not in lodestar-params, to prevent lodestar-params depending on SSZ // Since lodestar-params and lodestar-types are in the same mono-repo, running this test here is enough @@ -8,7 +9,7 @@ import {ssz} from "../../../src/index.js"; describe(`${constants.ACTIVE_PRESET}/ blobs pre-computed constants`, () => { const BLOB_SIDECAR_FIXED_SIZE = ssz.deneb.BlobSidecars.elementType.fixedSize; - const KZG_COMMITMENT_GINDEX0 = Number(ssz.deneb.BeaconBlockBody.getPathInfo(["blobKzgCommitments", 0]).gindex); + const KZG_COMMITMENT_GINDEX0 = bigintToNumber(ssz.deneb.BeaconBlockBody.getPathInfo(["blobKzgCommitments", 0]).gindex); const KZG_COMMITMENT_SUBTREE_INDEX0 = KZG_COMMITMENT_GINDEX0 - 2 ** constants.KZG_COMMITMENT_INCLUSION_PROOF_DEPTH; const correctConstants = { diff --git a/packages/types/test/unit/constants/lightclient.test.ts b/packages/types/test/unit/constants/lightclient.test.ts index dc46a5e76ad2..2235e3a45487 100644 --- a/packages/types/test/unit/constants/lightclient.test.ts +++ b/packages/types/test/unit/constants/lightclient.test.ts @@ -1,6 +1,7 @@ import {describe, expect, it} from "vitest"; import * as constants from "@lodestar/params"; import {ssz} from "../../../src/index.js"; +import {bigintToNumber} from "@lodestar/utils"; // NOTE: This test is here and not in lodestar-params, to prevent lodestar-params depending on SSZ // Since lodestar-params and lodestar-types are in the same mono-repo, running this test here is enough @@ -37,5 +38,5 @@ function floorlog2(num: number): number { /** Type safe wrapper for Number constructor that takes 'any' */ function bnToNum(bn: bigint): number { - return Number(bn); + return bigintToNumber(bn); } diff --git a/packages/utils/src/bigint.ts b/packages/utils/src/bigint.ts new file mode 100644 index 000000000000..adba857676b3 --- /dev/null +++ b/packages/utils/src/bigint.ts @@ -0,0 +1,14 @@ +/** + * Safely converts a bigint to a number, throwing an error if the value is outside the safe integer range + * or if the conversion would result in NaN. + */ +export function bigintToNumber(bn: bigint): number { + if (bn > BigInt(Number.MAX_SAFE_INTEGER) || bn < BigInt(Number.MIN_SAFE_INTEGER)) { + throw new Error(`Cannot safely convert bigint ${bn} to number - value outside safe integer range`); + } + const num = Number(bn); + if (Number.isNaN(num)) { + throw new Error(`Cannot convert bigint ${bn} to number - conversion resulted in NaN`); + } + return num; +} \ No newline at end of file diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index c98435c1c1d2..a62a1ee2e330 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -25,3 +25,4 @@ export * from "./url.js"; export * from "./verifyMerkleBranch.js"; export * from "./waitFor.js"; export * from "./yaml/index.js"; +export * from "./bigint.js"; \ No newline at end of file diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts index 94c23a5e5e53..f5d170fa1c78 100644 --- a/packages/utils/src/types.ts +++ b/packages/utils/src/types.ts @@ -1,3 +1,5 @@ +import { bigintToNumber } from "./bigint.ts"; + /** * Recursively make all properties optional */ @@ -26,7 +28,7 @@ export type RecursivePartial = /** Type safe wrapper for Number constructor that takes 'any' */ export function bnToNum(bn: bigint): number { - return Number(bn); + return bigintToNumber(bn); } export type NonEmptyArray = [T, ...T[]]; diff --git a/packages/validator/src/validator.ts b/packages/validator/src/validator.ts index 2f615ccbbce3..958dcc5e8f15 100644 --- a/packages/validator/src/validator.ts +++ b/packages/validator/src/validator.ts @@ -167,7 +167,7 @@ export class Validator { const {db, config: chainConfig, logger, slashingProtection, signers, valProposerConfig} = opts; const config = createBeaconConfig(chainConfig, genesis.genesisValidatorsRoot); const controller = opts.abortController; - const clock = new Clock(config, logger, {genesisTime: Number(genesis.genesisTime)}); + const clock = new Clock(config, logger, {genesisTime: genesis.genesisTime}); const loggerVc = getLoggerVc(logger, clock); let api: ApiClient;