UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

179 lines (167 loc) 8.97 kB
import {IBeaconStateView} from "@lodestar/state-transition"; import {RootHex, SignedBeaconBlock, Slot, ValidatorIndex} from "@lodestar/types"; import {LodestarError, toRootHex} from "@lodestar/utils"; import {ExecutionPayloadStatus} from "../../execution/engine/interface.js"; import {QueueErrorCode} from "../../util/queue/index.js"; import {GossipActionError} from "./gossipValidation.js"; export enum BlockErrorCode { /** The prestate cannot be fetched */ PRESTATE_MISSING = "BLOCK_ERROR_PRESTATE_MISSING", /** The parent block was unknown. */ PARENT_UNKNOWN = "BLOCK_ERROR_PARENT_UNKNOWN", /** The block slot is greater than the present slot. */ FUTURE_SLOT = "BLOCK_ERROR_FUTURE_SLOT", /** The block state_root does not match the generated state. */ STATE_ROOT_MISMATCH = "BLOCK_ERROR_STATE_ROOT_MISMATCH", /** The block was a genesis block, these blocks cannot be re-imported. */ GENESIS_BLOCK = "BLOCK_ERROR_GENESIS_BLOCK", /** The slot is finalized, no need to import. */ WOULD_REVERT_FINALIZED_SLOT = "BLOCK_ERROR_WOULD_REVERT_FINALIZED_SLOT", /** Block is already known, no need to re-import. */ ALREADY_KNOWN = "BLOCK_ERROR_ALREADY_KNOWN", /** A block for this proposer and slot has already been observed. */ REPEAT_PROPOSAL = "BLOCK_ERROR_REPEAT_PROPOSAL", /** The block slot exceeds the MAXIMUM_BLOCK_SLOT_NUMBER. */ BLOCK_SLOT_LIMIT_REACHED = "BLOCK_ERROR_BLOCK_SLOT_LIMIT_REACHED", /** The `BeaconBlock` has a `proposer_index` that does not match the index we computed locally. */ INCORRECT_PROPOSER = "BLOCK_ERROR_INCORRECT_PROPOSER", /** The proposal signature in invalid. */ PROPOSAL_SIGNATURE_INVALID = "BLOCK_ERROR_PROPOSAL_SIGNATURE_INVALID", /** The `block.proposer_index` is not known. */ UNKNOWN_PROPOSER = "BLOCK_ERROR_UNKNOWN_PROPOSER", /** A signature in the block is invalid (exactly which is unknown). */ INVALID_SIGNATURE = "BLOCK_ERROR_INVALID_SIGNATURE", /** Block transition returns invalid state root. */ INVALID_STATE_ROOT = "BLOCK_ERROR_INVALID_STATE_ROOT", /** Block (its parent) is not a descendant of current finalized block */ NOT_FINALIZED_DESCENDANT = "BLOCK_ERROR_NOT_FINALIZED_DESCENDANT", /** The provided block is from an later slot than its parent. */ NOT_LATER_THAN_PARENT = "BLOCK_ERROR_NOT_LATER_THAN_PARENT", /** At least one block in the chain segment did not have it's parent root set to the root of the prior block. */ NON_LINEAR_PARENT_ROOTS = "BLOCK_ERROR_NON_LINEAR_PARENT_ROOTS", /** The slots of the blocks in the chain segment were not strictly increasing. */ NON_LINEAR_SLOTS = "BLOCK_ERROR_NON_LINEAR_SLOTS", /** The block failed the specification's `per_block_processing` function, it is invalid. */ PER_BLOCK_PROCESSING_ERROR = "BLOCK_ERROR_PER_BLOCK_PROCESSING_ERROR", /** There was an error whilst processing the block. It is not necessarily invalid. */ BEACON_CHAIN_ERROR = "BLOCK_ERROR_BEACON_CHAIN_ERROR", /** Block did not pass validation during block processing. */ KNOWN_BAD_BLOCK = "BLOCK_ERROR_KNOWN_BAD_BLOCK", /** Blacklisted blocks that should not pass processing */ BLACKLISTED_BLOCK = "BLOCK_ERROR_BLACKLISTED_BLOCK", // Merge p2p /** executionPayload.timestamp is not the expected value */ INCORRECT_TIMESTAMP = "BLOCK_ERROR_INCORRECT_TIMESTAMP", /** executionPayload.gasUsed > executionPayload.gasLimit */ TOO_MUCH_GAS_USED = "BLOCK_ERROR_TOO_MUCH_GAS_USED", /** executionPayload.blockHash == executionPayload.parentHash */ SAME_PARENT_HASH = "BLOCK_ERROR_SAME_PARENT_HASH", /** Total size of executionPayload.transactions exceed a sane limit to prevent DOS attacks */ TRANSACTIONS_TOO_BIG = "BLOCK_ERROR_TRANSACTIONS_TOO_BIG", /** Execution engine is unavailable, syncing, or api call errored. Peers must not be downscored on this code */ EXECUTION_ENGINE_ERROR = "BLOCK_ERROR_EXECUTION_ERROR", /** The attestation head block is too far behind the attestation slot, causing many skip slots. This is deemed a DoS risk */ TOO_MANY_SKIPPED_SLOTS = "TOO_MANY_SKIPPED_SLOTS", /** The blobs are unavailable */ DATA_UNAVAILABLE = "BLOCK_ERROR_DATA_UNAVAILABLE", /** Block contains too many kzg commitments */ TOO_MANY_KZG_COMMITMENTS = "BLOCK_ERROR_TOO_MANY_KZG_COMMITMENTS", /** Bid parent block root does not match block parent root */ BID_PARENT_ROOT_MISMATCH = "BLOCK_ERROR_BID_PARENT_ROOT_MISMATCH", /** The parent block's execution payload has been verified as invalid */ PARENT_EXECUTION_INVALID = "BLOCK_ERROR_PARENT_EXECUTION_INVALID", /** The block's parent execution payload (defined by bid.parent_block_hash) has not been seen */ PARENT_PAYLOAD_UNKNOWN = "BLOCK_ERROR_PARENT_PAYLOAD_UNKNOWN", /** An execution payload envelope in the chain segment references a block root that does not match its slot's block */ ENVELOPE_BLOCK_ROOT_MISMATCH = "BLOCK_ERROR_ENVELOPE_BLOCK_ROOT_MISMATCH", } type ExecutionErrorStatus = Exclude< ExecutionPayloadStatus, ExecutionPayloadStatus.VALID | ExecutionPayloadStatus.ACCEPTED | ExecutionPayloadStatus.SYNCING >; export type BlockErrorType = | {code: BlockErrorCode.PRESTATE_MISSING; error: Error} | {code: BlockErrorCode.PARENT_UNKNOWN; parentRoot: RootHex} | {code: BlockErrorCode.FUTURE_SLOT; blockSlot: Slot; currentSlot: Slot} | {code: BlockErrorCode.STATE_ROOT_MISMATCH} | {code: BlockErrorCode.GENESIS_BLOCK} | {code: BlockErrorCode.TOO_MANY_SKIPPED_SLOTS; parentSlot: Slot; blockSlot: Slot} | {code: BlockErrorCode.WOULD_REVERT_FINALIZED_SLOT; blockSlot: Slot; finalizedSlot: Slot} | {code: BlockErrorCode.ALREADY_KNOWN; root: RootHex} | {code: BlockErrorCode.REPEAT_PROPOSAL; proposerIndex: ValidatorIndex} | {code: BlockErrorCode.BLOCK_SLOT_LIMIT_REACHED} | {code: BlockErrorCode.INCORRECT_PROPOSER; proposerIndex: ValidatorIndex} | {code: BlockErrorCode.PROPOSAL_SIGNATURE_INVALID; blockSlot: Slot} | {code: BlockErrorCode.UNKNOWN_PROPOSER; proposerIndex: ValidatorIndex} | {code: BlockErrorCode.INVALID_SIGNATURE; state: IBeaconStateView} | { code: BlockErrorCode.INVALID_STATE_ROOT; root: Uint8Array; expectedRoot: Uint8Array; preState: IBeaconStateView; postState: IBeaconStateView; } | {code: BlockErrorCode.NOT_FINALIZED_DESCENDANT; parentRoot: RootHex} | {code: BlockErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot} | {code: BlockErrorCode.NON_LINEAR_PARENT_ROOTS} | {code: BlockErrorCode.NON_LINEAR_SLOTS} | {code: BlockErrorCode.ENVELOPE_BLOCK_ROOT_MISMATCH; envelopeBlockRoot: RootHex; blockRoot: RootHex} | {code: BlockErrorCode.PER_BLOCK_PROCESSING_ERROR; error: Error} | {code: BlockErrorCode.BEACON_CHAIN_ERROR; error: Error} | {code: BlockErrorCode.KNOWN_BAD_BLOCK} | {code: BlockErrorCode.BLACKLISTED_BLOCK} | {code: BlockErrorCode.INCORRECT_TIMESTAMP; timestamp: number; expectedTimestamp: number} | {code: BlockErrorCode.TOO_MUCH_GAS_USED; gasUsed: number; gasLimit: number} | {code: BlockErrorCode.SAME_PARENT_HASH; blockHash: RootHex} | {code: BlockErrorCode.TRANSACTIONS_TOO_BIG; size: number; max: number} | {code: BlockErrorCode.EXECUTION_ENGINE_ERROR; execStatus: ExecutionErrorStatus; errorMessage: string} | {code: BlockErrorCode.DATA_UNAVAILABLE} | {code: BlockErrorCode.TOO_MANY_KZG_COMMITMENTS; blobKzgCommitmentsLen: number; commitmentLimit: number} | {code: BlockErrorCode.BID_PARENT_ROOT_MISMATCH; bidParentRoot: RootHex; blockParentRoot: RootHex} | {code: BlockErrorCode.PARENT_EXECUTION_INVALID; parentRoot: RootHex} | {code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN; parentRoot: RootHex; parentBlockHash: RootHex}; export class BlockGossipError extends GossipActionError<BlockErrorType> {} export class BlockError extends LodestarError<BlockErrorType> { constructor( readonly signedBlock: SignedBeaconBlock, type: BlockErrorType ) { super(type); } getMetadata(): Record<string, string | number | null> { return renderBlockErrorType(this.type); } } export function isBlockErrorAborted(e: unknown): e is BlockError { return ( e instanceof BlockError && e.type.code === BlockErrorCode.EXECUTION_ENGINE_ERROR && e.type.errorMessage === QueueErrorCode.QUEUE_ABORTED ); } export function renderBlockErrorType(type: BlockErrorType): Record<string, string | number | null> { switch (type.code) { case BlockErrorCode.PRESTATE_MISSING: case BlockErrorCode.PER_BLOCK_PROCESSING_ERROR: case BlockErrorCode.BEACON_CHAIN_ERROR: return { code: type.code, error: type.error.message, }; case BlockErrorCode.INVALID_SIGNATURE: return { code: type.code, slot: type.state.slot, }; case BlockErrorCode.INVALID_STATE_ROOT: return { code: type.code, slot: type.postState.slot, root: toRootHex(type.root), expectedRoot: toRootHex(type.expectedRoot), }; default: return type; } }