"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.init = init;
exports.reset = reset;
exports.getTxs = getTxs;
exports.dropInvalidTxs = dropInvalidTxs;
exports.updateRecord = updateRecord;
exports.parseRecord = parseRecord;
exports.queueRequest = queueRequest;
exports.sendRequests = sendRequests;
exports.validateRecordTypes = validateRecordTypes;
const utils_1 = require("../../utils");
const Archivers_1 = require("../Archivers");
const functions_1 = require("./functions");
const logging_1 = require("./logging");
const routes_1 = require("./routes");
const state_1 = require("./state");
const util_1 = require("util");
const logger_1 = require("../../logger");
const lib_types_1 = require("@shardeum-foundation/lib-types");
/** CycleCreator Functions */
/* These functions must be defined by all modules that implement a
     network action like going active, lost node detection, etc.
     These functions are called by CycleCreator
*/
/**
 * Gets called once when the CycleCreator system is initialized
 */
function init() {
    (0, logging_1.initLogging)();
    (0, logging_1.info)('init() called');
    // Init state
    reset();
    // Register routes
    (0, routes_1.registerRoutes)();
}
/**
 * This gets called before start of Q1
 */
function reset() {
    (0, logging_1.info)('reset() called');
}
/**
 * This gets called at the start of Q3.
 * @returns CycleTxs specific to this cycle module
 */
function getTxs() {
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)('getTxs() called');
    const lostArchivers = [];
    const refutedArchivers = [];
    // loop through lostArchiversMap
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)('  looping through lostArchiversMap');
    for (const entry of state_1.lostArchiversMap.values()) {
        /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
            (0, logging_1.info)(`    record: ${(0, util_1.inspect)(entry)}`);
        // Don't include entries you haven't investigated yet
        if (entry.isInvestigator && !entry.gossippedDownMsg)
            continue;
        // if status == 'down', Put entry's ArchiverDownMsg into lostArchivers array
        if (entry.status === 'down' && entry.archiverDownMsg) {
            (0, utils_1.insertSorted)(lostArchivers, entry.archiverDownMsg);
        }
        // if status == 'up', Put entry's ArchiverUpMsg into refutedArchivers array
        if (entry.status === 'up' && entry.archiverUpMsg) {
            (0, utils_1.insertSorted)(refutedArchivers, entry.archiverUpMsg);
        }
    }
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)('===Lost Archivers Txs===');
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)(`lostArchivers: ${(0, util_1.inspect)(lostArchivers)}`);
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)(`refutedArchivers: ${(0, util_1.inspect)(refutedArchivers)}`);
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)('===Lost Archivers Txs===');
    return {
        lostArchivers,
        refutedArchivers,
    };
}
/**
 * This gets called during Q3 after getTxs.
 * @param txs CycleTxs specific to this cycle module
 * @returns An object containing only valid txs for this cycle module
 */
function dropInvalidTxs(txs) {
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)('dropInvalidTxs() called');
    // filter lostArchivers array of any invalid ArchiverDownMsgs
    const lostArchivers = txs.lostArchivers.filter((tx) => (0, functions_1.errorForArchiverDownMsg)(tx) === null);
    // filter refutedArchivers array of any invalid ArchiverUpMsgs
    const refutedArchivers = txs.refutedArchivers.filter((tx) => (0, functions_1.errorForArchiverUpMsg)(tx) === null);
    return {
        lostArchivers,
        refutedArchivers,
    };
}
/**
 * This gets called during Q3 after dropInvalidTxs.
 * Given the txs and prev cycle record mutate the referenced record.
 * @param txs CycleTxs specific to this cycle module
 * @param record A reference to the currently being created Cycle Record
 * @param prev A reference to the previously created Cycle Record
 */
