import { MAX_REQUEST_LIGHT_CLIENT_UPDATES, isForkPostDeneb, isForkPostElectra } from "@lodestar/params";
import { ReqRespMethod, requestSszTypeByMethod } from "./types.js";
export const rateLimitQuotas = (fork, config) => ({
    [ReqRespMethod.Status]: {
        // Rationale: https://github.com/sigp/lighthouse/blob/bf533c8e42cc73c35730e285c21df8add0195369/beacon_node/lighthouse_network/src/rpc/mod.rs#L118-L130
        byPeer: { quota: 5, quotaTimeMs: 15_000 },
    },
    [ReqRespMethod.Goodbye]: {
        // Rationale: https://github.com/sigp/lighthouse/blob/bf533c8e42cc73c35730e285c21df8add0195369/beacon_node/lighthouse_network/src/rpc/mod.rs#L118-L130
        byPeer: { quota: 1, quotaTimeMs: 10_000 },
    },
    [ReqRespMethod.Ping]: {
        // Rationale: https://github.com/sigp/lighthouse/blob/bf533c8e42cc73c35730e285c21df8add0195369/beacon_node/lighthouse_network/src/rpc/mod.rs#L118-L130
        byPeer: { quota: 2, quotaTimeMs: 10_000 },
    },
    [ReqRespMethod.Metadata]: {
        // Rationale: https://github.com/sigp/lighthouse/blob/bf533c8e42cc73c35730e285c21df8add0195369/beacon_node/lighthouse_network/src/rpc/mod.rs#L118-L130
        byPeer: { quota: 2, quotaTimeMs: 5_000 },
    },
    // Do not matter
    [ReqRespMethod.BeaconBlocksByRange]: {
        // Rationale: https://github.com/sigp/lighthouse/blob/bf533c8e42cc73c35730e285c21df8add0195369/beacon_node/lighthouse_network/src/rpc/mod.rs#L118-L130
        byPeer: {
            quota: isForkPostDeneb(fork) ? config.MAX_REQUEST_BLOCKS_DENEB : config.MAX_REQUEST_BLOCKS,
            quotaTimeMs: 10_000,
        },
        getRequestCount: getRequestCountFn(fork, config, ReqRespMethod.BeaconBlocksByRange, (req) => req.count),
    },
    [ReqRespMethod.BeaconBlocksByRoot]: {
        // Rationale: https://github.com/sigp/lighthouse/blob/bf533c8e42cc73c35730e285c21df8add0195369/beacon_node/lighthouse_network/src/rpc/mod.rs#L118-L130
        byPeer: {
            quota: isForkPostDeneb(fork) ? config.MAX_REQUEST_BLOCKS_DENEB : config.MAX_REQUEST_BLOCKS,
            quotaTimeMs: 10_000,
        },
        getRequestCount: getRequestCountFn(fork, config, ReqRespMethod.BeaconBlocksByRoot, (req) => req.length),
    },
    [ReqRespMethod.BlobSidecarsByRange]: {
        // Rationale: MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK
        byPeer: {
            quota: isForkPostElectra(fork) ? config.MAX_REQUEST_BLOB_SIDECARS_ELECTRA : config.MAX_REQUEST_BLOB_SIDECARS,
            quotaTimeMs: 10_000,
        },
        getRequestCount: getRequestCountFn(fork, config, ReqRespMethod.BlobSidecarsByRange, (req) => req.count),
    },
    [ReqRespMethod.BlobSidecarsByRoot]: {
        // Rationale: quota of BeaconBlocksByRoot * MAX_BLOBS_PER_BLOCK
        byPeer: {
            quota: isForkPostElectra(fork) ? config.MAX_REQUEST_BLOB_SIDECARS_ELECTRA : config.MAX_REQUEST_BLOB_SIDECARS,
            quotaTimeMs: 10_000,
        },
        getRequestCount: getRequestCountFn(fork, config, ReqRespMethod.BlobSidecarsByRoot, (req) => req.length),
    },
    [ReqRespMethod.DataColumnSidecarsByRange]: {
        // Rationale: MAX_REQUEST_BLOCKS_DENEB * NUMBER_OF_COLUMNS
        byPeer: { quota: config.MAX_REQUEST_DATA_COLUMN_SIDECARS, quotaTimeMs: 10_000 },
        getRequestCount: getRequestCountFn(fork, config, ReqRespMethod.DataColumnSidecarsByRange, (req) => req.count * req.columns.length),
    },
    [ReqRespMethod.DataColumnSidecarsByRoot]: {
        // Rationale: quota of BeaconBlocksByRoot * NUMBER_OF_COLUMNS
        byPeer: { quota: config.MAX_REQUEST_DATA_COLUMN_SIDECARS, quotaTimeMs: 10_000 },
        getRequestCount: getRequestCountFn(fork, config, ReqRespMethod.DataColumnSidecarsByRoot, (req) => req.reduce((total, item) => total + item.columns.length, 0)),
    },
    [ReqRespMethod.LightClientBootstrap]: {
        // As similar in the nature of `Status` protocol so we use the same rate limits.
        byPeer: { quota: 5, quotaTimeMs: 15_000 },
    },
    [ReqRespMethod.LightClientUpdatesByRange]: {
        // Same rationale as for BeaconBlocksByRange
        byPeer: { quota: MAX_REQUEST_LIGHT_CLIENT_UPDATES, quotaTimeMs: 10_000 },
        getRequestCount: getRequestCountFn(fork, config, ReqRespMethod.LightClientUpdatesByRange, (req) => req.count),
    },
    [ReqRespMethod.LightClientFinalityUpdate]: {
        // Finality updates should not be requested more than once per epoch.
        // Allow 2 per slot and a very safe bound until there's more testing of real usage.
        byPeer: { quota: 2, quotaTimeMs: 12_000 },
    },
    [ReqRespMethod.LightClientOptimisticUpdate]: {
        // Optimistic updates should not be requested more than once per slot.
        // Allow 2 per slot and a very safe bound until there's more testing of real usage.
        byPeer: { quota: 2, quotaTimeMs: 12_000 },
    },
});
// Helper to produce a getRequestCount function
function getRequestCountFn(fork, config, method, fn) {
    const type = requestSszTypeByMethod(fork, config)[method];
    return (reqData) => {
        try {
            return (type && fn(type.deserialize(reqData))) ?? 1;
        }
        catch (_e) {
            return 1;
        }
    };
}
//# sourceMappingURL=rateLimit.js.map