"use strict";
/** ROUTES */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.routes = void 0;
const Comms = __importStar(require("../Comms"));
const CycleChain = __importStar(require("../CycleChain"));
const CycleCreator = __importStar(require("../CycleCreator"));
const NodeList = __importStar(require("../NodeList"));
const Self = __importStar(require("../Self"));
const utils = __importStar(require("../../utils"));
const lib_types_1 = require("@shardeum-foundation/lib-types");
const _1 = require(".");
const Context_1 = require("../Context");
const checkIP_1 = require("../../utils/functions/checkIP");
const isPortReachable_1 = require("../../utils/isPortReachable");
const nestedCounters_1 = require("../../utils/nestedCounters");
const profiler_1 = require("../../utils/profiler");
const GossipValidation_1 = require("../../utils/GossipValidation");
const acceptance = __importStar(require("./v2/acceptance"));
const v2_1 = require("./v2");
const syncFinished_1 = require("./v2/syncFinished");
const unjoin_1 = require("./v2/unjoin");
const Self_1 = require("../Self");
const logger_1 = require("../../logger");
const syncStarted_1 = require("./v2/syncStarted");
const standbyRefresh_1 = require("./v2/standbyRefresh");
const lib_types_2 = require("@shardeum-foundation/lib-types");
const utils_1 = require("../../utils");
const Helpers_1 = require("../../types/ajv/Helpers");
const AJVSchemaEnum_1 = require("../../types/enum/AJVSchemaEnum");
const promises_1 = require("../../utils/functions/promises");
const cycleMarkerRoute = {
    method: 'GET',
    name: 'cyclemarker',
    handler: (_req, res) => {
        const marker = CycleChain.newest ? CycleChain.newest.previous : '0'.repeat(64);
        res.json({ marker });
    },
};
/*
Currently not used

const cycleNumberRoute: P2P.P2PTypes.Route<Handler> = {
  method: 'GET',
  name: 'cyclenumber',
  handler: (_req, res) => {
    const number = CycleChain.newest ? CycleChain.newest.counter : 0
    res.json(number)
  },
}
*/
const joinRoute = {
    method: 'POST',
    name: 'join',
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    handler: async (req, res) => {
        try {
            const requestBody = req.body;
            // Validate the joinReq against the ajv schema]
            const errors = (0, Helpers_1.verifyPayload)(AJVSchemaEnum_1.AJVSchemaEnum.JoinReq, requestBody);
            if (errors) {
                res.status(400).json({
                    success: false,
                    fatal: true,
                    reason: 'Validation error: ' + errors.join('; '),
                });
                return;
            }
            const appJoinDataErrors = Context_1.shardus.app.verifyAppJoinData(requestBody.appJoinData);
            if (appJoinDataErrors) {
                res.status(400).json({
                    success: false,
                    fatal: true,
                    reason: 'Validation error: ' + appJoinDataErrors.join('; '),
                });
                return;
            }
            const joinRequest = lib_types_2.Utils.safeJsonParse(lib_types_2.Utils.safeStringify(requestBody));
            if (!Self_1.isActive && !Self.isRestartNetwork) {
                /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-reject: not-active`);
                /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
                    console.error(`join-reject: not-active`);
                // if we are not active yet, we cannot accept join requests
                res.status(400).json({
                    success: false,
                    fatal: false,
                    reason: `this node is not active yet`,
                });
                return;
            }
            if (CycleCreator.currentQuarter < 1) {
                /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-reject: CycleCreator.currentQuarter < 1 ${CycleCreator.currentQuarter}`);
                /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
                    console.error(`join-reject: CycleCreator.currentQuarter < 1 ${CycleCreator.currentQuarter} ${joinRequest.nodeInfo.publicKey}`);
                // if currentQuarter <= 0 then we are not ready
                res.status(400).json({
                    success: false,
                    fatal: false,
                    reason: `Can't join before quarter 1`,
                });
                return;
            }
            if ((NodeList.activeByIdOrder.length === 1 || Self.isRestartNetwork) &&
                Self.isFirst &&
                (0, checkIP_1.isBogonIP)(joinRequest.nodeInfo.externalIp) &&
                Context_1.config.p2p.forceBogonFilteringOn === false) {
                (0, _1.setAllowBogon)(true);
            }
            nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-allow-bogon-firstnode:${(0, _1.getAllowBogon)()}`);
            // Ensure IP and Port properties exist
            const { externalIp, externalPort, internalIp, internalPort } = joinRequest.nodeInfo || {};
            const externalPortReachable = await (0, isPortReachable_1.isPortReachable)({ host: externalIp, port: externalPort });
            const internalPortReachable = await (0, isPortReachable_1.isPortReachable)({ host: internalIp, port: internalPort });
            if (!externalPortReachable || !internalPortReachable) {
                /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-reject: !externalPortReachable || !internalPortReachable`);
                /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
                    console.error(`join-reject: !externalPortReachable || !internalPortReachable ${joinRequest.nodeInfo.publicKey} ${lib_types_2.Utils.safeStringify({ host: externalIp, port: externalPort })}`);
                res.json({
                    success: false,
                    fatal: true,
                    //the following message string is used by submitJoinV2.  if you change the string please update submitJoinV2
                    reason: `IP or Port is not reachable. ext:${externalIp}:${externalPort} int:${internalIp}:${internalPort}}`,
                });
                return;
            }
            // if the port of the join request was reachable, this join request is free to be
            // gossiped to all nodes according to Join Protocol v2.
            if (Context_1.config.p2p.useJoinProtocolV2) {
                // ensure this join request doesn't already exist in standby nodes
                if ((0, v2_1.getStandbyNodesInfoMap)().has(joinRequest.nodeInfo.publicKey)) {
                    /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-reject: already standby`);
                    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
                        console.error(`join-reject: already standby ${joinRequest.nodeInfo.publicKey}:`);
                    res.status(400).json({
                        success: false,
                        fatal: false,
                        reason: `Join request for pubkey ${joinRequest.nodeInfo.publicKey} already exists as a standby node`,
                    });
                    return;
                }
                // then validate the join request. if it's invalid for any reason, return
                // that reason.
                const validationError = (0, _1.validateJoinRequest)(joinRequest);
                if (validationError) {
                    /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-reject: validateJoinRequest ${validationError.reason}`);
                    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
                        console.error(`join-reject: validateJoinRequest ${validationError.reason} ${joinRequest.nodeInfo.publicKey}:`);
                    res.status(400).json(validationError);
                    return;
                }
                // then, verify the signature of the join request. this has to be done
                // before selectionNum is calculated because we will mutate the original
                // join request.
                const signatureError = (0, _1.verifyJoinRequestSignature)(joinRequest);
                if (signatureError) {
                    /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-reject: signature error`);
                    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
                        console.error(`join-reject: signature error ${joinRequest.nodeInfo.publicKey}:`);
                    res.status(400).json(signatureError);
                    return;
                }
                // then, calculate the selection number for this join request.
                const selectionNumResult = (0, _1.computeSelectionNum)(joinRequest);
                if (selectionNumResult.isErr()) {
                    /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-reject: failed selection number ${selectionNumResult.error.reason}`);
                    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
                        console.error(`failed to compute selection number for node ${joinRequest.nodeInfo.publicKey}:`, lib_types_2.Utils.safeStringify(selectionNumResult.error));
                    res.status(500).json(selectionNumResult.error);
                    return;
                }
                joinRequest.selectionNum = selectionNumResult.value;
                if (CycleCreator.currentQuarter > 1) {
                    /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `rejected-late-join-request ${CycleCreator.currentQuarter}`);
                    res.status(400).json({
                        success: false,
                        fatal: false,
                        reason: `Can't join after quarter 1`,
                    });
                    return;
                }
                // following block is DEPRECATED
                // add the join request to the global list of join requests. this will also
                // add it to the list of new join requests that will be processed as part of
                // cycle creation to create a standy node list.
                // saveJoinRequest(joinRequest)
                // then, queue this join request to be sent when sendRequests is called at the start of Q1
                (0, _1.queueJoinRequest)(joinRequest);
                /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join success`);
                // respond with the number of standby nodes for the user's information
                res.status(200).json({ success: true, numStandbyNodes: (0, v2_1.getStandbyNodesInfoMap)().size });
                return;
            }
            else {
                //  Validate of joinReq is done in addJoinRequest
                const joinRequestResponse = (0, _1.addJoinRequest)(joinRequest);
                // if the join request was valid and accepted, gossip that this join request
                // was accepted to other nodes
                if (joinRequestResponse.success) {
                    // only gossip join requests if we are still using the old join protocol
                    Comms.sendGossip('gossip-join', joinRequest, '', null, (0, _1.nodeListFromStates)([
                        lib_types_1.P2P.P2PTypes.NodeStatus.ACTIVE,
                        lib_types_1.P2P.P2PTypes.NodeStatus.READY,
                        lib_types_1.P2P.P2PTypes.NodeStatus.SYNCING,
                    ]), true);
                    nestedCounters_1.nestedCountersInstance.countEvent('p2p', 'initiate gossip-join');
                }
                res.json(joinRequestResponse);
                return;
            }
        }
        catch (error) {
            console.error('Error handling join request:', error);
            res.status(500).json({
                success: false,
                fatal: true,
                reason: 'An error occurred while processing the join request',
            });
            return;
        }
    },
};
const unjoinRoute = {
    method: 'POST',
    name: 'unjoin',
    handler: (req, res) => {
        try {
            const unjoinRequest = req.body;
            const processResult = (0, unjoin_1.processNewUnjoinRequest)(unjoinRequest);
            if (processResult.isErr()) {
                res.status(500).json({ error: processResult.error.message });
                return;
            }
            (0, unjoin_1.removeUnjoinRequest)(unjoinRequest.publicKey);
            (0, _1.queueUnjoinRequest)(unjoinRequest);
            res.status(200).json({ message: 'Unjoin request processed successfully' });
        }
        catch (error) {
            res.status(500).json({ error: error.message || 'An unknown error occurred' });
        }
    },
};
/*
Currently not used

const syncStartedRoute: P2P.P2PTypes.Route<Handler> = {
  method: 'POST',
  name: 'sync-started',
  handler: (req, res) => {
    const syncStarted = req.body
    const processResult = addSyncStarted(syncStarted)
    if (processResult.success === false) {
      return res.status(500).send(processResult.reason)
    }
    Comms.sendGossip('gossip-sync-started', syncStarted, '', null, NodeList.byIdOrder, true)
    return res.status(200).send()
  },
}
*/
const standbyRefreshRoute = {
    method: 'POST',
    name: 'standby-refresh',
    handler: async (req, res) => {
        // check if the config.debug.ignoreStandbyRefreshChance is a probability
        if (Context_1.config.debug.ignoreStandbyRefreshChance < 0 || Context_1.config.debug.ignoreStandbyRefreshChance > 1) {
            (0, _1.warn)('invalid config.debug.ignoreStandbyRefreshChance value: ' + Context_1.config.debug.ignoreStandbyRefreshChance);
            res.status(500).json({ error: 'invalid config.debug.ignoreStandbyRefreshChance value' });
            // check if we should ignore this request for testing purposes
        }
        else if (Context_1.config.debug.ignoreStandbyRefreshChance > 0) {
            // if we should ignore this request, sleep for 1.1 seconds since timeout is 1 second
            if ((0, utils_1.testFailChance)(Context_1.config.debug.ignoreStandbyRefreshChance, 'standby-refresh', '', '', false)) {
                await utils.sleep(3000);
                res.status(500).json({ error: 'simulated timeout' });
            }
        }
        const standbyRefreshPubKey = req.body.publicKey;
        let err = utils.validateTypes(req, { body: 'o' });
        if (err) {
            (0, _1.warn)('/standby-refresh bad req ' + err);
            res.status(400).json();
        }
        err = typeof standbyRefreshPubKey === 'string' ? '' : 'standbyRefreshPubKey is not a string';
        if (err) {
            (0, _1.warn)('/standby-refresh bad standby refresh public key ' + err);
            res.status(400).json();
        }
        (0, _1.queueStandbyRefreshRequest)(standbyRefreshPubKey);
        res.status(200).json();
        return;
    },
};
const joinedV2Route = {
    method: 'GET',
    name: 'joinedV2/:publicKey',
    handler: (req, res) => {
        // Respond with id if node's join request was accepted, otherwise undefined
        let err = utils.validateTypes(req, { params: 'o' });
        if (err) {
            (0, _1.warn)('joined/:publicKey bad req ' + err);
            // use res.send({ }) if returning an object
            res.json();
        }
        err = utils.validateTypes(req.params, { publicKey: 's' });
        if (err) {
            (0, _1.warn)('joined/:publicKey bad req.params ' + err);
            // use res.send({ }) if returning an object
            res.json();
        }
        const publicKey = req.params.publicKey;
        const id = NodeList.byPubKey.get(publicKey)?.id || null;
        res.json({ id, isOnStandbyList: (0, v2_1.isOnStandbyList)(publicKey) });
    },
};
const joinedRoute = {
    method: 'GET',
    name: 'joined/:publicKey',
    handler: (req, res) => {
        // Respond with id if node's join request was accepted, otherwise undefined
        let err = utils.validateTypes(req, { params: 'o' });
        if (err) {
            (0, _1.warn)('joined/:publicKey bad req ' + err);
            // use res.send({ }) if returning an object
            res.json();
        }
        err = utils.validateTypes(req.params, { publicKey: 's' });
        if (err) {
            (0, _1.warn)('joined/:publicKey bad req.params ' + err);
            // use res.send({ }) if returning an object
            res.json();
        }
        const publicKey = req.params.publicKey;
        const node = NodeList.byPubKey.get(publicKey);
        res.json({ node });
    },
};
/**
 * todo deprecate this or, finish it
 * for now deprecating the accepted path.  does not seem to have any value
 */
const acceptedRoute = {
    method: 'POST',
    name: 'accepted',
    handler: async (req, res) => {
        // Turns out the cycle check is unnecessary because the joining node will robust query for its node ID
        // The joinNetwork fn in startupV2 will handle acceptance
        acceptance.getEventEmitter().emit('accepted');
        /*
        const counter = CycleChain.getNewest().counter
        nestedCountersInstance.countEvent('joinV2', `C${counter}: acceptedRoute: start`)
    
        // check if we even need to check acceptance
        if (acceptance.getHasConfirmedAcceptance() || Self.isActive) {
          return res.status(400).send('no need to check acceptance; this node has already confirmed acceptance')
        } else if (acceptance.isAlreadyCheckingAcceptance()) {
          return res.status(400).send('node is already checking acceptance')
        }
    
        // then try to confirm acceptance if needed
        try {
          await attempt(
            async () => {
              const result = await acceptance.confirmAcceptance(req.body)
    
              if (result.isErr()) {
                // transform Err into a thrown Error if needed
                nestedCountersInstance.countEvent('joinV2', `C${counter}: acceptedRoute: confirmAcceptance error`)
                throw result.error
              } else if (!result.value) {
                // if the result is false, acceptance is not confirmed
                nestedCountersInstance.countEvent('joinV2', `C${counter}: acceptedRoute: node not in cycle`)
                throw new Error(`this node was not found in cycle ${req.body.cycleMarker}; assuming not accepted`)
              } else {
                // otherwise, at this point, the node has been confirmed to be accepted
                nestedCountersInstance.countEvent('joinV2', `C${counter}: acceptedRoute: node accepted`)
                acceptance.getEventEmitter().emit('accepted')
              }
            },
            {
              maxRetries: 5,
              delay: 2000,
            }
          )
        } catch (err) {
          nestedCountersInstance.countEvent('joinV2', `C${counter}: acceptedRoute: attempt error`)
          res.status(400).send(err)
        }
        */
    },
};
const gossipJoinRoute = (payload, sender, tracker) => {
    // only gossip join requests if we are still using the old join protocol
    if (!Context_1.config.p2p.useJoinProtocolV2) {
        profiler_1.profilerInstance.scopedProfileSectionStart('gossip-join');
        try {
            // validate payload structure and ignore gossip outside of Q1 and Q2
            // If the sender is the original sender check if in Q1 to accept the request
            if (!(0, GossipValidation_1.checkGossipPayload)(payload, {
                nodeInfo: 'o',
                selectionNum: 's',
                cycleMarker: 's',
                proofOfWork: 's',
                version: 's',
                sign: 'o',
                appJoinData: 'o',
            }, 'gossip-join', sender)) {
                return;
            }
            //  Validate of payload is done in addJoinRequest
            if ((0, _1.addJoinRequest)(payload).success)
                Comms.sendGossip('gossip-join', payload, tracker, sender, (0, _1.nodeListFromStates)([
                    lib_types_1.P2P.P2PTypes.NodeStatus.ACTIVE,
                    lib_types_1.P2P.P2PTypes.NodeStatus.READY,
                    lib_types_1.P2P.P2PTypes.NodeStatus.SYNCING,
                ]), false);
        }
        finally {
            profiler_1.profilerInstance.scopedProfileSectionEnd('gossip-join');
        }
    }
    else
        (0, _1.warn)('gossip-join received but ignored for join protocol v2');
};
/**
 * Part of Join Protocol v2. Gossips all valid join requests.
 */
const gossipValidJoinRequests = (payload, sender, tracker) => {
    if (!(0, GossipValidation_1.checkGossipPayload)(payload, {
        joinRequest: 'o',
        sign: 'o',
    }, 'gossip-ValidJoinRequest', sender)) {
        return;
    }
    const joinRequest = payload.joinRequest;
    // Validate the structure of payload.joinRequest
    // checkGossipPayload using validateTypes does not check its nested joinRequest
    const err = utils.validateTypes(joinRequest, {
        nodeInfo: 'o',
        selectionNum: 's',
        cycleMarker: 's',
        proofOfWork: 's',
        version: 's',
        sign: 'o',
        appJoinData: 'o',
    });
    if (err) {
        /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-gossip-reject: invalid payload.joinRequest`);
        (0, _1.warn)(`gossipValidJoinRequests: invalid payload.joinRequest: ${err}`);
        return;
    }
    // ensure this join request doesn't already exist in standby nodes
    if ((0, v2_1.getStandbyNodesInfoMap)().has(joinRequest.nodeInfo.publicKey)) {
        /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-gossip-reject: node already standby`);
        /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
            console.error(`join request for pubkey ${joinRequest.nodeInfo.publicKey} already exists as a standby node`);
        return;
    }
    // validate the join request first
    const validationError = (0, _1.validateJoinRequest)(joinRequest);
    if (validationError) {
        /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-gossip-reject: failed to validate join request`);
        /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
            console.error(`failed to validate join request when gossiping: ${validationError}`);
        return;
    }
    // set selectionNum to undefined so that we can verify the signature
    // it'll be added back soon anyways
    joinRequest.selectionNum = undefined;
    // then, verify the signature of the join request. this has to be done
    // before selectionNum is calculated because we will mutate the original
    // join request.
    const signatureError = (0, _1.verifyJoinRequestSignature)(joinRequest);
    if (signatureError) {
        /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-gossip-reject: signature error`);
        /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
            console.error(`join-gossip-reject: signature error ${joinRequest.nodeInfo.publicKey}:`);
        return;
    }
    // then, calculate the selection number for this join request
    const selectionNumResult = (0, _1.computeSelectionNum)(joinRequest);
    if (selectionNumResult.isErr()) {
        /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-gossip-reject: failed to compute selection number`);
        /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
            console.error(`failed to compute selection number for node ${joinRequest.nodeInfo.publicKey}:`, JSON.stringify(selectionNumResult.error));
        return;
    }
    joinRequest.selectionNum = selectionNumResult.value;
    // add the join request to the global list of join requests. this will also
    // add it to the list of new join requests that will be processed as part of
    // cycle creation to create a standy node list.
    (0, v2_1.saveJoinRequest)(joinRequest);
    /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `join-gossip: request saved and gossiped`);
    (0, promises_1.fireAndForget)(() => Comms.sendGossip('gossip-valid-join-requests', payload, tracker, sender, (0, _1.nodeListFromStates)([
        lib_types_1.P2P.P2PTypes.NodeStatus.ACTIVE,
        lib_types_1.P2P.P2PTypes.NodeStatus.READY,
        lib_types_1.P2P.P2PTypes.NodeStatus.SYNCING,
    ]), false));
};
const gossipUnjoinRequests = (payload, sender, tracker) => {
    if (!(0, GossipValidation_1.checkGossipPayload)(payload, {
        publicKey: 's',
        sign: 'o',
    }, 'gossip-unjoin', sender)) {
        return;
    }
    const processResult = (0, unjoin_1.processNewUnjoinRequest)(payload);
    if (processResult.isErr()) {
        (0, _1.warn)(`gossip-unjoin failed to process unjoin request: ${processResult.error}`);
        return;
    }
    (0, promises_1.fireAndForget)(() => Comms.sendGossip('gossip-unjoin', payload, tracker, sender, (0, _1.nodeListFromStates)([
        lib_types_1.P2P.P2PTypes.NodeStatus.ACTIVE,
        lib_types_1.P2P.P2PTypes.NodeStatus.READY,
        lib_types_1.P2P.P2PTypes.NodeStatus.SYNCING,
    ]), false));
};
const gossipSyncStartedRoute = (payload, sender, tracker) => {
    profiler_1.profilerInstance.scopedProfileSectionStart('gossip-sync-started');
    nestedCounters_1.nestedCountersInstance.countEvent('p2p', `received gossip-sync-started`);
    /* prettier-ignore */ if (logger_1.logFlags.verbose)
        console.log(`received gossip-sync-started`);
    try {
        if (!(0, GossipValidation_1.checkGossipPayload)(payload, {
            nodeId: 's',
            cycleNumber: 'n',
            sign: 'o',
        }, 'gossip-sync-started', sender)) {
            return;
        }
        //  Validate of payload is done in addSyncStarted
        const addSyncStartedResult = (0, syncStarted_1.addSyncStarted)(payload);
        nestedCounters_1.nestedCountersInstance.countEvent('p2p', `sync-started validation success: ${addSyncStartedResult.success}`);
        /* prettier-ignore */ if (logger_1.logFlags.verbose)
            console.log(`sync-started validation success: ${addSyncStartedResult.success}`);
        /* prettier-ignore */ if (!addSyncStartedResult.success)
            nestedCounters_1.nestedCountersInstance.countEvent('p2p', `sync-started failure reason: ${addSyncStartedResult.reason}`);
        /* prettier-ignore */ if (logger_1.logFlags.verbose && !addSyncStartedResult.success)
            console.log(`sync-started validation reason: ${addSyncStartedResult.reason}`);
        if (addSyncStartedResult.success)
            (0, promises_1.fireAndForget)(() => Comms.sendGossip('gossip-sync-started', payload, tracker, sender, (0, _1.nodeListFromStates)([
                lib_types_1.P2P.P2PTypes.NodeStatus.ACTIVE,
                lib_types_1.P2P.P2PTypes.NodeStatus.READY,
                lib_types_1.P2P.P2PTypes.NodeStatus.SYNCING,
            ]), false));
    }
    finally {
        profiler_1.profilerInstance.scopedProfileSectionEnd('gossip-sync-started');
    }
};
/**
 * Handler for syncing finished gossip. Gossip coming from Join Protocol v2 in `enterSyncingState()` of startupV2 in Self.ts and the function below.
 */
