@lodestar/beacon-node
Version:
A Typescript implementation of the beacon chain
133 lines (120 loc) • 6.3 kB
text/typescript
import {EventEmitter} from "node:events";
import {StrictEventEmitter} from "strict-event-emitter-types";
import {routes} from "@lodestar/api";
import {CheckpointWithHex} from "@lodestar/fork-choice";
import {IBeaconStateView} from "@lodestar/state-transition";
import {DataColumnSidecar, RootHex, deneb, phase0} from "@lodestar/types";
import {PeerIdStr} from "../util/peerId.js";
import {BlockInputSource, IBlockInput} from "./blocks/blockInput/types.js";
import {PayloadEnvelopeInput} from "./blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
/**
* Important chain events that occur during normal chain operation.
*
* Chain events can be broken into several categories:
* - Clock: the chain's clock is updated
* - Fork Choice: the chain's fork choice is updated
* - Checkpointing: the chain processes epoch boundaries
*/
export enum ChainEvent {
/**
* This event signals that the chain has processed (or reprocessed) a checkpoint.
*
* This event is not tied to clock events, but rather tied to generation (or regeneration) of state.
* This event is guaranteed to be called after _any_ checkpoint is processed, including skip-slot checkpoints, checkpoints that are formed as a result of processing blocks, etc.
*/
checkpoint = "checkpoint",
/**
* This event signals that the fork choice store has been updated.
*
* This event is guaranteed to be triggered whenever the fork choice justified checkpoint is updated. This is either in response to a newly processed block or a new clock tick.
*/
forkChoiceJustified = "forkChoice:justified",
/**
* This event signals that the fork choice store has been updated.
*
* This event is guaranteed to be triggered whenever the fork choice justified checkpoint is updated. This is in response to a newly processed block.
*/
forkChoiceFinalized = "forkChoice:finalized",
/**
* This event signals that dependent services (e.g. custody sampling) should update to account for the new target group count.
*/
updateTargetCustodyGroupCount = "updateTargetCustodyGroupCount",
/**
* This event signals that data columns have been fetched from the execution engine
* and are ready to be published.
*/
publishDataColumns = "publishDataColumns",
/**
* This event signals that blobs have been fetched from the execution engine
* and are ready to be published.
*/
publishBlobSidecars = "publishBlobSidecars",
/**
* Trigger an update of status so reqresp by peers have current earliestAvailableSlot
*/
updateStatus = "updateStatus",
/**
* Trigger BlockInputSync to find parent of a SignedBeaconBlock received
* Post-gloas, missing parent could be a SignedBeaconBlock and/or a SignedExecutionPayloadEnvelope
*/
blockUnknownParent = "blockUnknownParent",
/**
* Trigger BlockInputSync to find a SignedBeaconBlock with specified block root.
*/
unknownBlockRoot = "unknownBlockRoot",
/**
* Trigger BlockInputSync to find a SignedExecutionPayloadEnvelope with specified block root.
*/
unknownEnvelopeBlockRoot = "unknownEnvelopeBlockRoot",
/**
* Trigger BlockInputSync for blocks that are partially received via gossip but are not complete by time the
* cut-off window passes for waiting on gossip
*/
incompleteBlockInput = "incompleteBlockInput",
/**
* Post-gloas: trigger BlockInputSync for payload envelopes whose envelope and/or sampled columns are partially
* received via gossip but are not complete by time the cut-off window passes for waiting on gossip
*/
incompletePayloadEnvelope = "incompletePayloadEnvelope",
}
export type HeadEventData = routes.events.EventData[routes.events.EventType.head];
export type ReorgEventData = routes.events.EventData[routes.events.EventType.chainReorg];
// API events are emitted through the same ChainEventEmitter for re-use internally
type ApiEvents = {[K in routes.events.EventType]: (data: routes.events.EventData[K]) => void};
export type ChainEventData = {
[ChainEvent.blockUnknownParent]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
[ChainEvent.unknownBlockRoot]: {rootHex: RootHex; peer?: PeerIdStr; source: BlockInputSource};
[ChainEvent.incompleteBlockInput]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
[ChainEvent.incompletePayloadEnvelope]: {
payloadInput: PayloadEnvelopeInput;
peer: PeerIdStr;
source: BlockInputSource;
};
[ChainEvent.unknownEnvelopeBlockRoot]: {rootHex: RootHex; peer?: PeerIdStr; source: BlockInputSource};
};
export type IChainEvents = ApiEvents & {
[ChainEvent.checkpoint]: (checkpoint: phase0.Checkpoint, state: IBeaconStateView) => void;
[ChainEvent.forkChoiceJustified]: (checkpoint: CheckpointWithHex) => void;
[ChainEvent.forkChoiceFinalized]: (checkpoint: CheckpointWithHex) => void;
[ChainEvent.updateTargetCustodyGroupCount]: (targetGroupCount: number) => void;
[ChainEvent.publishDataColumns]: (sidecars: DataColumnSidecar[]) => void;
[ChainEvent.publishBlobSidecars]: (sidecars: deneb.BlobSidecar[]) => void;
[ChainEvent.updateStatus]: () => void;
// Sync events that are chain->chain. Initiated from network requests but do not cross the network
// barrier so are considered ChainEvent(s).
[ChainEvent.blockUnknownParent]: (data: ChainEventData[ChainEvent.blockUnknownParent]) => void;
[ChainEvent.unknownBlockRoot]: (data: ChainEventData[ChainEvent.unknownBlockRoot]) => void;
[ChainEvent.incompleteBlockInput]: (data: ChainEventData[ChainEvent.incompleteBlockInput]) => void;
[ChainEvent.incompletePayloadEnvelope]: (data: ChainEventData[ChainEvent.incompletePayloadEnvelope]) => void;
[ChainEvent.unknownEnvelopeBlockRoot]: (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRoot]) => void;
};
/**
* Emits important chain events that occur during normal chain operation.
*
* Chain events can be broken into several categories:
* - Clock: the chain's clock is updated
* - Fork Choice: the chain's fork choice is updated
* - Processing: the chain processes attestations and blocks, either successfully or with an error
* - Checkpointing: the chain processes epoch boundaries
*/
export class ChainEventEmitter extends (EventEmitter as {new (): StrictEventEmitter<EventEmitter, IChainEvents>}) {}