UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

193 lines • 7.88 kB
import { ChainForkConfig } from "@lodestar/config"; import { Epoch, Root, Slot, gloas } from "@lodestar/types"; import { Logger } from "@lodestar/utils"; import { IBlockInput } from "../../chain/blocks/blockInput/types.js"; import { PayloadEnvelopeInput } from "../../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js"; import { Metrics } from "../../metrics/metrics.js"; import { PeerAction } from "../../network/index.js"; import { PeerSyncMeta } from "../../network/peers/peersData.js"; import { IClock } from "../../util/clock.js"; import { CustodyConfig } from "../../util/dataColumns.js"; import { PeerIdStr } from "../../util/peerId.js"; import { WarnResult } from "../../util/wrapError.js"; import { DownloadByRangeError } from "../utils/downloadByRange.js"; import { RangeSyncType } from "../utils/remoteSyncType.js"; import { Batch, BatchErrorCode, BatchMetadata } from "./batch.js"; export type SyncChainModules = { config: ChainForkConfig; clock: IClock; custodyConfig: CustodyConfig; logger: Logger; metrics: Metrics | null; }; export type SyncChainFns = { /** * Must return if ALL blocks are processed successfully * If SOME blocks are processed must throw BlockProcessorError() */ processChainSegment: (blocks: IBlockInput[], payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null, syncType: RangeSyncType) => Promise<void>; /** Must download blocks, and validate their range */ downloadByRange: (peer: PeerSyncMeta, batch: Batch, syncType: RangeSyncType) => Promise<WarnResult<{ blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null; }, DownloadByRangeError>>; /** Report peer for negative actions. Decouples from the full network instance */ reportPeer: (peer: PeerIdStr, action: PeerAction, actionName: string) => void; /** Gets current peer custodyColumns and earliestAvailableSlot */ getConnectedPeerSyncMeta: (peerId: string) => PeerSyncMeta; /** Hook called when Chain state completes */ onEnd: (err: Error | null, target: ChainTarget | null) => void; /** Deletes an array of BlockInputs from the BlockInputCache */ pruneBlockInputs: (blockInputs: IBlockInput[]) => void; }; /** * Sync this up to this target. Uses slot instead of epoch to re-use logic for finalized sync * and head sync. The root is used to uniquely identify this chain on different forks */ export type ChainTarget = { slot: Slot; root: Root; }; export declare class SyncChainStartError extends Error { } export type SyncChainDebugState = { targetRoot: string | null; targetSlot: number | null; syncType: RangeSyncType; status: SyncChainStatus; startEpoch: number; peers: number; batches: BatchMetadata[]; }; export declare enum SyncChainStatus { Stopped = "Stopped", Syncing = "Syncing", Done = "Done", Error = "Error" } /** * Dynamic target sync chain. Peers with multiple targets but with the same syncType are added * through the `addPeer()` hook. * * A chain of blocks that need to be downloaded. Peers who claim to contain the target head * root are grouped into the peer pool and queried for batches when downloading the chain. */ export declare class SyncChain { /** Short string id to identify this SyncChain in logs */ readonly logId: string; readonly syncType: RangeSyncType; /** * Should sync up until this slot, then stop. * Finalized SyncChains have a dynamic target, so if this chain has no peers the target can become null */ target: ChainTarget; /** Number of validated epochs. For the SyncRange to prevent switching chains too fast */ validatedEpochs: number; readonly firstBatchEpoch: Epoch; /** * The start of the chain segment. Any epoch previous to this one has been validated. * Note: lastEpochWithProcessBlocks` signals the epoch at which 1 or more blocks have been processed * successfully. So that epoch itself may or may not be valid. */ private lastEpochWithProcessBlocks; private status; private readonly processChainSegment; private readonly downloadByRange; private readonly reportPeer; private readonly getConnectedPeerSyncMeta; private readonly pruneBlockInputs; /** AsyncIterable that guarantees processChainSegment is run only at once at anytime */ private readonly batchProcessor; /** Sorted map of batches undergoing some kind of processing. */ private readonly batches; /** * `true` until the first `Batch` is constructed via `includeNextBatch` */ private isFirstBatch; private readonly peerset; /** * Tracks peers that have rate-limited us, mapped to the timestamp (ms) until which we should avoid them. * This is a sync-layer optimization to avoid assigning batches to backed-off peers. * The reqresp SelfRateLimiter independently enforces backoff at the protocol level as a safety net. */ private readonly rateLimitedPeers; private rateLimitBackoffTimeout; private readonly logger; private readonly config; private readonly clock; private readonly metrics; private readonly custodyConfig; private readonly latestBid; constructor(initialBatchEpoch: Epoch, initialTarget: ChainTarget, syncType: RangeSyncType, fns: SyncChainFns, modules: SyncChainModules, latestBid: gloas.ExecutionPayloadBid | undefined); /** * Start syncing a new chain or an old one with an existing peer list * In the same call, advance the chain if localFinalizedEpoch > */ startSyncing(localFinalizedEpoch: Epoch): void; /** * Temporarily stop the chain. Will prevent batches from being processed */ stopSyncing(): void; /** * Permanently remove this chain. Throws the main AsyncIterable */ remove(): void; /** * Add peer to the chain and request batches if active */ addPeer(peer: PeerIdStr, target: ChainTarget): void; /** * Returns true if the peer existed and has been removed * NOTE: The RangeSync will take care of deleting the SyncChain if peers = 0 */ removePeer(peerId: PeerIdStr): boolean; /** * Helper to print internal state for debugging when chain gets stuck */ getBatchesState(): BatchMetadata[]; get lastValidatedSlot(): Slot; get isSyncing(): boolean; get isRemovable(): boolean; get peers(): number; getPeers(): PeerIdStr[]; /** Full debug state for lodestar API */ getDebugState(): SyncChainDebugState; private computeTarget; private sync; /** * Request to process batches if possible */ private triggerBatchProcessor; /** * Request to download batches if possible * Backlogs requests into a single pending request */ private triggerBatchDownloader; private scheduleRateLimitBackoffRetry; private clearRateLimitBackoffTimer; /** * Attempts to request the next required batches from the peer pool if the chain is syncing. * It will exhaust the peer pool and left over batches until the batch buffer is reached. */ private requestBatches; /** * Creates the next required batch from the chain. If there are no more batches required, returns `null`. */ private includeNextBatch; private sendBatch; private processBatch; /** * Drops any batches previous to `newLatestValidatedEpoch` and updates the chain boundaries */ private advanceChain; private scrapeMetrics; } /** * Enforces that a report peer action is defined for all BatchErrorCode exhaustively. * If peer should not be downscored, returns null. */ export declare function shouldReportPeerOnBatchError(code: BatchErrorCode): { action: PeerAction.LowToleranceError; reason: string; } | null; //# sourceMappingURL=chain.d.ts.map