UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

95 lines 4.7 kB
import { ForkSeq, ZERO_HASH } from "@lodestar/params"; import { computeEpochAtSlot, computeStartSlotAtEpoch, } from "@lodestar/state-transition"; import { ssz } from "@lodestar/types"; import { byteArrayEquals, toHex, toRootHex } from "@lodestar/utils"; import { GENESIS_SLOT } from "../constants/index.js"; import { getStateTypeFromBytes } from "../util/multifork.js"; export async function persistAnchorState(config, db, anchorState, anchorStateBytes) { if (anchorState.slot === GENESIS_SLOT) { const genesisBlock = createGenesisBlock(config, anchorState); const blockRoot = config.getForkTypes(GENESIS_SLOT).BeaconBlock.hashTreeRoot(genesisBlock.message); const latestBlockHeader = ssz.phase0.BeaconBlockHeader.clone(anchorState.latestBlockHeader); if (ssz.Root.equals(latestBlockHeader.stateRoot, ZERO_HASH)) { latestBlockHeader.stateRoot = anchorState.hashTreeRoot(); } const latestBlockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(latestBlockHeader); if (!byteArrayEquals(blockRoot, latestBlockRoot)) { throw Error(`Genesis block root ${toRootHex(blockRoot)} does not match genesis state latest block root ${toRootHex(latestBlockRoot)}`); } await Promise.all([ db.blockArchive.add(genesisBlock), db.block.add(genesisBlock), db.stateArchive.putBinary(anchorState.slot, anchorStateBytes), ]); } else { await db.stateArchive.putBinary(anchorState.slot, anchorStateBytes); } } export function createGenesisBlock(config, genesisState) { const types = config.getForkTypes(GENESIS_SLOT); const genesisBlock = types.SignedBeaconBlock.defaultValue(); const stateRoot = genesisState.hashTreeRoot(); genesisBlock.message.stateRoot = stateRoot; if (config.getForkSeq(GENESIS_SLOT) >= ForkSeq.gloas) { const gloasBlock = genesisBlock; const gloasState = genesisState; gloasBlock.message.body.signedExecutionPayloadBid.message = gloasState.latestExecutionPayloadBid.toValue(); } return genesisBlock; } /** * Restore the latest beacon state from db */ export async function initStateFromDb(config, db, logger) { const stateBytes = await db.stateArchive.lastBinary(); if (stateBytes == null) { throw new Error("No state exists in database"); } const state = getStateTypeFromBytes(config, stateBytes).deserializeToViewDU(stateBytes); logger.info("Initializing beacon state from db", { slot: state.slot, epoch: computeEpochAtSlot(state.slot), stateRoot: toRootHex(state.hashTreeRoot()), }); return state; } /** * Initialize and persist an anchor state (either weak subjectivity or genesis) */ export async function checkAndPersistAnchorState(config, db, logger, anchorState, anchorStateBytes, { isWithinWeakSubjectivityPeriod, isCheckpointState, }) { const expectedFork = config.getForkInfo(computeStartSlotAtEpoch(anchorState.fork.epoch)); const expectedForkVersion = toHex(expectedFork.version); const stateFork = toHex(anchorState.fork.currentVersion); if (stateFork !== expectedForkVersion) { throw Error(`State current fork version ${stateFork} not equal to current config ${expectedForkVersion}. Maybe caused by importing a state from a different network`); } const stateInfo = isCheckpointState ? "checkpoint" : "db"; if (isWithinWeakSubjectivityPeriod) { logger.info(`Initializing beacon from a valid ${stateInfo} state`, { slot: anchorState.slot, epoch: computeEpochAtSlot(anchorState.slot), stateRoot: toRootHex(anchorState.hashTreeRoot()), isWithinWeakSubjectivityPeriod, }); } else { logger.warn(`Initializing from a stale ${stateInfo} state vulnerable to long range attacks`, { slot: anchorState.slot, epoch: computeEpochAtSlot(anchorState.slot), stateRoot: toRootHex(anchorState.hashTreeRoot()), isWithinWeakSubjectivityPeriod, }); logger.warn("Checkpoint sync recommended, please use --help to see checkpoint sync options"); } if (isCheckpointState || anchorState.slot === GENESIS_SLOT) { await persistAnchorState(config, db, anchorState, anchorStateBytes); } } export function initBeaconMetrics(metrics, state) { metrics.headSlot.set(state.slot); metrics.previousJustifiedEpoch.set(state.previousJustifiedCheckpoint.epoch); metrics.currentJustifiedEpoch.set(state.currentJustifiedCheckpoint.epoch); metrics.finalizedEpoch.set(state.finalizedCheckpoint.epoch); } //# sourceMappingURL=initState.js.map