Dash Core  0.12.2.1
P2P Digital Currency
governance.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2017 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 "governance.h"
6 #include "governance-object.h"
7 #include "governance-vote.h"
8 #include "governance-classes.h"
9 #include "net_processing.h"
10 #include "masternode.h"
11 #include "masternode-sync.h"
12 #include "masternodeman.h"
13 #include "messagesigner.h"
14 #include "netfulfilledman.h"
15 #include "util.h"
16 
18 
20 
21 const std::string CGovernanceManager::SERIALIZATION_VERSION_STRING = "CGovernanceManager-Version-12";
24 
26  : nTimeLastDiff(0),
27  nCachedBlockHeight(0),
28  mapObjects(),
29  mapErasedGovernanceObjects(),
30  mapMasternodeOrphanObjects(),
31  mapWatchdogObjects(),
32  nHashWatchdogCurrent(),
33  nTimeWatchdogCurrent(0),
34  mapVoteToObject(MAX_CACHE_SIZE),
35  mapInvalidVotes(MAX_CACHE_SIZE),
36  mapOrphanVotes(MAX_CACHE_SIZE),
37  mapLastMasternodeObject(),
38  setRequestedObjects(),
39  fRateChecksEnabled(true),
40  cs()
41 {}
42 
43 // Accessors for thread-safe access to maps
45  LOCK(cs);
46  return (mapObjects.count(nHash) == 1 || mapPostponedObjects.count(nHash) == 1);
47 }
48 
50 {
51  LOCK(cs);
52  object_m_it it = mapObjects.find(nHash);
53  if (it == mapObjects.end()) {
54  it = mapPostponedObjects.find(nHash);
55  if (it == mapPostponedObjects.end())
56  return false;
57  }
58  ss << it->second;
59  return true;
60 }
61 
63 {
64  LOCK(cs);
65 
66  CGovernanceObject* pGovobj = NULL;
67  if(!mapVoteToObject.Get(nHash,pGovobj)) {
68  return false;
69  }
70 
71  if(!pGovobj->GetVoteFile().HasVote(nHash)) {
72  return false;
73  }
74  return true;
75 }
76 
78 {
79  LOCK(cs);
80  return (int)mapVoteToObject.GetSize();
81 }
82 
84 {
85  LOCK(cs);
86 
87  CGovernanceObject* pGovobj = NULL;
88  if(!mapVoteToObject.Get(nHash,pGovobj)) {
89  return false;
90  }
91 
92  CGovernanceVote vote;
93  if(!pGovobj->GetVoteFile().GetVote(nHash, vote)) {
94  return false;
95  }
96 
97  ss << vote;
98  return true;
99 }
100 
101 void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman)
102 {
103  // lite mode is not supported
104  if(fLiteMode) return;
105  if(!masternodeSync.IsBlockchainSynced()) return;
106 
107  if(pfrom->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) return;
108 
109  // ANOTHER USER IS ASKING US TO HELP THEM SYNC GOVERNANCE OBJECT DATA
110  if (strCommand == NetMsgType::MNGOVERNANCESYNC)
111  {
112 
113  // Ignore such requests until we are fully synced.
114  // We could start processing this after masternode list is synced
115  // but this is a heavy one so it's better to finish sync first.
116  if (!masternodeSync.IsSynced()) return;
117 
118  uint256 nProp;
119  CBloomFilter filter;
120 
121  vRecv >> nProp;
122 
124  vRecv >> filter;
125  filter.UpdateEmptyFull();
126  }
127  else {
128  filter.clear();
129  }
130 
131  if(nProp == uint256()) {
133  // Asking for the whole list multiple times in a short period of time is no good
134  LogPrint("gobject", "MNGOVERNANCESYNC -- peer already asked me for the list\n");
135  Misbehaving(pfrom->GetId(), 20);
136  return;
137  }
139  }
140 
141  Sync(pfrom, nProp, filter, connman);
142  LogPrint("gobject", "MNGOVERNANCESYNC -- syncing governance objects to our peer at %s\n", pfrom->addr.ToString());
143 
144  }
145 
146  // A NEW GOVERNANCE OBJECT HAS ARRIVED
147  else if (strCommand == NetMsgType::MNGOVERNANCEOBJECT)
148  {
149  // MAKE SURE WE HAVE A VALID REFERENCE TO THE TIP BEFORE CONTINUING
150 
151 
153  LogPrint("gobject", "MNGOVERNANCEOBJECT -- masternode list not synced\n");
154  return;
155  }
156 
157  CGovernanceObject govobj;
158  vRecv >> govobj;
159 
160  uint256 nHash = govobj.GetHash();
161  std::string strHash = nHash.ToString();
162 
163  pfrom->setAskFor.erase(nHash);
164 
165  LogPrint("gobject", "MNGOVERNANCEOBJECT -- Received object: %s\n", strHash);
166 
167  if(!AcceptObjectMessage(nHash)) {
168  LogPrintf("MNGOVERNANCEOBJECT -- Received unrequested object: %s\n", strHash);
169  return;
170  }
171 
172  LOCK2(cs_main, cs);
173 
174  if(mapObjects.count(nHash) || mapPostponedObjects.count(nHash) ||
175  mapErasedGovernanceObjects.count(nHash) || mapMasternodeOrphanObjects.count(nHash)) {
176  // TODO - print error code? what if it's GOVOBJ_ERROR_IMMATURE?
177  LogPrint("gobject", "MNGOVERNANCEOBJECT -- Received already seen object: %s\n", strHash);
178  return;
179  }
180 
181  bool fRateCheckBypassed = false;
182  if(!MasternodeRateCheck(govobj, true, false, fRateCheckBypassed)) {
183  LogPrintf("MNGOVERNANCEOBJECT -- masternode rate check failed - %s - (current block height %d) \n", strHash, nCachedBlockHeight);
184  return;
185  }
186 
187  std::string strError = "";
188  // CHECK OBJECT AGAINST LOCAL BLOCKCHAIN
189 
190  bool fMasternodeMissing = false;
191  bool fMissingConfirmations = false;
192  bool fIsValid = govobj.IsValidLocally(strError, fMasternodeMissing, fMissingConfirmations, true);
193 
194  if(fRateCheckBypassed && (fIsValid || fMasternodeMissing)) {
195  if(!MasternodeRateCheck(govobj, true)) {
196  LogPrintf("MNGOVERNANCEOBJECT -- masternode rate check failed (after signature verification) - %s - (current block height %d) \n", strHash, nCachedBlockHeight);
197  return;
198  }
199  }
200 
201  if(!fIsValid) {
202  if(fMasternodeMissing) {
203 
204  int& count = mapMasternodeOrphanCounter[govobj.GetMasternodeVin().prevout];
205  if (count >= 10) {
206  LogPrint("gobject", "MNGOVERNANCEOBJECT -- Too many orphan objects, missing masternode=%s\n", govobj.GetMasternodeVin().prevout.ToStringShort());
207  // ask for this object again in 2 minutes
208  CInv inv(MSG_GOVERNANCE_OBJECT, govobj.GetHash());
209  pfrom->AskFor(inv);
210  return;
211  }
212 
213  count++;
215  mapMasternodeOrphanObjects.insert(std::make_pair(nHash, object_info_pair_t(govobj, info)));
216  LogPrintf("MNGOVERNANCEOBJECT -- Missing masternode for: %s, strError = %s\n", strHash, strError);
217  } else if(fMissingConfirmations) {
218  AddPostponedObject(govobj);
219  LogPrintf("MNGOVERNANCEOBJECT -- Not enough fee confirmations for: %s, strError = %s\n", strHash, strError);
220  } else {
221  LogPrintf("MNGOVERNANCEOBJECT -- Governance object is invalid - %s\n", strError);
222  // apply node's ban score
223  Misbehaving(pfrom->GetId(), 20);
224  }
225 
226  return;
227  }
228 
229  AddGovernanceObject(govobj, connman, pfrom);
230  }
231 
232  // A NEW GOVERNANCE OBJECT VOTE HAS ARRIVED
233  else if (strCommand == NetMsgType::MNGOVERNANCEOBJECTVOTE)
234  {
235  // Ignore such messages until masternode list is synced
237  LogPrint("gobject", "MNGOVERNANCEOBJECTVOTE -- masternode list not synced\n");
238  return;
239  }
240 
241  CGovernanceVote vote;
242  vRecv >> vote;
243 
244  LogPrint("gobject", "MNGOVERNANCEOBJECTVOTE -- Received vote: %s\n", vote.ToString());
245 
246  uint256 nHash = vote.GetHash();
247  std::string strHash = nHash.ToString();
248 
249  pfrom->setAskFor.erase(nHash);
250 
251  if(!AcceptVoteMessage(nHash)) {
252  LogPrint("gobject", "MNGOVERNANCEOBJECTVOTE -- Received unrequested vote object: %s, hash: %s, peer = %d\n",
253  vote.ToString(), strHash, pfrom->GetId());
254  return;
255  }
256 
257  CGovernanceException exception;
258  if(ProcessVote(pfrom, vote, exception, connman)) {
259  LogPrint("gobject", "MNGOVERNANCEOBJECTVOTE -- %s new\n", strHash);
260  masternodeSync.BumpAssetLastTime("MNGOVERNANCEOBJECTVOTE");
261  vote.Relay(connman);
262  }
263  else {
264  LogPrint("gobject", "MNGOVERNANCEOBJECTVOTE -- Rejected vote, error = %s\n", exception.what());
265  if((exception.GetNodePenalty() != 0) && masternodeSync.IsSynced()) {
266  Misbehaving(pfrom->GetId(), exception.GetNodePenalty());
267  }
268  return;
269  }
270 
271  }
272 }
273 
275 {
276  uint256 nHash = govobj.GetHash();
277  std::vector<vote_time_pair_t> vecVotePairs;
278  mapOrphanVotes.GetAll(nHash, vecVotePairs);
279 
280  ScopedLockBool guard(cs, fRateChecksEnabled, false);
281 
282  int64_t nNow = GetAdjustedTime();
283  for(size_t i = 0; i < vecVotePairs.size(); ++i) {
284  bool fRemove = false;
285  vote_time_pair_t& pairVote = vecVotePairs[i];
286  CGovernanceVote& vote = pairVote.first;
287  CGovernanceException exception;
288  if(pairVote.second < nNow) {
289  fRemove = true;
290  }
291  else if(govobj.ProcessVote(NULL, vote, exception, connman)) {
292  vote.Relay(connman);
293  fRemove = true;
294  }
295  if(fRemove) {
296  mapOrphanVotes.Erase(nHash, pairVote);
297  }
298  }
299 }
300 
302 {
303  DBG( cout << "CGovernanceManager::AddGovernanceObject START" << endl; );
304 
305  uint256 nHash = govobj.GetHash();
306  std::string strHash = nHash.ToString();
307 
308  // UPDATE CACHED VARIABLES FOR THIS OBJECT AND ADD IT TO OUR MANANGED DATA
309 
310  govobj.UpdateSentinelVariables(); //this sets local vars in object
311 
312  LOCK2(cs_main, cs);
313  std::string strError = "";
314 
315  // MAKE SURE THIS OBJECT IS OK
316 
317  if(!govobj.IsValidLocally(strError, true)) {
318  LogPrintf("CGovernanceManager::AddGovernanceObject -- invalid governance object - %s - (nCachedBlockHeight %d) \n", strError, nCachedBlockHeight);
319  return;
320  }
321 
322  // IF WE HAVE THIS OBJECT ALREADY, WE DON'T WANT ANOTHER COPY
323 
324  if(mapObjects.count(nHash)) {
325  LogPrintf("CGovernanceManager::AddGovernanceObject -- already have governance object %s\n", nHash.ToString());
326  return;
327  }
328 
329  LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- Adding object: hash = %s, type = %d\n", nHash.ToString(), govobj.GetObjectType());
330 
332  // If it's a watchdog, make sure it fits required time bounds
335  ) {
336  // drop it
337  LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- CreationTime is out of bounds: hash = %s\n", nHash.ToString());
338  return;
339  }
340 
341  if(!UpdateCurrentWatchdog(govobj)) {
342  // Allow wd's which are not current to be reprocessed
343  if(pfrom && (nHashWatchdogCurrent != uint256())) {
345  }
346  LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- Watchdog not better than current: hash = %s\n", nHash.ToString());
347  return;
348  }
349  }
350 
351  // INSERT INTO OUR GOVERNANCE OBJECT MEMORY
352  mapObjects.insert(std::make_pair(nHash, govobj));
353 
354  // SHOULD WE ADD THIS OBJECT TO ANY OTHER MANANGERS?
355 
356  DBG( cout << "CGovernanceManager::AddGovernanceObject Before trigger block, strData = "
357  << govobj.GetDataAsString()
358  << ", nObjectType = " << govobj.nObjectType
359  << endl; );
360 
361  switch(govobj.nObjectType) {
363  DBG( cout << "CGovernanceManager::AddGovernanceObject Before AddNewTrigger" << endl; );
364  triggerman.AddNewTrigger(nHash);
365  DBG( cout << "CGovernanceManager::AddGovernanceObject After AddNewTrigger" << endl; );
366  break;
369  LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- Added watchdog to map: hash = %s\n", nHash.ToString());
370  break;
371  default:
372  break;
373  }
374 
375  LogPrintf("AddGovernanceObject -- %s new, received form %s\n", strHash, pfrom? pfrom->addrName : "NULL");
376  govobj.Relay(connman);
377 
378  // Update the rate buffer
379  MasternodeRateUpdate(govobj);
380 
381  masternodeSync.BumpAssetLastTime("CGovernanceManager::AddGovernanceObject");
382 
383  // WE MIGHT HAVE PENDING/ORPHAN VOTES FOR THIS OBJECT
384 
385  CGovernanceException exception;
386  CheckOrphanVotes(govobj, exception, connman);
387 
388  DBG( cout << "CGovernanceManager::AddGovernanceObject END" << endl; );
389 }
390 
392 {
393  bool fAccept = false;
394 
395  arith_uint256 nHashNew = UintToArith256(watchdogNew.GetHash());
397 
398  int64_t nExpirationDelay = GOVERNANCE_WATCHDOG_EXPIRATION_TIME / 2;
399  int64_t nNow = GetAdjustedTime();
400 
401  if(nHashWatchdogCurrent == uint256() || // no known current OR
402  ((nNow - watchdogNew.GetCreationTime() < nExpirationDelay) && // (new one is NOT expired AND
403  ((nNow - nTimeWatchdogCurrent > nExpirationDelay) || (nHashNew > nHashCurrent)))// (current is expired OR
404  // its hash is lower))
405  ) {
406  LOCK(cs);
408  if(it != mapObjects.end()) {
409  LogPrint("gobject", "CGovernanceManager::UpdateCurrentWatchdog -- Expiring previous current watchdog, hash = %s\n", nHashWatchdogCurrent.ToString());
410  it->second.fExpired = true;
411  if(it->second.nDeletionTime == 0) {
412  it->second.nDeletionTime = nNow;
413  }
414  }
415  nHashWatchdogCurrent = watchdogNew.GetHash();
416  nTimeWatchdogCurrent = watchdogNew.GetCreationTime();
417  fAccept = true;
418  LogPrint("gobject", "CGovernanceManager::UpdateCurrentWatchdog -- Current watchdog updated to: hash = %s\n",
419  ArithToUint256(nHashNew).ToString());
420  }
421 
422  return fAccept;
423 }
424 
426 {
427  LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean\n");
428 
429  std::vector<uint256> vecDirtyHashes = mnodeman.GetAndClearDirtyGovernanceObjectHashes();
430 
431  LOCK2(cs_main, cs);
432 
433  // Flag expired watchdogs for removal
434  int64_t nNow = GetAdjustedTime();
435  LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Number watchdogs in map: %d, current time = %d\n", mapWatchdogObjects.size(), nNow);
436  if(mapWatchdogObjects.size() > 1) {
437  hash_time_m_it it = mapWatchdogObjects.begin();
438  while(it != mapWatchdogObjects.end()) {
439  LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Checking watchdog: %s, expiration time = %d\n", it->first.ToString(), it->second);
440  if(it->second < nNow) {
441  LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Attempting to expire watchdog: %s, expiration time = %d\n", it->first.ToString(), it->second);
442  object_m_it it2 = mapObjects.find(it->first);
443  if(it2 != mapObjects.end()) {
444  LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Expiring watchdog: %s, expiration time = %d\n", it->first.ToString(), it->second);
445  it2->second.fExpired = true;
446  if(it2->second.nDeletionTime == 0) {
447  it2->second.nDeletionTime = nNow;
448  }
449  }
450  if(it->first == nHashWatchdogCurrent) {
452  }
453  mapWatchdogObjects.erase(it++);
454  }
455  else {
456  ++it;
457  }
458  }
459  }
460 
461  for(size_t i = 0; i < vecDirtyHashes.size(); ++i) {
462  object_m_it it = mapObjects.find(vecDirtyHashes[i]);
463  if(it == mapObjects.end()) {
464  continue;
465  }
466  it->second.ClearMasternodeVotes();
467  it->second.fDirtyCache = true;
468  }
469 
470  ScopedLockBool guard(cs, fRateChecksEnabled, false);
471 
472  // UPDATE CACHE FOR EACH OBJECT THAT IS FLAGGED DIRTYCACHE=TRUE
473 
474  object_m_it it = mapObjects.begin();
475 
476  // Clean up any expired or invalid triggers
478 
479  while(it != mapObjects.end())
480  {
481  CGovernanceObject* pObj = &((*it).second);
482 
483  if(!pObj) {
484  ++it;
485  continue;
486  }
487 
488  uint256 nHash = it->first;
489  std::string strHash = nHash.ToString();
490 
491  // IF CACHE IS NOT DIRTY, WHY DO THIS?
492  if(pObj->IsSetDirtyCache()) {
493  // UPDATE LOCAL VALIDITY AGAINST CRYPTO DATA
494  pObj->UpdateLocalValidity();
495 
496  // UPDATE SENTINEL SIGNALING VARIABLES
497  pObj->UpdateSentinelVariables();
498  }
499 
500  if(pObj->IsSetCachedDelete() && (nHash == nHashWatchdogCurrent)) {
502  }
503 
504  // IF DELETE=TRUE, THEN CLEAN THE MESS UP!
505 
506  int64_t nTimeSinceDeletion = GetAdjustedTime() - pObj->GetDeletionTime();
507 
508  LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Checking object for deletion: %s, deletion time = %d, time since deletion = %d, delete flag = %d, expired flag = %d\n",
509  strHash, pObj->GetDeletionTime(), nTimeSinceDeletion, pObj->IsSetCachedDelete(), pObj->IsSetExpired());
510 
511  if((pObj->IsSetCachedDelete() || pObj->IsSetExpired()) &&
512  (nTimeSinceDeletion >= GOVERNANCE_DELETION_DELAY)) {
513  LogPrintf("CGovernanceManager::UpdateCachesAndClean -- erase obj %s\n", (*it).first.ToString());
515 
516  // Remove vote references
518  object_ref_cache_t::list_cit lit = listItems.begin();
519  while(lit != listItems.end()) {
520  if(lit->value == pObj) {
521  uint256 nKey = lit->key;
522  ++lit;
523  mapVoteToObject.Erase(nKey);
524  }
525  else {
526  ++lit;
527  }
528  }
529 
530  int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing;
531  int64_t nTimeExpired = pObj->GetCreationTime() + 2 * nSuperblockCycleSeconds + GOVERNANCE_DELETION_DELAY;
532 
534  mapWatchdogObjects.erase(nHash);
535  } else if(pObj->GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) {
536  // keep hashes of deleted proposals forever
537  nTimeExpired = std::numeric_limits<int64_t>::max();
538  }
539 
540  mapErasedGovernanceObjects.insert(std::make_pair(nHash, nTimeExpired));
541  mapObjects.erase(it++);
542  } else {
543  ++it;
544  }
545  }
546 
547  // forget about expired deleted objects
549  while(s_it != mapErasedGovernanceObjects.end()) {
550  if(s_it->second < nNow)
551  mapErasedGovernanceObjects.erase(s_it++);
552  else
553  ++s_it;
554  }
555 
556  LogPrintf("CGovernanceManager::UpdateCachesAndClean -- %s\n", ToString());
557 }
558 
560 {
561  LOCK(cs);
562 
563  if(mapObjects.count(nHash))
564  return &mapObjects[nHash];
565 
566  return NULL;
567 }
568 
569 std::vector<CGovernanceVote> CGovernanceManager::GetMatchingVotes(const uint256& nParentHash)
570 {
571  LOCK(cs);
572  std::vector<CGovernanceVote> vecResult;
573 
574  object_m_it it = mapObjects.find(nParentHash);
575  if(it == mapObjects.end()) {
576  return vecResult;
577  }
578  CGovernanceObject& govobj = it->second;
579 
580  return govobj.GetVoteFile().GetVotes();
581 }
582 
583 std::vector<CGovernanceVote> CGovernanceManager::GetCurrentVotes(const uint256& nParentHash, const COutPoint& mnCollateralOutpointFilter)
584 {
585  LOCK(cs);
586  std::vector<CGovernanceVote> vecResult;
587 
588  // Find the governance object or short-circuit.
589  object_m_it it = mapObjects.find(nParentHash);
590  if(it == mapObjects.end()) return vecResult;
591  CGovernanceObject& govobj = it->second;
592 
593  CMasternode mn;
594  std::map<COutPoint, CMasternode> mapMasternodes;
595  if(mnCollateralOutpointFilter == COutPoint()) {
596  mapMasternodes = mnodeman.GetFullMasternodeMap();
597  } else if (mnodeman.Get(mnCollateralOutpointFilter, mn)) {
598  mapMasternodes[mnCollateralOutpointFilter] = mn;
599  }
600 
601  // Loop thru each MN collateral outpoint and get the votes for the `nParentHash` governance object
602  for (auto& mnpair : mapMasternodes)
603  {
604  // get a vote_rec_t from the govobj
605  vote_rec_t voteRecord;
606  if (!govobj.GetCurrentMNVotes(mnpair.first, voteRecord)) continue;
607 
608  for (vote_instance_m_it it3 = voteRecord.mapInstances.begin(); it3 != voteRecord.mapInstances.end(); ++it3) {
609  int signal = (it3->first);
610  int outcome = ((it3->second).eOutcome);
611  int64_t nCreationTime = ((it3->second).nCreationTime);
612 
613  CGovernanceVote vote = CGovernanceVote(mnpair.first, nParentHash, (vote_signal_enum_t)signal, (vote_outcome_enum_t)outcome);
614  vote.SetTime(nCreationTime);
615 
616  vecResult.push_back(vote);
617  }
618  }
619 
620  return vecResult;
621 }
622 
623 std::vector<CGovernanceObject*> CGovernanceManager::GetAllNewerThan(int64_t nMoreThanTime)
624 {
625  LOCK(cs);
626 
627  std::vector<CGovernanceObject*> vGovObjs;
628 
629  object_m_it it = mapObjects.begin();
630  while(it != mapObjects.end())
631  {
632  // IF THIS OBJECT IS OLDER THAN TIME, CONTINUE
633 
634  if((*it).second.GetCreationTime() < nMoreThanTime) {
635  ++it;
636  continue;
637  }
638 
639  // ADD GOVERNANCE OBJECT TO LIST
640 
641  CGovernanceObject* pGovObj = &((*it).second);
642  vGovObjs.push_back(pGovObj);
643 
644  // NEXT
645 
646  ++it;
647  }
648 
649  return vGovObjs;
650 }
651 
652 //
653 // Sort by votes, if there's a tie sort by their feeHash TX
654 //
656  bool operator()(const std::pair<CGovernanceObject*, int> &left, const std::pair<CGovernanceObject*, int> &right) {
657  if (left.second != right.second)
658  return (left.second > right.second);
659  return (UintToArith256(left.first->GetCollateralHash()) > UintToArith256(right.first->GetCollateralHash()));
660  }
661 };
662 
664 {
665  if(fLiteMode || !masternodeSync.IsSynced()) return;
666 
667  // CHECK OBJECTS WE'VE ASKED FOR, REMOVE OLD ENTRIES
668 
670 
671  RequestOrphanObjects(connman);
672 
673  // CHECK AND REMOVE - REPROCESS GOVERNANCE OBJECTS
674 
676 }
677 
679 {
680  // do not request objects until it's time to sync
681  if(!masternodeSync.IsWinnersListSynced()) return false;
682 
683  LOCK(cs);
684 
685  LogPrint("gobject", "CGovernanceManager::ConfirmInventoryRequest inv = %s\n", inv.ToString());
686 
687  // First check if we've already recorded this object
688  switch(inv.type) {
690  {
691  if(mapObjects.count(inv.hash) == 1 || mapPostponedObjects.count(inv.hash) == 1) {
692  LogPrint("gobject", "CGovernanceManager::ConfirmInventoryRequest already have governance object, returning false\n");
693  return false;
694  }
695  }
696  break;
698  {
699  if(mapVoteToObject.HasKey(inv.hash)) {
700  LogPrint("gobject", "CGovernanceManager::ConfirmInventoryRequest already have governance vote, returning false\n");
701  return false;
702  }
703  }
704  break;
705  default:
706  LogPrint("gobject", "CGovernanceManager::ConfirmInventoryRequest unknown type, returning false\n");
707  return false;
708  }
709 
710 
711  hash_s_t* setHash = NULL;
712  switch(inv.type) {
714  setHash = &setRequestedObjects;
715  break;
717  setHash = &setRequestedVotes;
718  break;
719  default:
720  return false;
721  }
722 
723  hash_s_cit it = setHash->find(inv.hash);
724  if(it == setHash->end()) {
725  setHash->insert(inv.hash);
726  LogPrint("gobject", "CGovernanceManager::ConfirmInventoryRequest added inv to requested set\n");
727  }
728 
729  LogPrint("gobject", "CGovernanceManager::ConfirmInventoryRequest reached end, returning true\n");
730  return true;
731 }
732 
733 void CGovernanceManager::Sync(CNode* pfrom, const uint256& nProp, const CBloomFilter& filter, CConnman& connman)
734 {
735 
736  /*
737  This code checks each of the hash maps for all known budget proposals and finalized budget proposals, then checks them against the
738  budget object to see if they're OK. If all checks pass, we'll send it to the peer.
739  */
740 
741  // do not provide any data until our node is synced
742  if(fMasterNode && !masternodeSync.IsSynced()) return;
743 
744  int nObjCount = 0;
745  int nVoteCount = 0;
746 
747  // SYNC GOVERNANCE OBJECTS WITH OTHER CLIENT
748 
749  LogPrint("gobject", "CGovernanceManager::Sync -- syncing to peer=%d, nProp = %s\n", pfrom->id, nProp.ToString());
750 
751  {
752  LOCK2(cs_main, cs);
753 
754  if(nProp == uint256()) {
755  // all valid objects, no votes
756  for(object_m_it it = mapObjects.begin(); it != mapObjects.end(); ++it) {
757  CGovernanceObject& govobj = it->second;
758  std::string strHash = it->first.ToString();
759 
760  LogPrint("gobject", "CGovernanceManager::Sync -- attempting to sync govobj: %s, peer=%d\n", strHash, pfrom->id);
761 
762  if(govobj.IsSetCachedDelete() || govobj.IsSetExpired()) {
763  LogPrintf("CGovernanceManager::Sync -- not syncing deleted/expired govobj: %s, peer=%d\n",
764  strHash, pfrom->id);
765  continue;
766  }
767 
768  // Push the inventory budget proposal message over to the other client
769  LogPrint("gobject", "CGovernanceManager::Sync -- syncing govobj: %s, peer=%d\n", strHash, pfrom->id);
770  pfrom->PushInventory(CInv(MSG_GOVERNANCE_OBJECT, it->first));
771  ++nObjCount;
772  }
773  } else {
774  // single valid object and its valid votes
775  object_m_it it = mapObjects.find(nProp);
776  if(it == mapObjects.end()) {
777  LogPrint("gobject", "CGovernanceManager::Sync -- no matching object for hash %s, peer=%d\n", nProp.ToString(), pfrom->id);
778  return;
779  }
780  CGovernanceObject& govobj = it->second;
781  std::string strHash = it->first.ToString();
782 
783  LogPrint("gobject", "CGovernanceManager::Sync -- attempting to sync govobj: %s, peer=%d\n", strHash, pfrom->id);
784 
785  if(govobj.IsSetCachedDelete() || govobj.IsSetExpired()) {
786  LogPrintf("CGovernanceManager::Sync -- not syncing deleted/expired govobj: %s, peer=%d\n",
787  strHash, pfrom->id);
788  return;
789  }
790 
791  // Push the inventory budget proposal message over to the other client
792  LogPrint("gobject", "CGovernanceManager::Sync -- syncing govobj: %s, peer=%d\n", strHash, pfrom->id);
793  pfrom->PushInventory(CInv(MSG_GOVERNANCE_OBJECT, it->first));
794  ++nObjCount;
795 
796  std::vector<CGovernanceVote> vecVotes = govobj.GetVoteFile().GetVotes();
797  for(size_t i = 0; i < vecVotes.size(); ++i) {
798  if(filter.contains(vecVotes[i].GetHash())) {
799  continue;
800  }
801  if(!vecVotes[i].IsValid(true)) {
802  continue;
803  }
804  pfrom->PushInventory(CInv(MSG_GOVERNANCE_OBJECT_VOTE, vecVotes[i].GetHash()));
805  ++nVoteCount;
806  }
807  }
808  }
809 
812  LogPrintf("CGovernanceManager::Sync -- sent %d objects and %d votes to peer=%d\n", nObjCount, nVoteCount, pfrom->id);
813 }
814 
815 
817 {
818  int nObjectType = govobj.GetObjectType();
819  if((nObjectType != GOVERNANCE_OBJECT_TRIGGER) && (nObjectType != GOVERNANCE_OBJECT_WATCHDOG))
820  return;
821 
822  const CTxIn& vin = govobj.GetMasternodeVin();
824 
825  if(it == mapLastMasternodeObject.end())
826  it = mapLastMasternodeObject.insert(txout_m_t::value_type(vin.prevout, last_object_rec(true))).first;
827 
828  int64_t nTimestamp = govobj.GetCreationTime();
829  if (GOVERNANCE_OBJECT_TRIGGER == nObjectType)
830  it->second.triggerBuffer.AddTimestamp(nTimestamp);
831  else if (GOVERNANCE_OBJECT_WATCHDOG == nObjectType)
832  it->second.watchdogBuffer.AddTimestamp(nTimestamp);
833 
835  // schedule additional relay for the object
836  setAdditionalRelayObjects.insert(govobj.GetHash());
837  }
838 
839  it->second.fStatusOK = true;
840 }
841 
842 bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus)
843 {
844  bool fRateCheckBypassed;
845  return MasternodeRateCheck(govobj, fUpdateFailStatus, true, fRateCheckBypassed);
846 }
847 
848 bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus, bool fForce, bool& fRateCheckBypassed)
849 {
850  LOCK(cs);
851 
852  fRateCheckBypassed = false;
853 
854  if(!masternodeSync.IsSynced()) {
855  return true;
856  }
857 
858  if(!fRateChecksEnabled) {
859  return true;
860  }
861 
862  int nObjectType = govobj.GetObjectType();
863  if((nObjectType != GOVERNANCE_OBJECT_TRIGGER) && (nObjectType != GOVERNANCE_OBJECT_WATCHDOG)) {
864  return true;
865  }
866 
867  const CTxIn& vin = govobj.GetMasternodeVin();
868  int64_t nTimestamp = govobj.GetCreationTime();
869  int64_t nNow = GetAdjustedTime();
870  int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing;
871 
872  std::string strHash = govobj.GetHash().ToString();
873 
874  if(nTimestamp < nNow - 2 * nSuperblockCycleSeconds) {
875  LogPrintf("CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too old timestamp, masternode vin = %s, timestamp = %d, current time = %d\n",
876  strHash, vin.prevout.ToStringShort(), nTimestamp, nNow);
877  return false;
878  }
879 
880  if(nTimestamp > nNow + MAX_TIME_FUTURE_DEVIATION) {
881  LogPrintf("CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too new (future) timestamp, masternode vin = %s, timestamp = %d, current time = %d\n",
882  strHash, vin.prevout.ToStringShort(), nTimestamp, nNow);
883  return false;
884  }
885 
887  if(it == mapLastMasternodeObject.end())
888  return true;
889 
890  if(it->second.fStatusOK && !fForce) {
891  fRateCheckBypassed = true;
892  return true;
893  }
894 
895  double dMaxRate = 1.1 / nSuperblockCycleSeconds;
896  double dRate = 0.0;
897  CRateCheckBuffer buffer;
898  switch(nObjectType) {
900  // Allow 1 trigger per mn per cycle, with a small fudge factor
901  buffer = it->second.triggerBuffer;
902  dMaxRate = 2 * 1.1 / double(nSuperblockCycleSeconds);
903  break;
905  buffer = it->second.watchdogBuffer;
906  dMaxRate = 2 * 1.1 / 3600.;
907  break;
908  default:
909  break;
910  }
911 
912  buffer.AddTimestamp(nTimestamp);
913  dRate = buffer.GetRate();
914 
915  bool fRateOK = ( dRate < dMaxRate );
916 
917  if(!fRateOK)
918  {
919  LogPrintf("CGovernanceManager::MasternodeRateCheck -- Rate too high: object hash = %s, masternode vin = %s, object timestamp = %d, rate = %f, max rate = %f\n",
920  strHash, vin.prevout.ToStringShort(), nTimestamp, dRate, dMaxRate);
921 
922  if (fUpdateFailStatus)
923  it->second.fStatusOK = false;
924  }
925 
926  return fRateOK;
927 }
928 
930 {
932  uint256 nHashVote = vote.GetHash();
933  if(mapInvalidVotes.HasKey(nHashVote)) {
934  std::ostringstream ostr;
935  ostr << "CGovernanceManager::ProcessVote -- Old invalid vote "
936  << ", MN outpoint = " << vote.GetMasternodeOutpoint().ToStringShort()
937  << ", governance object hash = " << vote.GetParentHash().ToString();
938  LogPrintf("%s\n", ostr.str());
939  exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_PERMANENT_ERROR, 20);
941  return false;
942  }
943 
944  uint256 nHashGovobj = vote.GetParentHash();
945  object_m_it it = mapObjects.find(nHashGovobj);
946  if(it == mapObjects.end()) {
947  std::ostringstream ostr;
948  ostr << "CGovernanceManager::ProcessVote -- Unknown parent object "
949  << ", MN outpoint = " << vote.GetMasternodeOutpoint().ToStringShort()
950  << ", governance object hash = " << vote.GetParentHash().ToString();
951  exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_WARNING);
954  RequestGovernanceObject(pfrom, nHashGovobj, connman);
955  LogPrintf("%s\n", ostr.str());
956  return false;
957  }
958 
959  LogPrint("gobject", "%s\n", ostr.str());
961  return false;
962  }
963 
964  CGovernanceObject& govobj = it->second;
965 
966  if(govobj.IsSetCachedDelete() || govobj.IsSetExpired()) {
967  LogPrint("gobject", "CGovernanceObject::ProcessVote -- ignoring vote for expired or deleted object, hash = %s\n", nHashGovobj.ToString());
969  return false;
970  }
971 
972  bool fOk = govobj.ProcessVote(pfrom, vote, exception, connman);
973  if(fOk) {
974  mapVoteToObject.Insert(nHashVote, &govobj);
975 
976  if(govobj.GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG) {
978  LogPrint("gobject", "CGovernanceObject::ProcessVote -- GOVERNANCE_OBJECT_WATCHDOG vote for %s\n", vote.GetParentHash().ToString());
979  }
980  }
982  return fOk;
983 }
984 
986 {
987  LOCK2(cs_main, cs);
988 
989  ScopedLockBool guard(cs, fRateChecksEnabled, false);
990 
991  for(object_m_it it = mapObjects.begin(); it != mapObjects.end(); ++it) {
992  it->second.CheckOrphanVotes(connman);
993  }
994 }
995 
997 {
998  LOCK2(cs_main, cs);
999  int64_t nNow = GetAdjustedTime();
1000  ScopedLockBool guard(cs, fRateChecksEnabled, false);
1002  while(it != mapMasternodeOrphanObjects.end()) {
1003  object_info_pair_t& pair = it->second;
1004  CGovernanceObject& govobj = pair.first;
1005 
1006  if(pair.second.nExpirationTime >= nNow) {
1007  string strError;
1008  bool fMasternodeMissing = false;
1009  bool fConfirmationsMissing = false;
1010  bool fIsValid = govobj.IsValidLocally(strError, fMasternodeMissing, fConfirmationsMissing, true);
1011 
1012  if(fIsValid) {
1013  AddGovernanceObject(govobj, connman);
1014  } else if(fMasternodeMissing) {
1015  ++it;
1016  continue;
1017  }
1018  } else {
1019  // apply node's ban score
1020  Misbehaving(pair.second.idFrom, 20);
1021  }
1022 
1023  auto it_count = mapMasternodeOrphanCounter.find(govobj.GetMasternodeVin().prevout);
1024  if(--it_count->second == 0)
1025  mapMasternodeOrphanCounter.erase(it_count);
1026 
1027  mapMasternodeOrphanObjects.erase(it++);
1028  }
1029 }
1030 
1032 {
1033  if(!masternodeSync.IsSynced()) return;
1034 
1035  LOCK2(cs_main, cs);
1036 
1037  // Check postponed proposals
1038  for(object_m_it it = mapPostponedObjects.begin(); it != mapPostponedObjects.end();) {
1039 
1040  const uint256& nHash = it->first;
1041  CGovernanceObject& govobj = it->second;
1042 
1043  assert(govobj.GetObjectType() != GOVERNANCE_OBJECT_WATCHDOG &&
1045 
1046  std::string strError;
1047  bool fMissingConfirmations;
1048  if (govobj.IsCollateralValid(strError, fMissingConfirmations))
1049  {
1050  if(govobj.IsValidLocally(strError, false))
1051  AddGovernanceObject(govobj, connman);
1052  else
1053  LogPrintf("CGovernanceManager::CheckPostponedObjects -- %s invalid\n", nHash.ToString());
1054 
1055  } else if(fMissingConfirmations) {
1056  // wait for more confirmations
1057  ++it;
1058  continue;
1059  }
1060 
1061  // remove processed or invalid object from the queue
1062  mapPostponedObjects.erase(it++);
1063  }
1064 
1065 
1066  // Perform additional relays for triggers/watchdogs
1067  int64_t nNow = GetAdjustedTime();
1068  int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing;
1069 
1070  for(hash_s_it it = setAdditionalRelayObjects.begin(); it != setAdditionalRelayObjects.end();) {
1071 
1072  object_m_it itObject = mapObjects.find(*it);
1073  if(itObject != mapObjects.end()) {
1074 
1075  CGovernanceObject& govobj = itObject->second;
1076 
1077  int64_t nTimestamp = govobj.GetCreationTime();
1078 
1079  bool fValid = (nTimestamp <= nNow + MAX_TIME_FUTURE_DEVIATION) && (nTimestamp >= nNow - 2 * nSuperblockCycleSeconds);
1080  bool fReady = (nTimestamp <= nNow + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME);
1081 
1082  if(fValid) {
1083  if(fReady) {
1084  LogPrintf("CGovernanceManager::CheckPostponedObjects -- additional relay: hash = %s\n", govobj.GetHash().ToString());
1085  govobj.Relay(connman);
1086  } else {
1087  it++;
1088  continue;
1089  }
1090  }
1091 
1092  } else {
1093  LogPrintf("CGovernanceManager::CheckPostponedObjects -- additional relay of unknown object: %s\n", it->ToString());
1094  }
1095 
1096  setAdditionalRelayObjects.erase(it++);
1097  }
1098 }
1099 
1100 void CGovernanceManager::RequestGovernanceObject(CNode* pfrom, const uint256& nHash, CConnman& connman, bool fUseFilter)
1101 {
1102  if(!pfrom) {
1103  return;
1104  }
1105 
1106  LogPrint("gobject", "CGovernanceObject::RequestGovernanceObject -- hash = %s (peer=%d)\n", nHash.ToString(), pfrom->GetId());
1107 
1109  connman.PushMessage(pfrom, NetMsgType::MNGOVERNANCESYNC, nHash);
1110  return;
1111  }
1112 
1113  CBloomFilter filter;
1114  filter.clear();
1115 
1116  int nVoteCount = 0;
1117  if(fUseFilter) {
1118  LOCK(cs);
1119  CGovernanceObject* pObj = FindGovernanceObject(nHash);
1120 
1121  if(pObj) {
1122  filter = CBloomFilter(Params().GetConsensus().nGovernanceFilterElements, GOVERNANCE_FILTER_FP_RATE, GetRandInt(999999), BLOOM_UPDATE_ALL);
1123  std::vector<CGovernanceVote> vecVotes = pObj->GetVoteFile().GetVotes();
1124  nVoteCount = vecVotes.size();
1125  for(size_t i = 0; i < vecVotes.size(); ++i) {
1126  filter.insert(vecVotes[i].GetHash());
1127  }
1128  }
1129  }
1130 
1131  LogPrint("gobject", "CGovernanceManager::RequestGovernanceObject -- nHash %s nVoteCount %d peer=%d\n", nHash.ToString(), nVoteCount, pfrom->id);
1132  connman.PushMessage(pfrom, NetMsgType::MNGOVERNANCESYNC, nHash, filter);
1133 }
1134 
1136 {
1137  if(pnode->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) return -3;
1138  std::vector<CNode*> vNodesCopy;
1139  vNodesCopy.push_back(pnode);
1140  return RequestGovernanceObjectVotes(vNodesCopy, connman);
1141 }
1142 
1143 int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector<CNode*>& vNodesCopy, CConnman& connman)
1144 {
1145  static std::map<uint256, std::map<CService, int64_t> > mapAskedRecently;
1146 
1147  if(vNodesCopy.empty()) return -1;
1148 
1149  int64_t nNow = GetTime();
1150  int nTimeout = 60 * 60;
1151  size_t nPeersPerHashMax = 3;
1152 
1153  std::vector<CGovernanceObject*> vpGovObjsTmp;
1154  std::vector<CGovernanceObject*> vpGovObjsTriggersTmp;
1155 
1156  // This should help us to get some idea about an impact this can bring once deployed on mainnet.
1157  // Testnet is ~40 times smaller in masternode count, but only ~1000 masternodes usually vote,
1158  // so 1 obj on mainnet == ~10 objs or ~1000 votes on testnet. However we want to test a higher
1159  // number of votes to make sure it's robust enough, so aim at 2000 votes per masternode per request.
1160  // On mainnet nMaxObjRequestsPerNode is always set to 1.
1161  int nMaxObjRequestsPerNode = 1;
1162  size_t nProjectedVotes = 2000;
1163  if(Params().NetworkIDString() != CBaseChainParams::MAIN) {
1164  nMaxObjRequestsPerNode = std::max(1, int(nProjectedVotes / std::max(1, mnodeman.size())));
1165  }
1166 
1167  {
1168  LOCK2(cs_main, cs);
1169 
1170  if(mapObjects.empty()) return -2;
1171 
1172  for(object_m_it it = mapObjects.begin(); it != mapObjects.end(); ++it) {
1173  if(mapAskedRecently.count(it->first)) {
1174  std::map<CService, int64_t>::iterator it1 = mapAskedRecently[it->first].begin();
1175  while(it1 != mapAskedRecently[it->first].end()) {
1176  if(it1->second < nNow) {
1177  mapAskedRecently[it->first].erase(it1++);
1178  } else {
1179  ++it1;
1180  }
1181  }
1182  if(mapAskedRecently[it->first].size() >= nPeersPerHashMax) continue;
1183  }
1184  if(it->second.nObjectType == GOVERNANCE_OBJECT_TRIGGER) {
1185  vpGovObjsTriggersTmp.push_back(&(it->second));
1186  } else {
1187  vpGovObjsTmp.push_back(&(it->second));
1188  }
1189  }
1190  }
1191 
1192  LogPrint("gobject", "CGovernanceManager::RequestGovernanceObjectVotes -- start: vpGovObjsTriggersTmp %d vpGovObjsTmp %d mapAskedRecently %d\n",
1193  vpGovObjsTriggersTmp.size(), vpGovObjsTmp.size(), mapAskedRecently.size());
1194 
1195  InsecureRand insecureRand;
1196  // shuffle pointers
1197  std::random_shuffle(vpGovObjsTriggersTmp.begin(), vpGovObjsTriggersTmp.end(), insecureRand);
1198  std::random_shuffle(vpGovObjsTmp.begin(), vpGovObjsTmp.end(), insecureRand);
1199 
1200  for (int i = 0; i < nMaxObjRequestsPerNode; ++i) {
1201  uint256 nHashGovobj;
1202 
1203  // ask for triggers first
1204  if(vpGovObjsTriggersTmp.size()) {
1205  nHashGovobj = vpGovObjsTriggersTmp.back()->GetHash();
1206  } else {
1207  if(vpGovObjsTmp.empty()) break;
1208  nHashGovobj = vpGovObjsTmp.back()->GetHash();
1209  }
1210  bool fAsked = false;
1211  BOOST_FOREACH(CNode* pnode, vNodesCopy) {
1212  // Only use regular peers, don't try to ask from outbound "masternode" connections -
1213  // they stay connected for a short period of time and it's possible that we won't get everything we should.
1214  // Only use outbound connections - inbound connection could be a "masternode" connection
1215  // initiated from another node, so skip it too.
1216  if(pnode->fMasternode || (fMasterNode && pnode->fInbound)) continue;
1217  // only use up to date peers
1218  if(pnode->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) continue;
1219  // stop early to prevent setAskFor overflow
1220  size_t nProjectedSize = pnode->setAskFor.size() + nProjectedVotes;
1221  if(nProjectedSize > SETASKFOR_MAX_SZ/2) continue;
1222  // to early to ask the same node
1223  if(mapAskedRecently[nHashGovobj].count(pnode->addr)) continue;
1224 
1225  RequestGovernanceObject(pnode, nHashGovobj, connman, true);
1226  mapAskedRecently[nHashGovobj][pnode->addr] = nNow + nTimeout;
1227  fAsked = true;
1228  // stop loop if max number of peers per obj was asked
1229  if(mapAskedRecently[nHashGovobj].size() >= nPeersPerHashMax) break;
1230  }
1231  // NOTE: this should match `if` above (the one before `while`)
1232  if(vpGovObjsTriggersTmp.size()) {
1233  vpGovObjsTriggersTmp.pop_back();
1234  } else {
1235  vpGovObjsTmp.pop_back();
1236  }
1237  if(!fAsked) i--;
1238  }
1239  LogPrint("gobject", "CGovernanceManager::RequestGovernanceObjectVotes -- end: vpGovObjsTriggersTmp %d vpGovObjsTmp %d mapAskedRecently %d\n",
1240  vpGovObjsTriggersTmp.size(), vpGovObjsTmp.size(), mapAskedRecently.size());
1241 
1242  return int(vpGovObjsTriggersTmp.size() + vpGovObjsTmp.size());
1243 }
1244 
1246 {
1247  LOCK(cs);
1248  return AcceptMessage(nHash, setRequestedObjects);
1249 }
1250 
1252 {
1253  LOCK(cs);
1254  return AcceptMessage(nHash, setRequestedVotes);
1255 }
1256 
1258 {
1259  hash_s_it it = setHash.find(nHash);
1260  if(it == setHash.end()) {
1261  // We never requested this
1262  return false;
1263  }
1264  // Only accept one response
1265  setHash.erase(it);
1266  return true;
1267 }
1268 
1270 {
1272  for(object_m_it it = mapObjects.begin(); it != mapObjects.end(); ++it) {
1273  CGovernanceObject& govobj = it->second;
1274  std::vector<CGovernanceVote> vecVotes = govobj.GetVoteFile().GetVotes();
1275  for(size_t i = 0; i < vecVotes.size(); ++i) {
1276  mapVoteToObject.Insert(vecVotes[i].GetHash(), &govobj);
1277  }
1278  }
1279 }
1280 
1282 {
1283  LOCK(cs);
1284 
1285  for(object_m_it it = mapObjects.begin(); it != mapObjects.end(); ++it) {
1286  CGovernanceObject& govobj = it->second;
1287 
1288  if(govobj.nObjectType != GOVERNANCE_OBJECT_TRIGGER) {
1289  continue;
1290  }
1291 
1292  triggerman.AddNewTrigger(govobj.GetHash());
1293  }
1294 }
1295 
1297 {
1298  LOCK(cs);
1299  int64_t nStart = GetTimeMillis();
1300  LogPrintf("Preparing masternode indexes and governance triggers...\n");
1301  RebuildIndexes();
1303  LogPrintf("Masternode indexes and governance triggers prepared %dms\n", GetTimeMillis() - nStart);
1304  LogPrintf(" %s\n", ToString());
1305 }
1306 
1307 std::string CGovernanceManager::ToString() const
1308 {
1309  LOCK(cs);
1310 
1311  int nProposalCount = 0;
1312  int nTriggerCount = 0;
1313  int nWatchdogCount = 0;
1314  int nOtherCount = 0;
1315 
1316  object_m_cit it = mapObjects.begin();
1317 
1318  while(it != mapObjects.end()) {
1319  switch(it->second.GetObjectType()) {
1321  nProposalCount++;
1322  break;
1324  nTriggerCount++;
1325  break;
1327  nWatchdogCount++;
1328  break;
1329  default:
1330  nOtherCount++;
1331  break;
1332  }
1333  ++it;
1334  }
1335 
1336  return strprintf("Governance Objects: %d (Proposals: %d, Triggers: %d, Watchdogs: %d/%d, Other: %d; Erased: %d), Votes: %d",
1337  (int)mapObjects.size(),
1338  nProposalCount, nTriggerCount, nWatchdogCount, mapWatchdogObjects.size(), nOtherCount, (int)mapErasedGovernanceObjects.size(),
1339  (int)mapVoteToObject.GetSize());
1340 }
1341 
1343 {
1344  // Note this gets called from ActivateBestChain without cs_main being held
1345  // so it should be safe to lock our mutex here without risking a deadlock
1346  // On the other hand it should be safe for us to access pindex without holding a lock
1347  // on cs_main because the CBlockIndex objects are dynamically allocated and
1348  // presumably never deleted.
1349  if(!pindex) {
1350  return;
1351  }
1352 
1353  nCachedBlockHeight = pindex->nHeight;
1354  LogPrint("gobject", "CGovernanceManager::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight);
1355 
1356  CheckPostponedObjects(connman);
1357 }
1358 
1360 {
1361  std::vector<CNode*> vNodesCopy = connman.CopyNodeVector();
1362 
1363  std::vector<uint256> vecHashesFiltered;
1364  {
1365  std::vector<uint256> vecHashes;
1366  LOCK(cs);
1367  mapOrphanVotes.GetKeys(vecHashes);
1368  for(size_t i = 0; i < vecHashes.size(); ++i) {
1369  const uint256& nHash = vecHashes[i];
1370  if(mapObjects.find(nHash) == mapObjects.end()) {
1371  vecHashesFiltered.push_back(nHash);
1372  }
1373  }
1374  }
1375 
1376  LogPrint("gobject", "CGovernanceObject::RequestOrphanObjects -- number objects = %d\n", vecHashesFiltered.size());
1377  for(size_t i = 0; i < vecHashesFiltered.size(); ++i) {
1378  const uint256& nHash = vecHashesFiltered[i];
1379  for(size_t j = 0; j < vNodesCopy.size(); ++j) {
1380  CNode* pnode = vNodesCopy[j];
1381  if(pnode->fMasternode) {
1382  continue;
1383  }
1384  RequestGovernanceObject(pnode, nHash, connman);
1385  }
1386  }
1387 
1388  connman.ReleaseNodeVector(vNodesCopy);
1389 }
1390 
1392 {
1393  LOCK(cs);
1395 
1396  int64_t nNow = GetAdjustedTime();
1397 
1398  vote_mcache_t::list_cit it = items.begin();
1399  while(it != items.end()) {
1400  vote_mcache_t::list_cit prevIt = it;
1401  ++it;
1402  const vote_time_pair_t& pairVote = prevIt->value;
1403  if(pairVote.second < nNow) {
1404  mapOrphanVotes.Erase(prevIt->key, prevIt->value);
1405  }
1406  }
1407 }
std::vector< CGovernanceObject * > GetAllNewerThan(int64_t nMoreThanTime)
Definition: governance.cpp:623
int nSuperblockCycle
Definition: params.h:55
static const std::string SERIALIZATION_VERSION_STRING
Definition: governance.h:224
int RequestGovernanceObjectVotes(CNode *pnode, CConnman &connman)
static const size_t SETASKFOR_MAX_SZ
Definition: net.h:77
static const int MASTERNODE_SYNC_GOVOBJ_VOTE
CMasternodeMan mnodeman
std::vector< CGovernanceVote > GetVotes() const
CMasternodeSync masternodeSync
hash_time_m_t mapErasedGovernanceObjects
Definition: governance.h:240
bool AcceptObjectMessage(const uint256 &nHash)
Called to indicate a requested object has been received.
std::set< uint256 > setAskFor
Definition: net.h:743
bool GetCurrentMNVotes(const COutPoint &mnCollateralOutpoint, vote_rec_t &voteRecord)
object_info_m_t mapMasternodeOrphanObjects
Definition: governance.h:242
static const int64_t GOVERNANCE_ORPHAN_EXPIRATION_TIME
object_info_m_t::iterator object_info_m_it
Definition: governance.h:211
int GetRandInt(int nMax)
Definition: random.cpp:109
bool Insert(const K &key, const V &value)
Definition: cachemultimap.h:92
std::pair< CGovernanceVote, int64_t > vote_time_pair_t
void AddFulfilledRequest(CAddress addr, std::string strRequest)
void CheckOrphanVotes(CGovernanceObject &govobj, CGovernanceException &exception, CConnman &connman)
Definition: governance.cpp:274
#define strprintf
Definition: tinyformat.h:1011
vote_instance_m_t mapInstances
uint64_t GetHash(const uint256 &salt) const
Definition: uint256.cpp:126
bool HaveObjectForHash(uint256 nHash)
Definition: governance.cpp:44
hash_s_t::iterator hash_s_it
Definition: governance.h:205
void RequestOrphanObjects(CConnman &connman)
uint256 hash
Definition: protocol.h:339
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:55
static const int MIN_GOVERNANCE_PEER_PROTO_VERSION
std::vector< CGovernanceVote > GetCurrentVotes(const uint256 &nParentHash, const COutPoint &mnCollateralOutpointFilter)
Definition: governance.cpp:583
bool Get(const COutPoint &outpoint, CMasternode &masternodeRet)
Versions of Find that are safe to use from outside the class.
#define DBG(x)
Definition: util.h:41
vote_mcache_t mapOrphanVotes
Definition: governance.h:258
CCriticalSection cs_main
Definition: validation.cpp:62
CGovernanceObject * FindGovernanceObject(const uint256 &nHash)
Definition: governance.cpp:559
int GetVoteCount() const
Definition: governance.cpp:77
bool GetVote(const uint256 &nHash, CGovernanceVote &vote) const
std::vector< CGovernanceVote > GetMatchingVotes(const uint256 &nParentHash)
Definition: governance.cpp:569
CAddress addr
Definition: net.h:688
txout_m_t::iterator txout_m_it
Definition: governance.h:197
const CTxIn & GetMasternodeVin() const
std::pair< CGovernanceObject, ExpirationInfo > object_info_pair_t
Definition: governance.h:36
hash_s_t setRequestedVotes
Definition: governance.h:264
bool IsSetExpired() const
Definition: net.h:108
static const int GOVERNANCE_OBJECT_PROPOSAL
NodeId id
Definition: net.h:718
hash_s_t setRequestedObjects
Definition: governance.h:262
const char * SYNCSTATUSCOUNT
Definition: protocol.cpp:63
void CheckPostponedObjects(CConnman &connman)
object_ref_cache_t mapVoteToObject
Definition: governance.h:254
void Erase(const K &key)
bool ProcessVote(CNode *pfrom, const CGovernanceVote &vote, CGovernanceException &exception, CConnman &connman)
Definition: governance.cpp:929
bool SerializeVoteForHash(uint256 nHash, CDataStream &ss)
Definition: governance.cpp:83
int64_t nTimeWatchdogCurrent
Definition: governance.h:252
std::string ToString(bool fUseGetnameinfo=true) const
Definition: netaddress.cpp:568
void ProcessMessage(CNode *pfrom, std::string &strCommand, CDataStream &vRecv, CConnman &connman)
Definition: governance.cpp:101
hash_time_m_t mapWatchdogObjects
Definition: governance.h:248
bool IsWinnersListSynced()
static const int64_t GOVERNANCE_WATCHDOG_EXPIRATION_TIME
bool HasFulfilledRequest(CAddress addr, std::string strRequest)
Requested operation cannot be performed.
bool contains(const std::vector< unsigned char > &vKey) const
const list_t & GetItemList() const
int nObjectType
Object typecode.
void Clear()
Definition: cachemap.h:91
uint256 GetHash() const
int64_t GetCreationTime() const
arith_uint256 UintToArith256(const uint256 &a)
void insert(const std::vector< unsigned char > &vKey)
static const double GOVERNANCE_FILTER_FP_RATE
object_m_t mapObjects
Definition: governance.h:235
bool fMasterNode
Definition: util.cpp:108
void RequestGovernanceObject(CNode *pfrom, const uint256 &nHash, CConnman &connman, bool fUseFilter=false)
bool ConfirmInventoryRequest(const CInv &inv)
Definition: governance.cpp:678
NodeId GetId() const
Definition: net.h:790
const char * MNGOVERNANCESYNC
Definition: protocol.cpp:64
uint256 nHashWatchdogCurrent
Definition: governance.h:250
bool fLiteMode
Definition: util.cpp:109
#define LOCK2(cs1, cs2)
Definition: sync.h:169
void ReleaseNodeVector(const std::vector< CNode *> &vecNodes)
Definition: net.cpp:2908
bool MasternodeRateCheck(const CGovernanceObject &govobj, bool fUpdateFailStatus=false)
Definition: governance.cpp:842
bool HasKey(const K &key) const
Definition: cachemap.h:127
static const int RELIABLE_PROPAGATION_TIME
Definition: governance.h:227
bool AcceptVoteMessage(const uint256 &nHash)
Called to indicate a requested vote has been received.
object_m_t::iterator object_m_it
Definition: governance.h:177
CGovernanceTriggerManager triggerman
void UpdateEmptyFull()
Checks for empty and full filters to avoid wasting cpu.
Definition: bloom.cpp:206
void Misbehaving(NodeId pnode, int howmuch)
void GetKeys(std::vector< K > &vecKeys)
void SetTime(int64_t nTimeIn)
#define LogPrintf(...)
Definition: util.h:98
void AskFor(const CInv &inv)
Definition: net.cpp:2745
hash_s_t setAdditionalRelayObjects
Definition: governance.h:246
static const int GOVERNANCE_OBJECT_WATCHDOG
void Insert(const K &key, const V &value)
Definition: cachemap.h:111
COutPoint prevout
Definition: transaction.h:61
#define LEAVE_CRITICAL_SECTION(cs)
Definition: sync.h:178
Definition: net.h:661
static int LogPrint(const char *category, const char *format)
Definition: util.h:126
void Relay(CConnman &connman)
#define LOCK(cs)
Definition: sync.h:168
const COutPoint & GetMasternodeOutpoint() const
void AddTimestamp(int64_t nTimestamp)
Definition: governance.h:58
static const int MAX_TIME_FUTURE_DEVIATION
Definition: governance.h:226
bool fInbound
Definition: net.h:702
void AddPostponedObject(const CGovernanceObject &govobj)
Definition: governance.h:386
static const int MASTERNODE_SYNC_GOVOBJ
const list_t & GetItemList() const
Definition: cachemap.h:155
bool operator()(const std::pair< CGovernanceObject *, int > &left, const std::pair< CGovernanceObject *, int > &right)
Definition: governance.cpp:656
void UpdatedBlockTip(const CBlockIndex *pindex, CConnman &connman)
std::vector< uint256 > GetAndClearDirtyGovernanceObjectHashes()
static const int GOVERNANCE_OBJECT_TRIGGER
void Sync(CNode *node, const uint256 &nProp, const CBloomFilter &filter, CConnman &connman)
Definition: governance.cpp:733
int64_t nPowTargetSpacing
Definition: params.h:80
void PushInventory(const CInv &inv)
Definition: net.h:866
bool SerializeObjectForHash(uint256 nHash, CDataStream &ss)
Definition: governance.cpp:49
std::string GetDataAsString()
double GetRate()
Definition: governance.h:117
static bool AcceptMessage(const uint256 &nHash, hash_s_t &setHash)
std::string ToString() const
Definition: uint256.cpp:65
bool UpdateCurrentWatchdog(CGovernanceObject &watchdogNew)
Definition: governance.cpp:391
bool IsCollateralValid(std::string &strError, bool &fMissingConfirmations)
Check the collateral transaction for the budget proposal/finalized budget.
int64_t GetDeletionTime() const
bool fMasternode
Definition: net.h:712
std::vector< CNode * > CopyNodeVector()
Definition: net.cpp:2896
const char * MNGOVERNANCEOBJECT
Definition: protocol.cpp:65
void DoMaintenance(CConnman &connman)
Definition: governance.cpp:663
int size()
Return the number of (unique) Masternodes.
static const int GOVERNANCE_FILTER_PROTO_VERSION
std::set< uint256 > hash_s_t
Definition: governance.h:203
void UpdateCachesAndClean()
Definition: governance.cpp:425
void MasternodeRateUpdate(const CGovernanceObject &govobj)
Definition: governance.cpp:816
std::string ToString() const
Definition: protocol.cpp:266
#define ENTER_CRITICAL_SECTION(cs)
Definition: sync.h:172
bool IsSetCachedDelete() const
bool IsValidLocally(std::string &strError, bool fCheckCollateral)
bool HasVote(const uint256 &nHash) const
void CheckMasternodeOrphanObjects(CConnman &connman)
Definition: governance.cpp:996
uint256 ArithToUint256(const arith_uint256 &a)
bool IsSetDirtyCache() const
const char * MNGOVERNANCEOBJECTVOTE
Definition: protocol.cpp:66
void CheckMasternodeOrphanVotes(CConnman &connman)
Definition: governance.cpp:985
std::map< COutPoint, CMasternode > GetFullMasternodeMap()
bool AddNewTrigger(uint256 nHash)
int nSubmittedFinalBudget
Definition: governance.cpp:19
const uint256 & GetParentHash() const
const CChainParams & Params()
Unusual condition requiring no caller action.
txout_m_t mapLastMasternodeObject
Definition: governance.h:260
int64_t GetTimeMillis()
Definition: utiltime.cpp:34
vote_outcome_enum_t
void UpdateWatchdogVoteTime(const COutPoint &outpoint, uint64_t nVoteTime=0)
int64_t GetAdjustedTime()
Definition: timedata.cpp:33
bool IsBlockchainSynced()
size_type GetSize() const
Definition: cachemap.h:107
list_t::const_iterator list_cit
Definition: cachemap.h:57
vote_cache_t mapInvalidVotes
Definition: governance.h:256
hash_s_t::const_iterator hash_s_cit
Definition: governance.h:207
vote_signal_enum_t
CNetFulfilledRequestManager netfulfilledman
object_m_t::const_iterator object_m_cit
Definition: governance.h:179
int type
Definition: protocol.h:338
txout_int_m_t mapMasternodeOrphanCounter
Definition: governance.h:243
Definition: protocol.h:314
static int count
Definition: tests.c:41
bool HaveVoteForHash(uint256 nHash)
Definition: governance.cpp:62
void RemoveGovernanceObject(uint256 nGovernanceObjectHash)
static const std::string MAIN
virtual uint256 GetHash()=0
std::string addrName
Definition: net.h:689
int64_t GetTime()
For unit testing.
Definition: utiltime.cpp:20
CGovernanceManager governance
Definition: governance.cpp:17
bool GetAll(const K &key, std::vector< V > &vecValues)
bool Get(const K &key, V &value) const
Definition: cachemap.h:133
virtual const char * what() const
void BumpAssetLastTime(std::string strFuncName)
static const int64_t GOVERNANCE_DELETION_DELAY
CGovernanceObjectVoteFile & GetVoteFile()
void clear()
Definition: bloom.cpp:118
void AddGovernanceObject(CGovernanceObject &govobj, CConnman &connman, CNode *pfrom=NULL)
Definition: governance.cpp:301
void Relay(CConnman &connman) const
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:113
std::string ToStringShort() const
Definition: transaction.cpp:17
std::list< item_t > list_t
Definition: cachemap.h:53
void Erase(const K &key)
Definition: cachemap.h:144
bool IsMasternodeListSynced()
hash_time_m_t::iterator hash_time_m_it
Definition: governance.h:217
CCriticalSection cs
Definition: governance.h:289
std::string ToString() const
void PushMessage(CNode *pnode, const std::string &sCommand, Args &&... args)
Definition: net.h:199
int GetObjectType() const
std::atomic< int > nVersion
Definition: net.h:692
bool ProcessVote(CNode *pfrom, const CGovernanceVote &vote, CGovernanceException &exception, CConnman &connman)
vote_instance_m_t::iterator vote_instance_m_it
object_m_t mapPostponedObjects
Definition: governance.h:245