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 : }