LCOV - code coverage report
Current view: top level - src - masternodeman.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 494 641 77.1 %
Date: 2026-08-09 10:51:41 Functions: 42 46 91.3 %

          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      245130 :     bool operator()(const std::pair<int64_t, T>& t1,
      34             :         const std::pair<int64_t, T>& t2) const
      35             :     {
      36      240196 :         return t1.first < t2.first;
      37             :     }
      38             : };
      39             : 
      40             : //
      41             : // CMasternodeDB
      42             : //
      43             : 
      44             : static const int MASTERNODE_DB_VERSION_BIP155 = 2;
      45             : 
      46         608 : CMasternodeDB::CMasternodeDB()
      47             : {
      48         608 :     pathMN = GetDataDir() / "mncache.dat";
      49         608 :     strMagicMessage = "MasternodeCache";
      50         608 : }
      51             : 
      52         315 : bool CMasternodeDB::Write(const CMasternodeMan& mnodemanToSave)
      53             : {
      54         315 :     int64_t nStart = GetTimeMillis();
      55         315 :     const auto& params = Params();
      56             : 
      57             :     // serialize, checksum data up to that point, then append checksum
      58             :     // Always done in the latest format.
      59         630 :     CDataStream ssMasternodes(SER_DISK, CLIENT_VERSION | ADDRV2_FORMAT);
      60         315 :     ssMasternodes << MASTERNODE_DB_VERSION_BIP155;
      61         315 :     ssMasternodes << strMagicMessage;                   // masternode cache file specific magic message
      62         315 :     ssMasternodes << params.MessageStart(); // network specific magic number
      63         315 :     ssMasternodes << mnodemanToSave;
      64         315 :     uint256 hash = Hash(ssMasternodes.begin(), ssMasternodes.end());
      65         315 :     ssMasternodes << hash;
      66             : 
      67             :     // open output file, and associate with CAutoFile
      68         315 :     FILE* file = fsbridge::fopen(pathMN, "wb");
      69         630 :     CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
      70         315 :     if (fileout.IsNull())
      71           0 :         return error("%s : Failed to open file %s", __func__, pathMN.string());
      72             : 
      73             :     // Write and commit header, data
      74         315 :     try {
      75         315 :         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         315 :     fileout.fclose();
      81             : 
      82         315 :     LogPrint(BCLog::MASTERNODE,"Written info to mncache.dat  %dms\n", GetTimeMillis() - nStart);
      83         626 :     LogPrint(BCLog::MASTERNODE,"  %s\n", mnodemanToSave.ToString());
      84             : 
      85             :     return true;
      86             : }
      87             : 
      88         293 : CMasternodeDB::ReadResult CMasternodeDB::Read(CMasternodeMan& mnodemanToLoad)
      89             : {
      90         293 :     int64_t nStart = GetTimeMillis();
      91             :     // open input file, and associate with CAutoFile
      92         293 :     FILE* file = fsbridge::fopen(pathMN, "rb");
      93         586 :     CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
      94         293 :     if (filein.IsNull()) {
      95         217 :         error("%s : Failed to open file %s", __func__, pathMN.string());
      96             :         return FileError;
      97             :     }
      98             : 
      99             :     // use file size to size memory buffer
     100          76 :     int fileSize = fs::file_size(pathMN);
     101          76 :     int dataSize = fileSize - sizeof(uint256);
     102             :     // Don't try to resize to a negative number if file is small
     103          76 :     if (dataSize < 0)
     104           0 :         dataSize = 0;
     105         369 :     std::vector<unsigned char> vchData;
     106          76 :     vchData.resize(dataSize);
     107          76 :     uint256 hashIn;
     108             : 
     109             :     // read data and checksum from file
     110          76 :     try {
     111          76 :         filein.read((char*)vchData.data(), dataSize);
     112          76 :         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          76 :     filein.fclose();
     118             : 
     119          76 :     const auto& params = Params();
     120             :     // serialize, checksum data up to that point, then append checksum
     121         152 :     CDataStream ssMasternodes(vchData, SER_DISK,  CLIENT_VERSION);
     122             : 
     123             :     // verify stored checksum matches input data
     124          76 :     uint256 hashTmp = Hash(ssMasternodes.begin(), ssMasternodes.end());
     125          76 :     if (hashIn != hashTmp) {
     126           0 :         error("%s : Checksum mismatch, data corrupted", __func__);
     127             :         return IncorrectHash;
     128             :     }
     129             : 
     130          76 :     int version;
     131         152 :     std::string strMagicMessageTmp;
     132          76 :     try {
     133             :         // de-serialize file header
     134          76 :         ssMasternodes >> version;
     135          76 :         ssMasternodes >> strMagicMessageTmp;
     136             : 
     137             :         // ... verify the message matches predefined one
     138          76 :         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          76 :         std::vector<unsigned char> pchMsgTmp(4);
     145          76 :         ssMasternodes >> MakeSpan(pchMsgTmp);
     146             : 
     147             :         // ... verify the network matches ours
     148          76 :         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          76 :         if (version == MASTERNODE_DB_VERSION_BIP155) {
     154          76 :             OverrideStream<CDataStream> s(&ssMasternodes, ssMasternodes.GetType(), ssMasternodes.GetVersion() | ADDRV2_FORMAT);
     155          76 :             s >> mnodemanToLoad;
     156             :         } else {
     157             :             // Old format
     158          76 :             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          76 :     LogPrint(BCLog::MASTERNODE,"Loaded info from mncache.dat (dbversion=%d) %dms\n", version, GetTimeMillis() - nStart);
     167         152 :     LogPrint(BCLog::MASTERNODE,"  %s\n", mnodemanToLoad.ToString());
     168             : 
     169             :     return Ok;
     170             : }
     171             : 
     172         315 : void DumpMasternodes()
     173             : {
     174         315 :     int64_t nStart = GetTimeMillis();
     175             : 
     176         630 :     CMasternodeDB mndb;
     177         315 :     LogPrint(BCLog::MASTERNODE,"Writing info to mncache.dat...\n");
     178         315 :     mndb.Write(mnodeman);
     179             : 
     180         315 :     LogPrint(BCLog::MASTERNODE,"Masternode dump finished  %dms\n", GetTimeMillis() - nStart);
     181         315 : }
     182             : 
     183         416 : CMasternodeMan::CMasternodeMan():
     184             :         cvLastBlockHashes(CACHED_BLOCK_HASHES, UINT256_ZERO),
     185         416 :         nDsqCount(0)
     186         416 : {}
     187             : 
     188          83 : bool CMasternodeMan::Add(CMasternode& mn)
     189             : {
     190             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     191          83 :     if (deterministicMNManager->LegacyMNObsolete()) {
     192             :         return false;
     193             :     }
     194             : 
     195          83 :     if (deterministicMNManager->GetListAtChainTip().HasMNByCollateral(mn.vin.prevout)) {
     196           0 :         LogPrint(BCLog::MASTERNODE, "ERROR: Not Adding Masternode %s as the collateral is already registered with a DMN\n",
     197             :                 mn.vin.prevout.ToString());
     198           0 :         return false;
     199             :     }
     200             : 
     201         166 :     LOCK(cs);
     202             : 
     203          83 :     if (!mn.IsAvailableState())
     204             :         return false;
     205             : 
     206          83 :     const auto& it = mapMasternodes.find(mn.vin.prevout);
     207          83 :     if (it == mapMasternodes.end()) {
     208         126 :         LogPrint(BCLog::MASTERNODE, "Adding new Masternode %s\n", mn.vin.prevout.ToString());
     209          83 :         mapMasternodes.emplace(mn.vin.prevout, std::make_shared<CMasternode>(mn));
     210          83 :         LogPrint(BCLog::MASTERNODE, "Masternode added. New total count: %d\n", mapMasternodes.size());
     211          83 :         return true;
     212             :     }
     213             : 
     214             :     return false;
     215             : }
     216             : 
     217           0 : void CMasternodeMan::AskForMN(CNode* pnode, const CTxIn& vin)
     218             : {
     219             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     220           0 :     if (deterministicMNManager->LegacyMNObsolete()) {
     221           0 :         return;
     222             :     }
     223             : 
     224           0 :     std::map<COutPoint, int64_t>::iterator i = mWeAskedForMasternodeListEntry.find(vin.prevout);
     225           0 :     if (i != mWeAskedForMasternodeListEntry.end()) {
     226           0 :         int64_t t = (*i).second;
     227           0 :         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           0 :     LogPrint(BCLog::MASTERNODE, "CMasternodeMan::AskForMN - Asking node for missing entry, vin: %s\n", vin.prevout.hash.ToString());
     233           0 :     g_connman->PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::GETMNLIST, vin));
     234           0 :     int64_t askAgain = GetTime() + MasternodeMinPingSeconds();
     235           0 :     mWeAskedForMasternodeListEntry[vin.prevout] = askAgain;
     236             : }
     237             : 
     238        1865 : int CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval)
     239             : {
     240             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     241        1865 :     if (deterministicMNManager->LegacyMNObsolete()) {
     242          98 :         LogPrint(BCLog::MASTERNODE, "Removing all legacy mn due to SPORK 21\n");
     243          98 :         Clear();
     244          98 :         return 0;
     245             :     }
     246             : 
     247        3632 :     LOCK(cs);
     248             : 
     249             :     //remove inactive and outdated (or replaced by DMN)
     250        1767 :     auto it = mapMasternodes.begin();
     251        2298 :     while (it != mapMasternodes.end()) {
     252         531 :         MasternodeRef& mn = it->second;
     253         531 :         auto activeState = mn->GetActiveState();
     254         531 :         if (activeState == CMasternode::MASTERNODE_REMOVE ||
     255         515 :             activeState == CMasternode::MASTERNODE_VIN_SPENT ||
     256        1046 :             (forceExpiredRemoval && activeState == CMasternode::MASTERNODE_EXPIRED) ||
     257         515 :             mn->protocolVersion < ActiveProtocol()) {
     258          32 :             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          16 :             std::map<uint256, CMasternodeBroadcast>::iterator it3 = mapSeenMasternodeBroadcast.begin();
     263          46 :             while (it3 != mapSeenMasternodeBroadcast.end()) {
     264          30 :                 if (it3->second.vin.prevout == it->first) {
     265          17 :                     g_tiertwo_sync_state.EraseSeenMNB((*it3).first);
     266          17 :                     it3 = mapSeenMasternodeBroadcast.erase(it3);
     267             :                 } else {
     268          59 :                     ++it3;
     269             :                 }
     270             :             }
     271             : 
     272             :             // allow us to ask for this masternode again if we see another ping
     273          16 :             std::map<COutPoint, int64_t>::iterator it2 = mWeAskedForMasternodeListEntry.begin();
     274          16 :             while (it2 != mWeAskedForMasternodeListEntry.end()) {
     275           0 :                 if (it2->first == it->first) {
     276           0 :                     it2 = mWeAskedForMasternodeListEntry.erase(it2);
     277             :                 } else {
     278          16 :                     ++it2;
     279             :                 }
     280             :             }
     281             : 
     282             :             // clean MN pings right away.
     283          16 :             auto itPing = mapSeenMasternodePing.begin();
     284         119 :             while (itPing != mapSeenMasternodePing.end()) {
     285         206 :                 if (itPing->second.GetVin().prevout == it->first) {
     286          49 :                     itPing = mapSeenMasternodePing.erase(itPing);
     287             :                 } else {
     288         173 :                     ++itPing;
     289             :                 }
     290             :             }
     291             : 
     292          16 :             it = mapMasternodes.erase(it);
     293          16 :             LogPrint(BCLog::MASTERNODE, "Masternode removed.\n");
     294             :         } else {
     295        2813 :             ++it;
     296             :         }
     297             :     }
     298        1767 :     LogPrint(BCLog::MASTERNODE, "New total masternode count: %d\n", mapMasternodes.size());
     299             : 
     300             :     // check who's asked for the Masternode list
     301        1767 :     std::map<CNetAddr, int64_t>::iterator it1 = mAskedUsForMasternodeList.begin();
     302        1767 :     while (it1 != mAskedUsForMasternodeList.end()) {
     303           0 :         if ((*it1).second < GetTime()) {
     304           0 :             it1 = mAskedUsForMasternodeList.erase(it1);
     305             :         } else {
     306        1767 :             ++it1;
     307             :         }
     308             :     }
     309             : 
     310             :     // check who we asked for the Masternode list
     311        1767 :     it1 = mWeAskedForMasternodeList.begin();
     312        1767 :     while (it1 != mWeAskedForMasternodeList.end()) {
     313           0 :         if ((*it1).second < GetTime()) {
     314           0 :             it1 = mWeAskedForMasternodeList.erase(it1);
     315             :         } else {
     316        1767 :             ++it1;
     317             :         }
     318             :     }
     319             : 
     320             :     // check which Masternodes we've asked for
     321        1767 :     std::map<COutPoint, int64_t>::iterator it2 = mWeAskedForMasternodeListEntry.begin();
     322        1767 :     while (it2 != mWeAskedForMasternodeListEntry.end()) {
     323           0 :         if ((*it2).second < GetTime()) {
     324           0 :             it2 = mWeAskedForMasternodeListEntry.erase(it2);
     325             :         } else {
     326        1767 :             ++it2;
     327             :         }
     328             :     }
     329             : 
     330             :     // remove expired mapSeenMasternodeBroadcast
     331        1767 :     std::map<uint256, CMasternodeBroadcast>::iterator it3 = mapSeenMasternodeBroadcast.begin();
     332        2289 :     while (it3 != mapSeenMasternodeBroadcast.end()) {
     333         522 :         if ((*it3).second.lastPing.sigTime < GetTime() - (MasternodeRemovalSeconds() * 2)) {
     334           0 :             g_tiertwo_sync_state.EraseSeenMNB((*it3).second.GetHash());
     335           0 :             it3 = mapSeenMasternodeBroadcast.erase(it3);
     336             :         } else {
     337        2811 :             ++it3;
     338             :         }
     339             :     }
     340             : 
     341             :     // remove expired mapSeenMasternodePing
     342        1767 :     std::map<uint256, CMasternodePing>::iterator it4 = mapSeenMasternodePing.begin();
     343        5059 :     while (it4 != mapSeenMasternodePing.end()) {
     344        3292 :         if ((*it4).second.sigTime < GetTime() - (MasternodeRemovalSeconds() * 2)) {
     345          77 :             it4 = mapSeenMasternodePing.erase(it4);
     346             :         } else {
     347        8274 :             ++it4;
     348             :         }
     349             :     }
     350             : 
     351        1767 :     return mapMasternodes.size();
     352             : }
     353             : 
     354          98 : void CMasternodeMan::Clear()
     355             : {
     356          98 :     LOCK(cs);
     357          98 :     mapMasternodes.clear();
     358          98 :     mAskedUsForMasternodeList.clear();
     359          98 :     mWeAskedForMasternodeList.clear();
     360          98 :     mWeAskedForMasternodeListEntry.clear();
     361          98 :     mapSeenMasternodeBroadcast.clear();
     362          98 :     mapSeenMasternodePing.clear();
     363          98 :     nDsqCount = 0;
     364          98 : }
     365             : 
     366          48 : static void CountNetwork(const CService& addr, int& ipv4, int& ipv6, int& onion)
     367             : {
     368          48 :     std::string strHost;
     369          48 :     int port;
     370          48 :     SplitHostPort(addr.ToString(), port, strHost);
     371          96 :     CNetAddr node;
     372          48 :     LookupHost(strHost, node, false);
     373          48 :     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          48 : }
     387             : 
     388          16 : CMasternodeMan::MNsInfo CMasternodeMan::getMNsInfo() const
     389             : {
     390          16 :     MNsInfo info;
     391          16 :     int nMinProtocol = ActiveProtocol();
     392          16 :     bool spork_8_active = sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT);
     393             : 
     394             :     // legacy masternodes
     395          16 :     {
     396          16 :         LOCK(cs);
     397          16 :         for (const auto& it : mapMasternodes) {
     398           0 :             const MasternodeRef& mn = it.second;
     399           0 :             info.total++;
     400           0 :             CountNetwork(mn->addr, info.ipv4, info.ipv6, info.onion);
     401           0 :             if (mn->protocolVersion < nMinProtocol || !mn->IsEnabled()) {
     402           0 :                 continue;
     403             :             }
     404           0 :             info.enabledSize++;
     405             :             // Eligible for payments
     406           0 :             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           0 :             info.stableSize++;
     410             :         }
     411             :     }
     412             : 
     413             :     // deterministic masternodes
     414          16 :     if (deterministicMNManager->IsDIP3Enforced()) {
     415          16 :         auto mnList = deterministicMNManager->GetListAtChainTip();
     416          16 :         mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
     417          96 :             info.total++;
     418          48 :             CountNetwork(dmn->pdmnState->addr, info.ipv4, info.ipv6, info.onion);
     419          48 :             if (!dmn->IsPoSeBanned()) {
     420          48 :                 info.enabledSize++;
     421          48 :                 info.stableSize++;
     422             :             }
     423          48 :         });
     424             :     }
     425             : 
     426          16 :     return info;
     427             : }
     428             : 
     429        4156 : int CMasternodeMan::CountEnabled(bool only_legacy) const
     430             : {
     431        4156 :     int count_enabled = 0;
     432        4156 :     int protocolVersion = ActiveProtocol();
     433             : 
     434        4156 :     {
     435        4156 :         LOCK(cs);
     436       67635 :         for (const auto& it : mapMasternodes) {
     437       63479 :             const MasternodeRef& mn = it.second;
     438       63479 :             if (mn->protocolVersion < protocolVersion || !mn->IsEnabled()) continue;
     439       60117 :             count_enabled++;
     440             :         }
     441             :     }
     442             : 
     443        4156 :     if (!only_legacy && deterministicMNManager->IsDIP3Enforced()) {
     444         346 :         count_enabled += deterministicMNManager->GetListAtChainTip().GetValidMNsCount();
     445             :     }
     446             : 
     447        4156 :     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      102831 : CMasternode* CMasternodeMan::Find(const COutPoint& collateralOut)
     477             : {
     478      102831 :     LOCK(cs);
     479      102831 :     auto it = mapMasternodes.find(collateralOut);
     480      102831 :     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          69 : CMasternode* CMasternodeMan::Find(const CPubKey& pubKeyMasternode)
     491             : {
     492          69 :     LOCK(cs);
     493             : 
     494          93 :     for (auto& it : mapMasternodes) {
     495          76 :         MasternodeRef& mn = it.second;
     496          76 :         if (mn->pubKeyMasternode == pubKeyMasternode)
     497          52 :             return mn.get();
     498             :     }
     499          17 :     return nullptr;
     500             : }
     501             : 
     502       24852 : void CMasternodeMan::CheckSpentCollaterals(const std::vector<CTransactionRef>& vtx)
     503             : {
     504             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     505       24852 :     if (deterministicMNManager->LegacyMNObsolete()) {
     506         300 :         return;
     507             :     }
     508             : 
     509       49104 :     LOCK(cs);
     510      169029 :     for (const auto& tx : vtx) {
     511      367959 :         for (const auto& in : tx->vin) {
     512      223482 :             auto it = mapMasternodes.find(in.prevout);
     513      223482 :             if (it != mapMasternodes.end()) {
     514           6 :                 it->second->SetSpent();
     515             :             }
     516             :         }
     517             :     }
     518             : }
     519             : 
     520          18 : static bool canScheduleMN(bool fFilterSigTime, const MasternodeRef& mn, int minProtocol,
     521             :                           int nMnCount, int nBlockHeight)
     522             : {
     523             :     // check protocol version
     524          18 :     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          18 :     if (masternodePayments.IsScheduled(*mn, nBlockHeight)) return false;
     528             : 
     529             :     // it's too new, wait for a cycle
     530           8 :     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           7 :     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          28 : 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          28 :     if (deterministicMNManager->LegacyMNObsolete(nBlockHeight)) {
     545           8 :         LogPrintf("%s: ERROR - called after legacy system disabled\n", __func__);
     546           8 :         return nullptr;
     547             :     }
     548             : 
     549          20 :     AssertLockNotHeld(cs_main);
     550          20 :     const CBlockIndex* BlockReading = (pChainTip == nullptr ? GetChainTip() : pChainTip);
     551          20 :     if (!BlockReading) return nullptr;
     552             : 
     553          48 :     MasternodeRef pBestMasternode = nullptr;
     554          40 :     std::vector<std::pair<int64_t, MasternodeRef> > vecMasternodeLastPaid;
     555             : 
     556             :     /*
     557             :         Make a vector with all of the last paid times
     558             :     */
     559          20 :     int minProtocol = ActiveProtocol();
     560          20 :     int count_enabled = CountEnabled();
     561          20 :     {
     562          20 :         LOCK(cs);
     563          41 :         for (const auto& it : mapMasternodes) {
     564          21 :             if (!it.second->IsEnabled()) continue;
     565           7 :             if (canScheduleMN(fFilterSigTime, it.second, minProtocol, count_enabled, nBlockHeight)) {
     566           5 :                 vecMasternodeLastPaid.emplace_back(SecondsSincePayment(it.second, count_enabled, BlockReading), it.second);
     567             :             }
     568             :         }
     569             :     }
     570             :     // Add deterministic masternodes to the vector
     571          20 :     if (deterministicMNManager->IsDIP3Enforced()) {
     572          19 :         CDeterministicMNList mnList = deterministicMNManager->GetListAtChainTip();
     573          19 :         mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
     574          11 :             const MasternodeRef mn = MakeMasternodeRefForDMN(dmn);
     575          11 :             if (canScheduleMN(fFilterSigTime, mn, minProtocol, count_enabled, nBlockHeight)) {
     576           2 :                 vecMasternodeLastPaid.emplace_back(SecondsSincePayment(mn, count_enabled, BlockReading), mn);
     577             :             }
     578          11 :         });
     579             :     }
     580             : 
     581          20 :     nCount = (int)vecMasternodeLastPaid.size();
     582             : 
     583             :     //when the network is in the process of upgrading, don't penalize nodes that recently restarted
     584          20 :     if (fFilterSigTime && nCount < count_enabled / 3) return GetNextMasternodeInQueueForPayment(nBlockHeight, false, nCount, BlockReading);
     585             : 
     586             :     // Sort them high to low
     587          20 :     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          20 :     int nTenthNetwork = count_enabled / 10;
     594          20 :     int nCountTenth = 0;
     595          20 :     arith_uint256 nHigh = ARITH_UINT256_ZERO;
     596          20 :     const uint256& hash = GetHashAtHeight(nBlockHeight - 101);
     597          20 :     for (const auto& s: vecMasternodeLastPaid) {
     598           7 :         const MasternodeRef pmn = s.second;
     599           7 :         if (!pmn) break;
     600             : 
     601           7 :         const arith_uint256& n = pmn->CalculateScore(hash);
     602           7 :         if (n > nHigh) {
     603          63 :             nHigh = n;
     604           7 :             pBestMasternode = pmn;
     605             :         }
     606           7 :         nCountTenth++;
     607           7 :         if (nCountTenth >= nTenthNetwork) break;
     608             :     }
     609          20 :     return pBestMasternode;
     610             : }
     611             : 
     612        9882 : MasternodeRef CMasternodeMan::GetCurrentMasterNode(const uint256& hash) const
     613             : {
     614        9882 :     int minProtocol = ActiveProtocol();
     615        9882 :     int64_t score = 0;
     616        9882 :     MasternodeRef winner = nullptr;
     617             : 
     618             :     // scan for winner
     619       10006 :     for (const auto& it : mapMasternodes) {
     620         124 :         const MasternodeRef& mn = it.second;
     621         124 :         if (mn->protocolVersion < minProtocol || !mn->IsEnabled()) continue;
     622             :         // calculate the score of the masternode
     623         111 :         const int64_t n = mn->CalculateScore(hash).GetCompact(false);
     624             :         // determine the winner
     625         111 :         if (n > score) {
     626          81 :             score = n;
     627         205 :             winner = mn;
     628             :         }
     629             :     }
     630             : 
     631             :     // scan also dmns
     632        9882 :     if (deterministicMNManager->IsDIP3Enforced()) {
     633          97 :         auto mnList = deterministicMNManager->GetListAtChainTip();
     634          97 :         mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
     635          37 :             const MasternodeRef mn = MakeMasternodeRefForDMN(dmn);
     636             :             // calculate the score of the masternode
     637          37 :             const int64_t n = mn->CalculateScore(hash).GetCompact(false);
     638             :             // determine the winner
     639          37 :             if (n > score) {
     640          22 :                 score = n;
     641          59 :                 winner = mn;
     642             :             }
     643          37 :         });
     644             :     }
     645             : 
     646        9882 :     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        1061 : int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight) const
     666             : {
     667        1061 :     const uint256& hash = GetHashAtHeight(nBlockHeight - 1);
     668             :     // height outside range
     669        1061 :     if (hash == UINT256_ZERO) return -1;
     670             : 
     671             :     // scan for winner
     672        1061 :     int minProtocol = ActiveProtocol();
     673        2122 :     std::vector<std::pair<int64_t, CTxIn> > vecMasternodeScores;
     674        1061 :     {
     675        1061 :         LOCK(cs);
     676       37290 :         for (const auto& it : mapMasternodes) {
     677       36229 :             const MasternodeRef& mn = it.second;
     678       36229 :             if (!mn->IsEnabled()) {
     679        1868 :                 continue; // Skip not enabled
     680             :             }
     681       34361 :             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       68712 :             if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) &&
     686       34351 :                     GetAdjustedTime() - mn->sigTime < MN_WINNER_MINIMUM_AGE) {
     687         226 :                 continue; // Skip masternodes younger than (default) 1 hour
     688             :             }
     689       34135 :             vecMasternodeScores.emplace_back(mn->CalculateScore(hash).GetCompact(false), mn->vin);
     690             :         }
     691             :     }
     692             : 
     693             :     // scan also dmns
     694        1061 :     if (deterministicMNManager->IsDIP3Enforced()) {
     695          47 :         auto mnList = deterministicMNManager->GetListAtChainTip();
     696          47 :         mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
     697          47 :             const MasternodeRef mn = MakeMasternodeRefForDMN(dmn);
     698          47 :             vecMasternodeScores.emplace_back(mn->CalculateScore(hash).GetCompact(false), mn->vin);
     699          47 :         });
     700             :     }
     701             : 
     702        1061 :     sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreMN());
     703             : 
     704        1061 :     int rank = 0;
     705        3852 :     for (std::pair<int64_t, CTxIn> & s : vecMasternodeScores) {
     706        3728 :         rank++;
     707        3728 :         if (s.second.prevout == vin.prevout) {
     708         937 :             return rank;
     709             :         }
     710             :     }
     711             : 
     712         124 :     return -1;
     713             : }
     714             : 
     715         282 : std::vector<std::pair<int64_t, MasternodeRef>> CMasternodeMan::GetMasternodeRanks(int nBlockHeight) const
     716             : {
     717         282 :     std::vector<std::pair<int64_t, MasternodeRef>> vecMasternodeScores;
     718         282 :     const uint256& hash = GetHashAtHeight(nBlockHeight - 1);
     719             :     // height outside range
     720         282 :     if (hash == UINT256_ZERO) return vecMasternodeScores;
     721         282 :     {
     722         282 :         LOCK(cs);
     723             :         // scan for winner
     724        5666 :         for (const auto& it : mapMasternodes) {
     725       10768 :             const MasternodeRef mn = it.second;
     726        5384 :             const uint32_t score = mn->IsEnabled() ? mn->CalculateScore(hash).GetCompact(false) : 9999;
     727             : 
     728        5384 :             vecMasternodeScores.emplace_back(score, mn);
     729             :         }
     730             :     }
     731             :     // scan also dmns
     732         282 :     if (deterministicMNManager->IsDIP3Enforced()) {
     733          88 :         auto mnList = deterministicMNManager->GetListAtChainTip();
     734          88 :         mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
     735          88 :             const MasternodeRef mn = MakeMasternodeRefForDMN(dmn);
     736          88 :             const uint32_t score = dmn->IsPoSeBanned() ? 9999 : mn->CalculateScore(hash).GetCompact(false);
     737             : 
     738          88 :             vecMasternodeScores.emplace_back(score, mn);
     739          88 :         });
     740             :     }
     741         282 :     sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreMN());
     742         282 :     return vecMasternodeScores;
     743             : }
     744             : 
     745          33 : bool CMasternodeMan::CheckInputs(CMasternodeBroadcast& mnb, int nChainHeight, int& nDoS)
     746             : {
     747          33 :     const auto& consensus = Params().GetConsensus();
     748             :     // incorrect ping or its sigTime
     749          33 :     if(mnb.lastPing.IsNull() || !mnb.lastPing.CheckAndUpdate(nDoS, false, true)) {
     750           0 :         return false;
     751             :     }
     752             : 
     753             :     // search existing Masternode list
     754          33 :     CMasternode* pmn = Find(mnb.vin.prevout);
     755          33 :     if (pmn != nullptr) {
     756             :         // nothing to do here if we already know about this masternode and it's enabled
     757           2 :         if (pmn->IsEnabled()) return true;
     758             :         // if it's not enabled, remove old MN first and continue
     759             :         else
     760           2 :             mnodeman.Remove(pmn->vin.prevout);
     761             :     }
     762             : 
     763          33 :     const Coin& collateralUtxo = pcoinsTip->AccessCoin(mnb.vin.prevout);
     764          33 :     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          33 :     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          66 :     CScript payee = GetScriptForDestination(mnb.pubKeyCollateralAddress.GetID());
     778          33 :     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          33 :     LogPrint(BCLog::MASTERNODE, "mnb - Accepted Masternode entry\n");
     785          33 :     const int utxoHeight = (int) collateralUtxo.nHeight;
     786          33 :     int collateralUtxoDepth = nChainHeight - utxoHeight + 1;
     787          33 :     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          99 :     CBlockIndex* pConfIndex = WITH_LOCK(cs_main, return chainActive[utxoHeight + consensus.MasternodeCollateralMinConf() - 1]); // block where tx got MASTERNODE_MIN_CONFIRMATIONS
     798          33 :     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          33 : int CMasternodeMan::ProcessMNBroadcast(CNode* pfrom, CMasternodeBroadcast& mnb)
     809             : {
     810          33 :     const uint256& mnbHash = mnb.GetHash();
     811          33 :     if (mapSeenMasternodeBroadcast.count(mnbHash)) { //seen
     812           0 :         g_tiertwo_sync_state.AddedMasternodeList(mnbHash);
     813           0 :         return 0;
     814             :     }
     815             : 
     816          33 :     int chainHeight = GetBestHeight();
     817          33 :     int nDoS = 0;
     818          33 :     if (!mnb.CheckAndUpdate(nDoS)) {
     819           0 :         return nDoS;
     820             :     }
     821             : 
     822             :     // make sure it's still unspent
     823          33 :     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          33 :     mapSeenMasternodeBroadcast.emplace(mnbHash, mnb);
     829             : 
     830             :     // All checks performed, add it
     831          66 :     LogPrint(BCLog::MASTERNODE,"%s - Got NEW Masternode entry - %s - %lli \n", __func__,
     832             :              mnb.vin.prevout.hash.ToString(), mnb.sigTime);
     833          66 :     CMasternode mn(mnb);
     834          33 :     if (!Add(mn)) {
     835           0 :         LogPrint(BCLog::MASTERNODE, "%s - Rejected Masternode entry %s\n", __func__,
     836             :                  mnb.vin.prevout.hash.ToString());
     837           0 :         return 0;
     838             :     }
     839             : 
     840             :     // if it matches our MN pubkey, then we've been remotely activated
     841          33 :     if (mnb.pubKeyMasternode == activeMasternode.pubKeyMasternode && mnb.protocolVersion == PROTOCOL_VERSION) {
     842           9 :         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          33 :     bool isLocal = (mnb.addr.IsRFC1918() || mnb.addr.IsLocal()) && !Params().IsRegTestNet();
     848          33 :     if (!isLocal && g_tiertwo_sync_state.IsSynced()) mnb.Relay();
     849             : 
     850             :     // Add it as a peer
     851          66 :     g_connman->AddNewAddress(CAddress(mnb.addr, NODE_NETWORK), pfrom->addr, 2 * 60 * 60);
     852             : 
     853             :     // Update sync status
     854          33 :     g_tiertwo_sync_state.AddedMasternodeList(mnbHash);
     855             : 
     856             :     // All good
     857             :     return 0;
     858             : }
     859             : 
     860       50409 : int CMasternodeMan::ProcessMNPing(CNode* pfrom, CMasternodePing& mnp)
     861             : {
     862       50409 :     const uint256& mnpHash = mnp.GetHash();
     863       50409 :     if (mapSeenMasternodePing.count(mnpHash)) return 0; //seen
     864             : 
     865       50409 :     int nDoS = 0;
     866       50409 :     if (mnp.CheckAndUpdate(nDoS)) return 0;
     867             : 
     868       50027 :     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       50025 :         CMasternode* pmn = Find(mnp.vin.prevout);
     874             :         // if it's known, don't ask for the mnb, just return
     875       50025 :         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           4 : void CMasternodeMan::BroadcastInvMN(CMasternode* mn, CNode* pfrom)
     889             : {
     890           4 :     CMasternodeBroadcast mnb = CMasternodeBroadcast(*mn);
     891           4 :     const uint256& hash = mnb.GetHash();
     892           4 :     pfrom->PushInventory(CInv(MSG_MASTERNODE_ANNOUNCE, hash));
     893             : 
     894             :     // Add to mapSeenMasternodeBroadcast in case that isn't there for some reason.
     895           8 :     if (!mapSeenMasternodeBroadcast.count(hash)) mapSeenMasternodeBroadcast.emplace(hash, mnb);
     896           4 : }
     897             : 
     898         361 : int CMasternodeMan::ProcessGetMNList(CNode* pfrom, CTxIn& vin)
     899             : {
     900             :     // Single MN request
     901         361 :     if (!vin.IsNull()) {
     902           0 :         CMasternode* mn = Find(vin.prevout);
     903           0 :         if (!mn || !mn->IsEnabled()) return 0; // Nothing to return.
     904             : 
     905             :         // Relay the MN.
     906           0 :         BroadcastInvMN(mn, pfrom);
     907           0 :         LogPrint(BCLog::MASTERNODE, "dseg - Sent 1 Masternode entry to peer %i\n", pfrom->GetId());
     908           0 :         return 0;
     909             :     }
     910             : 
     911             :     // Check if the node asked for mn list sync before.
     912         361 :     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         361 :     int nInvCount = 0;
     927         361 :     {
     928         361 :         LOCK(cs);
     929         365 :         for (auto& it : mapMasternodes) {
     930           4 :             MasternodeRef& mn = it.second;
     931           4 :             if (mn->addr.IsRFC1918()) continue; //local network
     932           4 :             if (mn->IsEnabled()) {
     933           8 :                 LogPrint(BCLog::MASTERNODE, "dseg - Sending Masternode entry - %s \n", mn->vin.prevout.hash.ToString());
     934           4 :                 BroadcastInvMN(mn.get(), pfrom);
     935           4 :                 nInvCount++;
     936             :             }
     937             :         }
     938             :     }
     939             : 
     940         361 :     g_connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_LIST, nInvCount));
     941         361 :     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       51039 : bool CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, int& dosScore)
     948             : {
     949       51039 :     dosScore = ProcessMessageInner(pfrom, strCommand, vRecv);
     950       51039 :     return dosScore == 0;
     951             : }
     952             : 
     953       51039 : int CMasternodeMan::ProcessMessageInner(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
     954             : {
     955       51039 :     if (!g_tiertwo_sync_state.IsBlockchainSynced()) return 0;
     956             : 
     957             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     958       51038 :     if (deterministicMNManager->LegacyMNObsolete()) {
     959          19 :         LogPrint(BCLog::MASTERNODE, "%s: skip obsolete message %s\n", __func__, strCommand);
     960          19 :         return 0;
     961             :     }
     962             : 
     963      102058 :     LOCK(cs_process_message);
     964             : 
     965       51019 :     if (strCommand == NetMsgType::MNBROADCAST) {
     966          66 :         CMasternodeBroadcast mnb;
     967          33 :         vRecv >> mnb;
     968          33 :         {
     969             :             // Clear inv request
     970          33 :             LOCK(cs_main);
     971          33 :             g_connman->RemoveAskFor(mnb.GetHash(), MSG_MASTERNODE_ANNOUNCE);
     972             :         }
     973          33 :         return ProcessMNBroadcast(pfrom, mnb);
     974             : 
     975       50986 :     } 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       50986 :     } else if (strCommand == NetMsgType::MNPING) {
     994             :         //Masternode Ping
     995      100818 :         CMasternodePing mnp;
     996       50409 :         vRecv >> mnp;
     997      100818 :         LogPrint(BCLog::MNPING, "mnp - Masternode ping, vin: %s\n", mnp.vin.prevout.hash.ToString());
     998       50409 :         {
     999             :             // Clear inv request
    1000       50409 :             LOCK(cs_main);
    1001       50409 :             g_connman->RemoveAskFor(mnp.GetHash(), MSG_MASTERNODE_PING);
    1002             :         }
    1003       50409 :         return ProcessMNPing(pfrom, mnp);
    1004             : 
    1005         577 :     } 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           3 : void CMasternodeMan::Remove(const COutPoint& collateralOut)
    1016             : {
    1017           3 :     LOCK(cs);
    1018           3 :     const auto it = mapMasternodes.find(collateralOut);
    1019           3 :     if (it != mapMasternodes.end()) {
    1020           3 :         mapMasternodes.erase(it);
    1021             :     }
    1022           3 : }
    1023             : 
    1024          10 : void CMasternodeMan::UpdateMasternodeList(CMasternodeBroadcast& mnb)
    1025             : {
    1026             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
    1027          10 :     if (deterministicMNManager->LegacyMNObsolete()) {
    1028             :         return;
    1029             :     }
    1030             : 
    1031          10 :     mapSeenMasternodePing.emplace(mnb.lastPing.GetHash(), mnb.lastPing);
    1032          10 :     mapSeenMasternodeBroadcast.emplace(mnb.GetHash(), mnb);
    1033          10 :     g_tiertwo_sync_state.AddedMasternodeList(mnb.GetHash());
    1034             : 
    1035          20 :     LogPrint(BCLog::MASTERNODE,"%s -- masternode=%s\n", __func__, mnb.vin.prevout.ToString());
    1036             : 
    1037          10 :     CMasternode* pmn = Find(mnb.vin.prevout);
    1038          10 :     if (pmn == nullptr) {
    1039          20 :         CMasternode mn(mnb);
    1040          10 :         Add(mn);
    1041             :     } else {
    1042           0 :         pmn->UpdateFromNewBroadcast(mnb);
    1043             :     }
    1044             : }
    1045             : 
    1046           7 : int64_t CMasternodeMan::SecondsSincePayment(const MasternodeRef& mn, int count_enabled, const CBlockIndex* BlockReading) const
    1047             : {
    1048           7 :     int64_t sec = (GetAdjustedTime() - GetLastPaid(mn, count_enabled, BlockReading));
    1049           7 :     int64_t month = 60 * 60 * 24 * 30;
    1050           7 :     if (sec < month) return sec; //if it's less than 30 days, give seconds
    1051             : 
    1052           7 :     CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
    1053           7 :     ss << mn->vin;
    1054           7 :     ss << mn->sigTime;
    1055          14 :     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           7 :     return month + hash.GetCompact(false);
    1059             : }
    1060             : 
    1061         155 : int64_t CMasternodeMan::GetLastPaid(const MasternodeRef& mn, int count_enabled, const CBlockIndex* BlockReading) const
    1062             : {
    1063         155 :     if (BlockReading == nullptr) return false;
    1064             : 
    1065         310 :     const CScript& mnpayee = mn->GetPayeeScript();
    1066             : 
    1067         155 :     CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
    1068         155 :     ss << mn->vin;
    1069         155 :     ss << mn->sigTime;
    1070         155 :     const uint256& hash = ss.GetHash();
    1071             : 
    1072             :     // use a deterministic offset to break a tie -- 2.5 minutes
    1073         155 :     int64_t nOffset = UintToArith256(hash).GetCompact(false) % 150;
    1074             : 
    1075         155 :     int max_depth = count_enabled * 1.25;
    1076         341 :     for (int n = 0; n < max_depth; n++) {
    1077         186 :         const auto& it = masternodePayments.mapMasternodeBlocks.find(BlockReading->nHeight);
    1078         186 :         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           0 :             if (it->second.HasPayeeWithVotes(mnpayee, 2))
    1082           0 :                 return BlockReading->nTime + nOffset;
    1083             :         }
    1084         186 :         BlockReading = BlockReading->pprev;
    1085             : 
    1086         186 :         if (BlockReading == nullptr || BlockReading->nHeight <= 0) {
    1087             :             break;
    1088             :         }
    1089             :     }
    1090             : 
    1091             :     return 0;
    1092             : }
    1093             : 
    1094         387 : std::string CMasternodeMan::ToString() const
    1095             : {
    1096         387 :     std::ostringstream info;
    1097         387 :     info << "Masternodes: " << (int)mapMasternodes.size()
    1098         387 :          << ", peers who asked us for Masternode list: " << (int)mAskedUsForMasternodeList.size()
    1099         387 :          << ", peers we asked for Masternode list: " << (int)mWeAskedForMasternodeList.size()
    1100         387 :          << ", entries in Masternode list we asked for: " << (int)mWeAskedForMasternodeListEntry.size();
    1101         387 :     return info.str();
    1102             : }
    1103             : 
    1104       48818 : void CMasternodeMan::CacheBlockHash(const CBlockIndex* pindex)
    1105             : {
    1106       48818 :     cvLastBlockHashes.Set(pindex->nHeight, pindex->GetBlockHash());
    1107       48818 : }
    1108             : 
    1109         166 : void CMasternodeMan::UncacheBlockHash(const CBlockIndex* pindex)
    1110             : {
    1111         166 :     cvLastBlockHashes.Set(pindex->nHeight, UINT256_ZERO);
    1112         166 : }
    1113             : 
    1114       67732 : uint256 CMasternodeMan::GetHashAtHeight(int nHeight) const
    1115             : {
    1116             :     // return zero if outside bounds
    1117       67732 :     if (nHeight < 0) {
    1118           0 :         LogPrint(BCLog::MASTERNODE, "%s: Negative height. Returning 0\n",  __func__);
    1119           0 :         return UINT256_ZERO;
    1120             :     }
    1121       67732 :     int nCurrentHeight = GetBestHeight();
    1122       67732 :     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       67731 :     if (nHeight > nCurrentHeight - (int) CACHED_BLOCK_HASHES) {
    1129             :         // Use cached hash
    1130       67731 :         return cvLastBlockHashes.Get(nHeight);
    1131             :     } else {
    1132             :         // Use chainActive
    1133           0 :         LOCK(cs_main);
    1134           0 :         return chainActive[nHeight]->GetBlockHash();
    1135             :     }
    1136             : }
    1137             : 
    1138       50477 : bool CMasternodeMan::IsWithinDepth(const uint256& nHash, int depth) const
    1139             : {
    1140             :     // Sanity checks
    1141      100954 :     if (nHash.IsNull()) {
    1142           0 :         return error("%s: Called with null hash\n", __func__);
    1143             :     }
    1144       50477 :     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       50477 :     const int nCurrentHeight = GetBestHeight();
    1149       50477 :     int nStopHeight = std::max(0, nCurrentHeight - depth);
    1150       56301 :     for (int i = nCurrentHeight; i >= nStopHeight; i--) {
    1151       56300 :         if (GetHashAtHeight(i) == nHash)
    1152             :             return true;
    1153             :     }
    1154             :     return false;
    1155             : }
    1156             : 
    1157         293 : void ThreadCheckMasternodes()
    1158             : {
    1159             :     // Make this thread recognisable as the wallet flushing thread
    1160         293 :     util::ThreadRename("pivx-masternodeman");
    1161         293 :     LogPrintf("Masternodes thread started\n");
    1162             : 
    1163         293 :     unsigned int c = 0;
    1164             : 
    1165         293 :     try {
    1166             :         // first clean up stale masternode payments data
    1167         293 :         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         293 :         auto itSeenMNB = mnodeman.mapSeenMasternodeBroadcast.begin();
    1172         293 :         while (itSeenMNB != mnodeman.mapSeenMasternodeBroadcast.end()) {
    1173           0 :             if (!itSeenMNB->second.addr.IsValid()) {
    1174           0 :                 itSeenMNB = mnodeman.mapSeenMasternodeBroadcast.erase(itSeenMNB);
    1175             :             } else {
    1176         293 :                 itSeenMNB++;
    1177             :             }
    1178             :         }
    1179             : 
    1180        9289 :         while (true) {
    1181             : 
    1182        9289 :             if (ShutdownRequested()) {
    1183             :                 break;
    1184             :             }
    1185             : 
    1186        9112 :             MilliSleep(1000);
    1187        8996 :             boost::this_thread::interruption_point();
    1188             : 
    1189             :             // try to sync from all available nodes, one step at a time
    1190        8996 :             masternodeSync.Process();
    1191             : 
    1192        8996 :             if (g_tiertwo_sync_state.IsBlockchainSynced()) {
    1193        8245 :                 c++;
    1194             : 
    1195             :                 // check if we should activate or ping every few minutes,
    1196             :                 // start right after sync is considered to be done
    1197        8245 :                 if (c % (MasternodePingSeconds()/2) == 0)
    1198         620 :                     activeMasternode.ManageStatus();
    1199             : 
    1200        8245 :                 if (c % (MasternodePingSeconds()/5) == 0) {
    1201        1572 :                     masternodePayments.CleanPaymentList(mnodeman.CheckAndRemove(), mnodeman.GetBestHeight());
    1202             :                 }
    1203             :             }
    1204             :         }
    1205         116 :     } catch (boost::thread_interrupted&) {
    1206             :         // nothing, thread interrupted.
    1207             :     }
    1208         293 : }

Generated by: LCOV version 1.14