import { ChainForkConfig } from "@lodestar/config";
import { Epoch, Root, Slot } from "@lodestar/types";
import { Logger } from "@lodestar/utils";
import { IBlockInput } from "../../chain/blocks/blockInput/types.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[], syncType: RangeSyncType) => Promise<void>;
    /** Must download blocks, and validate their range */
    downloadByRange: (peer: PeerSyncMeta, batch: Batch, syncType: RangeSyncType) => Promise<WarnResult<IBlockInput[], 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;
    private readonly peerset;
    private readonly logger;
    private readonly config;
    private readonly clock;
    private readonly metrics;
    private readonly custodyConfig;
    constructor(initialBatchEpoch: Epoch, initialTarget: ChainTarget, syncType: RangeSyncType, fns: SyncChainFns, modules: SyncChainModules);
    /**
     * 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;
    /**
     * 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