UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

90 lines (81 loc) 2.78 kB
import {BeaconConfig} from "@lodestar/config"; import { DataAvailabilityStatus, ExecutionPayloadStatus, IBeaconStateView, createBeaconStateViewForHistoricalRegen, } from "@lodestar/state-transition"; import {byteArrayEquals} from "@lodestar/utils"; import {IBeaconDb} from "../../../db/index.js"; import {HistoricalStateRegenMetrics} from "./metrics.js"; import {RegenErrorType} from "./types.js"; /** * Get the nearest BeaconState at or before a slot */ export async function getNearestState( slot: number, config: BeaconConfig, db: IBeaconDb, nativeStateView: boolean ): Promise<IBeaconStateView> { const stateBytesArr = await db.stateArchive.binaries({limit: 1, lte: slot, reverse: true}); if (!stateBytesArr.length) { throw new Error("No near state found in the database"); } const stateBytes = stateBytesArr[0]; return nativeStateView ? createBeaconStateViewForHistoricalRegen({useNative: true, stateBytes}) : createBeaconStateViewForHistoricalRegen({useNative: false, config, stateBytes}); } /** * Get and regenerate a historical state */ export async function getHistoricalState( slot: number, config: BeaconConfig, db: IBeaconDb, nativeStateView: boolean, metrics?: HistoricalStateRegenMetrics ): Promise<Uint8Array> { const regenTimer = metrics?.regenTime.startTimer(); const loadStateTimer = metrics?.loadStateTime.startTimer(); let state = await getNearestState(slot, config, db, nativeStateView).catch((e) => { metrics?.regenErrorCount.inc({reason: RegenErrorType.loadState}); throw e; }); loadStateTimer?.(); const transitionTimer = metrics?.stateTransitionTime.startTimer(); let blockCount = 0; for await (const block of db.blockArchive.valuesStream({gt: state.slot, lte: slot})) { try { state = state.stateTransition( block, { verifyProposer: false, verifySignatures: false, verifyStateRoot: false, executionPayloadStatus: ExecutionPayloadStatus.valid, dataAvailabilityStatus: DataAvailabilityStatus.Available, }, {metrics} ); } catch (e) { metrics?.regenErrorCount.inc({reason: RegenErrorType.blockProcessing}); throw e; } blockCount++; if (!byteArrayEquals(state.hashTreeRoot(), block.message.stateRoot)) { metrics?.regenErrorCount.inc({reason: RegenErrorType.invalidStateRoot}); } } 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?.(); regenTimer?.(); return stateBytes; }