Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

governance.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2019 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 
6 #include <consensus/validation.h>
11 #include <init.h>
14 #include <messagesigner.h>
15 #include <net_processing.h>
16 #include <netfulfilledman.h>
17 #include <netmessagemaker.h>
18 #include <spork.h>
19 #include <util.h>
20 #include <validation.h>
21 #include <validationinterface.h>
22 
24 
26 
27 const std::string CGovernanceManager::SERIALIZATION_VERSION_STRING = "CGovernanceManager-Version-15";
30 
32  nTimeLastDiff(0),
33  nCachedBlockHeight(0),
34  mapObjects(),
35  mapErasedGovernanceObjects(),
36  cmapVoteToObject(MAX_CACHE_SIZE),
37  cmapInvalidVotes(MAX_CACHE_SIZE),
38  cmmapOrphanVotes(MAX_CACHE_SIZE),
39  mapLastMasternodeObject(),
40  setRequestedObjects(),
41  fRateChecksEnabled(true),
42  cs()
43 {
44 }
45 
46 // Accessors for thread-safe access to maps
48 {
49  LOCK(cs);
50  return (mapObjects.count(nHash) == 1 || mapPostponedObjects.count(nHash) == 1);
51 }
52 
54 {
55  LOCK(cs);
56  object_m_cit it = mapObjects.find(nHash);
57  if (it == mapObjects.end()) {
58  it = mapPostponedObjects.find(nHash);
59  if (it == mapPostponedObjects.end())
60  return false;
61  }
62  ss << it->second;
63  return true;
64 }
65 
67 {
68  LOCK(cs);
69 
70  CGovernanceObject* pGovobj = nullptr;
71  return cmapVoteToObject.Get(nHash, pGovobj) && pGovobj->GetVoteFile().HasVote(nHash);
72 }
73 
75 {
76  LOCK(cs);
77  return (int)cmapVoteToObject.GetSize();
78 }
79 
81 {
82  LOCK(cs);
83 
84  CGovernanceObject* pGovobj = nullptr;
85  return cmapVoteToObject.Get(nHash, pGovobj) && pGovobj->GetVoteFile().SerializeVoteToStream(nHash, ss);
86 }
87 
88 void CGovernanceManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
89 {
90  if (fDisableGovernance) return;
91  if (!masternodeSync.IsBlockchainSynced()) return;
92 
93  // ANOTHER USER IS ASKING US TO HELP THEM SYNC GOVERNANCE OBJECT DATA
94  if (strCommand == NetMsgType::MNGOVERNANCESYNC) {
96  LogPrint(BCLog::GOBJECT, "MNGOVERNANCESYNC -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
97  if (g_enable_bip61) {
98  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
100  "Version must be %d or greater", MIN_GOVERNANCE_PEER_PROTO_VERSION)));
101  }
102  return;
103  }
104 
105  // Ignore such requests until we are fully synced.
106  // We could start processing this after masternode list is synced
107  // but this is a heavy one so it's better to finish sync first.
108  if (!masternodeSync.IsSynced()) return;
109 
110  uint256 nProp;
111  CBloomFilter filter;
112 
113  vRecv >> nProp;
114 
116  vRecv >> filter;
117  filter.UpdateEmptyFull();
118  } else {
119  filter.clear();
120  }
121 
122  if (nProp == uint256()) {
123  SyncObjects(pfrom, connman);
124  } else {
125  SyncSingleObjVotes(pfrom, nProp, filter, connman);
126  }
127  LogPrint(BCLog::GOBJECT, "MNGOVERNANCESYNC -- syncing governance objects to our peer %s\n", pfrom->GetLogString());
128  }
129 
130  // A NEW GOVERNANCE OBJECT HAS ARRIVED
131  else if (strCommand == NetMsgType::MNGOVERNANCEOBJECT) {
132  // MAKE SURE WE HAVE A VALID REFERENCE TO THE TIP BEFORE CONTINUING
133 
134  CGovernanceObject govobj;
135  vRecv >> govobj;
136 
137  uint256 nHash = govobj.GetHash();
138 
139  {
140  LOCK(cs_main);
142  }
143 
145  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
146  if (g_enable_bip61) {
147  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
149  "Version must be %d or greater", MIN_GOVERNANCE_PEER_PROTO_VERSION)));
150  }
151  return;
152  }
153 
155  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- masternode list not synced\n");
156  return;
157  }
158 
159  std::string strHash = nHash.ToString();
160 
161  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- Received object: %s\n", strHash);
162 
163  if (!AcceptObjectMessage(nHash)) {
164  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- Received unrequested object: %s\n", strHash);
165  return;
166  }
167 
168  LOCK2(cs_main, cs);
169 
170  if (mapObjects.count(nHash) || mapPostponedObjects.count(nHash) || mapErasedGovernanceObjects.count(nHash)) {
171  // TODO - print error code? what if it's GOVOBJ_ERROR_IMMATURE?
172  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- Received already seen object: %s\n", strHash);
173  return;
174  }
175 
176  bool fRateCheckBypassed = false;
177  if (!MasternodeRateCheck(govobj, true, false, fRateCheckBypassed)) {
178  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- masternode rate check failed - %s - (current block height %d) \n", strHash, nCachedBlockHeight);
179  return;
180  }
181 
182  std::string strError = "";
183  // CHECK OBJECT AGAINST LOCAL BLOCKCHAIN
184 
185  bool fMissingConfirmations = false;
186  bool fIsValid = govobj.IsValidLocally(strError, fMissingConfirmations, true);
187 
188  if (fRateCheckBypassed && fIsValid) {
189  if (!MasternodeRateCheck(govobj, true)) {
190  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- masternode rate check failed (after signature verification) - %s - (current block height %d)\n", strHash, nCachedBlockHeight);
191  return;
192  }
193  }
194 
195  if (!fIsValid) {
196  if (fMissingConfirmations) {
197  AddPostponedObject(govobj);
198  LogPrintf("MNGOVERNANCEOBJECT -- Not enough fee confirmations for: %s, strError = %s\n", strHash, strError);
199  } else {
200  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- Governance object is invalid - %s\n", strError);
201  // apply node's ban score
202  Misbehaving(pfrom->GetId(), 20);
203  }
204 
205  return;
206  }
207 
208  AddGovernanceObject(govobj, connman, pfrom);
209  }
210 
211  // A NEW GOVERNANCE OBJECT VOTE HAS ARRIVED
212  else if (strCommand == NetMsgType::MNGOVERNANCEOBJECTVOTE) {
213  CGovernanceVote vote;
214  vRecv >> vote;
215 
216  uint256 nHash = vote.GetHash();
217 
218  {
219  LOCK(cs_main);
221  }
222 
224  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
225  if (g_enable_bip61) {
226  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
228  "Version must be %d or greater", MIN_GOVERNANCE_PEER_PROTO_VERSION)));
229  }
230  }
231 
232  // Ignore such messages until masternode list is synced
234  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- masternode list not synced\n");
235  return;
236  }
237 
238  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Received vote: %s\n", vote.ToString());
239 
240  std::string strHash = nHash.ToString();
241 
242  if (!AcceptVoteMessage(nHash)) {
243  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Received unrequested vote object: %s, hash: %s, peer = %d\n",
244  vote.ToString(), strHash, pfrom->GetId());
245  return;
246  }
247 
248  CGovernanceException exception;
249  if (ProcessVote(pfrom, vote, exception, connman)) {
250  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- %s new\n", strHash);
251  masternodeSync.BumpAssetLastTime("MNGOVERNANCEOBJECTVOTE");
252  vote.Relay(connman);
253  } else {
254  LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Rejected vote, error = %s\n", exception.what());
255  if ((exception.GetNodePenalty() != 0) && masternodeSync.IsSynced()) {
256  LOCK(cs_main);
257  Misbehaving(pfrom->GetId(), exception.GetNodePenalty());
258  }
259  return;
260  }
261  // SEND NOTIFICATION TO SCRIPT/ZMQ
263  }
264 }
265 
267 {
268  uint256 nHash = govobj.GetHash();
269  std::vector<vote_time_pair_t> vecVotePairs;
270  cmmapOrphanVotes.GetAll(nHash, vecVotePairs);
271 
272  ScopedLockBool guard(cs, fRateChecksEnabled, false);
273 
274  int64_t nNow = GetAdjustedTime();
275  for (auto& pairVote : vecVotePairs) {
276  bool fRemove = false;
277  CGovernanceVote& vote = pairVote.first;
278  CGovernanceException exception;
279  if (pairVote.second < nNow) {
280  fRemove = true;
281  } else if (govobj.ProcessVote(nullptr, vote, exception, connman)) {
282  vote.Relay(connman);
283  fRemove = true;
284  }
285  if (fRemove) {
286  cmmapOrphanVotes.Erase(nHash, pairVote);
287  }
288  }
289 }
290 
292 {
293  uint256 nHash = govobj.GetHash();
294  std::string strHash = nHash.ToString();
295 
296  // UPDATE CACHED VARIABLES FOR THIS OBJECT AND ADD IT TO OUR MANANGED DATA
297 
298  govobj.UpdateSentinelVariables(); //this sets local vars in object
299 
300  LOCK2(cs_main, cs);
301  std::string strError = "";
302 
303  // MAKE SURE THIS OBJECT IS OK
304 
305  if (!govobj.IsValidLocally(strError, true)) {
306  LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- invalid governance object - %s - (nCachedBlockHeight %d) \n", strError, nCachedBlockHeight);
307  return;
308  }
309 
310  LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- Adding object: hash = %s, type = %d\n", nHash.ToString(), govobj.GetObjectType());
311 
312  // INSERT INTO OUR GOVERNANCE OBJECT MEMORY
313  // IF WE HAVE THIS OBJECT ALREADY, WE DON'T WANT ANOTHER COPY
314  auto objpair = mapObjects.emplace(nHash, govobj);
315 
316  if (!objpair.second) {
317  LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- already have governance object %s\n", nHash.ToString());
318  return;
319  }
320 
321  // SHOULD WE ADD THIS OBJECT TO ANY OTHER MANANGERS?
322 
323  LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- Before trigger block, GetDataAsPlainString = %s, nObjectType = %d\n",
324  govobj.GetDataAsPlainString(), govobj.GetObjectType());
325 
326  if (govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) {
327  if (!triggerman.AddNewTrigger(nHash)) {
328  LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- undo adding invalid trigger object: hash = %s\n", nHash.ToString());
329  objpair.first->second.PrepareDeletion(GetAdjustedTime());
330  return;
331  }
332  }
333 
334  LogPrintf("CGovernanceManager::AddGovernanceObject -- %s new, received from peer %s\n", strHash, pfrom ? pfrom->GetLogString() : "nullptr");
335  govobj.Relay(connman);
336 
337  // Update the rate buffer
338  MasternodeRateUpdate(govobj);
339 
340  masternodeSync.BumpAssetLastTime("CGovernanceManager::AddGovernanceObject");
341 
342  // WE MIGHT HAVE PENDING/ORPHAN VOTES FOR THIS OBJECT
343 
344  CGovernanceException exception;
345  CheckOrphanVotes(govobj, exception, connman);
346 
347  // SEND NOTIFICATION TO SCRIPT/ZMQ
349 }
350 
352 {
353  // Return on initial sync, spammed the debug.log and provided no use
355  return;
356  }
357 
358  LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean\n");
359 
360  std::vector<uint256> vecDirtyHashes = mmetaman.GetAndClearDirtyGovernanceObjectHashes();
361 
362  LOCK2(cs_main, cs);
363 
364  for (const uint256& nHash : vecDirtyHashes) {
365  object_m_it it = mapObjects.find(nHash);
366  if (it == mapObjects.end()) {
367  continue;
368  }
369  it->second.ClearMasternodeVotes();
370  }
371 
372  ScopedLockBool guard(cs, fRateChecksEnabled, false);
373 
374  // Clean up any expired or invalid triggers
376 
377  object_m_it it = mapObjects.begin();
378  int64_t nNow = GetAdjustedTime();
379 
380  while (it != mapObjects.end()) {
381  CGovernanceObject* pObj = &((*it).second);
382 
383  if (!pObj) {
384  ++it;
385  continue;
386  }
387 
388  uint256 nHash = it->first;
389  std::string strHash = nHash.ToString();
390 
391  // IF CACHE IS NOT DIRTY, WHY DO THIS?
392  if (pObj->IsSetDirtyCache()) {
393  // UPDATE LOCAL VALIDITY AGAINST CRYPTO DATA
394  pObj->UpdateLocalValidity();
395 
396  // UPDATE SENTINEL SIGNALING VARIABLES
397  pObj->UpdateSentinelVariables();
398  }
399 
400  // IF DELETE=TRUE, THEN CLEAN THE MESS UP!
401 
402  int64_t nTimeSinceDeletion = nNow - pObj->GetDeletionTime();
403 
404  LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean -- Checking object for deletion: %s, deletion time = %d, time since deletion = %d, delete flag = %d, expired flag = %d\n",
405  strHash, pObj->GetDeletionTime(), nTimeSinceDeletion, pObj->IsSetCachedDelete(), pObj->IsSetExpired());
406 
407  if ((pObj->IsSetCachedDelete() || pObj->IsSetExpired()) &&
408  (nTimeSinceDeletion >= GOVERNANCE_DELETION_DELAY)) {
409  LogPrintf("CGovernanceManager::UpdateCachesAndClean -- erase obj %s\n", (*it).first.ToString());
411 
412  // Remove vote references
414  object_ref_cm_t::list_cit lit = listItems.begin();
415  while (lit != listItems.end()) {
416  if (lit->value == pObj) {
417  uint256 nKey = lit->key;
418  ++lit;
419  cmapVoteToObject.Erase(nKey);
420  } else {
421  ++lit;
422  }
423  }
424 
425  int64_t nTimeExpired{0};
426 
427  if (pObj->GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
428  // keep hashes of deleted proposals forever
429  nTimeExpired = std::numeric_limits<int64_t>::max();
430  } else {
431  int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing;
432  nTimeExpired = pObj->GetCreationTime() + 2 * nSuperblockCycleSeconds + GOVERNANCE_DELETION_DELAY;
433  }
434 
435  mapErasedGovernanceObjects.insert(std::make_pair(nHash, nTimeExpired));
436  mapObjects.erase(it++);
437  } else {
438  // NOTE: triggers are handled via triggerman
439  if (pObj->GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
440  CProposalValidator validator(pObj->GetDataAsHexString(), true);
441  if (!validator.Validate()) {
442  LogPrintf("CGovernanceManager::UpdateCachesAndClean -- set for deletion expired obj %s\n", strHash);
443  pObj->PrepareDeletion(nNow);
444  }
445  }
446  ++it;
447  }
448  }
449 
450  // forget about expired deleted objects
452  while (s_it != mapErasedGovernanceObjects.end()) {
453  if (s_it->second < nNow) {
454  mapErasedGovernanceObjects.erase(s_it++);
455  } else {
456  ++s_it;
457  }
458  }
459 
460  LogPrintf("CGovernanceManager::UpdateCachesAndClean -- %s\n", ToString());
461 }
462 
464 {
465  LOCK(cs);
466 
467  if (mapObjects.count(nHash)) return &mapObjects[nHash];
468 
469  return nullptr;
470 }
471 
472 std::vector<CGovernanceVote> CGovernanceManager::GetCurrentVotes(const uint256& nParentHash, const COutPoint& mnCollateralOutpointFilter) const
473 {
474  LOCK(cs);
475  std::vector<CGovernanceVote> vecResult;
476 
477  // Find the governance object or short-circuit.
478  object_m_cit it = mapObjects.find(nParentHash);
479  if (it == mapObjects.end()) return vecResult;
480  const CGovernanceObject& govobj = it->second;
481 
482  auto mnList = deterministicMNManager->GetListAtChainTip();
483  std::map<COutPoint, CDeterministicMNCPtr> mapMasternodes;
484  if (mnCollateralOutpointFilter.IsNull()) {
485  mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
486  mapMasternodes.emplace(dmn->collateralOutpoint, dmn);
487  });
488  } else {
489  auto dmn = mnList.GetMNByCollateral(mnCollateralOutpointFilter);
490  if (dmn) {
491  mapMasternodes.emplace(dmn->collateralOutpoint, dmn);
492  }
493  }
494 
495  // Loop thru each MN collateral outpoint and get the votes for the `nParentHash` governance object
496  for (const auto& mnpair : mapMasternodes) {
497  // get a vote_rec_t from the govobj
498  vote_rec_t voteRecord;
499  if (!govobj.GetCurrentMNVotes(mnpair.first, voteRecord)) continue;
500 
501  for (const auto& voteInstancePair : voteRecord.mapInstances) {
502  int signal = voteInstancePair.first;
503  int outcome = voteInstancePair.second.eOutcome;
504  int64_t nCreationTime = voteInstancePair.second.nCreationTime;
505 
506  CGovernanceVote vote = CGovernanceVote(mnpair.first, nParentHash, (vote_signal_enum_t)signal, (vote_outcome_enum_t)outcome);
507  vote.SetTime(nCreationTime);
508 
509  vecResult.push_back(vote);
510  }
511  }
512 
513  return vecResult;
514 }
515 
516 std::vector<const CGovernanceObject*> CGovernanceManager::GetAllNewerThan(int64_t nMoreThanTime) const
517 {
518  LOCK(cs);
519 
520  std::vector<const CGovernanceObject*> vGovObjs;
521 
522  for (const auto& objPair : mapObjects) {
523  // IF THIS OBJECT IS OLDER THAN TIME, CONTINUE
524  if (objPair.second.GetCreationTime() < nMoreThanTime) {
525  continue;
526  }
527 
528  // ADD GOVERNANCE OBJECT TO LIST
529  const CGovernanceObject* pGovObj = &(objPair.second);
530  vGovObjs.push_back(pGovObj);
531  }
532 
533  return vGovObjs;
534 }
535 
536 //
537 // Sort by votes, if there's a tie sort by their feeHash TX
538 //
540  bool operator()(const std::pair<CGovernanceObject*, int>& left, const std::pair<CGovernanceObject*, int>& right)
541  {
542  if (left.second != right.second) return (left.second > right.second);
543  return (UintToArith256(left.first->GetCollateralHash()) > UintToArith256(right.first->GetCollateralHash()));
544  }
545 };
546 
548 {
550 
551  // CHECK OBJECTS WE'VE ASKED FOR, REMOVE OLD ENTRIES
552 
554 
555  RequestOrphanObjects(connman);
556 
557  // CHECK AND REMOVE - REPROCESS GOVERNANCE OBJECTS
558 
560 }
561 
563 {
564  // do not request objects until it's time to sync
565  if (!masternodeSync.IsBlockchainSynced()) return false;
566 
567  LOCK(cs);
568 
569  LogPrint(BCLog::GOBJECT, "CGovernanceManager::ConfirmInventoryRequest inv = %s\n", inv.ToString());
570 
571  // First check if we've already recorded this object
572  switch (inv.type) {
573  case MSG_GOVERNANCE_OBJECT: {
574  if (mapObjects.count(inv.hash) == 1 || mapPostponedObjects.count(inv.hash) == 1) {
575  LogPrint(BCLog::GOBJECT, "CGovernanceManager::ConfirmInventoryRequest already have governance object, returning false\n");
576  return false;
577  }
578  break;
579  }
581  if (cmapVoteToObject.HasKey(inv.hash)) {
582  LogPrint(BCLog::GOBJECT, "CGovernanceManager::ConfirmInventoryRequest already have governance vote, returning false\n");
583  return false;
584  }
585  break;
586  }
587  default:
588  LogPrint(BCLog::GOBJECT, "CGovernanceManager::ConfirmInventoryRequest unknown type, returning false\n");
589  return false;
590  }
591 
592 
593  hash_s_t* setHash = nullptr;
594  switch (inv.type) {
596  setHash = &setRequestedObjects;
597  break;
599  setHash = &setRequestedVotes;
600  break;
601  default:
602  return false;
603  }
604 
605  hash_s_cit it = setHash->find(inv.hash);
606  if (it == setHash->end()) {
607  setHash->insert(inv.hash);
608  LogPrint(BCLog::GOBJECT, "CGovernanceManager::ConfirmInventoryRequest added inv to requested set\n");
609  }
610 
611  LogPrint(BCLog::GOBJECT, "CGovernanceManager::ConfirmInventoryRequest reached end, returning true\n");
612  return true;
613 }
614 
615 void CGovernanceManager::SyncSingleObjVotes(CNode* pnode, const uint256& nProp, const CBloomFilter& filter, CConnman& connman)
616 {
617  // do not provide any data until our node is synced
618  if (!masternodeSync.IsSynced()) return;
619 
620  int nVoteCount = 0;
621 
622  // SYNC GOVERNANCE OBJECTS WITH OTHER CLIENT
623 
624  LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- syncing single object to peer=%d, nProp = %s\n", __func__, pnode->GetId(), nProp.ToString());
625 
626  LOCK2(cs_main, cs);
627 
628  // single valid object and its valid votes
629  object_m_it it = mapObjects.find(nProp);
630  if (it == mapObjects.end()) {
631  LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- no matching object for hash %s, peer=%d\n", __func__, nProp.ToString(), pnode->GetId());
632  return;
633  }
634  CGovernanceObject& govobj = it->second;
635  std::string strHash = it->first.ToString();
636 
637  LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- attempting to sync govobj: %s, peer=%d\n", __func__, strHash, pnode->GetId());
638 
639  if (govobj.IsSetCachedDelete() || govobj.IsSetExpired()) {
640  LogPrintf("CGovernanceManager::%s -- not syncing deleted/expired govobj: %s, peer=%d\n", __func__,
641  strHash, pnode->GetId());
642  return;
643  }
644 
645  auto fileVotes = govobj.GetVoteFile();
646 
647  for (const auto& vote : fileVotes.GetVotes()) {
648  uint256 nVoteHash = vote.GetHash();
649 
650  bool onlyVotingKeyAllowed = govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL && vote.GetSignal() == VOTE_SIGNAL_FUNDING;
651 
652  if (filter.contains(nVoteHash) || !vote.IsValid(onlyVotingKeyAllowed)) {
653  continue;
654  }
655  pnode->PushInventory(CInv(MSG_GOVERNANCE_OBJECT_VOTE, nVoteHash));
656  ++nVoteCount;
657  }
658 
659  CNetMsgMaker msgMaker(pnode->GetSendVersion());
660  connman.PushMessage(pnode, msgMaker.Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_GOVOBJ_VOTE, nVoteCount));
661  LogPrintf("CGovernanceManager::%s -- sent %d votes to peer=%d\n", __func__, nVoteCount, pnode->GetId());
662 }
663 
664 void CGovernanceManager::SyncObjects(CNode* pnode, CConnman& connman) const
665 {
666  // do not provide any data until our node is synced
667  if (!masternodeSync.IsSynced()) return;
668 
670  LOCK(cs_main);
671  // Asking for the whole list multiple times in a short period of time is no good
672  LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- peer already asked me for the list\n", __func__);
673  Misbehaving(pnode->GetId(), 20);
674  return;
675  }
677 
678  int nObjCount = 0;
679 
680  // SYNC GOVERNANCE OBJECTS WITH OTHER CLIENT
681 
682  LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- syncing all objects to peer=%d\n", __func__, pnode->GetId());
683 
684  LOCK2(cs_main, cs);
685 
686  // all valid objects, no votes
687  for (const auto& objPair : mapObjects) {
688  uint256 nHash = objPair.first;
689  const CGovernanceObject& govobj = objPair.second;
690  std::string strHash = nHash.ToString();
691 
692  LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- attempting to sync govobj: %s, peer=%d\n", __func__, strHash, pnode->GetId());
693 
694  if (govobj.IsSetCachedDelete() || govobj.IsSetExpired()) {
695  LogPrintf("CGovernanceManager::%s -- not syncing deleted/expired govobj: %s, peer=%d\n", __func__,
696  strHash, pnode->GetId());
697  continue;
698  }
699 
700  // Push the inventory budget proposal message over to the other client
701  LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- syncing govobj: %s, peer=%d\n", __func__, strHash, pnode->GetId());
702  pnode->PushInventory(CInv(MSG_GOVERNANCE_OBJECT, nHash));
703  ++nObjCount;
704  }
705 
706  CNetMsgMaker msgMaker(pnode->GetSendVersion());
707  connman.PushMessage(pnode, msgMaker.Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_GOVOBJ, nObjCount));
708  LogPrintf("CGovernanceManager::%s -- sent %d objects to peer=%d\n", __func__, nObjCount, pnode->GetId());
709 }
710 
712 {
713  if (govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) return;
714 
715  const COutPoint& masternodeOutpoint = govobj.GetMasternodeOutpoint();
716  txout_m_it it = mapLastMasternodeObject.find(masternodeOutpoint);
717 
718  if (it == mapLastMasternodeObject.end()) {
719  it = mapLastMasternodeObject.insert(txout_m_t::value_type(masternodeOutpoint, last_object_rec(true))).first;
720  }
721 
722  int64_t nTimestamp = govobj.GetCreationTime();
723  it->second.triggerBuffer.AddTimestamp(nTimestamp);
724 
726  // schedule additional relay for the object
727  setAdditionalRelayObjects.insert(govobj.GetHash());
728  }
729 
730  it->second.fStatusOK = true;
731 }
732 
733 bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus)
734 {
735  bool fRateCheckBypassed;
736  return MasternodeRateCheck(govobj, fUpdateFailStatus, true, fRateCheckBypassed);
737 }
738 
739 bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus, bool fForce, bool& fRateCheckBypassed)
740 {
741  LOCK(cs);
742 
743  fRateCheckBypassed = false;
744 
746  return true;
747  }
748 
749  if (govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) {
750  return true;
751  }
752 
753  const COutPoint& masternodeOutpoint = govobj.GetMasternodeOutpoint();
754  int64_t nTimestamp = govobj.GetCreationTime();
755  int64_t nNow = GetAdjustedTime();
756  int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing;
757 
758  std::string strHash = govobj.GetHash().ToString();
759 
760  if (nTimestamp < nNow - 2 * nSuperblockCycleSeconds) {
761  LogPrint(BCLog::GOBJECT, "CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too old timestamp, masternode = %s, timestamp = %d, current time = %d\n",
762  strHash, masternodeOutpoint.ToStringShort(), nTimestamp, nNow);
763  return false;
764  }
765 
766  if (nTimestamp > nNow + MAX_TIME_FUTURE_DEVIATION) {
767  LogPrint(BCLog::GOBJECT, "CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too new (future) timestamp, masternode = %s, timestamp = %d, current time = %d\n",
768  strHash, masternodeOutpoint.ToStringShort(), nTimestamp, nNow);
769  return false;
770  }
771 
772  txout_m_it it = mapLastMasternodeObject.find(masternodeOutpoint);
773  if (it == mapLastMasternodeObject.end()) return true;
774 
775  if (it->second.fStatusOK && !fForce) {
776  fRateCheckBypassed = true;
777  return true;
778  }
779 
780  // Allow 1 trigger per mn per cycle, with a small fudge factor
781  double dMaxRate = 2 * 1.1 / double(nSuperblockCycleSeconds);
782 
783  // Temporary copy to check rate after new timestamp is added
784  CRateCheckBuffer buffer = it->second.triggerBuffer;
785 
786  buffer.AddTimestamp(nTimestamp);
787  double dRate = buffer.GetRate();
788 
789  if (dRate < dMaxRate) {
790  return true;
791  }
792 
793  LogPrint(BCLog::GOBJECT, "CGovernanceManager::MasternodeRateCheck -- Rate too high: object hash = %s, masternode = %s, object timestamp = %d, rate = %f, max rate = %f\n",
794  strHash, masternodeOutpoint.ToStringShort(), nTimestamp, dRate, dMaxRate);
795 
796  if (fUpdateFailStatus) {
797  it->second.fStatusOK = false;
798  }
799 
800  return false;
801 }
802 
804 {
806  uint256 nHashVote = vote.GetHash();
807  uint256 nHashGovobj = vote.GetParentHash();
808 
809  if (cmapVoteToObject.HasKey(nHashVote)) {
810  LogPrint(BCLog::GOBJECT, "CGovernanceObject::ProcessVote -- skipping known valid vote %s for object %s\n", nHashVote.ToString(), nHashGovobj.ToString());
812  return false;
813  }
814 
815  if (cmapInvalidVotes.HasKey(nHashVote)) {
816  std::ostringstream ostr;
817  ostr << "CGovernanceManager::ProcessVote -- Old invalid vote "
818  << ", MN outpoint = " << vote.GetMasternodeOutpoint().ToStringShort()
819  << ", governance object hash = " << nHashGovobj.ToString();
820  LogPrint(BCLog::GOBJECT, "%s\n", ostr.str());
821  exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_PERMANENT_ERROR, 20);
823  return false;
824  }
825 
826  object_m_it it = mapObjects.find(nHashGovobj);
827  if (it == mapObjects.end()) {
828  std::ostringstream ostr;
829  ostr << "CGovernanceManager::ProcessVote -- Unknown parent object " << nHashGovobj.ToString()
830  << ", MN outpoint = " << vote.GetMasternodeOutpoint().ToStringShort();
831  exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_WARNING);
834  RequestGovernanceObject(pfrom, nHashGovobj, connman);
835  LogPrint(BCLog::GOBJECT, "%s\n", ostr.str());
836  return false;
837  }
838 
839  LogPrint(BCLog::GOBJECT, "%s\n", ostr.str());
841  return false;
842  }
843 
844  CGovernanceObject& govobj = it->second;
845 
846  if (govobj.IsSetCachedDelete() || govobj.IsSetExpired()) {
847  LogPrint(BCLog::GOBJECT, "CGovernanceObject::ProcessVote -- ignoring vote for expired or deleted object, hash = %s\n", nHashGovobj.ToString());
849  return false;
850  }
851 
852  bool fOk = govobj.ProcessVote(pfrom, vote, exception, connman) && cmapVoteToObject.Insert(nHashVote, &govobj);
854  return fOk;
855 }
856 
858 {
859  if (!masternodeSync.IsSynced()) return;
860 
861  LOCK2(cs_main, cs);
862 
863  // Check postponed proposals
864  for (object_m_it it = mapPostponedObjects.begin(); it != mapPostponedObjects.end();) {
865  const uint256& nHash = it->first;
866  CGovernanceObject& govobj = it->second;
867 
868  assert(govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER);
869 
870  std::string strError;
871  bool fMissingConfirmations;
872  if (govobj.IsCollateralValid(strError, fMissingConfirmations)) {
873  if (govobj.IsValidLocally(strError, false)) {
874  AddGovernanceObject(govobj, connman);
875  } else {
876  LogPrint(BCLog::GOBJECT, "CGovernanceManager::CheckPostponedObjects -- %s invalid\n", nHash.ToString());
877  }
878 
879  } else if (fMissingConfirmations) {
880  // wait for more confirmations
881  ++it;
882  continue;
883  }
884 
885  // remove processed or invalid object from the queue
886  mapPostponedObjects.erase(it++);
887  }
888 
889 
890  // Perform additional relays for triggers
891  int64_t nNow = GetAdjustedTime();
892  int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing;
893 
894  for (hash_s_it it = setAdditionalRelayObjects.begin(); it != setAdditionalRelayObjects.end();) {
895  object_m_it itObject = mapObjects.find(*it);
896  if (itObject != mapObjects.end()) {
897  CGovernanceObject& govobj = itObject->second;
898 
899  int64_t nTimestamp = govobj.GetCreationTime();
900 
901  bool fValid = (nTimestamp <= nNow + MAX_TIME_FUTURE_DEVIATION) && (nTimestamp >= nNow - 2 * nSuperblockCycleSeconds);
902  bool fReady = (nTimestamp <= nNow + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME);
903 
904  if (fValid) {
905  if (fReady) {
906  LogPrintf("CGovernanceManager::CheckPostponedObjects -- additional relay: hash = %s\n", govobj.GetHash().ToString());
907  govobj.Relay(connman);
908  } else {
909  it++;
910  continue;
911  }
912  }
913 
914  } else {
915  LogPrintf("CGovernanceManager::CheckPostponedObjects -- additional relay of unknown object: %s\n", it->ToString());
916  }
917 
918  setAdditionalRelayObjects.erase(it++);
919  }
920 }
921 
922 void CGovernanceManager::RequestGovernanceObject(CNode* pfrom, const uint256& nHash, CConnman& connman, bool fUseFilter)
923 {
924  if (!pfrom) {
925  return;
926  }
927 
928  LogPrint(BCLog::GOBJECT, "CGovernanceManager::RequestGovernanceObject -- nHash %s peer=%d\n", nHash.ToString(), pfrom->GetId());
929 
930  CNetMsgMaker msgMaker(pfrom->GetSendVersion());
931 
933  connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MNGOVERNANCESYNC, nHash));
934  return;
935  }
936 
937  CBloomFilter filter;
938  filter.clear();
939 
940  int nVoteCount = 0;
941  if (fUseFilter) {
942  LOCK(cs);
944 
945  if (pObj) {
946  filter = CBloomFilter(Params().GetConsensus().nGovernanceFilterElements, GOVERNANCE_FILTER_FP_RATE, GetRandInt(999999), BLOOM_UPDATE_ALL);
947  std::vector<CGovernanceVote> vecVotes = pObj->GetVoteFile().GetVotes();
948  nVoteCount = vecVotes.size();
949  for (const auto& vote : vecVotes) {
950  filter.insert(vote.GetHash());
951  }
952  }
953  }
954 
955  LogPrint(BCLog::GOBJECT, "CGovernanceManager::RequestGovernanceObject -- nHash %s nVoteCount %d peer=%d\n", nHash.ToString(), nVoteCount, pfrom->GetId());
956  connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MNGOVERNANCESYNC, nHash, filter));
957 }
958 
960 {
961  if (pnode->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) return -3;
962  std::vector<CNode*> vNodesCopy;
963  vNodesCopy.push_back(pnode);
964  return RequestGovernanceObjectVotes(vNodesCopy, connman);
965 }
966 
967 int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector<CNode*>& vNodesCopy, CConnman& connman)
968 {
969  static std::map<uint256, std::map<CService, int64_t> > mapAskedRecently;
970 
971  if (vNodesCopy.empty()) return -1;
972 
973  int64_t nNow = GetTime();
974  int nTimeout = 60 * 60;
975  size_t nPeersPerHashMax = 3;
976 
977  std::vector<uint256> vTriggerObjHashes;
978  std::vector<uint256> vOtherObjHashes;
979 
980  // This should help us to get some idea about an impact this can bring once deployed on mainnet.
981  // Testnet is ~40 times smaller in masternode count, but only ~1000 masternodes usually vote,
982  // so 1 obj on mainnet == ~10 objs or ~1000 votes on testnet. However we want to test a higher
983  // number of votes to make sure it's robust enough, so aim at 2000 votes per masternode per request.
984  // On mainnet nMaxObjRequestsPerNode is always set to 1.
985  int nMaxObjRequestsPerNode = 1;
986  size_t nProjectedVotes = 2000;
987  if (Params().NetworkIDString() != CBaseChainParams::MAIN) {
988  nMaxObjRequestsPerNode = std::max(1, int(nProjectedVotes / std::max(1, (int)deterministicMNManager->GetListAtChainTip().GetValidMNsCount())));
989  }
990 
991  {
992  LOCK2(cs_main, cs);
993 
994  if (mapObjects.empty()) return -2;
995 
996  for (const auto& objPair : mapObjects) {
997  uint256 nHash = objPair.first;
998  if (mapAskedRecently.count(nHash)) {
999  auto it = mapAskedRecently[nHash].begin();
1000  while (it != mapAskedRecently[nHash].end()) {
1001  if (it->second < nNow) {
1002  mapAskedRecently[nHash].erase(it++);
1003  } else {
1004  ++it;
1005  }
1006  }
1007  if (mapAskedRecently[nHash].size() >= nPeersPerHashMax) continue;
1008  }
1009 
1010  if (objPair.second.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) {
1011  vTriggerObjHashes.push_back(nHash);
1012  } else {
1013  vOtherObjHashes.push_back(nHash);
1014  }
1015  }
1016  }
1017 
1018  LogPrint(BCLog::GOBJECT, "CGovernanceManager::RequestGovernanceObjectVotes -- start: vTriggerObjHashes %d vOtherObjHashes %d mapAskedRecently %d\n",
1019  vTriggerObjHashes.size(), vOtherObjHashes.size(), mapAskedRecently.size());
1020 
1021  FastRandomContext insecure_rand;
1022  std::random_shuffle(vTriggerObjHashes.begin(), vTriggerObjHashes.end(), insecure_rand);
1023  std::random_shuffle(vOtherObjHashes.begin(), vOtherObjHashes.end(), insecure_rand);
1024 
1025  for (int i = 0; i < nMaxObjRequestsPerNode; ++i) {
1026  uint256 nHashGovobj;
1027 
1028  // ask for triggers first
1029  if (vTriggerObjHashes.size()) {
1030  nHashGovobj = vTriggerObjHashes.back();
1031  } else {
1032  if (vOtherObjHashes.empty()) break;
1033  nHashGovobj = vOtherObjHashes.back();
1034  }
1035  bool fAsked = false;
1036  for (const auto& pnode : vNodesCopy) {
1037  // Only use regular peers, don't try to ask from outbound "masternode" connections -
1038  // they stay connected for a short period of time and it's possible that we won't get everything we should.
1039  // Only use outbound connections - inbound connection could be a "masternode" connection
1040  // initiated from another node, so skip it too.
1041  if (pnode->fMasternode || (fMasternodeMode && pnode->fInbound)) continue;
1042  // only use up to date peers
1043  if (pnode->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) continue;
1044  // stop early to prevent setAskFor overflow
1045  {
1046  LOCK(cs_main);
1047  size_t nProjectedSize = GetRequestedObjectCount(pnode->GetId()) + nProjectedVotes;
1048  if (nProjectedSize > MAX_INV_SZ) continue;
1049  // to early to ask the same node
1050  if (mapAskedRecently[nHashGovobj].count(pnode->addr)) continue;
1051  }
1052 
1053  RequestGovernanceObject(pnode, nHashGovobj, connman, true);
1054  mapAskedRecently[nHashGovobj][pnode->addr] = nNow + nTimeout;
1055  fAsked = true;
1056  // stop loop if max number of peers per obj was asked
1057  if (mapAskedRecently[nHashGovobj].size() >= nPeersPerHashMax) break;
1058  }
1059  // NOTE: this should match `if` above (the one before `while`)
1060  if (vTriggerObjHashes.size()) {
1061  vTriggerObjHashes.pop_back();
1062  } else {
1063  vOtherObjHashes.pop_back();
1064  }
1065  if (!fAsked) i--;
1066  }
1067  LogPrint(BCLog::GOBJECT, "CGovernanceManager::RequestGovernanceObjectVotes -- end: vTriggerObjHashes %d vOtherObjHashes %d mapAskedRecently %d\n",
1068  vTriggerObjHashes.size(), vOtherObjHashes.size(), mapAskedRecently.size());
1069 
1070  return int(vTriggerObjHashes.size() + vOtherObjHashes.size());
1071 }
1072 
1074 {
1075  LOCK(cs);
1076  return AcceptMessage(nHash, setRequestedObjects);
1077 }
1078 
1080 {
1081  LOCK(cs);
1082  return AcceptMessage(nHash, setRequestedVotes);
1083 }
1084 
1086 {
1087  hash_s_it it = setHash.find(nHash);
1088  if (it == setHash.end()) {
1089  // We never requested this
1090  return false;
1091  }
1092  // Only accept one response
1093  setHash.erase(it);
1094  return true;
1095 }
1096 
1098 {
1099  LOCK(cs);
1100 
1102  for (auto& objPair : mapObjects) {
1103  CGovernanceObject& govobj = objPair.second;
1104  std::vector<CGovernanceVote> vecVotes = govobj.GetVoteFile().GetVotes();
1105  for (size_t i = 0; i < vecVotes.size(); ++i) {
1106  cmapVoteToObject.Insert(vecVotes[i].GetHash(), &govobj);
1107  }
1108  }
1109 }
1110 
1112 {
1113  LOCK(cs);
1114 
1115  for (auto& objpair : mapObjects) {
1116  CGovernanceObject& govobj = objpair.second;
1117 
1118  if (govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) {
1119  continue;
1120  }
1121 
1122  if (!triggerman.AddNewTrigger(govobj.GetHash())) {
1123  govobj.PrepareDeletion(GetAdjustedTime());
1124  }
1125  }
1126 }
1127 
1129 {
1130  LOCK(cs);
1131  int64_t nStart = GetTimeMillis();
1132  LogPrintf("Preparing masternode indexes and governance triggers...\n");
1133  RebuildIndexes();
1135  LogPrintf("Masternode indexes and governance triggers prepared %dms\n", GetTimeMillis() - nStart);
1136  LogPrintf(" %s\n", ToString());
1137 }
1138 
1139 std::string CGovernanceManager::ToString() const
1140 {
1141  LOCK(cs);
1142 
1143  int nProposalCount = 0;
1144  int nTriggerCount = 0;
1145  int nOtherCount = 0;
1146 
1147  for (const auto& objPair : mapObjects) {
1148  switch (objPair.second.GetObjectType()) {
1150  nProposalCount++;
1151  break;
1153  nTriggerCount++;
1154  break;
1155  default:
1156  nOtherCount++;
1157  break;
1158  }
1159  }
1160 
1161  return strprintf("Governance Objects: %d (Proposals: %d, Triggers: %d, Other: %d; Erased: %d), Votes: %d",
1162  (int)mapObjects.size(),
1163  nProposalCount, nTriggerCount, nOtherCount, (int)mapErasedGovernanceObjects.size(),
1164  (int)cmapVoteToObject.GetSize());
1165 }
1166 
1168 {
1169  LOCK(cs);
1170 
1171  int nProposalCount = 0;
1172  int nTriggerCount = 0;
1173  int nOtherCount = 0;
1174 
1175  for (const auto& objpair : mapObjects) {
1176  switch (objpair.second.GetObjectType()) {
1178  nProposalCount++;
1179  break;
1181  nTriggerCount++;
1182  break;
1183  default:
1184  nOtherCount++;
1185  break;
1186  }
1187  }
1188 
1189  UniValue jsonObj(UniValue::VOBJ);
1190  jsonObj.push_back(Pair("objects_total", (int)mapObjects.size()));
1191  jsonObj.push_back(Pair("proposals", nProposalCount));
1192  jsonObj.push_back(Pair("triggers", nTriggerCount));
1193  jsonObj.push_back(Pair("other", nOtherCount));
1194  jsonObj.push_back(Pair("erased", (int)mapErasedGovernanceObjects.size()));
1195  jsonObj.push_back(Pair("votes", (int)cmapVoteToObject.GetSize()));
1196  return jsonObj;
1197 }
1198 
1200 {
1201  // Note this gets called from ActivateBestChain without cs_main being held
1202  // so it should be safe to lock our mutex here without risking a deadlock
1203  // On the other hand it should be safe for us to access pindex without holding a lock
1204  // on cs_main because the CBlockIndex objects are dynamically allocated and
1205  // presumably never deleted.
1206  if (!pindex) {
1207  return;
1208  }
1209 
1210  nCachedBlockHeight = pindex->nHeight;
1211  LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight);
1212 
1213  if (deterministicMNManager->IsDIP3Enforced(pindex->nHeight)) {
1215  }
1216 
1217  CheckPostponedObjects(connman);
1218 
1220 }
1221 
1223 {
1224  std::vector<CNode*> vNodesCopy = connman.CopyNodeVector(CConnman::FullyConnectedOnly);
1225 
1226  std::vector<uint256> vecHashesFiltered;
1227  {
1228  std::vector<uint256> vecHashes;
1229  LOCK(cs);
1230  cmmapOrphanVotes.GetKeys(vecHashes);
1231  for (const uint256& nHash : vecHashes) {
1232  if (mapObjects.find(nHash) == mapObjects.end()) {
1233  vecHashesFiltered.push_back(nHash);
1234  }
1235  }
1236  }
1237 
1238  LogPrint(BCLog::GOBJECT, "CGovernanceObject::RequestOrphanObjects -- number objects = %d\n", vecHashesFiltered.size());
1239  for (const uint256& nHash : vecHashesFiltered) {
1240  for (CNode* pnode : vNodesCopy) {
1241  if (pnode->fMasternode) {
1242  continue;
1243  }
1244  RequestGovernanceObject(pnode, nHash, connman);
1245  }
1246  }
1247 
1248  connman.ReleaseNodeVector(vNodesCopy);
1249 }
1250 
1252 {
1253  LOCK(cs);
1255 
1256  int64_t nNow = GetAdjustedTime();
1257 
1258  vote_cmm_t::list_cit it = items.begin();
1259  while (it != items.end()) {
1260  vote_cmm_t::list_cit prevIt = it;
1261  ++it;
1262  const vote_time_pair_t& pairVote = prevIt->value;
1263  if (pairVote.second < nNow) {
1264  cmmapOrphanVotes.Erase(prevIt->key, prevIt->value);
1265  }
1266  }
1267 }
1268 
1270 {
1271  if (!masternodeSync.IsSynced()) {
1272  return;
1273  }
1274 
1275  LOCK(cs);
1276 
1277  auto curMNList = deterministicMNManager->GetListAtChainTip();
1278  auto diff = lastMNListForVotingKeys.BuildDiff(curMNList);
1279 
1280  std::vector<COutPoint> changedKeyMNs;
1281  for (const auto& p : diff.updatedMNs) {
1282  auto oldDmn = lastMNListForVotingKeys.GetMNByInternalId(p.first);
1283  if ((p.second.fields & CDeterministicMNStateDiff::Field_keyIDVoting) && p.second.state.keyIDVoting != oldDmn->pdmnState->keyIDVoting) {
1284  changedKeyMNs.emplace_back(oldDmn->collateralOutpoint);
1285  } else if ((p.second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && p.second.state.pubKeyOperator != oldDmn->pdmnState->pubKeyOperator) {
1286  changedKeyMNs.emplace_back(oldDmn->collateralOutpoint);
1287  }
1288  }
1289  for (const auto& id : diff.removedMns) {
1290  auto oldDmn = lastMNListForVotingKeys.GetMNByInternalId(id);
1291  changedKeyMNs.emplace_back(oldDmn->collateralOutpoint);
1292  }
1293 
1294  for (const auto& outpoint : changedKeyMNs) {
1295  for (auto& p : mapObjects) {
1296  auto removed = p.second.RemoveInvalidVotes(outpoint);
1297  if (removed.empty()) {
1298  continue;
1299  }
1300  for (auto& voteHash : removed) {
1301  cmapVoteToObject.Erase(voteHash);
1302  cmapInvalidVotes.Erase(voteHash);
1303  cmmapOrphanVotes.Erase(voteHash);
1304  setRequestedVotes.erase(voteHash);
1305  }
1306  }
1307  }
1308 
1309  // store current MN list for the next run so that we can determine which keys changed
1310  lastMNListForVotingKeys = curMNList;
1311 }
bool IsCollateralValid(std::string &strError, bool &fMissingConfirmations) const
Check the collateral transaction for the budget proposal/finalized budget.
std::list< item_t > list_t
Definition: cachemap.h:53
bool HasVote(const uint256 &nHash) const
Return true if the vote with this hash is currently cached in memory.
bool HasFulfilledRequest(const CService &addr, const std::string &strRequest)
object_m_t mapPostponedObjects
Definition: governance.h:236
const uint256 & GetParentHash() const
static const int MASTERNODE_SYNC_GOVOBJ_VOTE
CMasternodeSync masternodeSync
int GetSendVersion() const
Definition: net.cpp:887
txout_m_t::iterator txout_m_it
Definition: governance.h:199
bool HasKey(const K &key) const
Definition: cachemap.h:119
uint256 GetHash() const
GetHash()
std::string GetDataAsHexString() const
GetData - As
Governance Object.
static const int64_t GOVERNANCE_ORPHAN_EXPIRATION_TIME
void SyncSingleObjVotes(CNode *pnode, const uint256 &nProp, const CBloomFilter &filter, CConnman &connman)
Definition: governance.cpp:615
bool IsSetDirtyCache() const
const list_t & GetItemList() const
Definition: cachemap.h:145
int GetRandInt(int nMax)
Definition: random.cpp:379
void MasternodeRateUpdate(const CGovernanceObject &govobj)
Definition: governance.cpp:711
bool MasternodeRateCheck(const CGovernanceObject &govobj, bool fUpdateFailStatus=false)
Definition: governance.cpp:733
std::string ToString() const
Definition: protocol.cpp:283
std::pair< CGovernanceVote, int64_t > vote_time_pair_t
bool HaveVoteForHash(const uint256 &nHash) const
Definition: governance.cpp:66
void AddTimestamp(int64_t nTimestamp)
Definition: governance.h:63
bool ShutdownRequested()
Definition: init.cpp:179
#define strprintf
Definition: tinyformat.h:1066
vote_instance_m_t mapInstances
void UpdateCachesAndClean()
Definition: governance.cpp:351
const CGovernanceObjectVoteFile & GetVoteFile() const
inv message data
Definition: protocol.h:429
uint256 GetHash() const
static const int MIN_GOVERNANCE_PEER_PROTO_VERSION
void NotifyGovernanceVote(const CGovernanceVote &vote)
CDeterministicMNList lastMNListForVotingKeys
Definition: governance.h:254
const COutPoint & GetMasternodeOutpoint() const
static bool AcceptMessage(const uint256 &nHash, hash_s_t &setHash)
CCriticalSection cs_main
Definition: validation.cpp:213
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
static const int GOVERNANCE_OBJECT_PROPOSAL
void PrepareDeletion(int64_t nDeletionTime_)
int nSuperblockCycle
Definition: params.h:144
false true true true
Definition: bls_dkg.cpp:176
bool HaveObjectForHash(const uint256 &nHash) const
Definition: governance.cpp:47
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:103
std::shared_ptr< const CDeterministicMN > CDeterministicMNCPtr
bool ProcessVote(CNode *pfrom, const CGovernanceVote &vote, CGovernanceException &exception, CConnman &connman)
Definition: governance.cpp:803
CDeterministicMNListDiff BuildDiff(const CDeterministicMNList &to) const
void insert(const std::vector< unsigned char > &vKey)
Definition: bloom.cpp:62
bool IsBlockchainSynced()
hash_s_t::const_iterator hash_s_cit
Definition: governance.h:205
unsigned char * begin()
Definition: uint256.h:57
bool operator()(const std::pair< CGovernanceObject *, int > &left, const std::pair< CGovernanceObject *, int > &right)
Definition: governance.cpp:540
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
static constexpr const CFullyConnectedOnly FullyConnectedOnly
Definition: net.h:219
static const unsigned char REJECT_OBSOLETE
Definition: validation.h:14
Requested operation cannot be performed.
void AddPostponedObject(const CGovernanceObject &govobj)
Definition: governance.h:369
void NotifyGovernanceObject(const CGovernanceObject &object)
void PushInventory(const CInv &inv)
Definition: net.h:1054
CGovernanceObject * FindGovernanceObject(const uint256 &nHash)
Definition: governance.cpp:463
void Clear()
Definition: cachemap.h:87
arith_uint256 UintToArith256(const uint256 &a)
static const double GOVERNANCE_FILTER_FP_RATE
bool AddNewTrigger(uint256 nHash)
Add Governance Object.
static const std::string MAIN
BIP70 chain name strings (main, test or regtest)
const COutPoint & GetMasternodeOutpoint() const
CMasternodeMetaMan mmetaman
CDeterministicMNCPtr GetMNByInternalId(uint64_t internalId) const
CGovernanceManager governance
Definition: governance.cpp:23
object_m_t::const_iterator object_m_cit
Definition: governance.h:181
std::vector< uint256 > GetAndClearDirtyGovernanceObjectHashes()
void Misbehaving(NodeId pnode, int howmuch, const std::string &message)
Increase a node&#39;s misbehavior score.
int64_t GetTime()
Return system time (or mocked time, if set)
Definition: utiltime.cpp:22
bool fMasternodeMode
Definition: util.cpp:93
bool Get(const K &key, V &value) const
Definition: cachemap.h:124
#define LOCK2(cs1, cs2)
Definition: sync.h:179
bool ProcessVote(CNode *pfrom, const CGovernanceVote &vote, CGovernanceException &exception, CConnman &connman)
void Erase(const K &key)
Definition: cachemap.h:135
CGovernanceTriggerManager triggerman
bool push_back(const UniValue &val)
Definition: univalue.cpp:110
#define LogPrintf(...)
Definition: util.h:203
void Erase(const K &key)
void AddGovernanceObject(CGovernanceObject &govobj, CConnman &connman, CNode *pfrom=nullptr)
Definition: governance.cpp:291
int GetObjectType() const
void RequestGovernanceObject(CNode *pfrom, const uint256 &nHash, CConnman &connman, bool fUseFilter=false)
Definition: governance.cpp:922
#define LEAVE_CRITICAL_SECTION(cs)
Definition: sync.h:188
void BumpAssetLastTime(const std::string &strFuncName)
#define LOCK(cs)
Definition: sync.h:178
int type
Definition: protocol.h:455
void CheckPostponedObjects(CConnman &connman)
Definition: governance.cpp:857
Fast randomness source.
Definition: random.h:48
static const std::string SERIALIZATION_VERSION_STRING
Definition: governance.h:218
int RequestGovernanceObjectVotes(CNode *pnode, CConnman &connman)
Definition: governance.cpp:959
void clear()
Definition: bloom.cpp:125
int64_t nPowTargetSpacing
Definition: params.h:176
void Relay(CConnman &connman)
const list_t & GetItemList() const
object_m_t::iterator object_m_it
Definition: governance.h:179
void RequestOrphanObjects(CConnman &connman)
static const int MASTERNODE_SYNC_GOVOBJ
txout_m_t mapLastMasternodeObject
Definition: governance.h:245
void CleanAndRemove()
Clean And Remove.
bool IsSetCachedDelete() const
void ProcessMessage(CNode *pfrom, const std::string &strCommand, CDataStream &vRecv, CConnman &connman)
Definition: governance.cpp:88
static const int GOVERNANCE_OBJECT_TRIGGER
int GetVoteCount() const
Definition: governance.cpp:74
std::string ToString() const
uint256 hash
Definition: protocol.h:456
CMainSignals & GetMainSignals()
static const int RELIABLE_PROPAGATION_TIME
Definition: governance.h:221
bool GetAll(const K &key, std::vector< V > &vecValues)
A class which encapsulates information about a governance exception condition.
Definition: net.h:136
list_t::const_iterator list_cit
Definition: cachemap.h:57
int nSubmittedFinalBudget
Definition: governance.cpp:25
std::vector< const CGovernanceObject * > GetAllNewerThan(int64_t nMoreThanTime) const
Definition: governance.cpp:516
std::string ToString() const
Definition: uint256.cpp:62
bool SerializeObjectForHash(const uint256 &nHash, CDataStream &ss) const
Definition: governance.cpp:53
NodeId GetId() const
Definition: net.h:973
const char * MNGOVERNANCESYNC
Definition: protocol.cpp:57
void CheckOrphanVotes(CGovernanceObject &govobj, CGovernanceException &exception, CConnman &connman)
Definition: governance.cpp:266
bool ConfirmInventoryRequest(const CInv &inv)
This is called by AlreadyHave in net_processing.cpp as part of the inventory retrieval process...
Definition: governance.cpp:562
static std::pair< std::string, UniValue > Pair(const char *cKey, const char *cVal)
Definition: univalue.h:185
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:26
bool AcceptVoteMessage(const uint256 &nHash)
Called to indicate a requested vote has been received.
static const int GOVERNANCE_FILTER_PROTO_VERSION
std::vector< CGovernanceVote > GetCurrentVotes(const uint256 &nParentHash, const COutPoint &mnCollateralOutpointFilter) const
Definition: governance.cpp:472
static const int MAX_TIME_FUTURE_DEVIATION
Definition: governance.h:220
void UpdatedBlockTip(const CBlockIndex *pindex, CConnman &connman)
virtual const char * what() const noexcept override
int64_t GetCreationTime() const
bool SerializeVoteForHash(const uint256 &nHash, CDataStream &ss) const
Definition: governance.cpp:80
const char * REJECT
The reject message informs the receiving node that one of its previous messages has been rejected...
Definition: protocol.cpp:37
const CAddress addr
Definition: net.h:834
const char * SYNCSTATUSCOUNT
Definition: protocol.cpp:56
void SetTime(int64_t nTimeIn)
object_ref_cm_t cmapVoteToObject
Definition: governance.h:239
#define LogPrint(category,...)
Definition: util.h:214
#define ENTER_CRITICAL_SECTION(cs)
Definition: sync.h:182
bool IsValidLocally(std::string &strError, bool fCheckCollateral) const
hash_s_t setAdditionalRelayObjects
Definition: governance.h:237
256-bit opaque blob.
Definition: uint256.h:123
std::string GetDataAsPlainString() const
hash_s_t setRequestedObjects
Definition: governance.h:247
void ReleaseNodeVector(const std::vector< CNode *> &vecNodes)
Definition: net.cpp:3850
std::set< uint256 > hash_s_t
Definition: governance.h:201
vote_cmm_t cmmapOrphanVotes
Definition: governance.h:243
void SyncObjects(CNode *pnode, CConnman &connman) const
Definition: governance.cpp:664
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.
Unusual condition requiring no caller action.
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: utiltime.cpp:56
vote_outcome_enum_t
double GetRate()
Definition: governance.h:121
int64_t GetAdjustedTime()
Definition: timedata.cpp:35
bool IsSetExpired() const
hash_s_t setRequestedVotes
Definition: governance.h:249
void Relay(CConnman &connman) const
vote_signal_enum_t
hash_s_t::iterator hash_s_it
Definition: governance.h:203
CNetFulfilledRequestManager netfulfilledman
hash_time_m_t::iterator hash_time_m_it
Definition: governance.h:213
std::string GetLogString() const
Definition: net.cpp:750
hash_time_m_t mapErasedGovernanceObjects
Definition: governance.h:234
static int count
Definition: tests.c:45
bool Insert(const K &key, const V &value)
Definition: cachemap.h:106
std::atomic< int > nVersion
Definition: net.h:838
size_type GetSize() const
Definition: cachemap.h:102
void EraseObjectRequest(CNodeState *nodestate, const CInv &inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
void UpdateEmptyFull()
Checks for empty and full filters to avoid wasting cpu.
Definition: bloom.cpp:288
std::vector< CGovernanceVote > GetVotes() const
CCriticalSection cs
Definition: governance.h:278
std::vector< CNode * > CopyNodeVector(std::function< bool(const CNode *pnode)> cond)
Definition: net.cpp:3830
bool IsNull() const
Definition: transaction.h:44
UniValue ToJson() const
const char * MNGOVERNANCEOBJECT
Definition: protocol.cpp:58
const char * MNGOVERNANCEOBJECTVOTE
Definition: protocol.cpp:59
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
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:54
vote_cm_t cmapInvalidVotes
Definition: governance.h:241
static const int64_t GOVERNANCE_DELETION_DELAY
bool fDisableGovernance
Definition: util.cpp:94
bool SerializeVoteToStream(const uint256 &nHash, CDataStream &ss) const
Retrieve a vote cached in memory.
size_t GetRequestedObjectCount(NodeId nodeId)
static void ExecuteBestSuperblock(int nBlockHeight)
static const unsigned int MAX_INV_SZ
The maximum number of entries in an &#39;inv&#39; protocol message.
Definition: net.h:62
bool g_enable_bip61
Enable BIP61 (sending reject messages)
void GetKeys(std::vector< K > &vecKeys)
bool Insert(const K &key, const V &value)
Definition: cachemultimap.h:87
bool GetCurrentMNVotes(const COutPoint &mnCollateralOutpoint, vote_rec_t &voteRecord) const
object_m_t mapObjects
Definition: governance.h:229
void AddFulfilledRequest(const CService &addr, const std::string &strRequest)
int64_t GetDeletionTime() const
bool AcceptObjectMessage(const uint256 &nHash)
Called to indicate a requested object has been received.
bool contains(const std::vector< unsigned char > &vKey) const
Definition: bloom.cpp:89
void DoMaintenance(CConnman &connman)
Definition: governance.cpp:547
void RemoveGovernanceObject(const uint256 &nGovernanceObjectHash)
std::string ToStringShort() const
Definition: transaction.cpp:17
Released under the MIT license