LCOV - code coverage report
Current view: top level - src - masternodeman.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 528 641 82.4 %
Date: 2025-02-23 09:33:43 Functions: 43 46 93.5 %

          Line data    Source code
       1             : // Copyright (c) 2014-2015 The Dash developers
       2             : // Copyright (c) 2015-2022 The PIVX Core developers
       3             : // Distributed under the MIT/X11 software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "masternodeman.h"
       7             : 
       8             : #include "addrman.h"
       9             : #include "evo/deterministicmns.h"
      10             : #include "fs.h"
      11             : #include "masternode-payments.h"
      12             : #include "masternode-sync.h"
      13             : #include "masternode.h"
      14             : #include "messagesigner.h"
      15             : #include "netbase.h"
      16             : #include "netmessagemaker.h"
      17             : #include "shutdown.h"
      18             : #include "spork.h"
      19             : #include "tiertwo/tiertwo_sync_state.h"
      20             : #include "validation.h"
      21             : 
      22             : #include <boost/thread/thread.hpp>
      23             : 
      24             : #define MN_WINNER_MINIMUM_AGE 8000    // Age in seconds. This should be > MASTERNODE_REMOVAL_SECONDS to avoid misconfigured new nodes in the list.
      25             : 
      26             : /** Masternode manager */
      27             : CMasternodeMan mnodeman;
      28             : /** Keep track of the active Masternode */
      29             : CActiveMasternode activeMasternode;
      30             : 
      31             : struct CompareScoreMN {
      32             :     template <typename T>
      33      251954 :     bool operator()(const std::pair<int64_t, T>& t1,
      34             :         const std::pair<int64_t, T>& t2) const
      35             :     {
      36      247016 :         return t1.first < t2.first;
      37             :     }
      38             : };
      39             : 
      40             : //
      41             : // CMasternodeDB
      42             : //
      43             : 
      44             : static const int MASTERNODE_DB_VERSION_BIP155 = 2;
      45             : 
      46         733 : CMasternodeDB::CMasternodeDB()
      47             : {
      48         733 :     pathMN = GetDataDir() / "mncache.dat";
      49         733 :     strMagicMessage = "MasternodeCache";
      50         733 : }
      51             : 
      52         378 : bool CMasternodeDB::Write(const CMasternodeMan& mnodemanToSave)
      53             : {
      54         378 :     int64_t nStart = GetTimeMillis();
      55         378 :     const auto& params = Params();
      56             : 
      57             :     // serialize, checksum data up to that point, then append checksum
      58             :     // Always done in the latest format.
      59         756 :     CDataStream ssMasternodes(SER_DISK, CLIENT_VERSION | ADDRV2_FORMAT);
      60         378 :     ssMasternodes << MASTERNODE_DB_VERSION_BIP155;
      61         378 :     ssMasternodes << strMagicMessage;                   // masternode cache file specific magic message
      62         378 :     ssMasternodes << params.MessageStart(); // network specific magic number
      63         378 :     ssMasternodes << mnodemanToSave;
      64         378 :     uint256 hash = Hash(ssMasternodes.begin(), ssMasternodes.end());
      65         378 :     ssMasternodes << hash;
      66             : 
      67             :     // open output file, and associate with CAutoFile
      68         378 :     FILE* file = fsbridge::fopen(pathMN, "wb");
      69         756 :     CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
      70         378 :     if (fileout.IsNull())
      71           0 :         return error("%s : Failed to open file %s", __func__, pathMN.string());
      72             : 
      73             :     // Write and commit header, data
      74         378 :     try {
      75         378 :         fileout << ssMasternodes;
      76           0 :     } catch (const std::exception& e) {
      77           0 :         return error("%s : Serialize or I/O error - %s", __func__, e.what());
      78             :     }
      79             :     //    FileCommit(fileout);
      80         378 :     fileout.fclose();
      81             : 
      82         378 :     LogPrint(BCLog::MASTERNODE,"Written info to mncache.dat  %dms\n", GetTimeMillis() - nStart);
      83         752 :     LogPrint(BCLog::MASTERNODE,"  %s\n", mnodemanToSave.ToString());
      84             : 
      85             :     return true;
      86             : }
      87             : 
      88         355 : CMasternodeDB::ReadResult CMasternodeDB::Read(CMasternodeMan& mnodemanToLoad)
      89             : {
      90         355 :     int64_t nStart = GetTimeMillis();
      91             :     // open input file, and associate with CAutoFile
      92         355 :     FILE* file = fsbridge::fopen(pathMN, "rb");
      93         710 :     CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
      94         355 :     if (filein.IsNull()) {
      95         273 :         error("%s : Failed to open file %s", __func__, pathMN.string());
      96             :         return FileError;
      97             :     }
      98             : 
      99             :     // use file size to size memory buffer
     100          82 :     int fileSize = fs::file_size(pathMN);
     101          82 :     int dataSize = fileSize - sizeof(uint256);
     102             :     // Don't try to resize to a negative number if file is small
     103          82 :     if (dataSize < 0)
     104           0 :         dataSize = 0;
     105         437 :     std::vector<unsigned char> vchData;
     106          82 :     vchData.resize(dataSize);
     107          82 :     uint256 hashIn;
     108             : 
     109             :     // read data and checksum from file
     110          82 :     try {
     111          82 :         filein.read((char*)vchData.data(), dataSize);
     112          82 :         filein >> hashIn;
     113           0 :     } catch (const std::exception& e) {
     114           0 :         error("%s : Deserialize or I/O error - %s", __func__, e.what());
     115           0 :         return HashReadError;
     116             :     }
     117          82 :     filein.fclose();
     118             : 
     119          82 :     const auto& params = Params();
     120             :     // serialize, checksum data up to that point, then append checksum
     121         164 :     CDataStream ssMasternodes(vchData, SER_DISK,  CLIENT_VERSION);
     122             : 
     123             :     // verify stored checksum matches input data
     124          82 :     uint256 hashTmp = Hash(ssMasternodes.begin(), ssMasternodes.end());
     125          82 :     if (hashIn != hashTmp) {
     126           0 :         error("%s : Checksum mismatch, data corrupted", __func__);
     127             :         return IncorrectHash;
     128             :     }
     129             : 
     130          82 :     int version;
     131         164 :     std::string strMagicMessageTmp;
     132          82 :     try {
     133             :         // de-serialize file header
     134          82 :         ssMasternodes >> version;
     135          82 :         ssMasternodes >> strMagicMessageTmp;
     136             : 
     137             :         // ... verify the message matches predefined one
     138          82 :         if (strMagicMessage != strMagicMessageTmp) {
     139           0 :             error("%s : Invalid masternode cache magic message", __func__);
     140           0 :             return IncorrectMagicMessage;
     141             :         }
     142             : 
     143             :         // de-serialize file header (network specific magic number) and ..
     144          82 :         std::vector<unsigned char> pchMsgTmp(4);
     145          82 :         ssMasternodes >> MakeSpan(pchMsgTmp);
     146             : 
     147             :         // ... verify the network matches ours
     148          82 :         if (memcmp(pchMsgTmp.data(), params.MessageStart(), pchMsgTmp.size()) != 0) {
     149           0 :             error("%s : Invalid network magic number", __func__);
     150           0 :             return IncorrectMagicNumber;
     151             :         }
     152             :         // de-serialize data into CMasternodeMan object.
     153          82 :         if (version == MASTERNODE_DB_VERSION_BIP155) {
     154          82 :             OverrideStream<CDataStream> s(&ssMasternodes, ssMasternodes.GetType(), ssMasternodes.GetVersion() | ADDRV2_FORMAT);
     155          82 :             s >> mnodemanToLoad;
     156             :         } else {
     157             :             // Old format
     158          82 :             ssMasternodes >> mnodemanToLoad;
     159             :         }
     160           0 :     } catch (const std::exception& e) {
     161           0 :         mnodemanToLoad.Clear();
     162           0 :         error("%s : Deserialize or I/O error - %s", __func__, e.what());
     163           0 :         return IncorrectFormat;
     164             :     }
     165             : 
     166          82 :     LogPrint(BCLog::MASTERNODE,"Loaded info from mncache.dat (dbversion=%d) %dms\n", version, GetTimeMillis() - nStart);
     167         164 :     LogPrint(BCLog::MASTERNODE,"  %s\n", mnodemanToLoad.ToString());
     168             : 
     169             :     return Ok;
     170             : }
     171             : 
     172         378 : void DumpMasternodes()
     173             : {
     174         378 :     int64_t nStart = GetTimeMillis();
     175             : 
     176         756 :     CMasternodeDB mndb;
     177         378 :     LogPrint(BCLog::MASTERNODE,"Writing info to mncache.dat...\n");
     178         378 :     mndb.Write(mnodeman);
     179             : 
     180         378 :     LogPrint(BCLog::MASTERNODE,"Masternode dump finished  %dms\n", GetTimeMillis() - nStart);
     181         378 : }
     182             : 
     183         479 : CMasternodeMan::CMasternodeMan():
     184             :         cvLastBlockHashes(CACHED_BLOCK_HASHES, UINT256_ZERO),
     185         479 :         nDsqCount(0)
     186         479 : {}
     187             : 
     188         120 : bool CMasternodeMan::Add(CMasternode& mn)
     189             : {
     190             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     191         120 :     if (deterministicMNManager->LegacyMNObsolete()) {
     192             :         return false;
     193             :     }
     194             : 
     195         120 :     if (deterministicMNManager->GetListAtChainTip().HasMNByCollateral(mn.vin.prevout)) {
     196           6 :         LogPrint(BCLog::MASTERNODE, "ERROR: Not Adding Masternode %s as the collateral is already registered with a DMN\n",
     197             :                 mn.vin.prevout.ToString());
     198           3 :         return false;
     199             :     }
     200             : 
     201         237 :     LOCK(cs);
     202             : 
     203         117 :     if (!mn.IsAvailableState())
     204             :         return false;
     205             : 
     206         117 :     const auto& it = mapMasternodes.find(mn.vin.prevout);
     207         117 :     if (it == mapMasternodes.end()) {
     208         194 :         LogPrint(BCLog::MASTERNODE, "Adding new Masternode %s\n", mn.vin.prevout.ToString());
     209         117 :         mapMasternodes.emplace(mn.vin.prevout, std::make_shared<CMasternode>(mn));
     210         117 :         LogPrint(BCLog::MASTERNODE, "Masternode added. New total count: %d\n", mapMasternodes.size());
     211         117 :         return true;
     212             :     }
     213             : 
     214             :     return false;
     215             : }
     216             : 
     217           4 : void CMasternodeMan::AskForMN(CNode* pnode, const CTxIn& vin)
     218             : {
     219             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     220           4 :     if (deterministicMNManager->LegacyMNObsolete()) {
     221           2 :         return;
     222             :     }
     223             : 
     224           4 :     std::map<COutPoint, int64_t>::iterator i = mWeAskedForMasternodeListEntry.find(vin.prevout);
     225           4 :     if (i != mWeAskedForMasternodeListEntry.end()) {
     226           2 :         int64_t t = (*i).second;
     227           2 :         if (GetTime() < t) return; // we've asked recently
     228             :     }
     229             : 
     230             :     // ask for the mnb info once from the node that sent mnp
     231             : 
     232           4 :     LogPrint(BCLog::MASTERNODE, "CMasternodeMan::AskForMN - Asking node for missing entry, vin: %s\n", vin.prevout.hash.ToString());
     233           2 :     g_connman->PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::GETMNLIST, vin));
     234           2 :     int64_t askAgain = GetTime() + MasternodeMinPingSeconds();
     235           2 :     mWeAskedForMasternodeListEntry[vin.prevout] = askAgain;
     236             : }
     237             : 
     238        3627 : int CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval)
     239             : {
     240             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     241        3627 :     if (deterministicMNManager->LegacyMNObsolete()) {
     242         948 :         LogPrint(BCLog::MASTERNODE, "Removing all legacy mn due to SPORK 21\n");
     243         948 :         Clear();
     244         948 :         return 0;
     245             :     }
     246             : 
     247        6306 :     LOCK(cs);
     248             : 
     249             :     //remove inactive and outdated (or replaced by DMN)
     250        2679 :     auto it = mapMasternodes.begin();
     251        3817 :     while (it != mapMasternodes.end()) {
     252        1138 :         MasternodeRef& mn = it->second;
     253        1138 :         auto activeState = mn->GetActiveState();
     254        1138 :         if (activeState == CMasternode::MASTERNODE_REMOVE ||
     255        1105 :             activeState == CMasternode::MASTERNODE_VIN_SPENT ||
     256        2243 :             (forceExpiredRemoval && activeState == CMasternode::MASTERNODE_EXPIRED) ||
     257        1105 :             mn->protocolVersion < ActiveProtocol()) {
     258          66 :             LogPrint(BCLog::MASTERNODE, "Removing inactive (legacy) Masternode %s\n", it->first.ToString());
     259             :             //erase all of the broadcasts we've seen from this vin
     260             :             // -- if we missed a few pings and the node was removed, this will allow is to get it back without them
     261             :             //    sending a brand new mnb
     262          33 :             std::map<uint256, CMasternodeBroadcast>::iterator it3 = mapSeenMasternodeBroadcast.begin();
     263         107 :             while (it3 != mapSeenMasternodeBroadcast.end()) {
     264          74 :                 if (it3->second.vin.prevout == it->first) {
     265          39 :                     g_tiertwo_sync_state.EraseSeenMNB((*it3).first);
     266          39 :                     it3 = mapSeenMasternodeBroadcast.erase(it3);
     267             :                 } else {
     268         142 :                     ++it3;
     269             :                 }
     270             :             }
     271             : 
     272             :             // allow us to ask for this masternode again if we see another ping
     273          33 :             std::map<COutPoint, int64_t>::iterator it2 = mWeAskedForMasternodeListEntry.begin();
     274          33 :             while (it2 != mWeAskedForMasternodeListEntry.end()) {
     275           0 :                 if (it2->first == it->first) {
     276           0 :                     it2 = mWeAskedForMasternodeListEntry.erase(it2);
     277             :                 } else {
     278          33 :                     ++it2;
     279             :                 }
     280             :             }
     281             : 
     282             :             // clean MN pings right away.
     283          33 :             auto itPing = mapSeenMasternodePing.begin();
     284         719 :             while (itPing != mapSeenMasternodePing.end()) {
     285        1372 :                 if (itPing->second.GetVin().prevout == it->first) {
     286         322 :                     itPing = mapSeenMasternodePing.erase(itPing);
     287             :                 } else {
     288        1083 :                     ++itPing;
     289             :                 }
     290             :             }
     291             : 
     292          33 :             it = mapMasternodes.erase(it);
     293          33 :             LogPrint(BCLog::MASTERNODE, "Masternode removed.\n");
     294             :         } else {
     295        4922 :             ++it;
     296             :         }
     297             :     }
     298        2679 :     LogPrint(BCLog::MASTERNODE, "New total masternode count: %d\n", mapMasternodes.size());
     299             : 
     300             :     // check who's asked for the Masternode list
     301        2679 :     std::map<CNetAddr, int64_t>::iterator it1 = mAskedUsForMasternodeList.begin();
     302        2679 :     while (it1 != mAskedUsForMasternodeList.end()) {
     303           0 :         if ((*it1).second < GetTime()) {
     304           0 :             it1 = mAskedUsForMasternodeList.erase(it1);
     305             :         } else {
     306        2679 :             ++it1;
     307             :         }
     308             :     }
     309             : 
     310             :     // check who we asked for the Masternode list
     311        2679 :     it1 = mWeAskedForMasternodeList.begin();
     312        2679 :     while (it1 != mWeAskedForMasternodeList.end()) {
     313           0 :         if ((*it1).second < GetTime()) {
     314           0 :             it1 = mWeAskedForMasternodeList.erase(it1);
     315             :         } else {
     316        2679 :             ++it1;
     317             :         }
     318             :     }
     319             : 
     320             :     // check which Masternodes we've asked for
     321        2679 :     std::map<COutPoint, int64_t>::iterator it2 = mWeAskedForMasternodeListEntry.begin();
     322        2689 :     while (it2 != mWeAskedForMasternodeListEntry.end()) {
     323          10 :         if ((*it2).second < GetTime()) {
     324           2 :             it2 = mWeAskedForMasternodeListEntry.erase(it2);
     325             :         } else {
     326        2697 :             ++it2;
     327             :         }
     328             :     }
     329             : 
     330             :     // remove expired mapSeenMasternodeBroadcast
     331        2679 :     std::map<uint256, CMasternodeBroadcast>::iterator it3 = mapSeenMasternodeBroadcast.begin();
     332        3861 :     while (it3 != mapSeenMasternodeBroadcast.end()) {
     333        1182 :         if ((*it3).second.lastPing.sigTime < GetTime() - (MasternodeRemovalSeconds() * 2)) {
     334           3 :             g_tiertwo_sync_state.EraseSeenMNB((*it3).second.GetHash());
     335           3 :             it3 = mapSeenMasternodeBroadcast.erase(it3);
     336             :         } else {
     337        5040 :             ++it3;
     338             :         }
     339             :     }
     340             : 
     341             :     // remove expired mapSeenMasternodePing
     342        2679 :     std::map<uint256, CMasternodePing>::iterator it4 = mapSeenMasternodePing.begin();
     343       21229 :     while (it4 != mapSeenMasternodePing.end()) {
     344       18550 :         if ((*it4).second.sigTime < GetTime() - (MasternodeRemovalSeconds() * 2)) {
     345        1590 :             it4 = mapSeenMasternodePing.erase(it4);
     346             :         } else {
     347       38189 :             ++it4;
     348             :         }
     349             :     }
     350             : 
     351        2679 :     return mapMasternodes.size();
     352             : }
     353             : 
     354         948 : void CMasternodeMan::Clear()
     355             : {
     356         948 :     LOCK(cs);
     357         948 :     mapMasternodes.clear();
     358         948 :     mAskedUsForMasternodeList.clear();
     359         948 :     mWeAskedForMasternodeList.clear();
     360         948 :     mWeAskedForMasternodeListEntry.clear();
     361         948 :     mapSeenMasternodeBroadcast.clear();
     362         948 :     mapSeenMasternodePing.clear();
     363         948 :     nDsqCount = 0;
     364         948 : }
     365             : 
     366         881 : static void CountNetwork(const CService& addr, int& ipv4, int& ipv6, int& onion)
     367             : {
     368         881 :     std::string strHost;
     369         881 :     int port;
     370         881 :     SplitHostPort(addr.ToString(), port, strHost);
     371        1762 :     CNetAddr node;
     372         881 :     LookupHost(strHost, node, false);
     373         881 :     switch(node.GetNetwork()) {
     374           0 :         case NET_IPV4:
     375           0 :             ipv4++;
     376           0 :             break;
     377           0 :         case NET_IPV6:
     378           0 :             ipv6++;
     379           0 :             break;
     380           0 :         case NET_ONION:
     381           0 :             onion++;
     382           0 :             break;
     383             :         default:
     384             :             break;
     385             :     }
     386         881 : }
     387             : 
     388         212 : CMasternodeMan::MNsInfo CMasternodeMan::getMNsInfo() const
     389             : {
     390         212 :     MNsInfo info;
     391         212 :     int nMinProtocol = ActiveProtocol();
     392         212 :     bool spork_8_active = sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT);
     393             : 
     394             :     // legacy masternodes
     395         212 :     {
     396         212 :         LOCK(cs);
     397         254 :         for (const auto& it : mapMasternodes) {
     398          42 :             const MasternodeRef& mn = it.second;
     399          42 :             info.total++;
     400          42 :             CountNetwork(mn->addr, info.ipv4, info.ipv6, info.onion);
     401          42 :             if (mn->protocolVersion < nMinProtocol || !mn->IsEnabled()) {
     402           0 :                 continue;
     403             :             }
     404          42 :             info.enabledSize++;
     405             :             // Eligible for payments
     406          42 :             if (spork_8_active && (GetAdjustedTime() - mn->sigTime < MN_WINNER_MINIMUM_AGE)) {
     407           0 :                 continue; // Skip masternodes younger than (default) 8000 sec (MUST be > MASTERNODE_REMOVAL_SECONDS)
     408             :             }
     409          42 :             info.stableSize++;
     410             :         }
     411             :     }
     412             : 
     413             :     // deterministic masternodes
     414         212 :     if (deterministicMNManager->IsDIP3Enforced()) {
     415         212 :         auto mnList = deterministicMNManager->GetListAtChainTip();
     416         212 :         mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
     417        1590 :             info.total++;
     418         839 :             CountNetwork(dmn->pdmnState->addr, info.ipv4, info.ipv6, info.onion);
     419         839 :             if (!dmn->IsPoSeBanned()) {
     420         751 :                 info.enabledSize++;
     421         751 :                 info.stableSize++;
     422             :             }
     423         839 :         });
     424             :     }
     425             : 
     426         212 :     return info;
     427             : }
     428             : 
     429       11926 : int CMasternodeMan::CountEnabled(bool only_legacy) const
     430             : {
     431       11926 :     int count_enabled = 0;
     432       11926 :     int protocolVersion = ActiveProtocol();
     433             : 
     434       11926 :     {
     435       11926 :         LOCK(cs);
     436       83617 :         for (const auto& it : mapMasternodes) {
     437       71691 :             const MasternodeRef& mn = it.second;
     438       71691 :             if (mn->protocolVersion < protocolVersion || !mn->IsEnabled()) continue;
     439       68200 :             count_enabled++;
     440             :         }
     441             :     }
     442             : 
     443       11926 :     if (!only_legacy && deterministicMNManager->IsDIP3Enforced()) {
     444        6876 :         count_enabled += deterministicMNManager->GetListAtChainTip().GetValidMNsCount();
     445             :     }
     446             : 
     447       11926 :     return count_enabled;
     448             : }
     449             : 
     450           0 : bool CMasternodeMan::RequestMnList(CNode* pnode)
     451             : {
     452             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     453           0 :     if (deterministicMNManager->LegacyMNObsolete()) {
     454             :         return false;
     455             :     }
     456             : 
     457           0 :     LOCK(cs);
     458           0 :     if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
     459           0 :         if (!(pnode->addr.IsRFC1918() || pnode->addr.IsLocal())) {
     460           0 :             std::map<CNetAddr, int64_t>::iterator it = mWeAskedForMasternodeList.find(pnode->addr);
     461           0 :             if (it != mWeAskedForMasternodeList.end()) {
     462           0 :                 if (GetTime() < (*it).second) {
     463           0 :                     LogPrint(BCLog::MASTERNODE, "dseg - we already asked peer %i for the list; skipping...\n", pnode->GetId());
     464           0 :                     return false;
     465             :                 }
     466             :             }
     467             :         }
     468             :     }
     469             : 
     470           0 :     g_connman->PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::GETMNLIST, CTxIn()));
     471           0 :     int64_t askAgain = GetTime() + MASTERNODES_REQUEST_SECONDS;
     472           0 :     mWeAskedForMasternodeList[pnode->addr] = askAgain;
     473           0 :     return true;
     474             : }
     475             : 
     476      106245 : CMasternode* CMasternodeMan::Find(const COutPoint& collateralOut)
     477             : {
     478      106245 :     LOCK(cs);
     479      106245 :     auto it = mapMasternodes.find(collateralOut);
     480      106245 :     return it != mapMasternodes.end() ? it->second.get() : nullptr;
     481             : }
     482             : 
     483           0 : const CMasternode* CMasternodeMan::Find(const COutPoint& collateralOut) const
     484             : {
     485           0 :     LOCK(cs);
     486           0 :     auto const& it = mapMasternodes.find(collateralOut);
     487           0 :     return it != mapMasternodes.end() ? it->second.get() : nullptr;
     488             : }
     489             : 
     490         130 : CMasternode* CMasternodeMan::Find(const CPubKey& pubKeyMasternode)
     491             : {
     492         130 :     LOCK(cs);
     493             : 
     494         183 :     for (auto& it : mapMasternodes) {
     495         150 :         MasternodeRef& mn = it.second;
     496         150 :         if (mn->pubKeyMasternode == pubKeyMasternode)
     497          97 :             return mn.get();
     498             :     }
     499          33 :     return nullptr;
     500             : }
     501             : 
     502       41568 : void CMasternodeMan::CheckSpentCollaterals(const std::vector<CTransactionRef>& vtx)
     503             : {
     504             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     505       41568 :     if (deterministicMNManager->LegacyMNObsolete()) {
     506        6271 :         return;
     507             :     }
     508             : 
     509       70594 :     LOCK(cs);
     510      325307 :     for (const auto& tx : vtx) {
     511      789451 :         for (const auto& in : tx->vin) {
     512      499441 :             auto it = mapMasternodes.find(in.prevout);
     513      499441 :             if (it != mapMasternodes.end()) {
     514          12 :                 it->second->SetSpent();
     515             :             }
     516             :         }
     517             :     }
     518             : }
     519             : 
     520        1549 : static bool canScheduleMN(bool fFilterSigTime, const MasternodeRef& mn, int minProtocol,
     521             :                           int nMnCount, int nBlockHeight)
     522             : {
     523             :     // check protocol version
     524        1549 :     if (mn->protocolVersion < minProtocol) return false;
     525             : 
     526             :     // it's in the list (up to 8 entries ahead of current block to allow propagation) -- so let's skip it
     527        1549 :     if (masternodePayments.IsScheduled(*mn, nBlockHeight)) return false;
     528             : 
     529             :     // it's too new, wait for a cycle
     530         446 :     if (fFilterSigTime && mn->sigTime + (nMnCount * 2.6 * 60) > GetAdjustedTime()) return false;
     531             : 
     532             :     // make sure it has as many confirmations as there are masternodes
     533         284 :     if (pcoinsTip->GetCoinDepthAtHeight(mn->vin.prevout, nBlockHeight) < nMnCount) return false;
     534             : 
     535             :     return true;
     536             : }
     537             : 
     538             : //
     539             : // Deterministically select the oldest/best masternode to pay on the network
     540             : //
     541         698 : MasternodeRef CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight, bool fFilterSigTime, int& nCount, const CBlockIndex* pChainTip) const
     542             : {
     543             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     544         698 :     if (deterministicMNManager->LegacyMNObsolete(nBlockHeight)) {
     545         136 :         LogPrintf("%s: ERROR - called after legacy system disabled\n", __func__);
     546         136 :         return nullptr;
     547             :     }
     548             : 
     549         562 :     AssertLockNotHeld(cs_main);
     550         562 :     const CBlockIndex* BlockReading = (pChainTip == nullptr ? GetChainTip() : pChainTip);
     551         562 :     if (!BlockReading) return nullptr;
     552             : 
     553        1260 :     MasternodeRef pBestMasternode = nullptr;
     554        1124 :     std::vector<std::pair<int64_t, MasternodeRef> > vecMasternodeLastPaid;
     555             : 
     556             :     /*
     557             :         Make a vector with all of the last paid times
     558             :     */
     559         562 :     int minProtocol = ActiveProtocol();
     560         562 :     int count_enabled = CountEnabled();
     561         562 :     {
     562         562 :         LOCK(cs);
     563        1246 :         for (const auto& it : mapMasternodes) {
     564         684 :             if (!it.second->IsEnabled()) continue;
     565         669 :             if (canScheduleMN(fFilterSigTime, it.second, minProtocol, count_enabled, nBlockHeight)) {
     566         143 :                 vecMasternodeLastPaid.emplace_back(SecondsSincePayment(it.second, count_enabled, BlockReading), it.second);
     567             :             }
     568             :         }
     569             :     }
     570             :     // Add deterministic masternodes to the vector
     571         562 :     if (deterministicMNManager->IsDIP3Enforced()) {
     572         558 :         CDeterministicMNList mnList = deterministicMNManager->GetListAtChainTip();
     573         558 :         mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
     574         880 :             const MasternodeRef mn = MakeMasternodeRefForDMN(dmn);
     575         880 :             if (canScheduleMN(fFilterSigTime, mn, minProtocol, count_enabled, nBlockHeight)) {
     576         134 :                 vecMasternodeLastPaid.emplace_back(SecondsSincePayment(mn, count_enabled, BlockReading), mn);
     577             :             }
     578         880 :         });
     579             :     }
     580             : 
     581         562 :     nCount = (int)vecMasternodeLastPaid.size();
     582             : 
     583             :     //when the network is in the process of upgrading, don't penalize nodes that recently restarted
     584         562 :     if (fFilterSigTime && nCount < count_enabled / 3) return GetNextMasternodeInQueueForPayment(nBlockHeight, false, nCount, BlockReading);
     585             : 
     586             :     // Sort them high to low
     587         422 :     sort(vecMasternodeLastPaid.rbegin(), vecMasternodeLastPaid.rend(), CompareScoreMN());
     588             : 
     589             :     // Look at 1/10 of the oldest nodes (by last payment), calculate their scores and pay the best one
     590             :     //  -- This doesn't look at who is being paid in the +8-10 blocks, allowing for double payments very rarely
     591             :     //  -- 1/100 payments should be a double payment on mainnet - (1/(3000/10))*2
     592             :     //  -- (chance per block * chances before IsScheduled will fire)
     593         422 :     int nTenthNetwork = count_enabled / 10;
     594         422 :     int nCountTenth = 0;
     595         422 :     arith_uint256 nHigh = ARITH_UINT256_ZERO;
     596         422 :     const uint256& hash = GetHashAtHeight(nBlockHeight - 101);
     597         422 :     for (const auto& s: vecMasternodeLastPaid) {
     598         198 :         const MasternodeRef pmn = s.second;
     599         198 :         if (!pmn) break;
     600             : 
     601         198 :         const arith_uint256& n = pmn->CalculateScore(hash);
     602         198 :         if (n > nHigh) {
     603        1782 :             nHigh = n;
     604         198 :             pBestMasternode = pmn;
     605             :         }
     606         198 :         nCountTenth++;
     607         198 :         if (nCountTenth >= nTenthNetwork) break;
     608             :     }
     609         562 :     return pBestMasternode;
     610             : }
     611             : 
     612       14122 : MasternodeRef CMasternodeMan::GetCurrentMasterNode(const uint256& hash) const
     613             : {
     614       14122 :     int minProtocol = ActiveProtocol();
     615       14122 :     int64_t score = 0;
     616       14122 :     MasternodeRef winner = nullptr;
     617             : 
     618             :     // scan for winner
     619       14473 :     for (const auto& it : mapMasternodes) {
     620         351 :         const MasternodeRef& mn = it.second;
     621         351 :         if (mn->protocolVersion < minProtocol || !mn->IsEnabled()) continue;
     622             :         // calculate the score of the masternode
     623         334 :         const int64_t n = mn->CalculateScore(hash).GetCompact(false);
     624             :         // determine the winner
     625         334 :         if (n > score) {
     626         280 :             score = n;
     627         631 :             winner = mn;
     628             :         }
     629             :     }
     630             : 
     631             :     // scan also dmns
     632       14122 :     if (deterministicMNManager->IsDIP3Enforced()) {
     633         303 :         auto mnList = deterministicMNManager->GetListAtChainTip();
     634         303 :         mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
     635         133 :             const MasternodeRef mn = MakeMasternodeRefForDMN(dmn);
     636             :             // calculate the score of the masternode
     637         133 :             const int64_t n = mn->CalculateScore(hash).GetCompact(false);
     638             :             // determine the winner
     639         133 :             if (n > score) {
     640          73 :                 score = n;
     641         206 :                 winner = mn;
     642             :             }
     643         133 :         });
     644             :     }
     645             : 
     646       14122 :     return winner;
     647             : }
     648             : 
     649           0 : std::vector<std::pair<MasternodeRef, int>> CMasternodeMan::GetMnScores(int nLast) const
     650             : {
     651           0 :     std::vector<std::pair<MasternodeRef, int>> ret;
     652           0 :     int nChainHeight = GetBestHeight();
     653           0 :     if (nChainHeight < 0) return ret;
     654             : 
     655           0 :     for (int nHeight = nChainHeight - nLast; nHeight < nChainHeight + 20; nHeight++) {
     656           0 :         const uint256& hash = GetHashAtHeight(nHeight - 101);
     657           0 :         MasternodeRef winner = GetCurrentMasterNode(hash);
     658           0 :         if (winner) {
     659           0 :             ret.emplace_back(winner, nHeight);
     660             :         }
     661             :     }
     662           0 :     return ret;
     663             : }
     664             : 
     665        2495 : int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight) const
     666             : {
     667        2495 :     const uint256& hash = GetHashAtHeight(nBlockHeight - 1);
     668             :     // height outside range
     669        2495 :     if (hash == UINT256_ZERO) return -1;
     670             : 
     671             :     // scan for winner
     672        2495 :     int minProtocol = ActiveProtocol();
     673        4990 :     std::vector<std::pair<int64_t, CTxIn> > vecMasternodeScores;
     674        2495 :     {
     675        2495 :         LOCK(cs);
     676       40621 :         for (const auto& it : mapMasternodes) {
     677       38126 :             const MasternodeRef& mn = it.second;
     678       38126 :             if (!mn->IsEnabled()) {
     679        1876 :                 continue; // Skip not enabled
     680             :             }
     681       36250 :             if (mn->protocolVersion < minProtocol) {
     682           0 :                 LogPrint(BCLog::MASTERNODE,"Skipping Masternode with obsolete version %d\n", mn->protocolVersion);
     683           0 :                 continue; // Skip obsolete versions
     684             :             }
     685       71686 :             if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) &&
     686       35436 :                     GetAdjustedTime() - mn->sigTime < MN_WINNER_MINIMUM_AGE) {
     687        1137 :                 continue; // Skip masternodes younger than (default) 1 hour
     688             :             }
     689       35113 :             vecMasternodeScores.emplace_back(mn->CalculateScore(hash).GetCompact(false), mn->vin);
     690             :         }
     691             :     }
     692             : 
     693             :     // scan also dmns
     694        2495 :     if (deterministicMNManager->IsDIP3Enforced()) {
     695        1483 :         auto mnList = deterministicMNManager->GetListAtChainTip();
     696        1483 :         mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
     697        2638 :             const MasternodeRef mn = MakeMasternodeRefForDMN(dmn);
     698        2638 :             vecMasternodeScores.emplace_back(mn->CalculateScore(hash).GetCompact(false), mn->vin);
     699        2638 :         });
     700             :     }
     701             : 
     702        2495 :     sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreMN());
     703             : 
     704        2495 :     int rank = 0;
     705        6538 :     for (std::pair<int64_t, CTxIn> & s : vecMasternodeScores) {
     706        6210 :         rank++;
     707        6210 :         if (s.second.prevout == vin.prevout) {
     708        2167 :             return rank;
     709             :         }
     710             :     }
     711             : 
     712         328 :     return -1;
     713             : }
     714             : 
     715         468 : std::vector<std::pair<int64_t, MasternodeRef>> CMasternodeMan::GetMasternodeRanks(int nBlockHeight) const
     716             : {
     717         468 :     std::vector<std::pair<int64_t, MasternodeRef>> vecMasternodeScores;
     718         468 :     const uint256& hash = GetHashAtHeight(nBlockHeight - 1);
     719             :     // height outside range
     720         468 :     if (hash == UINT256_ZERO) return vecMasternodeScores;
     721         468 :     {
     722         468 :         LOCK(cs);
     723             :         // scan for winner
     724        6061 :         for (const auto& it : mapMasternodes) {
     725       11186 :             const MasternodeRef mn = it.second;
     726        5593 :             const uint32_t score = mn->IsEnabled() ? mn->CalculateScore(hash).GetCompact(false) : 9999;
     727             : 
     728        5593 :             vecMasternodeScores.emplace_back(score, mn);
     729             :         }
     730             :     }
     731             :     // scan also dmns
     732         468 :     if (deterministicMNManager->IsDIP3Enforced()) {
     733         156 :         auto mnList = deterministicMNManager->GetListAtChainTip();
     734         156 :         mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
     735         179 :             const MasternodeRef mn = MakeMasternodeRefForDMN(dmn);
     736         179 :             const uint32_t score = dmn->IsPoSeBanned() ? 9999 : mn->CalculateScore(hash).GetCompact(false);
     737             : 
     738         179 :             vecMasternodeScores.emplace_back(score, mn);
     739         179 :         });
     740             :     }
     741         468 :     sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreMN());
     742         468 :     return vecMasternodeScores;
     743             : }
     744             : 
     745          68 : bool CMasternodeMan::CheckInputs(CMasternodeBroadcast& mnb, int nChainHeight, int& nDoS)
     746             : {
     747          68 :     const auto& consensus = Params().GetConsensus();
     748             :     // incorrect ping or its sigTime
     749          68 :     if(mnb.lastPing.IsNull() || !mnb.lastPing.CheckAndUpdate(nDoS, false, true)) {
     750           0 :         return false;
     751             :     }
     752             : 
     753             :     // search existing Masternode list
     754          68 :     CMasternode* pmn = Find(mnb.vin.prevout);
     755          68 :     if (pmn != nullptr) {
     756             :         // nothing to do here if we already know about this masternode and it's enabled
     757          10 :         if (pmn->IsEnabled()) return true;
     758             :         // if it's not enabled, remove old MN first and continue
     759             :         else
     760          10 :             mnodeman.Remove(pmn->vin.prevout);
     761             :     }
     762             : 
     763          68 :     const Coin& collateralUtxo = pcoinsTip->AccessCoin(mnb.vin.prevout);
     764          68 :     if (collateralUtxo.IsSpent()) {
     765           0 :         LogPrint(BCLog::MASTERNODE,"mnb - vin %s spent\n", mnb.vin.prevout.ToString());
     766           0 :         return false;
     767             :     }
     768             : 
     769             :     // Check collateral value
     770          68 :     if (collateralUtxo.out.nValue != consensus.nMNCollateralAmt) {
     771           0 :         LogPrint(BCLog::MASTERNODE,"mnb - invalid amount for mnb collateral %s\n", mnb.vin.prevout.ToString());
     772           0 :         nDoS = 33;
     773           0 :         return false;
     774             :     }
     775             : 
     776             :     // Check collateral association with mnb pubkey
     777         136 :     CScript payee = GetScriptForDestination(mnb.pubKeyCollateralAddress.GetID());
     778          68 :     if (collateralUtxo.out.scriptPubKey != payee) {
     779           0 :         LogPrint(BCLog::MASTERNODE,"mnb - collateral %s not associated with mnb pubkey\n", mnb.vin.prevout.ToString());
     780           0 :         nDoS = 33;
     781           0 :         return false;
     782             :     }
     783             : 
     784          68 :     LogPrint(BCLog::MASTERNODE, "mnb - Accepted Masternode entry\n");
     785          68 :     const int utxoHeight = (int) collateralUtxo.nHeight;
     786          68 :     int collateralUtxoDepth = nChainHeight - utxoHeight + 1;
     787          68 :     if (collateralUtxoDepth < consensus.MasternodeCollateralMinConf()) {
     788           0 :         LogPrint(BCLog::MASTERNODE,"mnb - Input must have at least %d confirmations\n", consensus.MasternodeCollateralMinConf());
     789             :         // maybe we miss few blocks, let this mnb to be checked again later
     790           0 :         mapSeenMasternodeBroadcast.erase(mnb.GetHash());
     791           0 :         g_tiertwo_sync_state.EraseSeenMNB(mnb.GetHash());
     792           0 :         return false;
     793             :     }
     794             : 
     795             :     // verify that sig time is legit in past
     796             :     // should be at least not earlier than block when 1000 PIV tx got MASTERNODE_MIN_CONFIRMATIONS
     797         204 :     CBlockIndex* pConfIndex = WITH_LOCK(cs_main, return chainActive[utxoHeight + consensus.MasternodeCollateralMinConf() - 1]); // block where tx got MASTERNODE_MIN_CONFIRMATIONS
     798          68 :     if (pConfIndex->GetBlockTime() > mnb.sigTime) {
     799           0 :         LogPrint(BCLog::MASTERNODE,"mnb - Bad sigTime %d for Masternode %s (%i conf block is at %d)\n",
     800             :                  mnb.sigTime, mnb.vin.prevout.hash.ToString(), consensus.MasternodeCollateralMinConf(), pConfIndex->GetBlockTime());
     801           0 :         return false;
     802             :     }
     803             : 
     804             :     // Good input
     805             :     return true;
     806             : }
     807             : 
     808          68 : int CMasternodeMan::ProcessMNBroadcast(CNode* pfrom, CMasternodeBroadcast& mnb)
     809             : {
     810          68 :     const uint256& mnbHash = mnb.GetHash();
     811          68 :     if (mapSeenMasternodeBroadcast.count(mnbHash)) { //seen
     812           0 :         g_tiertwo_sync_state.AddedMasternodeList(mnbHash);
     813           0 :         return 0;
     814             :     }
     815             : 
     816          68 :     int chainHeight = GetBestHeight();
     817          68 :     int nDoS = 0;
     818          68 :     if (!mnb.CheckAndUpdate(nDoS)) {
     819           0 :         return nDoS;
     820             :     }
     821             : 
     822             :     // make sure it's still unspent
     823          68 :     if (!CheckInputs(mnb, chainHeight, nDoS)) {
     824           0 :         return nDoS; // error set internally
     825             :     }
     826             : 
     827             :     // now that did the mnb checks, can add it.
     828          68 :     mapSeenMasternodeBroadcast.emplace(mnbHash, mnb);
     829             : 
     830             :     // All checks performed, add it
     831         136 :     LogPrint(BCLog::MASTERNODE,"%s - Got NEW Masternode entry - %s - %lli \n", __func__,
     832             :              mnb.vin.prevout.hash.ToString(), mnb.sigTime);
     833         136 :     CMasternode mn(mnb);
     834          68 :     if (!Add(mn)) {
     835           4 :         LogPrint(BCLog::MASTERNODE, "%s - Rejected Masternode entry %s\n", __func__,
     836             :                  mnb.vin.prevout.hash.ToString());
     837           2 :         return 0;
     838             :     }
     839             : 
     840             :     // if it matches our MN pubkey, then we've been remotely activated
     841          66 :     if (mnb.pubKeyMasternode == activeMasternode.pubKeyMasternode && mnb.protocolVersion == PROTOCOL_VERSION) {
     842          13 :         activeMasternode.EnableHotColdMasterNode(mnb.vin, mnb.addr);
     843             :     }
     844             : 
     845             :     // Relay only if we are synchronized and if the mnb address is not local.
     846             :     // Makes no sense to relay MNBs to the peers from where we are syncing them.
     847          66 :     bool isLocal = (mnb.addr.IsRFC1918() || mnb.addr.IsLocal()) && !Params().IsRegTestNet();
     848          66 :     if (!isLocal && g_tiertwo_sync_state.IsSynced()) mnb.Relay();
     849             : 
     850             :     // Add it as a peer
     851         132 :     g_connman->AddNewAddress(CAddress(mnb.addr, NODE_NETWORK), pfrom->addr, 2 * 60 * 60);
     852             : 
     853             :     // Update sync status
     854          66 :     g_tiertwo_sync_state.AddedMasternodeList(mnbHash);
     855             : 
     856             :     // All good
     857             :     return 0;
     858             : }
     859             : 
     860       52121 : int CMasternodeMan::ProcessMNPing(CNode* pfrom, CMasternodePing& mnp)
     861             : {
     862       52121 :     const uint256& mnpHash = mnp.GetHash();
     863       52121 :     if (mapSeenMasternodePing.count(mnpHash)) return 0; //seen
     864             : 
     865       52121 :     int nDoS = 0;
     866       52121 :     if (mnp.CheckAndUpdate(nDoS)) return 0;
     867             : 
     868       50037 :     if (nDoS > 0) {
     869             :         // if anything significant failed, mark that node
     870             :         return nDoS;
     871             :     } else {
     872             :         // if nothing significant failed, search existing Masternode list
     873       50031 :         CMasternode* pmn = Find(mnp.vin.prevout);
     874             :         // if it's known, don't ask for the mnb, just return
     875       50031 :         if (pmn != nullptr) return 0;
     876             :     }
     877             : 
     878             :     // something significant is broken or mn is unknown,
     879             :     // we might have to ask for the mn entry (while we aren't syncing).
     880       50000 :     if (g_tiertwo_sync_state.IsSynced()) {
     881           0 :         AskForMN(pfrom, mnp.vin);
     882             :     }
     883             : 
     884             :     // All good
     885             :     return 0;
     886             : }
     887             : 
     888          20 : void CMasternodeMan::BroadcastInvMN(CMasternode* mn, CNode* pfrom)
     889             : {
     890          20 :     CMasternodeBroadcast mnb = CMasternodeBroadcast(*mn);
     891          20 :     const uint256& hash = mnb.GetHash();
     892          20 :     pfrom->PushInventory(CInv(MSG_MASTERNODE_ANNOUNCE, hash));
     893             : 
     894             :     // Add to mapSeenMasternodeBroadcast in case that isn't there for some reason.
     895          40 :     if (!mapSeenMasternodeBroadcast.count(hash)) mapSeenMasternodeBroadcast.emplace(hash, mnb);
     896          20 : }
     897             : 
     898         845 : int CMasternodeMan::ProcessGetMNList(CNode* pfrom, CTxIn& vin)
     899             : {
     900             :     // Single MN request
     901         845 :     if (!vin.IsNull()) {
     902           2 :         CMasternode* mn = Find(vin.prevout);
     903           4 :         if (!mn || !mn->IsEnabled()) return 0; // Nothing to return.
     904             : 
     905             :         // Relay the MN.
     906           2 :         BroadcastInvMN(mn, pfrom);
     907           2 :         LogPrint(BCLog::MASTERNODE, "dseg - Sent 1 Masternode entry to peer %i\n", pfrom->GetId());
     908           2 :         return 0;
     909             :     }
     910             : 
     911             :     // Check if the node asked for mn list sync before.
     912         843 :     bool isLocal = (pfrom->addr.IsRFC1918() || pfrom->addr.IsLocal());
     913           0 :     if (!isLocal) {
     914           0 :         auto itAskedUsMNList = mAskedUsForMasternodeList.find(pfrom->addr);
     915           0 :         if (itAskedUsMNList != mAskedUsForMasternodeList.end()) {
     916           0 :             int64_t t = (*itAskedUsMNList).second;
     917           0 :             if (GetTime() < t) {
     918           0 :                 LogPrintf("CMasternodeMan::ProcessMessage() : dseg - peer already asked me for the list\n");
     919           0 :                 return 20;
     920             :             }
     921             :         }
     922           0 :         int64_t askAgain = GetTime() + MASTERNODES_REQUEST_SECONDS;
     923           0 :         mAskedUsForMasternodeList[pfrom->addr] = askAgain;
     924             :     }
     925             : 
     926         843 :     int nInvCount = 0;
     927         843 :     {
     928         843 :         LOCK(cs);
     929         861 :         for (auto& it : mapMasternodes) {
     930          18 :             MasternodeRef& mn = it.second;
     931          18 :             if (mn->addr.IsRFC1918()) continue; //local network
     932          18 :             if (mn->IsEnabled()) {
     933          36 :                 LogPrint(BCLog::MASTERNODE, "dseg - Sending Masternode entry - %s \n", mn->vin.prevout.hash.ToString());
     934          18 :                 BroadcastInvMN(mn.get(), pfrom);
     935          18 :                 nInvCount++;
     936             :             }
     937             :         }
     938             :     }
     939             : 
     940         843 :     g_connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_LIST, nInvCount));
     941         843 :     LogPrint(BCLog::MASTERNODE, "dseg - Sent %d Masternode entries to peer %i\n", nInvCount, pfrom->GetId());
     942             : 
     943             :     // All good
     944             :     return 0;
     945             : }
     946             : 
     947       55750 : bool CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, int& dosScore)
     948             : {
     949       55750 :     dosScore = ProcessMessageInner(pfrom, strCommand, vRecv);
     950       55750 :     return dosScore == 0;
     951             : }
     952             : 
     953       55750 : int CMasternodeMan::ProcessMessageInner(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
     954             : {
     955       55750 :     if (!g_tiertwo_sync_state.IsBlockchainSynced()) return 0;
     956             : 
     957             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     958       55740 :     if (deterministicMNManager->LegacyMNObsolete()) {
     959         878 :         LogPrint(BCLog::MASTERNODE, "%s: skip obsolete message %s\n", __func__, strCommand);
     960         878 :         return 0;
     961             :     }
     962             : 
     963      110612 :     LOCK(cs_process_message);
     964             : 
     965       54862 :     if (strCommand == NetMsgType::MNBROADCAST) {
     966         136 :         CMasternodeBroadcast mnb;
     967          68 :         vRecv >> mnb;
     968          68 :         {
     969             :             // Clear inv request
     970          68 :             LOCK(cs_main);
     971          68 :             g_connman->RemoveAskFor(mnb.GetHash(), MSG_MASTERNODE_ANNOUNCE);
     972             :         }
     973          68 :         return ProcessMNBroadcast(pfrom, mnb);
     974             : 
     975       54794 :     } else if (strCommand == NetMsgType::MNBROADCAST2) {
     976           0 :         CMasternodeBroadcast mnb;
     977           0 :         OverrideStream<CDataStream> s(&vRecv, vRecv.GetType(), vRecv.GetVersion() | ADDRV2_FORMAT);
     978           0 :         s >> mnb;
     979           0 :         {
     980             :             // Clear inv request
     981           0 :             LOCK(cs_main);
     982           0 :             g_connman->RemoveAskFor(mnb.GetHash(), MSG_MASTERNODE_ANNOUNCE);
     983             :         }
     984             : 
     985             :         // For now, let's not process mnb2 with pre-BIP155 node addr format.
     986           0 :         if (mnb.addr.IsAddrV1Compatible()) {
     987           0 :             LogPrint(BCLog::MASTERNODE, "%s: mnb2 with pre-BIP155 node addr format rejected\n", __func__);
     988           0 :             return 30;
     989             :         }
     990             : 
     991           0 :         return ProcessMNBroadcast(pfrom, mnb);
     992             : 
     993       54794 :     } else if (strCommand == NetMsgType::MNPING) {
     994             :         //Masternode Ping
     995      104242 :         CMasternodePing mnp;
     996       52121 :         vRecv >> mnp;
     997      104242 :         LogPrint(BCLog::MNPING, "mnp - Masternode ping, vin: %s\n", mnp.vin.prevout.hash.ToString());
     998       52121 :         {
     999             :             // Clear inv request
    1000       52121 :             LOCK(cs_main);
    1001       52121 :             g_connman->RemoveAskFor(mnp.GetHash(), MSG_MASTERNODE_PING);
    1002             :         }
    1003       52121 :         return ProcessMNPing(pfrom, mnp);
    1004             : 
    1005        2673 :     } else if (strCommand == NetMsgType::GETMNLIST) {
    1006             :         //Get Masternode list or specific entry
    1007           0 :         CTxIn vin;
    1008           0 :         vRecv >> vin;
    1009           0 :         return ProcessGetMNList(pfrom, vin);
    1010             :     }
    1011             :     // Nothing to report
    1012             :     return 0;
    1013             : }
    1014             : 
    1015          11 : void CMasternodeMan::Remove(const COutPoint& collateralOut)
    1016             : {
    1017          11 :     LOCK(cs);
    1018          11 :     const auto it = mapMasternodes.find(collateralOut);
    1019          11 :     if (it != mapMasternodes.end()) {
    1020          11 :         mapMasternodes.erase(it);
    1021             :     }
    1022          11 : }
    1023             : 
    1024          14 : void CMasternodeMan::UpdateMasternodeList(CMasternodeBroadcast& mnb)
    1025             : {
    1026             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
    1027          14 :     if (deterministicMNManager->LegacyMNObsolete()) {
    1028             :         return;
    1029             :     }
    1030             : 
    1031          14 :     mapSeenMasternodePing.emplace(mnb.lastPing.GetHash(), mnb.lastPing);
    1032          14 :     mapSeenMasternodeBroadcast.emplace(mnb.GetHash(), mnb);
    1033          14 :     g_tiertwo_sync_state.AddedMasternodeList(mnb.GetHash());
    1034             : 
    1035          28 :     LogPrint(BCLog::MASTERNODE,"%s -- masternode=%s\n", __func__, mnb.vin.prevout.ToString());
    1036             : 
    1037          14 :     CMasternode* pmn = Find(mnb.vin.prevout);
    1038          14 :     if (pmn == nullptr) {
    1039          24 :         CMasternode mn(mnb);
    1040          12 :         Add(mn);
    1041             :     } else {
    1042           2 :         pmn->UpdateFromNewBroadcast(mnb);
    1043             :     }
    1044             : }
    1045             : 
    1046         277 : int64_t CMasternodeMan::SecondsSincePayment(const MasternodeRef& mn, int count_enabled, const CBlockIndex* BlockReading) const
    1047             : {
    1048         277 :     int64_t sec = (GetAdjustedTime() - GetLastPaid(mn, count_enabled, BlockReading));
    1049         277 :     int64_t month = 60 * 60 * 24 * 30;
    1050         277 :     if (sec < month) return sec; //if it's less than 30 days, give seconds
    1051             : 
    1052         217 :     CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
    1053         217 :     ss << mn->vin;
    1054         217 :     ss << mn->sigTime;
    1055         434 :     const arith_uint256& hash = UintToArith256(ss.GetHash());
    1056             : 
    1057             :     // return some deterministic value for unknown/unpaid but force it to be more than 30 days old
    1058         217 :     return month + hash.GetCompact(false);
    1059             : }
    1060             : 
    1061         591 : int64_t CMasternodeMan::GetLastPaid(const MasternodeRef& mn, int count_enabled, const CBlockIndex* BlockReading) const
    1062             : {
    1063         591 :     if (BlockReading == nullptr) return false;
    1064             : 
    1065        1182 :     const CScript& mnpayee = mn->GetPayeeScript();
    1066             : 
    1067         591 :     CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
    1068         591 :     ss << mn->vin;
    1069         591 :     ss << mn->sigTime;
    1070         591 :     const uint256& hash = ss.GetHash();
    1071             : 
    1072             :     // use a deterministic offset to break a tie -- 2.5 minutes
    1073         591 :     int64_t nOffset = UintToArith256(hash).GetCompact(false) % 150;
    1074             : 
    1075         591 :     int max_depth = count_enabled * 1.25;
    1076        1840 :     for (int n = 0; n < max_depth; n++) {
    1077        1309 :         const auto& it = masternodePayments.mapMasternodeBlocks.find(BlockReading->nHeight);
    1078        1309 :         if (it != masternodePayments.mapMasternodeBlocks.end()) {
    1079             :             // Search for this payee, with at least 2 votes. This will aid in consensus
    1080             :             // allowing the network to converge on the same payees quickly, then keep the same schedule.
    1081         230 :             if (it->second.HasPayeeWithVotes(mnpayee, 2))
    1082          60 :                 return BlockReading->nTime + nOffset;
    1083             :         }
    1084        1249 :         BlockReading = BlockReading->pprev;
    1085             : 
    1086        1249 :         if (BlockReading == nullptr || BlockReading->nHeight <= 0) {
    1087             :             break;
    1088             :         }
    1089             :     }
    1090             : 
    1091             :     return 0;
    1092             : }
    1093             : 
    1094         456 : std::string CMasternodeMan::ToString() const
    1095             : {
    1096         456 :     std::ostringstream info;
    1097         456 :     info << "Masternodes: " << (int)mapMasternodes.size()
    1098         456 :          << ", peers who asked us for Masternode list: " << (int)mAskedUsForMasternodeList.size()
    1099         456 :          << ", peers we asked for Masternode list: " << (int)mWeAskedForMasternodeList.size()
    1100         456 :          << ", entries in Masternode list we asked for: " << (int)mWeAskedForMasternodeListEntry.size();
    1101         456 :     return info.str();
    1102             : }
    1103             : 
    1104       66091 : void CMasternodeMan::CacheBlockHash(const CBlockIndex* pindex)
    1105             : {
    1106       66091 :     cvLastBlockHashes.Set(pindex->nHeight, pindex->GetBlockHash());
    1107       66091 : }
    1108             : 
    1109         166 : void CMasternodeMan::UncacheBlockHash(const CBlockIndex* pindex)
    1110             : {
    1111         166 :     cvLastBlockHashes.Set(pindex->nHeight, UINT256_ZERO);
    1112         166 : }
    1113             : 
    1114       98420 : uint256 CMasternodeMan::GetHashAtHeight(int nHeight) const
    1115             : {
    1116             :     // return zero if outside bounds
    1117       98420 :     if (nHeight < 0) {
    1118           0 :         LogPrint(BCLog::MASTERNODE, "%s: Negative height. Returning 0\n",  __func__);
    1119           0 :         return UINT256_ZERO;
    1120             :     }
    1121       98420 :     int nCurrentHeight = GetBestHeight();
    1122       98420 :     if (nHeight > nCurrentHeight) {
    1123           1 :         LogPrint(BCLog::MASTERNODE, "%s: height %d over current height %d. Returning 0\n",
    1124             :                 __func__, nHeight, nCurrentHeight);
    1125           1 :         return UINT256_ZERO;
    1126             :     }
    1127             : 
    1128       98419 :     if (nHeight > nCurrentHeight - (int) CACHED_BLOCK_HASHES) {
    1129             :         // Use cached hash
    1130       98419 :         return cvLastBlockHashes.Get(nHeight);
    1131             :     } else {
    1132             :         // Use chainActive
    1133           0 :         LOCK(cs_main);
    1134           0 :         return chainActive[nHeight]->GetBlockHash();
    1135             :     }
    1136             : }
    1137             : 
    1138       52269 : bool CMasternodeMan::IsWithinDepth(const uint256& nHash, int depth) const
    1139             : {
    1140             :     // Sanity checks
    1141      104538 :     if (nHash.IsNull()) {
    1142           0 :         return error("%s: Called with null hash\n", __func__);
    1143             :     }
    1144       52269 :     if (depth < 0 || (unsigned) depth >= CACHED_BLOCK_HASHES) {
    1145           0 :         return error("%s: Invalid depth %d. Cached block hashes: %d\n", __func__, depth, CACHED_BLOCK_HASHES);
    1146             :     }
    1147             :     // Check last depth blocks to find one with matching hash
    1148       52269 :     const int nCurrentHeight = GetBestHeight();
    1149       52269 :     int nStopHeight = std::max(0, nCurrentHeight - depth);
    1150       80329 :     for (int i = nCurrentHeight; i >= nStopHeight; i--) {
    1151       80328 :         if (GetHashAtHeight(i) == nHash)
    1152             :             return true;
    1153             :     }
    1154             :     return false;
    1155             : }
    1156             : 
    1157         355 : void ThreadCheckMasternodes()
    1158             : {
    1159             :     // Make this thread recognisable as the wallet flushing thread
    1160         355 :     util::ThreadRename("pivx-masternodeman");
    1161         355 :     LogPrintf("Masternodes thread started\n");
    1162             : 
    1163         355 :     unsigned int c = 0;
    1164             : 
    1165         355 :     try {
    1166             :         // first clean up stale masternode payments data
    1167         355 :         masternodePayments.CleanPaymentList(mnodeman.CheckAndRemove(), mnodeman.GetBestHeight());
    1168             : 
    1169             :         // Startup-only, clean any stored seen MN broadcast with an invalid service that
    1170             :         // could have been invalidly stored on a previous release
    1171         355 :         auto itSeenMNB = mnodeman.mapSeenMasternodeBroadcast.begin();
    1172         355 :         while (itSeenMNB != mnodeman.mapSeenMasternodeBroadcast.end()) {
    1173           0 :             if (!itSeenMNB->second.addr.IsValid()) {
    1174           0 :                 itSeenMNB = mnodeman.mapSeenMasternodeBroadcast.erase(itSeenMNB);
    1175             :             } else {
    1176         355 :                 itSeenMNB++;
    1177             :             }
    1178             :         }
    1179             : 
    1180       19407 :         while (true) {
    1181             : 
    1182       19407 :             if (ShutdownRequested()) {
    1183             :                 break;
    1184             :             }
    1185             : 
    1186       19217 :             MilliSleep(1000);
    1187       19052 :             boost::this_thread::interruption_point();
    1188             : 
    1189             :             // try to sync from all available nodes, one step at a time
    1190       19052 :             masternodeSync.Process();
    1191             : 
    1192       19052 :             if (g_tiertwo_sync_state.IsBlockchainSynced()) {
    1193       16776 :                 c++;
    1194             : 
    1195             :                 // check if we should activate or ping every few minutes,
    1196             :                 // start right after sync is considered to be done
    1197       16776 :                 if (c % (MasternodePingSeconds()/2) == 0)
    1198        1287 :                     activeMasternode.ManageStatus();
    1199             : 
    1200       16776 :                 if (c % (MasternodePingSeconds()/5) == 0) {
    1201        3265 :                     masternodePayments.CleanPaymentList(mnodeman.CheckAndRemove(), mnodeman.GetBestHeight());
    1202             :                 }
    1203             :             }
    1204             :         }
    1205         165 :     } catch (boost::thread_interrupted&) {
    1206             :         // nothing, thread interrupted.
    1207             :     }
    1208         355 : }

Generated by: LCOV version 1.14