LCOV - code coverage report
Current view: top level - src - masternode-sync.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 110 225 48.9 %
Date: 2025-02-23 09:33:43 Functions: 9 14 64.3 %

          Line data    Source code
       1             : // Copyright (c) 2014-2015 The Dash developers
       2             : // Copyright (c) 2015-2022 The PIVX Core developers
       3             : // Distributed under the MIT/X11 software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : // clang-format off
       7             : #include "activemasternode.h"
       8             : #include "addrman.h"
       9             : #include "budget/budgetmanager.h"
      10             : #include "evo/deterministicmns.h"
      11             : #include "masternode-sync.h"
      12             : #include "masternode.h"
      13             : #include "masternodeman.h"
      14             : #include "netmessagemaker.h"
      15             : #include "tiertwo/netfulfilledman.h"
      16             : #include "spork.h"
      17             : #include "tiertwo/tiertwo_sync_state.h"
      18             : #include "util/system.h"
      19             : #include "validation.h"
      20             : // clang-format on
      21             : 
      22             : class CMasternodeSync;
      23             : CMasternodeSync masternodeSync;
      24             : 
      25         479 : CMasternodeSync::CMasternodeSync()
      26             : {
      27         479 :     Reset();
      28         479 : }
      29             : 
      30         561 : bool CMasternodeSync::NotCompleted()
      31             : {
      32         561 :     return (!g_tiertwo_sync_state.IsSynced() && (
      33         192 :             !g_tiertwo_sync_state.IsSporkListSynced() ||
      34         192 :             sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) ||
      35         192 :             sporkManager.IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) ||
      36          96 :             sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)));
      37             : }
      38             : 
      39        3967 : void CMasternodeSync::UpdateBlockchainSynced(bool isRegTestNet)
      40             : {
      41        3967 :     if (!isRegTestNet && !g_tiertwo_sync_state.CanUpdateChainSync(lastProcess)) return;
      42        3967 :     if (fImporting || fReindex) return;
      43             : 
      44        3967 :     int64_t blockTime = 0;
      45        3967 :     {
      46        3967 :         TRY_LOCK(g_best_block_mutex, lock);
      47        3967 :         if (!lock) return;
      48        3967 :         blockTime = g_best_block_time;
      49             :     }
      50             : 
      51             :     // Synced only if the last block happened in the last 60 minutes
      52        3967 :     bool is_chain_synced = blockTime + 60 * 60 > lastProcess;
      53        3967 :     g_tiertwo_sync_state.SetBlockchainSync(is_chain_synced, lastProcess);
      54             : }
      55             : 
      56         538 : void CMasternodeSync::Reset()
      57             : {
      58         538 :     g_tiertwo_sync_state.SetBlockchainSync(false, 0);
      59         538 :     g_tiertwo_sync_state.ResetData();
      60         538 :     lastProcess = 0;
      61         538 :     lastFailure = 0;
      62         538 :     nCountFailures = 0;
      63         538 :     sumMasternodeList = 0;
      64         538 :     sumMasternodeWinner = 0;
      65         538 :     sumBudgetItemProp = 0;
      66         538 :     sumBudgetItemFin = 0;
      67         538 :     countMasternodeList = 0;
      68         538 :     countMasternodeWinner = 0;
      69         538 :     countBudgetItemProp = 0;
      70         538 :     countBudgetItemFin = 0;
      71         538 :     g_tiertwo_sync_state.SetCurrentSyncPhase(MASTERNODE_SYNC_INITIAL);
      72         538 :     RequestedMasternodeAttempt = 0;
      73         538 :     nAssetSyncStarted = GetTime();
      74         538 : }
      75             : 
      76           0 : bool CMasternodeSync::IsBudgetPropEmpty()
      77             : {
      78           0 :     return sumBudgetItemProp == 0 && countBudgetItemProp > 0;
      79             : }
      80             : 
      81           0 : bool CMasternodeSync::IsBudgetFinEmpty()
      82             : {
      83           0 :     return sumBudgetItemFin == 0 && countBudgetItemFin > 0;
      84             : }
      85             : 
      86        4127 : int CMasternodeSync::GetNextAsset(int currentAsset)
      87             : {
      88        4127 :     if (currentAsset > MASTERNODE_SYNC_FINISHED) {
      89           0 :         LogPrintf("%s - invalid asset %d\n", __func__, currentAsset);
      90           0 :         return MASTERNODE_SYNC_FAILED;
      91             :     }
      92        4127 :     switch (currentAsset) {
      93             :     case (MASTERNODE_SYNC_INITIAL):
      94             :     case (MASTERNODE_SYNC_FAILED):
      95             :         return MASTERNODE_SYNC_SPORKS;
      96        2167 :     case (MASTERNODE_SYNC_SPORKS):
      97        2167 :         return deterministicMNManager->LegacyMNObsolete() ? MASTERNODE_SYNC_BUDGET : MASTERNODE_SYNC_LIST;
      98         841 :     case (MASTERNODE_SYNC_LIST):
      99         841 :         return deterministicMNManager->LegacyMNObsolete() ? MASTERNODE_SYNC_BUDGET : MASTERNODE_SYNC_MNW;
     100         756 :     case (MASTERNODE_SYNC_MNW):
     101         756 :         return MASTERNODE_SYNC_BUDGET;
     102         143 :     case (MASTERNODE_SYNC_BUDGET):
     103         143 :     default:
     104         143 :         return MASTERNODE_SYNC_FINISHED;
     105             :     }
     106             : }
     107             : 
     108         220 : void CMasternodeSync::SwitchToNextAsset()
     109             : {
     110         220 :     int RequestedMasternodeAssets = g_tiertwo_sync_state.GetSyncPhase();
     111         220 :     if (RequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL ||
     112         220 :             RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED) {
     113         220 :         ClearFulfilledRequest();
     114             :     }
     115         220 :     const int nextAsset = GetNextAsset(RequestedMasternodeAssets);
     116         220 :     if (nextAsset == MASTERNODE_SYNC_FINISHED) {
     117           0 :         LogPrintf("%s - Sync has finished\n", __func__);
     118             :     }
     119         220 :     g_tiertwo_sync_state.SetCurrentSyncPhase(nextAsset);
     120         220 :     RequestedMasternodeAttempt = 0;
     121         220 :     nAssetSyncStarted = GetTime();
     122         220 : }
     123             : 
     124           0 : std::string CMasternodeSync::GetSyncStatus()
     125             : {
     126           0 :     switch (g_tiertwo_sync_state.GetSyncPhase()) {
     127           0 :     case MASTERNODE_SYNC_INITIAL:
     128           0 :         return _("MNs synchronization pending...");
     129           0 :     case MASTERNODE_SYNC_SPORKS:
     130           0 :         return _("Synchronizing sporks...");
     131           0 :     case MASTERNODE_SYNC_LIST:
     132           0 :         return _("Synchronizing masternodes...");
     133           0 :     case MASTERNODE_SYNC_MNW:
     134           0 :         return _("Synchronizing masternode winners...");
     135           0 :     case MASTERNODE_SYNC_BUDGET:
     136           0 :         return _("Synchronizing budgets...");
     137           0 :     case MASTERNODE_SYNC_FAILED:
     138           0 :         return _("Synchronization failed");
     139           0 :     case MASTERNODE_SYNC_FINISHED:
     140           0 :         return _("Synchronization finished");
     141             :     }
     142           0 :     return "";
     143             : }
     144             : 
     145        1754 : void CMasternodeSync::ProcessSyncStatusMsg(int nItemID, int nCount)
     146             : {
     147        1754 :     int RequestedMasternodeAssets = g_tiertwo_sync_state.GetSyncPhase();
     148        1754 :     if (RequestedMasternodeAssets >= MASTERNODE_SYNC_FINISHED) return;
     149             : 
     150             :     //this means we will receive no further communication
     151        1754 :     switch (nItemID) {
     152         841 :         case (MASTERNODE_SYNC_LIST):
     153         841 :             if (nItemID != RequestedMasternodeAssets) return;
     154         196 :             sumMasternodeList += nCount;
     155         196 :             countMasternodeList++;
     156         196 :             break;
     157         756 :         case (MASTERNODE_SYNC_MNW):
     158         756 :             if (nItemID != RequestedMasternodeAssets) return;
     159         150 :             sumMasternodeWinner += nCount;
     160         150 :             countMasternodeWinner++;
     161         150 :             break;
     162         143 :         case (MASTERNODE_SYNC_BUDGET_PROP):
     163         143 :             if (RequestedMasternodeAssets != MASTERNODE_SYNC_BUDGET) return;
     164         142 :             sumBudgetItemProp += nCount;
     165         142 :             countBudgetItemProp++;
     166         142 :             break;
     167          14 :         case (MASTERNODE_SYNC_BUDGET_FIN):
     168          14 :             if (RequestedMasternodeAssets != MASTERNODE_SYNC_BUDGET) return;
     169          14 :             sumBudgetItemFin += nCount;
     170          14 :             countBudgetItemFin++;
     171          14 :             break;
     172             :         default:
     173             :             break;
     174             :     }
     175             : 
     176         502 :     LogPrint(BCLog::MASTERNODE, "CMasternodeSync:ProcessMessage - ssc - got inventory count %d %d\n", nItemID, nCount);
     177             : }
     178             : 
     179         221 : void CMasternodeSync::ClearFulfilledRequest()
     180             : {
     181         221 :     g_netfulfilledman.Clear();
     182         221 : }
     183             : 
     184       19052 : void CMasternodeSync::Process()
     185             : {
     186       19052 :     static int tick = 0;
     187       19052 :     const bool isRegTestNet = Params().IsRegTestNet();
     188             : 
     189       19052 :     if (tick++ % MASTERNODE_SYNC_TIMEOUT != 0) return;
     190             : 
     191             :     // if the last call to this function was more than 60 minutes ago (client was in sleep mode)
     192             :     // reset the sync process
     193        3967 :     int64_t now = GetTime();
     194        3967 :     if (lastProcess != 0 && now > lastProcess + 60 * 60) {
     195          58 :         Reset();
     196             :     }
     197        3967 :     lastProcess = now;
     198             : 
     199             :     // Update chain sync status using the 'lastProcess' time
     200        3967 :     UpdateBlockchainSynced(isRegTestNet);
     201             : 
     202        3967 :     if (g_tiertwo_sync_state.IsSynced()) {
     203        2538 :         if (isRegTestNet) {
     204             :             return;
     205             :         }
     206           0 :         bool legacy_obsolete = deterministicMNManager->LegacyMNObsolete();
     207             :         // Check if we lost all masternodes (except the local one in case the node is a MN)
     208             :         // from sleep/wake or failure to sync originally (after spork 21, check if we lost
     209             :         // all proposals instead). If we did, resync from scratch.
     210           0 :         if ((!legacy_obsolete && mnodeman.CountEnabled(true /* only_legacy */) <= 1) ||
     211           0 :             (legacy_obsolete && g_budgetman.CountProposals() == 0)) {
     212           0 :             Reset();
     213             :         } else {
     214           0 :             return;
     215             :         }
     216             :     }
     217             : 
     218             :     // Try syncing again
     219        1429 :     int RequestedMasternodeAssets = g_tiertwo_sync_state.GetSyncPhase();
     220        1429 :     if (RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED && lastFailure + (1 * 60) < GetTime()) {
     221           0 :         Reset();
     222        1429 :     } else if (RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED) {
     223             :         return;
     224             :     }
     225             : 
     226        1429 :     if (RequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL) SwitchToNextAsset();
     227             : 
     228             :     // sporks synced but blockchain is not, wait until we're almost at a recent block to continue
     229        1429 :     if (!g_tiertwo_sync_state.IsBlockchainSynced() &&
     230             :         RequestedMasternodeAssets > MASTERNODE_SYNC_SPORKS) return;
     231             : 
     232             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     233        1082 :     bool fLegacyMnObsolete = deterministicMNManager->LegacyMNObsolete();
     234             : 
     235        1082 :     CMasternodeSync* sync = this;
     236             : 
     237             :     // New sync architecture, regtest only for now.
     238        1082 :     if (isRegTestNet) {
     239        1082 :         g_connman->ForEachNode([sync](CNode* pnode){
     240        2533 :             return sync->SyncRegtest(pnode);
     241             :         });
     242        1082 :         return;
     243             :     }
     244             : 
     245             :     // Mainnet sync
     246           0 :     g_connman->ForEachNodeInRandomOrderContinueIf([sync, fLegacyMnObsolete](CNode* pnode){
     247           0 :         return sync->SyncWithNode(pnode, fLegacyMnObsolete);
     248             :     });
     249             : }
     250             : 
     251           0 : void CMasternodeSync::syncTimeout(const std::string& reason)
     252             : {
     253           0 :     LogPrintf("%s - ERROR - Sync has failed on %s, will retry later\n", __func__, reason);
     254           0 :     g_tiertwo_sync_state.SetCurrentSyncPhase(MASTERNODE_SYNC_FAILED);
     255           0 :     RequestedMasternodeAttempt = 0;
     256           0 :     lastFailure = GetTime();
     257           0 :     nCountFailures++;
     258           0 : }
     259             : 
     260           0 : bool CMasternodeSync::SyncWithNode(CNode* pnode, bool fLegacyMnObsolete)
     261             : {
     262           0 :     int RequestedMasternodeAssets = g_tiertwo_sync_state.GetSyncPhase();
     263           0 :     CNetMsgMaker msgMaker(pnode->GetSendVersion());
     264             : 
     265             :     //set to synced
     266           0 :     if (RequestedMasternodeAssets == MASTERNODE_SYNC_SPORKS) {
     267             : 
     268             :         // Sync sporks from at least 2 peers
     269           0 :         if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) {
     270           0 :             SwitchToNextAsset();
     271           0 :             return false;
     272             :         }
     273             : 
     274             :         // Request sporks sync if we haven't requested it yet.
     275           0 :         if (g_netfulfilledman.HasFulfilledRequest(pnode->addr, "getspork")) return true;
     276           0 :         g_netfulfilledman.AddFulfilledRequest(pnode->addr, "getspork");
     277             : 
     278           0 :         g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::GETSPORKS));
     279           0 :         RequestedMasternodeAttempt++;
     280           0 :         return false;
     281             :     }
     282             : 
     283           0 :     if (pnode->nVersion < ActiveProtocol() || !pnode->CanRelay()) {
     284           0 :         return true; // move to next peer
     285             :     }
     286             : 
     287           0 :     if (RequestedMasternodeAssets == MASTERNODE_SYNC_LIST) {
     288           0 :         if (fLegacyMnObsolete) {
     289           0 :             SwitchToNextAsset();
     290           0 :             return false;
     291             :         }
     292             : 
     293           0 :         int lastMasternodeList = g_tiertwo_sync_state.GetlastMasternodeList();
     294           0 :         LogPrint(BCLog::MASTERNODE, "CMasternodeSync::Process() - lastMasternodeList %lld (GetTime() - MASTERNODE_SYNC_TIMEOUT) %lld\n", lastMasternodeList, GetTime() - MASTERNODE_SYNC_TIMEOUT);
     295           0 :         if (lastMasternodeList > 0 && lastMasternodeList < GetTime() - MASTERNODE_SYNC_TIMEOUT * 8 && RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) {
     296             :             // hasn't received a new item in the last 40 seconds AND has sent at least a minimum of MASTERNODE_SYNC_THRESHOLD GETMNLIST requests,
     297             :             // so we'll move to the next asset.
     298           0 :             SwitchToNextAsset();
     299           0 :             return false;
     300             :         }
     301             : 
     302             :         // timeout
     303           0 :         if (lastMasternodeList == 0 &&
     304           0 :             (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3 || GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5)) {
     305           0 :             if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) {
     306           0 :                 syncTimeout("MASTERNODE_SYNC_LIST");
     307             :             } else {
     308           0 :                 SwitchToNextAsset();
     309             :             }
     310           0 :             return false;
     311             :         }
     312             : 
     313             :         // Don't request mnlist initial sync to more than 8 randomly ordered peers in this round
     314           0 :         if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 4) return false;
     315             : 
     316             :         // Request mnb sync if we haven't requested it yet.
     317           0 :         if (g_netfulfilledman.HasFulfilledRequest(pnode->addr, "mnsync")) return true;
     318             : 
     319             :         // Try to request MN list sync.
     320           0 :         if (!mnodeman.RequestMnList(pnode)) {
     321             :             return true; // Failed, try next peer.
     322             :         }
     323             : 
     324             :         // Mark sync requested.
     325           0 :         g_netfulfilledman.AddFulfilledRequest(pnode->addr, "mnsync");
     326             :         // Increase the sync attempt count
     327           0 :         RequestedMasternodeAttempt++;
     328             : 
     329           0 :         return false; // sleep 1 second before do another request round.
     330             :     }
     331             : 
     332           0 :     if (RequestedMasternodeAssets == MASTERNODE_SYNC_MNW) {
     333           0 :         if (fLegacyMnObsolete) {
     334           0 :             SwitchToNextAsset();
     335           0 :             return false;
     336             :         }
     337             : 
     338           0 :         int lastMasternodeWinner = g_tiertwo_sync_state.GetlastMasternodeWinner();
     339           0 :         if (lastMasternodeWinner > 0 && lastMasternodeWinner < GetTime() - MASTERNODE_SYNC_TIMEOUT * 2 && RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) { //hasn't received a new item in the last five seconds, so we'll move to the
     340           0 :             SwitchToNextAsset();
     341             :             // in case we received a budget item while we were syncing the mnw, let's reset the last budget item received time.
     342             :             // reason: if we received for example a single proposal +50 seconds ago, then once the budget sync starts (right after this call),
     343             :             // it will look like the sync is finished, and will not wait to receive any budget data and declare the sync over.
     344           0 :             g_tiertwo_sync_state.ResetLastBudgetItem();
     345           0 :             return false;
     346             :         }
     347             : 
     348             :         // timeout
     349           0 :         if (lastMasternodeWinner == 0 &&
     350           0 :             (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 2 || GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5)) {
     351           0 :             if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) {
     352           0 :                 syncTimeout("MASTERNODE_SYNC_MNW");
     353             :             } else {
     354           0 :                 SwitchToNextAsset();
     355             :                 // Same as above (future: remove all of this duplicated code in v6.0.)
     356             :                 // in case we received a budget item while we were syncing the mnw, let's reset the last budget item received time.
     357             :                 // reason: if we received for example a single proposal +50 seconds ago, then once the budget sync starts (right after this call),
     358             :                 // it will look like the sync is finished, and will not wait to receive any budget data and declare the sync over.
     359           0 :                 g_tiertwo_sync_state.ResetLastBudgetItem();
     360             :             }
     361           0 :             return false;
     362             :         }
     363             : 
     364             :         // Don't request mnw initial sync to more than 4 randomly ordered peers in this round.
     365           0 :         if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 2) return false;
     366             : 
     367             :         // Request mnw sync if we haven't requested it yet.
     368           0 :         if (g_netfulfilledman.HasFulfilledRequest(pnode->addr, "mnwsync")) return true;
     369             : 
     370             :         // Mark sync requested.
     371           0 :         g_netfulfilledman.AddFulfilledRequest(pnode->addr, "mnwsync");
     372             : 
     373             :         // Sync mn winners
     374           0 :         int nMnCount = mnodeman.CountEnabled(true /* only_legacy */);
     375           0 :         g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::GETMNWINNERS, nMnCount));
     376           0 :         RequestedMasternodeAttempt++;
     377             : 
     378           0 :         return false; // sleep 1 second before do another request round.
     379             :     }
     380             : 
     381           0 :     if (RequestedMasternodeAssets == MASTERNODE_SYNC_BUDGET) {
     382           0 :         int lastBudgetItem = g_tiertwo_sync_state.GetlastBudgetItem();
     383             :         // We'll start rejecting votes if we accidentally get set as synced too soon
     384           0 :         if (lastBudgetItem > 0 && lastBudgetItem < GetTime() - MASTERNODE_SYNC_TIMEOUT * 10 && RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) {
     385             :             // Hasn't received a new item in the last fifty seconds and more than MASTERNODE_SYNC_THRESHOLD requests were sent,
     386             :             // so we'll move to the next asset
     387           0 :             SwitchToNextAsset();
     388             : 
     389             :             // Try to activate our masternode if possible
     390           0 :             activeMasternode.ManageStatus();
     391           0 :             return false;
     392             :         }
     393             : 
     394             :         // timeout
     395           0 :         if (lastBudgetItem == 0 &&
     396           0 :             (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3 || GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5)) {
     397             :             // maybe there is no budgets at all, so just finish syncing
     398           0 :             SwitchToNextAsset();
     399           0 :             activeMasternode.ManageStatus();
     400           0 :             return false;
     401             :         }
     402             : 
     403             :         // Don't request budget initial sync to more than 6 randomly ordered peers in this round.
     404           0 :         if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3) return false;
     405             : 
     406             :         // Request bud sync if we haven't requested it yet.
     407           0 :         if (g_netfulfilledman.HasFulfilledRequest(pnode->addr, "busync")) return true;
     408             : 
     409             :         // Mark sync requested.
     410           0 :         g_netfulfilledman.AddFulfilledRequest(pnode->addr, "busync");
     411             : 
     412             :         // Sync proposals, finalizations and votes
     413           0 :         uint256 n;
     414           0 :         g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::BUDGETVOTESYNC, n));
     415           0 :         RequestedMasternodeAttempt++;
     416             : 
     417           0 :         return false; // sleep 1 second before do another request round.
     418             :     }
     419             : 
     420             :     return true;
     421             : }

Generated by: LCOV version 1.14