Line data Source code
1 : // Copyright (c) 2014-2025 The Dash Core developers 2 : // Distributed under the MIT/X11 software license, see the accompanying 3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : 5 : #include <masternode/sync.h> 6 : 7 : #include <chain.h> 8 : #include <logging.h> 9 : #include <util/time.h> 10 : #include <util/translation.h> 11 : 12 : #include <cassert> 13 : 14 0 : void NullNodeSyncNotifier::SyncReset() { assert(false); } 15 0 : void NullNodeSyncNotifier::SyncFinished() { assert(false); } 16 : 17 368 : CMasternodeSync::CMasternodeSync(std::unique_ptr<NodeSyncNotifier>&& sync_notifier) : 18 : nTimeAssetSyncStarted{GetTime()}, 19 : nTimeLastBumped{GetTime()}, 20 : m_sync_notifier{std::move(sync_notifier)} 21 184 : { 22 : assert(m_sync_notifier != nullptr); 23 184 : } 24 : 25 368 : CMasternodeSync::~CMasternodeSync() = default; 26 : 27 2 : void CMasternodeSync::Reset(bool fForce, bool fNotifyReset) 28 : { 29 : // Avoid resetting the sync process if we just "recently" received a new block 30 2 : if (!fForce) { 31 2 : if (GetTime() - nTimeLastUpdateBlockTip < MASTERNODE_SYNC_RESET_SECONDS) { 32 0 : return; 33 : } 34 2 : } 35 2 : nCurrentAsset = MASTERNODE_SYNC_BLOCKCHAIN; 36 2 : nTriedPeerCount = 0; 37 2 : nTimeAssetSyncStarted = GetTime(); 38 2 : nTimeLastBumped = GetTime(); 39 2 : nTimeLastUpdateBlockTip = 0; 40 2 : fReachedBestHeader = false; 41 2 : if (fNotifyReset) { 42 2 : m_sync_notifier->SyncReset(); 43 2 : } 44 2 : } 45 : 46 0 : void CMasternodeSync::BumpAssetLastTime(const std::string& strFuncName) 47 : { 48 0 : if (IsSynced()) return; 49 0 : nTimeLastBumped = GetTime(); 50 0 : LogPrint(BCLog::MNSYNC, "CMasternodeSync::BumpAssetLastTime -- %s\n", strFuncName); 51 0 : } 52 : 53 0 : std::string CMasternodeSync::GetAssetName() const 54 : { 55 0 : switch(nCurrentAsset) 56 : { 57 0 : case(MASTERNODE_SYNC_BLOCKCHAIN): return "MASTERNODE_SYNC_BLOCKCHAIN"; 58 0 : case(MASTERNODE_SYNC_GOVERNANCE): return "MASTERNODE_SYNC_GOVERNANCE"; 59 0 : case MASTERNODE_SYNC_FINISHED: return "MASTERNODE_SYNC_FINISHED"; 60 0 : default: return "UNKNOWN"; 61 : } 62 0 : } 63 : 64 0 : void CMasternodeSync::SwitchToNextAsset() 65 : { 66 0 : switch(nCurrentAsset) 67 : { 68 : case(MASTERNODE_SYNC_BLOCKCHAIN): 69 0 : LogPrintf("CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted); 70 0 : nCurrentAsset = MASTERNODE_SYNC_GOVERNANCE; 71 0 : LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName()); 72 0 : break; 73 : case(MASTERNODE_SYNC_GOVERNANCE): 74 0 : LogPrintf("CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted); 75 0 : nCurrentAsset = MASTERNODE_SYNC_FINISHED; 76 0 : m_sync_notifier->SyncFinished(); 77 0 : LogPrintf("CMasternodeSync::SwitchToNextAsset -- Sync has finished\n"); 78 : 79 0 : break; 80 : } 81 0 : nTriedPeerCount = 0; 82 0 : nTimeAssetSyncStarted = GetTime(); 83 0 : BumpAssetLastTime("CMasternodeSync::SwitchToNextAsset"); 84 0 : } 85 : 86 0 : std::string CMasternodeSync::GetSyncStatus() const 87 : { 88 0 : switch (nCurrentAsset) { 89 0 : case MASTERNODE_SYNC_BLOCKCHAIN: return _("Synchronizing blockchain…").translated; 90 0 : case MASTERNODE_SYNC_GOVERNANCE: return _("Synchronizing governance objects…").translated; 91 0 : case MASTERNODE_SYNC_FINISHED: return _("Synchronization finished").translated; 92 0 : default: return ""; 93 : } 94 0 : } 95 : 96 0 : void CMasternodeSync::AcceptedBlockHeader(const CBlockIndex *pindexNew) 97 : { 98 0 : LogPrint(BCLog::MNSYNC, "CMasternodeSync::AcceptedBlockHeader -- pindexNew->nHeight: %d\n", pindexNew->nHeight); 99 : 100 0 : if (!IsBlockchainSynced()) { 101 : // Postpone timeout each time new block header arrives while we are still syncing blockchain 102 0 : BumpAssetLastTime("CMasternodeSync::AcceptedBlockHeader"); 103 0 : } 104 0 : } 105 : 106 0 : void CMasternodeSync::NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload) 107 : { 108 0 : if (pindexNew == nullptr) { 109 0 : return; 110 : } 111 0 : LogPrint(BCLog::MNSYNC, "CMasternodeSync::NotifyHeaderTip -- pindexNew->nHeight: %d fInitialDownload=%d\n", pindexNew->nHeight, fInitialDownload); 112 0 : if (IsSynced()) 113 0 : return; 114 : 115 0 : if (!IsBlockchainSynced()) { 116 : // Postpone timeout each time new block arrives while we are still syncing blockchain 117 0 : BumpAssetLastTime("CMasternodeSync::NotifyHeaderTip"); 118 0 : } 119 0 : } 120 : 121 0 : void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindexTip, const CBlockIndex *pindexNew, bool fInitialDownload) 122 : { 123 0 : LogPrint(BCLog::MNSYNC, "CMasternodeSync::UpdatedBlockTip -- pindexNew->nHeight: %d fInitialDownload=%d\n", pindexNew->nHeight, fInitialDownload); 124 0 : nTimeLastUpdateBlockTip = GetTime<std::chrono::seconds>().count(); 125 : 126 0 : if (IsSynced()) 127 0 : return; 128 : 129 0 : if (!IsBlockchainSynced()) { 130 : // Postpone timeout each time new block arrives while we are still syncing blockchain 131 0 : BumpAssetLastTime("CMasternodeSync::UpdatedBlockTip"); 132 0 : } 133 : 134 0 : if (fInitialDownload) { 135 : // switched too early 136 0 : if (IsBlockchainSynced()) { 137 0 : Reset(true); 138 0 : } 139 : 140 : // no need to check any further while still in IBD mode 141 0 : return; 142 : } 143 : 144 : // Note: since we sync headers first, it should be ok to use this 145 0 : if (pindexTip == nullptr) return; 146 0 : bool fReachedBestHeaderNew = pindexNew->GetBlockHash() == pindexTip->GetBlockHash(); 147 : 148 0 : if (fReachedBestHeader && !fReachedBestHeaderNew) { 149 : // Switching from true to false means that we previously stuck syncing headers for some reason, 150 : // probably initial timeout was not enough, 151 : // because there is no way we can update tip not having best header 152 0 : Reset(true); 153 0 : } 154 : 155 0 : fReachedBestHeader = fReachedBestHeaderNew; 156 0 : LogPrint(BCLog::MNSYNC, "CMasternodeSync::UpdatedBlockTip -- pindexNew->nHeight: %d pindexTip->nHeight: %d fInitialDownload=%d fReachedBestHeader=%d\n", 157 : pindexNew->nHeight, pindexTip->nHeight, fInitialDownload, fReachedBestHeader); 158 0 : }