UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

222 lines 8.4 kB
import { ChainForkConfig } from "@lodestar/config"; import { ForkName } from "@lodestar/params"; import { Epoch, RootHex, Slot, gloas } from "@lodestar/types"; import { LodestarError } from "@lodestar/utils"; import { IBlockInput } from "../../chain/blocks/blockInput/types.js"; import { PayloadEnvelopeInput } from "../../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.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 { DownloadByRangeRequests, ParentPayloadCommitments } from "../utils/downloadByRange.js"; /** * Current state of a batch */ export declare enum BatchStatus { /** The batch has failed either downloading or processing, but can be requested again. */ AwaitingDownload = "AwaitingDownload", /** The batch is being downloaded. */ Downloading = "Downloading", /** The batch has been completely downloaded and is ready for processing. */ AwaitingProcessing = "AwaitingProcessing", /** The batch is being processed. */ Processing = "Processing", /** * The batch was successfully processed and is waiting to be validated. * * It is not sufficient to process a batch successfully to consider it correct. This is * because batches could be erroneously empty, or incomplete. Therefore, a batch is considered * valid, only if the next sequential batch imports at least a block. */ AwaitingValidation = "AwaitingValidation" } export type Attempt = { /** The peer that made the attempt */ peers: PeerIdStr[]; /** The hash of the blocks of the attempt */ hash: RootHex; }; type TrackedRequest = { /** only happen for the 1st batch in checkpoint sync */ parentPayload: boolean; /** * we always issue by_range before parent_payload, so we don't model this as null */ byRangeColumns: Set<number>; }; export type AwaitingDownloadState = { status: BatchStatus.AwaitingDownload; blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null; }; export type DownloadSuccessState = { status: BatchStatus.AwaitingProcessing; blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null; }; export type BatchState = AwaitingDownloadState | { status: BatchStatus.Downloading; peer: PeerIdStr; request: TrackedRequest; blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null; } | DownloadSuccessState | { status: BatchStatus.Processing; blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null; attempt: Attempt; } | { status: BatchStatus.AwaitingValidation; blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null; attempt: Attempt; }; export type BatchMetadata = { startEpoch: Epoch; startSlot: Slot; count: number; status: BatchStatus; blocksReq?: string; blobsReq?: string; columnsReq?: string; envelopesReq?: string; downloadAttempts: number; processingAttempts: number; failedDownloadPeers?: string; failedProcessingPeers?: string; }; /** * Batches are downloaded at the first block of the epoch. * * For example: * * Epoch boundary | | * ... | 30 | 31 | 32 | 33 | 34 | ... | 61 | 62 | 63 | 64 | 65 | * Batch 1 | Batch 2 | Batch 3 * * Jul2022: Offset changed from 1 to 0, see rationale in {@link BATCH_SLOT_OFFSET} */ export declare class Batch { readonly forkName: ForkName; readonly startEpoch: Epoch; readonly startSlot: Slot; readonly count: number; /** Block, blob and column requests that are used to determine the best peer and are used in downloadByRange */ requests: DownloadByRangeRequests; /** State of the batch. */ state: BatchState; /** Peers that provided good data, with column coverage for by_range requests */ private readonly successfulDownloads; /** The `Attempts` that have been made and failed to send us this batch. */ readonly failedProcessingAttempts: Attempt[]; /** The `Attempts` that have been made and failed because of execution malfunction. */ readonly executionErrorAttempts: Attempt[]; /** The number of download retries this batch has undergone due to a failed request. */ private readonly failedDownloadAttempts; private readonly config; private readonly clock; private readonly custodyConfig; private readonly isFirstBatchInChain; private readonly latestBid; constructor(startEpoch: Epoch, config: ChainForkConfig, clock: IClock, custodyConfig: CustodyConfig, isFirstBatchInChain: boolean, latestBid: gloas.ExecutionPayloadBid | undefined, targetSlot: Slot); private shouldDownloadParentEnvelope; getParentPayloadCommitments(parentBlockRoot: Uint8Array): ParentPayloadCommitments; /** * Builds ByRange requests for block, blobs and columns */ private getRequests; /** * Post-fulu we should only get columns that peer has advertised */ getRequestsForPeer(peer: PeerSyncMeta): DownloadByRangeRequests; /** * Gives a list of peers from which this batch has had a failed download or processing attempt. */ getFailedPeers(): PeerIdStr[]; /** * True only if the peer has already returned a successful response for the current request. * A by_range success may update `this.requests` to parent_payload, and the same peer is then * still eligible for the newly discovered parent payload data. * For by_range, a peer that previously succeeded with a superset of requested columns is skipped. */ hasPeerSucceededCurrentRequest(peer: PeerSyncMeta): boolean; private getSuccessfulPeers; getMetadata(): BatchMetadata; getBlocks(): IBlockInput[]; getPayloadEnvelopes(): Map<Slot, PayloadEnvelopeInput> | null; /** * AwaitingDownload -> Downloading */ startDownloading(peer: PeerSyncMeta): void; /** * Downloading -> AwaitingProcessing */ downloadingSuccess(peer: PeerIdStr, blocks: IBlockInput[], payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null): DownloadSuccessState; /** * Downloading -> AwaitingDownload */ downloadingError(peer: PeerIdStr): void; /** * Downloading -> AwaitingDownload (without counting as a failed attempt). * Used when the peer rate-limited us — the request was never actually served. */ downloadingRateLimited(): void; /** * AwaitingProcessing -> Processing */ startProcessing(): { blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null; peers: PeerIdStr[]; }; /** * Processing -> AwaitingValidation */ processingSuccess(): void; /** * Processing -> AwaitingDownload */ processingError(err: Error): void; /** * AwaitingValidation -> AwaitingDownload */ validationError(err: Error): void; /** * AwaitingValidation -> Done */ validationSuccess(): Attempt; private onExecutionEngineError; private onProcessingError; /** Helper to construct typed BatchError. Stack traces are correct as the error is thrown above */ private errorType; private wrongStatusErrorType; } export declare enum BatchErrorCode { WRONG_STATUS = "BATCH_ERROR_WRONG_STATUS", INVALID_COUNT = "BATCH_ERROR_INVALID_COUNT", MAX_DOWNLOAD_ATTEMPTS = "BATCH_ERROR_MAX_DOWNLOAD_ATTEMPTS", MAX_PROCESSING_ATTEMPTS = "BATCH_ERROR_MAX_PROCESSING_ATTEMPTS", MAX_EXECUTION_ENGINE_ERROR_ATTEMPTS = "MAX_EXECUTION_ENGINE_ERROR_ATTEMPTS" } type BatchErrorType = { code: BatchErrorCode.WRONG_STATUS; expectedStatus: BatchStatus; } | { code: BatchErrorCode.INVALID_COUNT; count: number; expected: number; } | { code: BatchErrorCode.MAX_DOWNLOAD_ATTEMPTS; } | { code: BatchErrorCode.MAX_PROCESSING_ATTEMPTS; } | { code: BatchErrorCode.MAX_EXECUTION_ENGINE_ERROR_ATTEMPTS; }; type BatchErrorMetadata = { startEpoch: number; status: BatchStatus; }; export declare class BatchError extends LodestarError<BatchErrorType & BatchErrorMetadata> { } export {}; //# sourceMappingURL=batch.d.ts.map