function updateRecord(txs, record, prev) {
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)('updateRecord function called');
    const lostArchivers = [];
    const refutedArchivers = [];
    const removedArchivers = [];
    // add all txs.lostArchivers publicKeys to record.lostArchivers
    for (const tx of txs.lostArchivers) {
        const target = tx.investigateMsg?.target;
        if (target) {
            (0, utils_1.insertSorted)(lostArchivers, target);
        }
        else {
            /* prettier-ignore */ if (logger_1.logFlags.debug)
                console.log(`publicKey undefined for tx: ${lib_types_1.Utils.safeStringify(tx)} in lostArchivers`);
        }
    }
    // add all txs.refutedArchivers publicKeys to record.refutedArchivers
    for (const tx of txs.refutedArchivers) {
        const target = tx.downMsg?.investigateMsg?.target;
        if (target) {
            (0, utils_1.insertSorted)(refutedArchivers, target);
        }
        else {
            /* prettier-ignore */ if (logger_1.logFlags.debug)
                console.log(`publicKey undefined for tx: ${lib_types_1.Utils.safeStringify(tx)} in refutedArchivers`);
        }
    }
    // loop through prev.lostArchivers
    if (prev) {
        for (const publicKey of prev.lostArchivers) {
            // get lostArchiversMap entry from publicKey
            const record = state_1.lostArchiversMap.get(publicKey);
            if (!record)
                continue;
            // wait cyclesToWait before adding the lostArchiver to removedArchivers
            if (record.cyclesToWait > 0) {
                // decrement cyclesToWait
                record.cyclesToWait--;
            }
            else {
                // add publicKey to record.removedArchivers
                (0, utils_1.insertSorted)(removedArchivers, publicKey);
            }
        }
    }
    record.lostArchivers = lostArchivers;
    record.refutedArchivers = refutedArchivers;
    record.removedArchivers = removedArchivers;
}
/**
 * This is called after Q4 of the prev cycle and before Q1 of the next cycle by CycleCreator
 * @param record The latest create Cycle Record
 * @returns A Change describing an addition, removal, or update from the Nodelist
 */
function parseRecord(record) {
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)('parseRecord function called');
    // loop through publicKeys from record.removedArchivers
    for (const publicKey of record.removedArchivers) {
        // delete publicKey entry from Archivers.archivers map
        (0, Archivers_1.removeArchiverByPublicKey)(publicKey);
        // delete publicKey entry from lostArchiversMap
        state_1.lostArchiversMap.delete(publicKey);
    }
    // loop through publicKeys from record.refutedArchivers
    for (const publicKey of record.refutedArchivers) {
        // delete publicKey entry from lostArchiversMap
        state_1.lostArchiversMap.delete(publicKey);
    }
    return {
        added: [],
        removed: [],
        updated: [],
    };
}
function queueRequest(request) {
    /** Not used by LostArchivers */
}
/**
 * This is called once per cycle at the start of Q1 by CycleCreator.
 */
function sendRequests() {
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)('sendRequests function called');
    // DBG pretty print internal lostArchiversMap to logs
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)('=== lostArchiversMap ===');
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)(`${(0, util_1.inspect)(state_1.lostArchiversMap)}`);
    /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
        (0, logging_1.info)('=== lostArchiversMap ===');
    // loop through lostArchiversMap
    for (const [publicKey, record] of state_1.lostArchiversMap) {
        /* prettier-ignore */ if (logger_1.logFlags.p2pNonFatal)
            (0, logging_1.info)(`  record: ${(0, util_1.inspect)(record)}`);
        // any entries with status 'reported'
        if (record.status === 'reported') {
            // Create InvestigateArchiverMsg and send it to the lostArchiverInvestigate route
            (0, functions_1.informInvestigator)(publicKey);
            // Delete record from map
            state_1.lostArchiversMap.delete(publicKey);
            continue;
        }
        // if isInvestigator
        if (record.isInvestigator) {
            // if status == 'down' && not gossipped
            if (record.status === 'down' && !record.gossippedDownMsg) {
                // Create ArchiverDownMsg and gossip it on the lostArchiverDownGossip route
                (0, functions_1.tellNetworkArchiverIsDown)(record);
                // set gossipped to true
                record.gossippedDownMsg = true;
            }
            continue;
        }
        if (record.status === 'up' && !record.gossippedUpMsg) {
            // Create ArchiverUpMsg and gossip it on the lostArchiverUpGossip route
            (0, functions_1.tellNetworkArchiverIsUp)(record);
            // set gossiped to true
            record.gossippedUpMsg = true;
            continue;
        }
    }
    return;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function validateRecordTypes(rec) {
    return '';
}
//# sourceMappingURL=index.js.map