UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

92 lines (79 loc) 3.13 kB
import {PeerId} from "@libp2p/interface"; import {BeaconConfig} from "@lodestar/config"; import {ForkName, GENESIS_EPOCH, GENESIS_SLOT, isForkPostDeneb} from "@lodestar/params"; import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {fulu} from "@lodestar/types"; import {toRootHex} from "@lodestar/utils"; import {IBeaconChain} from "../../../chain/index.js"; import {getParentRootFromSignedBeaconBlockSerialized} from "../../../util/sszBytes.js"; import {prettyPrintPeerId} from "../../util.js"; // See https://github.com/ethereum/consensus-specs/pull/5181 export async function* onBeaconBlocksByHead( request: fulu.BeaconBlocksByHeadRequest, chain: IBeaconChain, peerId: PeerId, peerClient: string ): AsyncIterable<ResponseOutgoing> { const currentFork = chain.config.getForkName(chain.clock.currentSlot); const {beaconRoot, count} = validateBeaconBlocksByHeadRequest(currentFork, chain.config, request); const requestedRootHex = toRootHex(beaconRoot); let blockRootHex = requestedRootHex; const minimumRequestEpoch = Math.max( GENESIS_EPOCH, chain.clock.currentEpoch - chain.config.MIN_EPOCHS_FOR_BLOCK_REQUESTS ); const minimumRequestSlot = computeStartSlotAtEpoch(minimumRequestEpoch); for (let blocksSent = 0; blocksSent < count; blocksSent++) { const blockBytes = await chain.getSerializedBlockByRoot(blockRootHex); if (!blockBytes) { if (blocksSent === 0) { throw new ResponseError(RespStatus.RESOURCE_UNAVAILABLE, `Unknown block root ${requestedRootHex}`); } return; } if (blockBytes.slot < minimumRequestSlot) { if (blocksSent === 0) { chain.logger.verbose("Peer requested unavailable block for BeaconBlocksByHead", { peer: prettyPrintPeerId(peerId), client: peerClient, requestedRoot: requestedRootHex, slot: blockBytes.slot, minimumRequestSlot, }); } return; } yield { data: blockBytes.block, boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(blockBytes.slot)), }; if (blockBytes.slot === GENESIS_SLOT) { return; } const parentRootHex = getParentRootFromSignedBeaconBlockSerialized(blockBytes.block); if (parentRootHex === null) { throw new ResponseError( RespStatus.SERVER_ERROR, `Invalid block bytes for root ${blockRootHex} slot ${blockBytes.slot}` ); } blockRootHex = parentRootHex; } } export function validateBeaconBlocksByHeadRequest( fork: ForkName, config: BeaconConfig, request: fulu.BeaconBlocksByHeadRequest ): fulu.BeaconBlocksByHeadRequest { const {beaconRoot} = request; let {count} = request; if (count < 1) { throw new ResponseError(RespStatus.INVALID_REQUEST, "count < 1"); } const maxRequestBlocks = isForkPostDeneb(fork) ? config.MAX_REQUEST_BLOCKS_DENEB : config.MAX_REQUEST_BLOCKS; if (count > maxRequestBlocks) { count = maxRequestBlocks; } return {beaconRoot, count}; }