import { ChainForkConfig } from "@lodestar/config";
import { Logger } from "@lodestar/utils";
import { IBeaconChain } from "../chain/index.js";
import { Metrics } from "../metrics/index.js";
import { INetwork } from "../network/index.js";
import { PeerSyncMeta } from "../network/peers/peersData.js";
import { PeerIdStr } from "../util/peerId.js";
import { SyncOptions } from "./options.js";
/**
 * BlockInputSync is a class that handles ReqResp to find blocks and data related to a specific blockRoot.  The
 * blockRoot may have been found via object gossip, or the API.  Gossip objects that can trigger a search are block,
 * blobs, columns, attestations, etc.  In the case of blocks and data this is generally during the current slot but
 * can also be for items that are received late but are not fully verified and thus not in fork-choice (old blocks on
 * an unknown fork). It can also be triggered via an attestation (or sync committee message or any other item that
 * gets gossiped) that references a blockRoot that is not in fork-choice.  In rare (and realistically should not happen)
 * situations it can get triggered via the API when the validator attempts to publish a block, attestation, aggregate
 * and proof or a sync committee contribution that has unknown information included (parentRoot for instance).
 *
 * The goal of the class is to make sure that all information that is necessary for import into fork-choice is pulled
 * from peers so that the block and data can be processed, and thus the object that triggered the search can be
 * referenced and validated.
 *
 * The most common case for this search is a set of block/data that comes across gossip for the current slot, during
 * normal chain operation, but not everything was received before the gossip cutoff window happens so it is necessary
 * to pull remaining data via req/resp so that fork-choice can be updated prior to making an attestation for the
 * current slot.
 *
 * Event sources for old UnknownBlock
 *
 * - publishBlock
 * - gossipHandlers
 * - searchUnknownBlock
 *    = produceSyncCommitteeContribution
 *    = validateGossipFnRetryUnknownRoot
 *        * submitPoolAttestationsV2
 *        * publishAggregateAndProofsV2
 *    = onPendingGossipsubMessage
 *        * NetworkEvent.pendingGossipsubMessage
 *            - onGossipsubMessage
 */
export declare class BlockInputSync {
    private readonly config;
    private readonly network;
    private readonly chain;
    private readonly logger;
    private readonly metrics;
    private readonly opts?;
    /**
     * block RootHex -> PendingBlock. To avoid finding same root at the same time
     */
    private readonly pendingBlocks;
    private readonly pendingPayloads;
    private readonly knownBadBlocks;
    private readonly maxPendingBlocks;
    private subscribedToNetworkEvents;
    private peerBalancer;
    private rateLimitBackoffTimeout;
    constructor(config: ChainForkConfig, network: INetwork, chain: IBeaconChain, logger: Logger, metrics: Metrics | null, opts?: SyncOptions | undefined);
    subscribeToNetwork(): void;
    unsubscribeFromNetwork(): void;
    close(): void;
    isSubscribedToNetwork(): boolean;
    /**
     * Process an unknownBlock event and register the block in `pendingBlocks` Map.
     */
    private onUnknownBlockRoot;
    /**
     * Process an unknownBlockInput event and register the block in `pendingBlocks` Map.
     */
    private onIncompleteBlockInput;
    private onUnknownEnvelopeBlockRoot;
    private onIncompletePayloadEnvelope;
    /**
     * Process an unknownBlockParent event and register the block in `pendingBlocks` Map.
     */
    private onUnknownParent;
    private onBlockImported;
    private onPayloadImported;
    private addByRootHex;
    private addByBlockInput;
    private addByPayloadRootHex;
    private addByPayloadInput;
    private onPeerConnected;
    private onPeerDisconnected;
    /**
     * Post-gloas, a locally complete block can still be blocked on its parent's execution payload lineage.
     * Distinguish which dependency is missing so the scheduler can enqueue the right follow-up work.
     */
    private getMissingBlockDependency;
    private advancePendingBlock;
    private toPendingPayloadInput;
    /**
     * Gather tip parent blocks with unknown parent and do a search for all of them
     */
    private triggerUnknownBlockSearch;
    private scheduleRateLimitBackoffRetry;
    private clearRateLimitBackoffTimer;
    private downloadBlock;
    private processReadyBlock;
    private reconcilePayloadEnvelope;
    private downloadPayload;
    private processPayload;
    private fetchPayloadInput;
    private fetchExecutionPayloadEnvelope;
    private fetchPayloadColumns;
    private fetchBlockInput;
    /**
     * Gets all descendant blocks of `block` recursively from `pendingBlocks`.
     * Assumes that if a parent block does not exist or is not processable, all descendant blocks are bad too.
     * Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
     * referenced more than one bad block.
     */
    private removeAndDownScoreAllDescendants;
    private removePendingPayloadAndDescendants;
    private removeAllDescendants;
    private getMaxDownloadAttempts;
}
/**
 * Class to track active byRoots requests and balance them across eligible peers.
 */
export declare class UnknownBlockPeerBalancer {
    readonly peersMeta: Map<PeerIdStr, PeerSyncMeta>;
    readonly activeRequests: Map<PeerIdStr, number>;
    readonly rateLimitedUntilByPeer: Map<PeerIdStr, number>;
    constructor();
    /** Trigger on each peer re-status */
    onPeerConnected(peerId: PeerIdStr, syncMeta: PeerSyncMeta): void;
    onPeerDisconnected(peerId: PeerIdStr): void;
    onRateLimited(peerId: PeerIdStr, rateLimitedUntilMs: number): void;
    getNextRateLimitRetryAt(pendingColumns?: Set<number>, excludedPeers?: Set<PeerIdStr>): number | null;
    /**
     * called from fetchBlockInput() where we only have block root and nothing else
     * excludedPeers are the peers that we requested already so we don't want to try again
     * pendingColumns is empty for prefulu, or the 1st time we we download a block by root
     */
    bestPeerForPendingColumns(pendingColumns: Set<number>, excludedPeers: Set<PeerIdStr>): PeerSyncMeta | null;
    /**
     * Consumers don't need to call this method directly, it is called internally by bestPeer*() methods
     * make this public for testing
     */
    onRequest(peerId: PeerIdStr): void;
    /**
     * Consumers should call this method when a request is completed for a peer.
     */
    onRequestCompleted(peerId: PeerIdStr): void;
    getTotalActiveRequests(): number;
    private filterPeers;
    private peerHasPendingColumns;
}
//# sourceMappingURL=unknownBlock.d.ts.map