LCOV - code coverage report
Current view: top level - src/tiertwo - init.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 133 184 72.3 %
Date: 2026-08-09 10:51:41 Functions: 16 18 88.9 %

          Line data    Source code
       1             : // Copyright (c) 2021-2022 The PIVX Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include "tiertwo/init.h"
       6             : 
       7             : #include "budget/budgetdb.h"
       8             : #include "evo/evodb.h"
       9             : #include "evo/evonotificationinterface.h"
      10             : #include "flatdb.h"
      11             : #include "guiinterface.h"
      12             : #include "guiinterfaceutil.h"
      13             : #include "masternodeman.h"
      14             : #include "masternode-payments.h"
      15             : #include "masternodeconfig.h"
      16             : #include "llmq/quorums_init.h"
      17             : #include "scheduler.h"
      18             : #include "tiertwo/masternode_meta_manager.h"
      19             : #include "tiertwo/netfulfilledman.h"
      20             : #include "validation.h"
      21             : #include "wallet/wallet.h"
      22             : 
      23             : #include <boost/thread.hpp>
      24             : 
      25             : static std::unique_ptr<EvoNotificationInterface> pEvoNotificationInterface{nullptr};
      26             : 
      27           1 : std::string GetTierTwoHelpString(bool showDebug)
      28             : {
      29           1 :     std::string strUsage = HelpMessageGroup("Masternode options:");
      30           3 :     strUsage += HelpMessageOpt("-masternode=<n>", strprintf("Enable the client to act as a masternode (0-1, default: %u)", DEFAULT_MASTERNODE));
      31           3 :     strUsage += HelpMessageOpt("-mnconf=<file>", strprintf("Specify masternode configuration file (default: %s)", PIVX_MASTERNODE_CONF_FILENAME));
      32           3 :     strUsage += HelpMessageOpt("-mnconflock=<n>", strprintf("Lock masternodes from masternode configuration file (default: %u)", DEFAULT_MNCONFLOCK));
      33           4 :     strUsage += HelpMessageOpt("-masternodeprivkey=<n>", "Set the masternode private key");
      34           4 :     strUsage += HelpMessageOpt("-masternodeaddr=<n>", strprintf("Set external address:port to get to this masternode (example: %s). Only for Legacy Masternodes", "128.127.106.235:51472"));
      35           4 :     strUsage += HelpMessageOpt("-budgetvotemode=<mode>", "Change automatic finalized budget voting behavior. mode=auto: Vote for only exact finalized budget match to my generated budget. (string, default: auto)");
      36           4 :     strUsage += HelpMessageOpt("-mnoperatorprivatekey=<bech32>", "Set the masternode operator private key. Only valid with -masternode=1. When set, the masternode acts as a deterministic masternode.");
      37           1 :     if (showDebug) {
      38           0 :         strUsage += HelpMessageOpt("-pushversion", strprintf("Modifies the mnauth serialization if the version is lower than %d."
      39           0 :                                                              "testnet/regtest only; ", MNAUTH_NODE_VER_VERSION));
      40           0 :         strUsage += HelpMessageOpt("-disabledkg", "Disable the DKG sessions process threads for the entire lifecycle. testnet/regtest only.");
      41             :     }
      42           1 :     return strUsage;
      43             : }
      44             : 
      45         295 : void InitTierTwoInterfaces()
      46             : {
      47         295 :     pEvoNotificationInterface = std::make_unique<EvoNotificationInterface>();
      48         295 :     RegisterValidationInterface(pEvoNotificationInterface.get());
      49         295 : }
      50             : 
      51         315 : void ResetTierTwoInterfaces()
      52             : {
      53         315 :     if (pEvoNotificationInterface) {
      54         295 :         UnregisterValidationInterface(pEvoNotificationInterface.get());
      55         295 :         pEvoNotificationInterface.reset();
      56             :     }
      57             : 
      58         315 :     if (activeMasternodeManager) {
      59           7 :         UnregisterValidationInterface(activeMasternodeManager);
      60           7 :         delete activeMasternodeManager;
      61           7 :         activeMasternodeManager = nullptr;
      62             :     }
      63         315 : }
      64             : 
      65         295 : void InitTierTwoPreChainLoad(bool fReindex)
      66             : {
      67         295 :     int64_t nEvoDbCache = 1024 * 1024 * 64; // Max cache is 64MB
      68         295 :     deterministicMNManager.reset();
      69         295 :     evoDb.reset();
      70         295 :     evoDb.reset(new CEvoDB(nEvoDbCache, false, fReindex));
      71         295 :     deterministicMNManager.reset(new CDeterministicMNManager(*evoDb));
      72         295 : }
      73             : 
      74         295 : void InitTierTwoPostCoinsCacheLoad(CScheduler* scheduler)
      75             : {
      76             :     // Initialize LLMQ system
      77         295 :     llmq::InitLLMQSystem(*evoDb, scheduler, false);
      78         295 : }
      79             : 
      80         293 : void InitTierTwoChainTip()
      81             : {
      82             :     // force UpdatedBlockTip to initialize nCachedBlockHeight for DS, MN payments and budgets
      83             :     // but don't call it directly to prevent triggering of other listeners like zmq etc.
      84         293 :     pEvoNotificationInterface->InitializeCurrentBlockTip();
      85         293 : }
      86             : 
      87             : // Sets the last CACHED_BLOCK_HASHES hashes into masternode manager cache
      88         293 : static void LoadBlockHashesCache(CMasternodeMan& man)
      89             : {
      90         293 :     LOCK(cs_main);
      91         293 :     const CBlockIndex* pindex = chainActive.Tip();
      92             :     unsigned int inserted = 0;
      93       24151 :     while (pindex && inserted < CACHED_BLOCK_HASHES) {
      94       23858 :         man.CacheBlockHash(pindex);
      95       23858 :         pindex = pindex->pprev;
      96       23858 :         ++inserted;
      97             :     }
      98         293 : }
      99             : 
     100         293 : bool LoadTierTwo(int chain_active_height, bool load_cache_files)
     101             : {
     102             :     // ################################# //
     103             :     // ## Legacy Masternodes Manager ### //
     104             :     // ################################# //
     105         293 :     uiInterface.InitMessage(_("Loading masternode cache..."));
     106             : 
     107         293 :     mnodeman.SetBestHeight(chain_active_height);
     108         293 :     LoadBlockHashesCache(mnodeman);
     109         586 :     CMasternodeDB mndb;
     110         293 :     CMasternodeDB::ReadResult readResult = mndb.Read(mnodeman);
     111         293 :     if (readResult == CMasternodeDB::FileError)
     112         217 :         LogPrintf("Missing masternode cache file - mncache.dat, will try to recreate\n");
     113          76 :     else if (readResult != CMasternodeDB::Ok) {
     114           0 :         LogPrintf("Error reading mncache.dat - cached data discarded\n");
     115             :     }
     116             : 
     117             :     // ##################### //
     118             :     // ## Budget Manager ### //
     119             :     // ##################### //
     120         293 :     uiInterface.InitMessage(_("Loading budget cache..."));
     121             : 
     122         586 :     CBudgetDB budgetdb;
     123         293 :     const bool fDryRun = (chain_active_height <= 0);
     124         293 :     if (!fDryRun) g_budgetman.SetBestHeight(chain_active_height);
     125         293 :     CBudgetDB::ReadResult readResult2 = budgetdb.Read(g_budgetman, fDryRun);
     126             : 
     127         293 :     if (readResult2 == CBudgetDB::FileError)
     128         217 :         LogPrintf("Missing budget cache - budget.dat, will try to recreate\n");
     129          76 :     else if (readResult2 != CBudgetDB::Ok) {
     130           0 :         LogPrintf("Error reading budget.dat - cached data discarded\n");
     131             :     }
     132             : 
     133             :     // flag our cached items so we send them to our peers
     134         293 :     g_budgetman.ResetSync();
     135         293 :     g_budgetman.ReloadMapSeen();
     136             : 
     137             :     // ######################################### //
     138             :     // ## Legacy Masternodes-Payments Manager ## //
     139             :     // ######################################### //
     140         293 :     uiInterface.InitMessage(_("Loading masternode payment cache..."));
     141             : 
     142         293 :     CMasternodePaymentDB mnpayments;
     143         293 :     CMasternodePaymentDB::ReadResult readResult3 = mnpayments.Read(masternodePayments);
     144         293 :     if (readResult3 == CMasternodePaymentDB::FileError)
     145         217 :         LogPrintf("Missing masternode payment cache - mnpayments.dat, will try to recreate\n");
     146          76 :     else if (readResult3 != CMasternodePaymentDB::Ok) {
     147           0 :         LogPrintf("Error reading mnpayments.dat - cached data discarded\n");
     148             :     }
     149             : 
     150             :     // ###################################### //
     151             :     // ## Legacy Parse 'masternodes.conf'  ## //
     152             :     // ###################################### //
     153         586 :     std::string strErr;
     154         293 :     if (!masternodeConfig.read(strErr)) {
     155           0 :         return UIError(strprintf(_("Error reading masternode configuration file: %s"), strErr));
     156             :     }
     157             : 
     158             :     // ############################## //
     159             :     // ## Net MNs Metadata Manager ## //
     160             :     // ############################## //
     161         293 :     uiInterface.InitMessage(_("Loading masternode cache..."));
     162         586 :     CFlatDB<CMasternodeMetaMan> metadb(MN_META_CACHE_FILENAME, MN_META_CACHE_FILE_ID);
     163         293 :     if (load_cache_files) {
     164         286 :         if (!metadb.Load(g_mmetaman)) {
     165           0 :             return UIError(strprintf(_("Failed to load masternode metadata cache from: %s"), metadb.GetDbPath().string()));
     166             :         }
     167             :     } else {
     168          14 :         CMasternodeMetaMan mmetamanTmp;
     169           7 :         if (!metadb.Dump(mmetamanTmp)) {
     170           0 :             return UIError(strprintf(_("Failed to clear masternode metadata cache at: %s"), metadb.GetDbPath().string()));
     171             :         }
     172             :     }
     173             : 
     174             :     // ############################## //
     175             :     // ## Network Requests Manager ## //
     176             :     // ############################## //
     177         293 :     uiInterface.InitMessage(_("Loading network requests cache..."));
     178         293 :     CFlatDB<CNetFulfilledRequestManager> netRequestsDb(NET_REQUESTS_CACHE_FILENAME, NET_REQUESTS_CACHE_FILE_ID);
     179         293 :     if (load_cache_files) {
     180         286 :         if (!netRequestsDb.Load(g_netfulfilledman)) {
     181           0 :             LogPrintf("Failed to load network requests cache from %s\n", netRequestsDb.GetDbPath().string());
     182             :         }
     183             :     } else {
     184          14 :         CNetFulfilledRequestManager netfulfilledmanTmp(0);
     185           7 :         if (!netRequestsDb.Dump(netfulfilledmanTmp)) {
     186           0 :             LogPrintf("Failed to clear network requests cache at %s\n", netRequestsDb.GetDbPath().string());
     187             :         }
     188             :     }
     189             : 
     190         293 :     return true;
     191             : }
     192             : 
     193         293 : void RegisterTierTwoValidationInterface()
     194             : {
     195         293 :     RegisterValidationInterface(&g_budgetman);
     196         293 :     RegisterValidationInterface(&masternodePayments);
     197         293 :     if (activeMasternodeManager) RegisterValidationInterface(activeMasternodeManager);
     198         293 : }
     199             : 
     200         315 : void DumpTierTwo()
     201             : {
     202         315 :     DumpMasternodes();
     203         315 :     DumpBudgets(g_budgetman);
     204         315 :     DumpMasternodePayments();
     205         315 :     CFlatDB<CMasternodeMetaMan>(MN_META_CACHE_FILENAME, MN_META_CACHE_FILE_ID).Dump(g_mmetaman);
     206         315 :     CFlatDB<CNetFulfilledRequestManager>(NET_REQUESTS_CACHE_FILENAME, NET_REQUESTS_CACHE_FILE_ID).Dump(g_netfulfilledman);
     207         315 : }
     208             : 
     209         293 : void SetBudgetFinMode(const std::string& mode)
     210             : {
     211         293 :     g_budgetman.strBudgetMode = mode;
     212         293 :     LogPrintf("Budget Mode %s\n", g_budgetman.strBudgetMode);
     213         293 : }
     214             : 
     215         293 : bool InitActiveMN()
     216             : {
     217         293 :     fMasterNode = gArgs.GetBoolArg("-masternode", DEFAULT_MASTERNODE);
     218         293 :     if ((fMasterNode || masternodeConfig.getCount() > -1) && fTxIndex == false) {
     219           0 :         return UIError(strprintf(_("Enabling Masternode support requires turning on transaction indexing."
     220             :                                    "Please add %s to your configuration and start with %s"), "txindex=1", "-reindex"));
     221             :     }
     222             : 
     223         293 :     if (fMasterNode) {
     224             : 
     225           0 :         if (gArgs.IsArgSet("-connect") && gArgs.GetArgs("-connect").size() > 0) {
     226           0 :             return UIError(_("Cannot be a masternode and only connect to specific nodes"));
     227             :         }
     228             : 
     229           0 :         if (gArgs.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS) < DEFAULT_MAX_PEER_CONNECTIONS) {
     230           0 :             return UIError(strprintf(_("Masternode must be able to handle at least %d connections, set %s=%d"),
     231             :                                      DEFAULT_MAX_PEER_CONNECTIONS, "-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS));
     232             :         }
     233             : 
     234           0 :         const std::string& mnoperatorkeyStr = gArgs.GetArg("-mnoperatorprivatekey", "");
     235           0 :         const bool fDeterministic = !mnoperatorkeyStr.empty();
     236           0 :         LogPrintf("IS %s MASTERNODE\n", (fDeterministic ? "DETERMINISTIC " : ""));
     237             : 
     238           0 :         if (fDeterministic) {
     239             :             // Check enforcement
     240           0 :             if (!deterministicMNManager->IsDIP3Enforced()) {
     241           0 :                 const std::string strError = strprintf(
     242           0 :                         _("Cannot start deterministic masternode before enforcement. Remove %s to start as legacy masternode"),
     243           0 :                         "-mnoperatorprivatekey");
     244           0 :                 LogPrintf("-- ERROR: %s\n", strError);
     245           0 :                 return UIError(strError);
     246             :             }
     247             :             // Create and register activeMasternodeManager
     248           0 :             activeMasternodeManager = new CActiveDeterministicMasternodeManager();
     249           0 :             auto res = activeMasternodeManager->SetOperatorKey(mnoperatorkeyStr);
     250           0 :             if (!res) { return UIError(res.getError()); }
     251             :             // Init active masternode
     252           0 :             const CBlockIndex* pindexTip = WITH_LOCK(cs_main, return chainActive.Tip(););
     253           0 :             activeMasternodeManager->Init(pindexTip);
     254           0 :             if (activeMasternodeManager->GetState() == CActiveDeterministicMasternodeManager::MASTERNODE_ERROR) {
     255           0 :                 return UIError(activeMasternodeManager->GetStatus()); // state logged internally
     256             :             }
     257             :         } else {
     258             :             // Check enforcement
     259           0 :             if (deterministicMNManager->LegacyMNObsolete()) {
     260           0 :                 const std::string strError = strprintf(
     261           0 :                         _("Legacy masternode system disabled. Use %s to start as deterministic masternode"),
     262           0 :                         "-mnoperatorprivatekey");
     263           0 :                 LogPrintf("-- ERROR: %s\n", strError);
     264           0 :                 return UIError(strError);
     265             :             }
     266           0 :             auto res = initMasternode(gArgs.GetArg("-masternodeprivkey", ""), gArgs.GetArg("-masternodeaddr", ""),
     267           0 :                                       true);
     268           0 :             if (!res) { return UIError(res.getError()); }
     269             :         }
     270             :     }
     271             : 
     272             : #ifdef ENABLE_WALLET
     273             :     // !TODO: remove after complete transition to DMN
     274             :     // use only the first wallet here. This section can be removed after transition to DMN
     275         586 :     if (gArgs.GetBoolArg("-mnconflock", DEFAULT_MNCONFLOCK) && !vpwallets.empty() && vpwallets[0]) {
     276         562 :         LOCK(vpwallets[0]->cs_wallet);
     277         281 :         LogPrintf("Locking Masternodes collateral utxo:\n");
     278         281 :         uint256 mnTxHash;
     279         281 :         for (const auto& mne : masternodeConfig.getEntries()) {
     280           0 :             mnTxHash.SetHex(mne.getTxHash());
     281           0 :             COutPoint outpoint = COutPoint(mnTxHash, (unsigned int) std::stoul(mne.getOutputIndex()));
     282           0 :             vpwallets[0]->LockCoin(outpoint);
     283           0 :             LogPrintf("Locked collateral, MN: %s, tx hash: %s, output index: %s\n",
     284           0 :                       mne.getAlias(), mne.getTxHash(), mne.getOutputIndex());
     285             :         }
     286             :     }
     287             : 
     288             :     // automatic lock for DMN
     289         293 :     if (gArgs.GetBoolArg("-mnconflock", DEFAULT_MNCONFLOCK)) {
     290         293 :         LogPrintf("Locking masternode collaterals...\n");
     291         293 :         const auto& mnList = deterministicMNManager->GetListAtChainTip();
     292         293 :         mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
     293           0 :             for (CWallet* pwallet : vpwallets) {
     294           0 :                 pwallet->LockOutpointIfMineWithMutex(nullptr, dmn->collateralOutpoint);
     295             :             }
     296           0 :         });
     297             :     }
     298             : #endif
     299             :     // All good
     300             :     return true;
     301             : }
     302             : 
     303         293 : void StartTierTwoThreadsAndScheduleJobs(boost::thread_group& threadGroup, CScheduler& scheduler)
     304             : {
     305         293 :     threadGroup.create_thread(std::bind(&ThreadCheckMasternodes));
     306         293 :     scheduler.scheduleEvery(std::bind(&CNetFulfilledRequestManager::DoMaintenance, std::ref(g_netfulfilledman)), 60 * 1000);
     307             : 
     308             :     // Start LLMQ system
     309         293 :     if (gArgs.GetBoolArg("-disabledkg", false)) {
     310           8 :         if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
     311           0 :             throw std::runtime_error("DKG system can be disabled only on testnet/regtest");
     312             :         } else {
     313           8 :             LogPrintf("DKG system disabled.\n");
     314             :         }
     315             :     } else {
     316         285 :         llmq::StartLLMQSystem();
     317             :     }
     318         293 : }
     319             : 
     320         315 : void StopTierTwoThreads()
     321             : {
     322         315 :     llmq::StopLLMQSystem();
     323         315 : }
     324             : 
     325         315 : void DeleteTierTwo()
     326             : {
     327         315 :     llmq::DestroyLLMQSystem();
     328         315 :     deterministicMNManager.reset();
     329         315 :     evoDb.reset();
     330         315 : }
     331             : 
     332         315 : void InterruptTierTwo()
     333             : {
     334         315 :     llmq::InterruptLLMQSystem();
     335         315 : }

Generated by: LCOV version 1.14