@@ -139,23 +139,22 @@ void CMasternodeSync::ProcessTick(CConnman& connman)
139139 }
140140
141141 nTimeLastProcess = GetTime ();
142+ std::vector<CNode*> vNodesCopy = connman.CopyNodeVector (CConnman::FullyConnectedOnly);
142143
143144 // gradually request the rest of the votes after sync finished
144145 if (IsSynced ()) {
145- std::vector<CNode*> vNodesCopy = connman.CopyNodeVector (CConnman::FullyConnectedOnly);
146146 governance.RequestGovernanceObjectVotes (vNodesCopy, connman);
147147 connman.ReleaseNodeVector (vNodesCopy);
148148 return ;
149149 }
150150
151+ {
151152 LOCK (cs);
152153 // Calculate "progress" for LOG reporting / GUI notification
153154 double nSyncProgress = double (nTriedPeerCount + (nCurrentAsset - 1 ) * 8 ) / (8 *4 );
154155 LogPrint (BCLog::MNSYNC, " CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d nTriedPeerCount %d nSyncProgress %f\n " , nTick, nCurrentAsset, nTriedPeerCount, nSyncProgress);
155156 uiInterface.NotifyAdditionalDataSyncProgressChanged (nSyncProgress);
156157
157- std::vector<CNode*> vNodesCopy = connman.CopyNodeVector (CConnman::FullyConnectedOnly);
158-
159158 for (auto & pnode : vNodesCopy)
160159 {
161160 CNetMsgMaker msgMaker (pnode->GetSendVersion ());
@@ -256,37 +255,10 @@ void CMasternodeSync::ProcessTick(CConnman& connman)
256255 return ;
257256 }
258257
259- // only request obj sync once from each peer, then request votes on per-obj basis
258+ // only request obj sync once from each peer
260259 if (netfulfilledman.HasFulfilledRequest (pnode->addr , " governance-sync" )) {
261- int nObjsLeftToAsk = governance.RequestGovernanceObjectVotes (pnode, connman);
262- static int64_t nTimeNoObjectsLeft = 0 ;
263- // check for data
264- if (nObjsLeftToAsk == 0 ) {
265- static int nLastTick = 0 ;
266- static int nLastVotes = 0 ;
267- if (nTimeNoObjectsLeft == 0 ) {
268- // asked all objects for votes for the first time
269- nTimeNoObjectsLeft = GetTime ();
270- }
271- // make sure the condition below is checked only once per tick
272- if (nLastTick == nTick) continue ;
273- if (GetTime () - nTimeNoObjectsLeft > MASTERNODE_SYNC_TIMEOUT_SECONDS &&
274- governance.GetVoteCount () - nLastVotes < std::max (int (0.0001 * nLastVotes), MASTERNODE_SYNC_TICK_SECONDS)
275- ) {
276- // We already asked for all objects, waited for MASTERNODE_SYNC_TIMEOUT_SECONDS
277- // after that and less then 0.01% or MASTERNODE_SYNC_TICK_SECONDS
278- // (i.e. 1 per second) votes were received during the last tick.
279- // We can be pretty sure that we are done syncing.
280- LogPrintf (" CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d -- asked for all objects, nothing to do\n " , nTick, nCurrentAsset);
281- // reset nTimeNoObjectsLeft to be able to use the same condition on resync
282- nTimeNoObjectsLeft = 0 ;
283- SwitchToNextAsset (connman);
284- connman.ReleaseNodeVector (vNodesCopy);
285- return ;
286- }
287- nLastTick = nTick;
288- nLastVotes = governance.GetVoteCount ();
289- }
260+ // will request votes on per-obj basis from each node in a separate loop below
261+ // to avoid deadlocks here
290262 continue ;
291263 }
292264 netfulfilledman.AddFulfilledRequest (pnode->addr , " governance-sync" );
@@ -296,11 +268,55 @@ void CMasternodeSync::ProcessTick(CConnman& connman)
296268
297269 SendGovernanceSyncRequest (pnode, connman);
298270
271+ break ; // this will cause each peer to get one request each six seconds for the various assets we need
272+ }
273+ }
274+ }
275+ } // cs
276+
277+
278+ if (WITH_LOCK (cs, return nCurrentAsset != MASTERNODE_SYNC_GOVERNANCE)) {
279+ // looped through all nodes and not syncing governance yet/already, release them
280+ connman.ReleaseNodeVector (vNodesCopy);
281+ return ;
282+ }
283+
284+ // request votes on per-obj basis from each node
285+ for (auto & pnode : vNodesCopy) {
286+ if (!netfulfilledman.HasFulfilledRequest (pnode->addr , " governance-sync" )) {
287+ continue ; // to early for this node
288+ }
289+ int nObjsLeftToAsk = governance.RequestGovernanceObjectVotes (pnode, connman);
290+ static int64_t nTimeNoObjectsLeft = 0 ;
291+ // check for data
292+ if (nObjsLeftToAsk == 0 ) {
293+ static int nLastTick = 0 ;
294+ static int nLastVotes = 0 ;
295+ if (nTimeNoObjectsLeft == 0 ) {
296+ // asked all objects for votes for the first time
297+ nTimeNoObjectsLeft = GetTime ();
298+ }
299+ // make sure the condition below is checked only once per tick
300+ if (nLastTick == nTick) continue ;
301+ if (GetTime () - nTimeNoObjectsLeft > MASTERNODE_SYNC_TIMEOUT_SECONDS &&
302+ governance.GetVoteCount () - nLastVotes < std::max (int (0.0001 * nLastVotes), MASTERNODE_SYNC_TICK_SECONDS)
303+ ) {
304+ // We already asked for all objects, waited for MASTERNODE_SYNC_TIMEOUT_SECONDS
305+ // after that and less then 0.01% or MASTERNODE_SYNC_TICK_SECONDS
306+ // (i.e. 1 per second) votes were received during the last tick.
307+ // We can be pretty sure that we are done syncing.
308+ LogPrintf (" CMasternodeSync::ProcessTick -- nTick %d nCurrentAsset %d -- asked for all objects, nothing to do\n " , nTick, MASTERNODE_SYNC_GOVERNANCE);
309+ // reset nTimeNoObjectsLeft to be able to use the same condition on resync
310+ nTimeNoObjectsLeft = 0 ;
311+ SwitchToNextAsset (connman);
299312 connman.ReleaseNodeVector (vNodesCopy);
300- return ; // this will cause each peer to get one request each six seconds for the various assets we need
313+ return ;
301314 }
315+ nLastTick = nTick;
316+ nLastVotes = governance.GetVoteCount ();
302317 }
303318 }
319+
304320 // looped through all nodes, release them
305321 connman.ReleaseNodeVector (vNodesCopy);
306322}
0 commit comments