import {PeerId} from "@libp2p/interface-peer-id"; import {IBeaconConfig, IForkConfig, IForkDigestContext} from "@lodestar/config"; import {ForkName} from "@lodestar/params"; import {Slot} from "@lodestar/types"; import {LodestarError} from "@lodestar/utils"; import {RateLimiterQuota} from "./rate_limiter/rateLimiterGRCA.js"; export enum EncodedPayloadType { ssz, bytes, } export interface EncodedPayloadSsz { type: EncodedPayloadType.ssz; data: T; } export interface EncodedPayloadBytes { type: EncodedPayloadType.bytes; bytes: Uint8Array; contextBytes: ContextBytes; } export type EncodedPayload = EncodedPayloadSsz | EncodedPayloadBytes; export type ReqRespHandler = (req: Req, peerId: PeerId) => AsyncIterable>; export interface Protocol { readonly protocolPrefix: string; /** Protocol name identifier `beacon_blocks_by_range` or `status` */ readonly method: string; /** Version counter: `1`, `2` etc */ readonly version: number; readonly encoding: Encoding; } export interface InboundRateLimitQuota { // Will be tracked for the protocol per peer byPeer?: RateLimiterQuota; // Will be tracked regardless of the peer total?: RateLimiterQuota; // Some requests may be counted multiple e.g. getBlocksByRange // for such implement this method else `1` will be used default getRequestCount?: (req: Req) => number; } // `protocolPrefix` is added runtime so not part of definition export interface ProtocolDefinition extends Omit { handler: ReqRespHandler; // eslint-disable-next-line @typescript-eslint/no-explicit-any requestType: (fork: ForkName) => TypeSerializer | null; // eslint-disable-next-line @typescript-eslint/no-explicit-any responseType: (fork: ForkName) => TypeSerializer; ignoreResponse?: boolean; renderRequestBody?: (request: Req) => string; contextBytes: ContextBytesFactory; inboundRateLimits?: InboundRateLimitQuota; } export type ProtocolDefinitionGenerator = ( // "inboundRateLimiter" is available only on handler context not on generator modules: {config: IBeaconConfig}, handler: ReqRespHandler ) => ProtocolDefinition; export type HandlerTypeFromMessage = T extends ProtocolDefinitionGenerator ? ReqRespHandler : never; export const protocolPrefix = "/eth2/beacon_chain/req"; /** * Available request/response encoding strategies: * https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md#encoding-strategies */ export enum Encoding { SSZ_SNAPPY = "ssz_snappy", } export const CONTEXT_BYTES_FORK_DIGEST_LENGTH = 4; export type ContextBytesFactory = | {type: ContextBytesType.Empty} | { type: ContextBytesType.ForkDigest; forkDigestContext: IForkDigestContext & Pick; forkFromResponse: (response: Response) => ForkName; }; export type ContextBytes = {type: ContextBytesType.Empty} | {type: ContextBytesType.ForkDigest; forkSlot: Slot}; export enum ContextBytesType { /** 0 bytes chunk, can be ignored */ Empty, /** A fixed-width 4 byte , set to the ForkDigest matching the chunk: compute_fork_digest(fork_version, genesis_validators_root) */ ForkDigest, } export enum LightClientServerErrorCode { RESOURCE_UNAVAILABLE = "RESOURCE_UNAVAILABLE", } export type LightClientServerErrorType = {code: LightClientServerErrorCode.RESOURCE_UNAVAILABLE}; export class LightClientServerError extends LodestarError {} /** * Lightweight interface of ssz Type */ export interface TypeSerializer { serialize(data: T): Uint8Array; deserialize(bytes: Uint8Array): T; maxSize: number; minSize: number; equals(a: T, b: T): boolean; } export interface ReqRespRateLimiterOpts { rateLimitMultiplier?: number; onRateLimit?: (peer: PeerId, method: string) => void; }