Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

masternode-sync.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2020 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 
7 #include <init.h>
8 #include <validation.h>
11 #include <netfulfilledman.h>
12 #include <netmessagemaker.h>
13 #include <ui_interface.h>
14 #include <evo/deterministicmns.h>
15 
18 
19 void CMasternodeSync::Reset(bool fForce, bool fNotifyReset)
20 {
21  // Avoid resetting the sync process if we just "recently" received a new block
24  nTriedPeerCount = 0;
28  fReachedBestHeader = false;
29  if (fNotifyReset) {
31  }
32  }
33 }
34 
35 void CMasternodeSync::BumpAssetLastTime(const std::string& strFuncName)
36 {
37  if (IsSynced()) return;
39  LogPrint(BCLog::MNSYNC, "CMasternodeSync::BumpAssetLastTime -- %s\n", strFuncName);
40 }
41 
43 {
44  switch(nCurrentAsset)
45  {
46  case(MASTERNODE_SYNC_BLOCKCHAIN): return "MASTERNODE_SYNC_BLOCKCHAIN";
47  case(MASTERNODE_SYNC_GOVERNANCE): return "MASTERNODE_SYNC_GOVERNANCE";
48  case MASTERNODE_SYNC_FINISHED: return "MASTERNODE_SYNC_FINISHED";
49  default: return "UNKNOWN";
50  }
51 }
52 
54 {
55  switch(nCurrentAsset)
56  {
58  LogPrintf("CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted);
60  LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName());
61  break;
63  LogPrintf("CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted);
66 
67  connman.ForEachNode(CConnman::AllNodes, [](CNode* pnode) {
68  netfulfilledman.AddFulfilledRequest(pnode->addr, "full-sync");
69  });
70  LogPrintf("CMasternodeSync::SwitchToNextAsset -- Sync has finished\n");
71 
72  break;
73  }
74  nTriedPeerCount = 0;
76  BumpAssetLastTime("CMasternodeSync::SwitchToNextAsset");
77 }
78 
80 {
81  switch (masternodeSync.nCurrentAsset) {
82  case MASTERNODE_SYNC_BLOCKCHAIN: return _("Synchronizing blockchain...");
83  case MASTERNODE_SYNC_GOVERNANCE: return _("Synchronizing governance objects...");
84  case MASTERNODE_SYNC_FINISHED: return _("Synchronization finished");
85  default: return "";
86  }
87 }
88 
89 void CMasternodeSync::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv)
90 {
91  if (strCommand == NetMsgType::SYNCSTATUSCOUNT) { //Sync status count
92 
93  //do not care about stats if sync process finished
94  if (IsSynced()) return;
95 
96  int nItemID;
97  int nCount;
98  vRecv >> nItemID >> nCount;
99 
100  LogPrintf("SYNCSTATUSCOUNT -- got inventory count: nItemID=%d nCount=%d peer=%d\n", nItemID, nCount, pfrom->GetId());
101  }
102 }
103 
105 {
106  static int nTick = 0;
107  nTick++;
108 
109  const static int64_t nSyncStart = GetTimeMillis();
110  const static std::string strAllow = strprintf("allow-sync-%lld", nSyncStart);
111 
112  // reset the sync process if the last call to this function was more than 60 minutes ago (client was in sleep mode)
113  static int64_t nTimeLastProcess = GetTime();
114  if(GetTime() - nTimeLastProcess > 60*60 && !fMasternodeMode) {
115  LogPrintf("CMasternodeSync::ProcessTick -- WARNING: no actions for too long, restarting sync...\n");
116  Reset(true);
117  nTimeLastProcess = GetTime();
118  return;
119  }
120 
121  if(GetTime() - nTimeLastProcess < MASTERNODE_SYNC_TICK_SECONDS) {
122  // too early, nothing to do here
123  return;
124  }
125 
126  nTimeLastProcess = GetTime();
127 
128  // gradually request the rest of the votes after sync finished
129  if(IsSynced()) {
130  std::vector<CNode*> vNodesCopy = connman.CopyNodeVector(CConnman::FullyConnectedOnly);
131  governance.RequestGovernanceObjectVotes(vNodesCopy, connman);
132  connman.ReleaseNodeVector(vNodesCopy);
133  return;
134  }
135 
136  // Calculate "progress" for LOG reporting / GUI notification
137  double nSyncProgress = double(nTriedPeerCount + (nCurrentAsset - 1) * 8) / (8*4);
138  LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d nTriedPeerCount %d nSyncProgress %f\n", nTick, nCurrentAsset, nTriedPeerCount, nSyncProgress);
140 
141  std::vector<CNode*> vNodesCopy = connman.CopyNodeVector(CConnman::FullyConnectedOnly);
142 
143  for (auto& pnode : vNodesCopy)
144  {
145  CNetMsgMaker msgMaker(pnode->GetSendVersion());
146 
147  // Don't try to sync any data from outbound "masternode" connections -
148  // they are temporary and should be considered unreliable for a sync process.
149  // Inbound connection this early is most likely a "masternode" connection
150  // initiated from another node, so skip it too.
151  if(pnode->fMasternode || (fMasternodeMode && pnode->fInbound)) continue;
152 
153  // QUICK MODE (REGTEST ONLY!)
155  {
157  connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETSPORKS)); //get current network sporks
158  SwitchToNextAsset(connman);
160  SendGovernanceSyncRequest(pnode, connman);
161  SwitchToNextAsset(connman);
162  }
163  connman.ReleaseNodeVector(vNodesCopy);
164  return;
165  }
166 
167  // NORMAL NETWORK MODE - TESTNET/MAINNET
168  {
169  if ((pnode->fWhitelisted || pnode->m_manual_connection) && !netfulfilledman.HasFulfilledRequest(pnode->addr, strAllow)) {
171  netfulfilledman.AddFulfilledRequest(pnode->addr, strAllow);
172  LogPrintf("CMasternodeSync::ProcessTick -- skipping mnsync restrictions for peer=%d\n", pnode->GetId());
173  }
174 
175  if(netfulfilledman.HasFulfilledRequest(pnode->addr, "full-sync")) {
176  // We already fully synced from this node recently,
177  // disconnect to free this connection slot for another peer.
178  pnode->fDisconnect = true;
179  LogPrintf("CMasternodeSync::ProcessTick -- disconnecting from recently synced peer=%d\n", pnode->GetId());
180  continue;
181  }
182 
183  // SPORK : ALWAYS ASK FOR SPORKS AS WE SYNC
184 
185  if(!netfulfilledman.HasFulfilledRequest(pnode->addr, "spork-sync")) {
186  // always get sporks first, only request once from each peer
187  netfulfilledman.AddFulfilledRequest(pnode->addr, "spork-sync");
188  // get current network sporks
189  connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETSPORKS));
190  LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d -- requesting sporks from peer=%d\n", nTick, nCurrentAsset, pnode->GetId());
191  }
192 
194  int64_t nTimeSyncTimeout = vNodesCopy.size() > 3 ? MASTERNODE_SYNC_TICK_SECONDS : MASTERNODE_SYNC_TIMEOUT_SECONDS;
195  if (fReachedBestHeader && (GetTime() - nTimeLastBumped > nTimeSyncTimeout)) {
196  // At this point we know that:
197  // a) there are peers (because we are looping on at least one of them);
198  // b) we waited for at least MASTERNODE_SYNC_TICK_SECONDS/MASTERNODE_SYNC_TIMEOUT_SECONDS
199  // (depending on the number of connected peers) since we reached the headers tip the last
200  // time (i.e. since fReachedBestHeader has been set to true);
201  // c) there were no blocks (UpdatedBlockTip, NotifyHeaderTip) or headers (AcceptedBlockHeader)
202  // for at least MASTERNODE_SYNC_TICK_SECONDS/MASTERNODE_SYNC_TIMEOUT_SECONDS (depending on
203  // the number of connected peers).
204  // We must be at the tip already, let's move to the next asset.
205  SwitchToNextAsset(connman);
207 
208  if (gArgs.GetBoolArg("-syncmempool", DEFAULT_SYNC_MEMPOOL)) {
209  // Now that the blockchain is synced request the mempool from the connected outbound nodes if possible
210  for (auto pNodeTmp : vNodesCopy) {
211  bool fRequestedEarlier = netfulfilledman.HasFulfilledRequest(pNodeTmp->addr, "mempool-sync");
212  if (pNodeTmp->nVersion >= 70216 && !pNodeTmp->fInbound && !fRequestedEarlier) {
213  netfulfilledman.AddFulfilledRequest(pNodeTmp->addr, "mempool-sync");
214  connman.PushMessage(pNodeTmp, msgMaker.Make(NetMsgType::MEMPOOL));
215  LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d -- syncing mempool from peer=%d\n", nTick, nCurrentAsset, pNodeTmp->GetId());
216  }
217  }
218  }
219  }
220  }
221 
222  // GOVOBJ : SYNC GOVERNANCE ITEMS FROM OUR PEERS
223 
225  if (fDisableGovernance) {
226  SwitchToNextAsset(connman);
227  connman.ReleaseNodeVector(vNodesCopy);
228  return;
229  }
230  LogPrint(BCLog::GOBJECT, "CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d nTimeLastBumped %lld GetTime() %lld diff %lld\n", nTick, nCurrentAsset, nTimeLastBumped, GetTime(), GetTime() - nTimeLastBumped);
231 
232  // check for timeout first
234  LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d -- timeout\n", nTick, nCurrentAsset);
235  if(nTriedPeerCount == 0) {
236  LogPrintf("CMasternodeSync::ProcessTick -- WARNING: failed to sync %s\n", GetAssetName());
237  // it's kind of ok to skip this for now, hopefully we'll catch up later?
238  }
239  SwitchToNextAsset(connman);
240  connman.ReleaseNodeVector(vNodesCopy);
241  return;
242  }
243 
244  // only request obj sync once from each peer, then request votes on per-obj basis
245  if(netfulfilledman.HasFulfilledRequest(pnode->addr, "governance-sync")) {
246  int nObjsLeftToAsk = governance.RequestGovernanceObjectVotes(pnode, connman);
247  static int64_t nTimeNoObjectsLeft = 0;
248  // check for data
249  if(nObjsLeftToAsk == 0) {
250  static int nLastTick = 0;
251  static int nLastVotes = 0;
252  if(nTimeNoObjectsLeft == 0) {
253  // asked all objects for votes for the first time
254  nTimeNoObjectsLeft = GetTime();
255  }
256  // make sure the condition below is checked only once per tick
257  if(nLastTick == nTick) continue;
258  if(GetTime() - nTimeNoObjectsLeft > MASTERNODE_SYNC_TIMEOUT_SECONDS &&
259  governance.GetVoteCount() - nLastVotes < std::max(int(0.0001 * nLastVotes), MASTERNODE_SYNC_TICK_SECONDS)
260  ) {
261  // We already asked for all objects, waited for MASTERNODE_SYNC_TIMEOUT_SECONDS
262  // after that and less then 0.01% or MASTERNODE_SYNC_TICK_SECONDS
263  // (i.e. 1 per second) votes were recieved during the last tick.
264  // We can be pretty sure that we are done syncing.
265  LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d -- asked for all objects, nothing to do\n", nTick, nCurrentAsset);
266  // reset nTimeNoObjectsLeft to be able to use the same condition on resync
267  nTimeNoObjectsLeft = 0;
268  SwitchToNextAsset(connman);
269  connman.ReleaseNodeVector(vNodesCopy);
270  return;
271  }
272  nLastTick = nTick;
273  nLastVotes = governance.GetVoteCount();
274  }
275  continue;
276  }
277  netfulfilledman.AddFulfilledRequest(pnode->addr, "governance-sync");
278 
279  if (pnode->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) continue;
280  nTriedPeerCount++;
281 
282  SendGovernanceSyncRequest(pnode, connman);
283 
284  connman.ReleaseNodeVector(vNodesCopy);
285  return; //this will cause each peer to get one request each six seconds for the various assets we need
286  }
287  }
288  }
289  // looped through all nodes, release them
290  connman.ReleaseNodeVector(vNodesCopy);
291 }
292 
294 {
295  CNetMsgMaker msgMaker(pnode->GetSendVersion());
296 
298  CBloomFilter filter;
299  filter.clear();
300 
301  connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MNGOVERNANCESYNC, uint256(), filter));
302  }
303  else {
304  connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MNGOVERNANCESYNC, uint256()));
305  }
306 }
307 
309 {
310  LogPrint(BCLog::MNSYNC, "CMasternodeSync::AcceptedBlockHeader -- pindexNew->nHeight: %d\n", pindexNew->nHeight);
311 
312  if (!IsBlockchainSynced()) {
313  // Postpone timeout each time new block header arrives while we are still syncing blockchain
314  BumpAssetLastTime("CMasternodeSync::AcceptedBlockHeader");
315  }
316 }
317 
318 void CMasternodeSync::NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload, CConnman& connman)
319 {
320  LogPrint(BCLog::MNSYNC, "CMasternodeSync::NotifyHeaderTip -- pindexNew->nHeight: %d fInitialDownload=%d\n", pindexNew->nHeight, fInitialDownload);
321 
322  if (IsSynced() || !pindexBestHeader)
323  return;
324 
325  if (!IsBlockchainSynced()) {
326  // Postpone timeout each time new block arrives while we are still syncing blockchain
327  BumpAssetLastTime("CMasternodeSync::NotifyHeaderTip");
328  }
329 }
330 
331 void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDownload, CConnman& connman)
332 {
333  LogPrint(BCLog::MNSYNC, "CMasternodeSync::UpdatedBlockTip -- pindexNew->nHeight: %d fInitialDownload=%d\n", pindexNew->nHeight, fInitialDownload);
334 
336 
337  if (IsSynced() || !pindexBestHeader)
338  return;
339 
340  if (!IsBlockchainSynced()) {
341  // Postpone timeout each time new block arrives while we are still syncing blockchain
342  BumpAssetLastTime("CMasternodeSync::UpdatedBlockTip");
343  }
344 
345  if (fInitialDownload) {
346  // switched too early
347  if (IsBlockchainSynced()) {
348  Reset(true);
349  }
350 
351  // no need to check any further while still in IBD mode
352  return;
353  }
354 
355  // Note: since we sync headers first, it should be ok to use this
356  bool fReachedBestHeaderNew = pindexNew->GetBlockHash() == pindexBestHeader->GetBlockHash();
357 
358  if (fReachedBestHeader && !fReachedBestHeaderNew) {
359  // Switching from true to false means that we previousely stuck syncing headers for some reason,
360  // probably initial timeout was not enough,
361  // because there is no way we can update tip not having best header
362  Reset(true);
363  }
364 
365  fReachedBestHeader = fReachedBestHeaderNew;
366 
367  LogPrint(BCLog::MNSYNC, "CMasternodeSync::UpdatedBlockTip -- pindexNew->nHeight: %d pindexBestHeader->nHeight: %d fInitialDownload=%d fReachedBestHeader=%d\n",
368  pindexNew->nHeight, pindexBestHeader->nHeight, fInitialDownload, fReachedBestHeader);
369 }
370 
372 {
373  if (ShutdownRequested()) return;
374 
375  ProcessTick(connman);
376 }
void SwitchToNextAsset(CConnman &connman)
bool HasFulfilledRequest(const CService &addr, const std::string &strRequest)
std::string NetworkIDString() const
Return the BIP70 network string (main, test or regtest)
Definition: chainparams.h:76
static constexpr const CAllNodes AllNodes
Definition: net.h:225
CMasternodeSync masternodeSync
int GetSendVersion() const
Definition: net.cpp:887
static const std::string REGTEST
int64_t nTimeLastUpdateBlockTip
Last time UpdateBlockTip has been called.
static const int MASTERNODE_SYNC_RESET_SECONDS
bool ShutdownRequested()
Definition: init.cpp:179
#define strprintf
Definition: tinyformat.h:1066
static const int MIN_GOVERNANCE_PEER_PROTO_VERSION
void ProcessTick(CConnman &connman)
BloomFilter is a probabilistic filter which SPV clients provide so that we can filter the transaction...
Definition: bloom.h:46
void PushMessage(CNode *pnode, CSerializedNetMsg &&msg)
Definition: net.cpp:3733
void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload, CConnman &connman)
static const int MASTERNODE_SYNC_BLOCKCHAIN
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:103
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: util.cpp:824
bool IsBlockchainSynced()
static const int MASTERNODE_SYNC_FINISHED
static const int MASTERNODE_SYNC_GOVERNANCE
static constexpr const CFullyConnectedOnly FullyConnectedOnly
Definition: net.h:219
boost::signals2::signal< void(double nSyncProgress)> NotifyAdditionalDataSyncProgressChanged
Additional data sync progress changed.
Definition: ui_interface.h:114
void ForEachNode(const Condition &cond, Callable &&func)
Definition: net.h:288
uint256 GetBlockHash() const
Definition: chain.h:292
int64_t nTimeAssetSyncStarted
CGovernanceManager governance
Definition: governance.cpp:23
int64_t GetTime()
Return system time (or mocked time, if set)
Definition: utiltime.cpp:22
bool fMasternodeMode
Definition: util.cpp:93
#define LogPrintf(...)
Definition: util.h:203
CBlockIndex * pindexBestHeader
Best header we&#39;ve seen so far (used for getheaders queries&#39; starting points).
Definition: validation.cpp:218
static const int MASTERNODE_SYNC_TIMEOUT_SECONDS
void BumpAssetLastTime(const std::string &strFuncName)
std::string GetSyncStatus()
void AcceptedBlockHeader(const CBlockIndex *pindexNew)
std::string GetAssetName()
int RequestGovernanceObjectVotes(CNode *pnode, CConnman &connman)
Definition: governance.cpp:959
void clear()
Definition: bloom.cpp:125
const char * MEMPOOL
The mempool message requests the TXIDs of transactions that the receiving node has verified as valid ...
Definition: protocol.cpp:30
const char * GETSPORKS
Definition: protocol.cpp:46
int64_t nTimeLastBumped
int GetVoteCount() const
Definition: governance.cpp:74
Definition: net.h:136
NodeId GetId() const
Definition: net.h:973
const char * MNGOVERNANCESYNC
Definition: protocol.cpp:57
static const bool DEFAULT_SYNC_MEMPOOL
Default for -syncmempool.
Definition: validation.h:130
void DoMaintenance(CConnman &connman)
static const int GOVERNANCE_FILTER_PROTO_VERSION
const CAddress addr
Definition: net.h:834
const char * SYNCSTATUSCOUNT
Definition: protocol.cpp:56
#define LogPrint(category,...)
Definition: util.h:214
static const int MASTERNODE_SYNC_TICK_SECONDS
void ProcessMessage(CNode *pfrom, const std::string &strCommand, CDataStream &vRecv)
256-bit opaque blob.
Definition: uint256.h:123
ArgsManager gArgs
Definition: util.cpp:108
void ReleaseNodeVector(const std::vector< CNode *> &vecNodes)
Definition: net.cpp:3850
bool fReachedBestHeader
Set to true if best header is reached in CMasternodeSync::UpdatedBlockTip.
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:170
const CChainParams & Params()
Return the currently selected parameters.
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: utiltime.cpp:56
int64_t GetAdjustedTime()
Definition: timedata.cpp:35
void UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDownload, CConnman &connman)
CNetFulfilledRequestManager netfulfilledman
std::atomic< int > nVersion
Definition: net.h:838
std::vector< CNode * > CopyNodeVector(std::function< bool(const CNode *pnode)> cond)
Definition: net.cpp:3830
CClientUIInterface uiInterface
Definition: ui_interface.cpp:8
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:183
Information about a peer.
Definition: net.h:800
bool fDisableGovernance
Definition: util.cpp:94
void SendGovernanceSyncRequest(CNode *pnode, CConnman &connman)
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a boost::optional result...
Definition: util.h:92
void AddFulfilledRequest(const CService &addr, const std::string &strRequest)
void RemoveAllFulfilledRequests(const CService &addr)
void Reset(bool fForce=false, bool fNotifyReset=true)
Released under the MIT license