PIVX Core  5.6.99
P2P Digital Currency
masternode-sync.cpp
Go to the documentation of this file.
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"
16 #include "spork.h"
18 #include "util/system.h"
19 #include "validation.h"
20 // clang-format on
21 
22 class CMasternodeSync;
24 
26 {
27  Reset();
28 }
29 
31 {
32  return (!g_tiertwo_sync_state.IsSynced() && (
37 }
38 
40 {
41  if (!isRegTestNet && !g_tiertwo_sync_state.CanUpdateChainSync(lastProcess)) return;
42  if (fImporting || fReindex) return;
43 
44  int64_t blockTime = 0;
45  {
47  if (!lock) return;
48  blockTime = g_best_block_time;
49  }
50 
51  // Synced only if the last block happened in the last 60 minutes
52  bool is_chain_synced = blockTime + 60 * 60 > lastProcess;
54 }
55 
57 {
60  lastProcess = 0;
61  lastFailure = 0;
62  nCountFailures = 0;
66  sumBudgetItemFin = 0;
74 }
75 
77 {
78  return sumBudgetItemProp == 0 && countBudgetItemProp > 0;
79 }
80 
82 {
83  return sumBudgetItemFin == 0 && countBudgetItemFin > 0;
84 }
85 
86 int CMasternodeSync::GetNextAsset(int currentAsset)
87 {
88  if (currentAsset > MASTERNODE_SYNC_FINISHED) {
89  LogPrintf("%s - invalid asset %d\n", __func__, currentAsset);
91  }
92  switch (currentAsset) {
98  case (MASTERNODE_SYNC_LIST):
100  case (MASTERNODE_SYNC_MNW):
101  return MASTERNODE_SYNC_BUDGET;
102  case (MASTERNODE_SYNC_BUDGET):
103  default:
105  }
106 }
107 
109 {
110  int RequestedMasternodeAssets = g_tiertwo_sync_state.GetSyncPhase();
111  if (RequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL ||
112  RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED) {
114  }
115  const int nextAsset = GetNextAsset(RequestedMasternodeAssets);
116  if (nextAsset == MASTERNODE_SYNC_FINISHED) {
117  LogPrintf("%s - Sync has finished\n", __func__);
118  }
122 }
123 
125 {
128  return _("MNs synchronization pending...");
130  return _("Synchronizing sporks...");
132  return _("Synchronizing masternodes...");
133  case MASTERNODE_SYNC_MNW:
134  return _("Synchronizing masternode winners...");
136  return _("Synchronizing budgets...");
138  return _("Synchronization failed");
140  return _("Synchronization finished");
141  }
142  return "";
143 }
144 
145 void CMasternodeSync::ProcessSyncStatusMsg(int nItemID, int nCount)
146 {
147  int RequestedMasternodeAssets = g_tiertwo_sync_state.GetSyncPhase();
148  if (RequestedMasternodeAssets >= MASTERNODE_SYNC_FINISHED) return;
149 
150  //this means we will receive no further communication
151  switch (nItemID) {
152  case (MASTERNODE_SYNC_LIST):
153  if (nItemID != RequestedMasternodeAssets) return;
154  sumMasternodeList += nCount;
156  break;
157  case (MASTERNODE_SYNC_MNW):
158  if (nItemID != RequestedMasternodeAssets) return;
159  sumMasternodeWinner += nCount;
161  break;
163  if (RequestedMasternodeAssets != MASTERNODE_SYNC_BUDGET) return;
164  sumBudgetItemProp += nCount;
166  break;
168  if (RequestedMasternodeAssets != MASTERNODE_SYNC_BUDGET) return;
169  sumBudgetItemFin += nCount;
171  break;
172  default:
173  break;
174  }
175 
176  LogPrint(BCLog::MASTERNODE, "CMasternodeSync:ProcessMessage - ssc - got inventory count %d %d\n", nItemID, nCount);
177 }
178 
180 {
182 }
183 
185 {
186  static int tick = 0;
187  const bool isRegTestNet = Params().IsRegTestNet();
188 
189  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  int64_t now = GetTime();
194  if (lastProcess != 0 && now > lastProcess + 60 * 60) {
195  Reset();
196  }
197  lastProcess = now;
198 
199  // Update chain sync status using the 'lastProcess' time
200  UpdateBlockchainSynced(isRegTestNet);
201 
203  if (isRegTestNet) {
204  return;
205  }
206  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  if ((!legacy_obsolete && mnodeman.CountEnabled(true /* only_legacy */) <= 1) ||
211  (legacy_obsolete && g_budgetman.CountProposals() == 0)) {
212  Reset();
213  } else {
214  return;
215  }
216  }
217 
218  // Try syncing again
219  int RequestedMasternodeAssets = g_tiertwo_sync_state.GetSyncPhase();
220  if (RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED && lastFailure + (1 * 60) < GetTime()) {
221  Reset();
222  } else if (RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED) {
223  return;
224  }
225 
226  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
230  RequestedMasternodeAssets > MASTERNODE_SYNC_SPORKS) return;
231 
232  // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
233  bool fLegacyMnObsolete = deterministicMNManager->LegacyMNObsolete();
234 
235  CMasternodeSync* sync = this;
236 
237  // New sync architecture, regtest only for now.
238  if (isRegTestNet) {
239  g_connman->ForEachNode([sync](CNode* pnode){
240  return sync->SyncRegtest(pnode);
241  });
242  return;
243  }
244 
245  // Mainnet sync
246  g_connman->ForEachNodeInRandomOrderContinueIf([sync, fLegacyMnObsolete](CNode* pnode){
247  return sync->SyncWithNode(pnode, fLegacyMnObsolete);
248  });
249 }
250 
251 void CMasternodeSync::syncTimeout(const std::string& reason)
252 {
253  LogPrintf("%s - ERROR - Sync has failed on %s, will retry later\n", __func__, reason);
256  lastFailure = GetTime();
257  nCountFailures++;
258 }
259 
260 bool CMasternodeSync::SyncWithNode(CNode* pnode, bool fLegacyMnObsolete)
261 {
262  int RequestedMasternodeAssets = g_tiertwo_sync_state.GetSyncPhase();
263  CNetMsgMaker msgMaker(pnode->GetSendVersion());
264 
265  //set to synced
266  if (RequestedMasternodeAssets == MASTERNODE_SYNC_SPORKS) {
267 
268  // Sync sporks from at least 2 peers
271  return false;
272  }
273 
274  // Request sporks sync if we haven't requested it yet.
275  if (g_netfulfilledman.HasFulfilledRequest(pnode->addr, "getspork")) return true;
276  g_netfulfilledman.AddFulfilledRequest(pnode->addr, "getspork");
277 
278  g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::GETSPORKS));
280  return false;
281  }
282 
283  if (pnode->nVersion < ActiveProtocol() || !pnode->CanRelay()) {
284  return true; // move to next peer
285  }
286 
287  if (RequestedMasternodeAssets == MASTERNODE_SYNC_LIST) {
288  if (fLegacyMnObsolete) {
290  return false;
291  }
292 
293  int lastMasternodeList = g_tiertwo_sync_state.GetlastMasternodeList();
294  LogPrint(BCLog::MASTERNODE, "CMasternodeSync::Process() - lastMasternodeList %lld (GetTime() - MASTERNODE_SYNC_TIMEOUT) %lld\n", lastMasternodeList, GetTime() - MASTERNODE_SYNC_TIMEOUT);
295  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.
299  return false;
300  }
301 
302  // timeout
303  if (lastMasternodeList == 0 &&
306  syncTimeout("MASTERNODE_SYNC_LIST");
307  } else {
309  }
310  return false;
311  }
312 
313  // Don't request mnlist initial sync to more than 8 randomly ordered peers in this round
314  if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 4) return false;
315 
316  // Request mnb sync if we haven't requested it yet.
317  if (g_netfulfilledman.HasFulfilledRequest(pnode->addr, "mnsync")) return true;
318 
319  // Try to request MN list sync.
320  if (!mnodeman.RequestMnList(pnode)) {
321  return true; // Failed, try next peer.
322  }
323 
324  // Mark sync requested.
325  g_netfulfilledman.AddFulfilledRequest(pnode->addr, "mnsync");
326  // Increase the sync attempt count
328 
329  return false; // sleep 1 second before do another request round.
330  }
331 
332  if (RequestedMasternodeAssets == MASTERNODE_SYNC_MNW) {
333  if (fLegacyMnObsolete) {
335  return false;
336  }
337 
338  int lastMasternodeWinner = g_tiertwo_sync_state.GetlastMasternodeWinner();
339  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
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.
345  return false;
346  }
347 
348  // timeout
349  if (lastMasternodeWinner == 0 &&
352  syncTimeout("MASTERNODE_SYNC_MNW");
353  } else {
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.
360  }
361  return false;
362  }
363 
364  // Don't request mnw initial sync to more than 4 randomly ordered peers in this round.
365  if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 2) return false;
366 
367  // Request mnw sync if we haven't requested it yet.
368  if (g_netfulfilledman.HasFulfilledRequest(pnode->addr, "mnwsync")) return true;
369 
370  // Mark sync requested.
371  g_netfulfilledman.AddFulfilledRequest(pnode->addr, "mnwsync");
372 
373  // Sync mn winners
374  int nMnCount = mnodeman.CountEnabled(true /* only_legacy */);
375  g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::GETMNWINNERS, nMnCount));
377 
378  return false; // sleep 1 second before do another request round.
379  }
380 
381  if (RequestedMasternodeAssets == MASTERNODE_SYNC_BUDGET) {
382  int lastBudgetItem = g_tiertwo_sync_state.GetlastBudgetItem();
383  // We'll start rejecting votes if we accidentally get set as synced too soon
384  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
388 
389  // Try to activate our masternode if possible
391  return false;
392  }
393 
394  // timeout
395  if (lastBudgetItem == 0 &&
397  // maybe there is no budgets at all, so just finish syncing
400  return false;
401  }
402 
403  // Don't request budget initial sync to more than 6 randomly ordered peers in this round.
404  if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3) return false;
405 
406  // Request bud sync if we haven't requested it yet.
407  if (g_netfulfilledman.HasFulfilledRequest(pnode->addr, "busync")) return true;
408 
409  // Mark sync requested.
410  g_netfulfilledman.AddFulfilledRequest(pnode->addr, "busync");
411 
412  // Sync proposals, finalizations and votes
413  uint256 n;
414  g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::BUDGETVOTESYNC, n));
416 
417  return false; // sleep 1 second before do another request round.
418  }
419 
420  return true;
421 }
CBudgetManager g_budgetman
const CChainParams & Params()
Return the currently selected parameters.
void ManageStatus()
Manage status of main Masternode.
bool IsRegTestNet() const
Definition: chainparams.h:98
int CountEnabled(bool only_legacy=false) const
bool RequestMnList(CNode *pnode)
void ProcessSyncStatusMsg(int nItemID, int itemCount)
void UpdateBlockchainSynced(bool isRegTestNet)
bool SyncWithNode(CNode *pnode, bool fLegacyMnObsolete)
static int GetNextAsset(int currentAsset)
int RequestedMasternodeAttempt
void SyncRegtest(CNode *pnode)
std::atomic< int64_t > lastProcess
int64_t nAssetSyncStarted
std::string GetSyncStatus()
void syncTimeout(const std::string &reason)
void AddFulfilledRequest(const CService &addr, const std::string &strRequest)
bool HasFulfilledRequest(const CService &addr, const std::string &strRequest) const
CSerializedNetMsg Make(int nFlags, std::string sCommand, Args &&... args)
Information about a peer.
Definition: net.h:669
std::atomic< int > nVersion
Definition: net.h:699
int GetSendVersion() const
Definition: net.cpp:789
const CAddress addr
Definition: net.h:698
bool CanRelay() const
Definition: net.h:946
bool IsSporkActive(SporkId nSporkID)
Definition: spork.cpp:220
bool IsSporkListSynced() const
bool IsBlockchainSynced() const
bool IsSynced() const
int64_t GetlastMasternodeWinner() const
int64_t GetlastMasternodeList() const
int GetSyncPhase() const
bool CanUpdateChainSync(int64_t cur_time) const
void SetBlockchainSync(bool f, int64_t cur_time)
void SetCurrentSyncPhase(int sync_phase)
int64_t GetlastBudgetItem() const
256-bit opaque blob.
Definition: uint256.h:138
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:90
#define LogPrint(category,...)
Definition: logging.h:163
CMasternodeSync masternodeSync
#define MASTERNODE_SYNC_TIMEOUT
CMasternodeMan mnodeman
Masternode manager.
CActiveMasternode activeMasternode
Keep track of the active Masternode.
@ MASTERNODE
Definition: logging.h:59
const char * BUDGETVOTESYNC
The budgetvotesync message is used to request budget vote data from connected peers.
Definition: protocol.cpp:51
const char * GETMNWINNERS
The getmnwinners message is used to request winning masternode data from connected peers.
Definition: protocol.cpp:48
const char * GETSPORKS
The getsporks message is used to request spork data from connected peers.
Definition: protocol.cpp:43
CNetFulfilledRequestManager g_netfulfilledman(DEFAULT_ITEMS_FILTER_SIZE)
CSporkManager sporkManager
Definition: spork.cpp:29
@ SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT
Definition: sporkid.h:19
@ SPORK_13_ENABLE_SUPERBLOCKS
Definition: sporkid.h:20
@ SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT
Definition: sporkid.h:18
#define TRY_LOCK(cs, name)
Definition: sync.h:224
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a Optional result.
Definition: system.h:65
TierTwoSyncState g_tiertwo_sync_state
#define MASTERNODE_SYNC_MNW
#define MASTERNODE_SYNC_SPORKS
#define MASTERNODE_SYNC_BUDGET_PROP
#define MASTERNODE_SYNC_BUDGET
#define MASTERNODE_SYNC_THRESHOLD
#define MASTERNODE_SYNC_INITIAL
#define MASTERNODE_SYNC_BUDGET_FIN
#define MASTERNODE_SYNC_FINISHED
#define MASTERNODE_SYNC_FAILED
#define MASTERNODE_SYNC_LIST
int64_t GetTime()
DEPRECATED Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)
Definition: utiltime.cpp:27
int ActiveProtocol()
See whether the protocol update is enforced for connected nodes.
int64_t g_best_block_time
Definition: validation.cpp:91
std::atomic< bool > fImporting
Definition: validation.cpp:94
Mutex g_best_block_mutex
Definition: validation.cpp:88
std::atomic< bool > fReindex
Definition: validation.cpp:95