const gossipSyncFinishedRoute = (payload, sender, tracker) => {
    profiler_1.profilerInstance.scopedProfileSectionStart('gossip-sync-finished');
    try {
        if (!(0, GossipValidation_1.checkGossipPayload)(payload, {
            nodeId: 's',
            cycleNumber: 'n',
            sign: 'o',
        }, 'gossip-sync-finished', sender)) {
            return;
        }
        /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal && logger_1.logFlags.console)
            console.log('gossipSyncFinishedRoute: after quarter check');
        // Validate payload in addFinishedSyncing
        const addFinishedSyncingResult = (0, syncFinished_1.addFinishedSyncing)(payload);
        /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `sync-finished validation success: ${addFinishedSyncingResult.success}`);
        if (!addFinishedSyncingResult.success) {
            /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `sync-finished failure reason: ${addFinishedSyncingResult.reason}`);
        }
        if (addFinishedSyncingResult.success) {
            Comms.sendGossip('gossip-sync-finished', payload, tracker, sender, (0, _1.nodeListFromStates)([
                lib_types_1.P2P.P2PTypes.NodeStatus.ACTIVE,
                lib_types_1.P2P.P2PTypes.NodeStatus.READY,
                lib_types_1.P2P.P2PTypes.NodeStatus.SYNCING,
            ]), false);
        }
        else {
            /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal && logger_1.logFlags.console)
                console.log(`gossipSyncFinishedRoute: addFinishedSyncing failed: ${addFinishedSyncingResult.reason} fatal:${addFinishedSyncingResult.fatal} node:${payload.nodeId} cycle:${payload.cycleNumber}`);
        }
    }
    finally {
        profiler_1.profilerInstance.scopedProfileSectionEnd('gossip-sync-finished');
    }
};
const gossipStandbyRefresh = async (payload, sender, tracker) => {
    profiler_1.profilerInstance.scopedProfileSectionStart('gossip-standby-refresh');
    nestedCounters_1.nestedCountersInstance.countEvent('p2p', `received gossip-standby-refresh`);
    /* prettier-ignore */ if (logger_1.logFlags.verbose)
        console.log(`received gossip-standby-refresh`);
    try {
        if (!(0, GossipValidation_1.checkGossipPayload)(payload, {
            publicKey: 's',
            cycleNumber: 'n',
            sign: 'o',
        }, 'gossip-standby-refresh', sender)) {
            return;
        }
        const added = (0, standbyRefresh_1.addStandbyRefresh)(payload);
        /* prettier-ignore */ nestedCounters_1.nestedCountersInstance.countEvent('p2p', `standby-refresh validation success: ${added.success}`);
        /* prettier-ignore */ if (logger_1.logFlags.verbose)
            console.log(`standby-refresh validation success: ${added.success}`);
        /* prettier-ignore */ if (!added.success)
            nestedCounters_1.nestedCountersInstance.countEvent('p2p', `standby-refresh failure reason: ${added.reason}`);
        /* prettier-ignore */ if (logger_1.logFlags.verbose && !added.success)
            console.log(`standby-refresh validation reason: ${added.reason}`);
        if (added.success)
            Comms.sendGossip('gossip-standby-refresh', payload, tracker, sender, (0, _1.nodeListFromStates)([
                lib_types_1.P2P.P2PTypes.NodeStatus.ACTIVE,
                lib_types_1.P2P.P2PTypes.NodeStatus.READY,
                lib_types_1.P2P.P2PTypes.NodeStatus.SYNCING,
            ]), false);
    }
    finally {
        profiler_1.profilerInstance.scopedProfileSectionEnd('gossip-standby-refresh');
    }
};
exports.routes = {
    external: [cycleMarkerRoute, joinRoute, joinedRoute, joinedV2Route, acceptedRoute, unjoinRoute, standbyRefreshRoute],
    gossip: {
        'gossip-join': gossipJoinRoute,
        'gossip-valid-join-requests': gossipValidJoinRequests,
        'gossip-unjoin': gossipUnjoinRequests,
        'gossip-sync-started': gossipSyncStartedRoute,
        'gossip-sync-finished': gossipSyncFinishedRoute,
        'gossip-standby-refresh': gossipStandbyRefresh,
    },
};
//# sourceMappingURL=routes.js.map