LCOV - code coverage report
Current view: top level - src - masternode-payments.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 380 431 88.2 %
Date: 2025-02-23 09:33:43 Functions: 32 33 97.0 %

          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 "masternode-payments.h"
       7             : 
       8             : #include "chainparams.h"
       9             : #include "evo/deterministicmns.h"
      10             : #include "fs.h"
      11             : #include "budget/budgetmanager.h"
      12             : #include "masternodeman.h"
      13             : #include "netmessagemaker.h"
      14             : #include "tiertwo/netfulfilledman.h"
      15             : #include "spork.h"
      16             : #include "sync.h"
      17             : #include "tiertwo/tiertwo_sync_state.h"
      18             : #include "util/system.h"
      19             : #include "utilmoneystr.h"
      20             : #include "validation.h"
      21             : 
      22             : 
      23             : /** Object for who's going to get paid on which blocks */
      24             : CMasternodePayments masternodePayments;
      25             : 
      26             : RecursiveMutex cs_vecPayments;
      27             : RecursiveMutex cs_mapMasternodeBlocks;
      28             : RecursiveMutex cs_mapMasternodePayeeVotes;
      29             : 
      30             : static const int MNPAYMENTS_DB_VERSION = 1;
      31             : 
      32             : //
      33             : // CMasternodePaymentDB
      34             : //
      35             : 
      36         733 : CMasternodePaymentDB::CMasternodePaymentDB()
      37             : {
      38         733 :     pathDB = GetDataDir() / "mnpayments.dat";
      39         733 :     strMagicMessage = "MasternodePayments";
      40         733 : }
      41             : 
      42         378 : bool CMasternodePaymentDB::Write(const CMasternodePayments& objToSave)
      43             : {
      44         378 :     int64_t nStart = GetTimeMillis();
      45             : 
      46             :     // serialize, checksum data up to that point, then append checksum
      47         756 :     CDataStream ssObj(SER_DISK, CLIENT_VERSION);
      48         378 :     ssObj << MNPAYMENTS_DB_VERSION;
      49         378 :     ssObj << strMagicMessage;                   // masternode cache file specific magic message
      50         378 :     ssObj << Params().MessageStart(); // network specific magic number
      51         378 :     ssObj << objToSave;
      52         378 :     uint256 hash = Hash(ssObj.begin(), ssObj.end());
      53         378 :     ssObj << hash;
      54             : 
      55             :     // open output file, and associate with CAutoFile
      56         378 :     FILE* file = fsbridge::fopen(pathDB, "wb");
      57         756 :     CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
      58         378 :     if (fileout.IsNull())
      59           0 :         return error("%s : Failed to open file %s", __func__, pathDB.string());
      60             : 
      61             :     // Write and commit header, data
      62         378 :     try {
      63         378 :         fileout << ssObj;
      64           0 :     } catch (const std::exception& e) {
      65           0 :         return error("%s : Serialize or I/O error - %s", __func__, e.what());
      66             :     }
      67         378 :     fileout.fclose();
      68             : 
      69         378 :     LogPrint(BCLog::MASTERNODE,"Written info to mnpayments.dat  %dms\n", GetTimeMillis() - nStart);
      70             : 
      71             :     return true;
      72             : }
      73             : 
      74         355 : CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& objToLoad)
      75             : {
      76         355 :     int64_t nStart = GetTimeMillis();
      77             :     // open input file, and associate with CAutoFile
      78         355 :     FILE* file = fsbridge::fopen(pathDB, "rb");
      79         710 :     CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
      80         355 :     if (filein.IsNull()) {
      81         273 :         error("%s : Failed to open file %s", __func__, pathDB.string());
      82             :         return FileError;
      83             :     }
      84             : 
      85             :     // use file size to size memory buffer
      86          82 :     int fileSize = fs::file_size(pathDB);
      87          82 :     int dataSize = fileSize - sizeof(uint256);
      88             :     // Don't try to resize to a negative number if file is small
      89          82 :     if (dataSize < 0)
      90           0 :         dataSize = 0;
      91         437 :     std::vector<unsigned char> vchData;
      92          82 :     vchData.resize(dataSize);
      93          82 :     uint256 hashIn;
      94             : 
      95             :     // read data and checksum from file
      96          82 :     try {
      97          82 :         filein.read((char*)vchData.data(), dataSize);
      98          82 :         filein >> hashIn;
      99           0 :     } catch (const std::exception& e) {
     100           0 :         error("%s : Deserialize or I/O error - %s", __func__, e.what());
     101           0 :         return HashReadError;
     102             :     }
     103          82 :     filein.fclose();
     104             : 
     105         164 :     CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION);
     106             : 
     107             :     // verify stored checksum matches input data
     108          82 :     uint256 hashTmp = Hash(ssObj.begin(), ssObj.end());
     109          82 :     if (hashIn != hashTmp) {
     110           0 :         error("%s : Checksum mismatch, data corrupted", __func__);
     111             :         return IncorrectHash;
     112             :     }
     113             : 
     114          82 :     int version;
     115         164 :     std::string strMagicMessageTmp;
     116          82 :     try {
     117             :         // de-serialize file header
     118          82 :         ssObj >> version;
     119          82 :         ssObj >> strMagicMessageTmp;
     120             : 
     121             :         // ... verify the message matches predefined one
     122          82 :         if (strMagicMessage != strMagicMessageTmp) {
     123           0 :             error("%s : Invalid masternode payement cache magic message", __func__);
     124           0 :             return IncorrectMagicMessage;
     125             :         }
     126             : 
     127             :         // de-serialize file header (network specific magic number) and ..
     128          82 :         std::vector<unsigned char> pchMsgTmp(4);
     129          82 :         ssObj >> MakeSpan(pchMsgTmp);
     130             : 
     131             :         // ... verify the network matches ours
     132          82 :         if (memcmp(pchMsgTmp.data(), Params().MessageStart(), pchMsgTmp.size()) != 0) {
     133           0 :             error("%s : Invalid network magic number", __func__);
     134           0 :             return IncorrectMagicNumber;
     135             :         }
     136             : 
     137             :         // de-serialize data into CMasternodePayments object
     138         164 :         ssObj >> objToLoad;
     139           0 :     } catch (const std::exception& e) {
     140           0 :         objToLoad.Clear();
     141           0 :         error("%s : Deserialize or I/O error - %s", __func__, e.what());
     142           0 :         return IncorrectFormat;
     143             :     }
     144             : 
     145          82 :     LogPrint(BCLog::MASTERNODE,"Loaded info from mnpayments.dat (dbversion=%d) %dms\n", version, GetTimeMillis() - nStart);
     146         164 :     LogPrint(BCLog::MASTERNODE,"  %s\n", objToLoad.ToString());
     147             : 
     148             :     return Ok;
     149             : }
     150             : 
     151       11661 : uint256 CMasternodePaymentWinner::GetHash() const
     152             : {
     153       11661 :     CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
     154       46644 :     ss << std::vector<unsigned char>(payee.begin(), payee.end());
     155       11661 :     ss << nBlockHeight;
     156       11661 :     ss << vinMasternode.prevout;
     157       23322 :     return ss.GetHash();
     158             : }
     159             : 
     160           0 : std::string CMasternodePaymentWinner::GetStrMessage() const
     161             : {
     162           0 :     return vinMasternode.prevout.ToStringShort() + std::to_string(nBlockHeight) + HexStr(payee);
     163             : }
     164             : 
     165        1825 : bool CMasternodePaymentWinner::IsValid(CNode* pnode, CValidationState& state, int chainHeight)
     166             : {
     167        1825 :     int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight - 100);
     168        1825 :     if (n < 1 || n > MNPAYMENTS_SIGNATURES_TOTAL) {
     169          15 :         return state.Error(strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL, n));
     170             :     }
     171             : 
     172             :     // Must be a P2PKH
     173        1820 :     if (!payee.IsPayToPublicKeyHash()) {
     174           3 :         return state.Error("payee must be a P2PKH");
     175             :     }
     176             : 
     177             :     return true;
     178             : }
     179             : 
     180        1979 : void CMasternodePaymentWinner::Relay()
     181             : {
     182        1979 :     CInv inv(MSG_MASTERNODE_WINNER, GetHash());
     183        1979 :     g_connman->RelayInv(inv);
     184        1979 : }
     185             : 
     186         378 : void DumpMasternodePayments()
     187             : {
     188         378 :     int64_t nStart = GetTimeMillis();
     189             : 
     190         756 :     CMasternodePaymentDB paymentdb;
     191         378 :     LogPrint(BCLog::MASTERNODE,"Writing info to mnpayments.dat...\n");
     192         378 :     paymentdb.Write(masternodePayments);
     193             : 
     194         378 :     LogPrint(BCLog::MASTERNODE,"Budget dump finished  %dms\n", GetTimeMillis() - nStart);
     195         378 : }
     196             : 
     197       56436 : bool IsBlockValueValid(int nHeight, CAmount& nExpectedValue, CAmount nMinted, CAmount& nBudgetAmt)
     198             : {
     199       56436 :     const Consensus::Params& consensus = Params().GetConsensus();
     200       56436 :     if (!g_tiertwo_sync_state.IsSynced()) {
     201             :         //there is no budget data to use to check anything
     202             :         //super blocks will always be on these blocks, max 100 per budgeting
     203       37074 :         if (nHeight % consensus.nBudgetCycleBlocks < 100) {
     204       29245 :             if (Params().IsTestnet()) {
     205             :                 return true;
     206             :             }
     207       29245 :             nExpectedValue += g_budgetman.GetTotalBudget(nHeight);
     208             :         }
     209             :     } else {
     210             :         // we're synced and have data so check the budget schedule
     211             :         // if the superblock spork is enabled
     212       19362 :         if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) {
     213             :             // add current payee amount to the expected block value
     214        2383 :             if (g_budgetman.GetExpectedPayeeAmount(nHeight, nBudgetAmt)) {
     215          32 :                 nExpectedValue += nBudgetAmt;
     216             :             }
     217             :         }
     218             :     }
     219             : 
     220       56436 :     if (nMinted < 0 && consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_V5_3)) {
     221             :         return false;
     222             :     }
     223             : 
     224       56435 :     return nMinted <= nExpectedValue;
     225             : }
     226             : 
     227       55624 : bool IsBlockPayeeValid(const CBlock& block, const CBlockIndex* pindexPrev)
     228             : {
     229       55624 :     int nBlockHeight = pindexPrev->nHeight + 1;
     230       55624 :     TrxValidationStatus transactionStatus = TrxValidationStatus::InValid;
     231             : 
     232       55624 :     if (!g_tiertwo_sync_state.IsSynced()) { //there is no budget data to use to check anything -- find the longest chain
     233       36278 :         LogPrint(BCLog::MASTERNODE, "Client not synced, skipping block payee checks\n");
     234       36278 :         return true;
     235             :     }
     236             : 
     237       25642 :     const bool fPayCoinstake = Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_POS) &&
     238        6296 :                                !Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_V6_0);
     239       19346 :     const CTransaction& txNew = *(fPayCoinstake ? block.vtx[1] : block.vtx[0]);
     240             : 
     241             :     //check if it's a budget block
     242       19346 :     if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) {
     243        2374 :         if (g_budgetman.IsBudgetPaymentBlock(nBlockHeight)) {
     244          27 :             transactionStatus = g_budgetman.IsTransactionValid(txNew, block.GetHash(), nBlockHeight);
     245          27 :             if (transactionStatus == TrxValidationStatus::Valid) {
     246             :                 return true;
     247             :             }
     248             : 
     249           3 :             if (transactionStatus == TrxValidationStatus::InValid) {
     250           3 :                 LogPrint(BCLog::MASTERNODE,"Invalid budget payment detected %s\n", txNew.ToString().c_str());
     251           3 :                 if (sporkManager.IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT))
     252             :                     return false;
     253             : 
     254           0 :                 LogPrint(BCLog::MASTERNODE,"Budget enforcement is disabled, accepting block\n");
     255             :             }
     256             :         }
     257             :     }
     258             : 
     259             :     // If we end here the transaction was either TrxValidationStatus::InValid and Budget enforcement is disabled, or
     260             :     // a double budget payment (status = TrxValidationStatus::DoublePayment) was detected, or no/not enough masternode
     261             :     // votes (status = TrxValidationStatus::VoteThreshold) for a finalized budget were found
     262             :     // In all cases a masternode will get the payment for this block
     263             : 
     264             :     //check for masternode payee
     265       19319 :     if (masternodePayments.IsTransactionValid(txNew, pindexPrev))
     266             :         return true;
     267           4 :     LogPrint(BCLog::MASTERNODE,"Invalid mn payment detected %s\n", txNew.ToString().c_str());
     268             : 
     269           3 :     if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT))
     270             :         return false;
     271           0 :     LogPrint(BCLog::MASTERNODE,"Masternode payment enforcement is disabled, accepting block\n");
     272             :     return true;
     273             : }
     274             : 
     275             : 
     276       15323 : void FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const CBlockIndex* pindexPrev, bool fProofOfStake)
     277             : {
     278       15881 :     if (!sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) ||           // if superblocks are not enabled
     279             :             // ... or this is not a superblock
     280         558 :             !g_budgetman.FillBlockPayee(txCoinbase, txCoinstake, pindexPrev->nHeight + 1, fProofOfStake) ) {
     281             :         // ... or there's no budget with enough votes, then pay a masternode
     282       15315 :         masternodePayments.FillBlockPayee(txCoinbase, txCoinstake, pindexPrev, fProofOfStake);
     283             :     }
     284       15323 : }
     285             : 
     286          30 : std::string GetRequiredPaymentsString(int nBlockHeight)
     287             : {
     288          30 :     if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && g_budgetman.IsBudgetPaymentBlock(nBlockHeight)) {
     289           0 :         return g_budgetman.GetRequiredPaymentsString(nBlockHeight);
     290             :     } else {
     291          30 :         return masternodePayments.GetRequiredPaymentsString(nBlockHeight);
     292             :     }
     293             : }
     294             : 
     295       22546 : bool CMasternodePayments::GetMasternodeTxOuts(const CBlockIndex* pindexPrev, std::vector<CTxOut>& voutMasternodePaymentsRet) const
     296             : {
     297       22546 :     if (deterministicMNManager->LegacyMNObsolete(pindexPrev->nHeight + 1)) {
     298        8217 :         CAmount masternodeReward = GetMasternodePayment(pindexPrev->nHeight + 1);
     299       16434 :         auto dmnPayee = deterministicMNManager->GetListForBlock(pindexPrev).GetMNPayee();
     300        8217 :         if (!dmnPayee) {
     301         121 :             return error("%s: Failed to get payees for block at height %d", __func__, pindexPrev->nHeight + 1);
     302             :         }
     303        8096 :         CAmount operatorReward = 0;
     304        8096 :         if (dmnPayee->nOperatorReward != 0 && !dmnPayee->pdmnState->scriptOperatorPayout.empty()) {
     305         116 :             operatorReward = (masternodeReward * dmnPayee->nOperatorReward) / 10000;
     306         116 :             masternodeReward -= operatorReward;
     307             :         }
     308        8096 :         if (masternodeReward > 0) {
     309        8096 :             voutMasternodePaymentsRet.emplace_back(masternodeReward, dmnPayee->pdmnState->scriptPayout);
     310             :         }
     311        8096 :         if (operatorReward > 0) {
     312         116 :             voutMasternodePaymentsRet.emplace_back(operatorReward, dmnPayee->pdmnState->scriptOperatorPayout);
     313             :         }
     314        8096 :         return true;
     315             :     }
     316             : 
     317             :     // Legacy payment logic. !TODO: remove when transition to DMN is complete
     318       14329 :     return GetLegacyMasternodeTxOut(pindexPrev->nHeight + 1, voutMasternodePaymentsRet);
     319             : }
     320             : 
     321       14329 : bool CMasternodePayments::GetLegacyMasternodeTxOut(int nHeight, std::vector<CTxOut>& voutMasternodePaymentsRet) const
     322             : {
     323       14329 :     voutMasternodePaymentsRet.clear();
     324             : 
     325       28658 :     CScript payee;
     326       14329 :     if (!GetBlockPayee(nHeight, payee)) {
     327             :         //no masternode detected
     328       14122 :         const uint256& hash = mnodeman.GetHashAtHeight(nHeight - 1);
     329       14379 :         MasternodeRef winningNode = mnodeman.GetCurrentMasterNode(hash);
     330       14122 :         if (winningNode) {
     331         257 :             payee = winningNode->GetPayeeScript();
     332             :         } else {
     333       13865 :             LogPrint(BCLog::MASTERNODE,"CreateNewBlock: Failed to detect masternode to pay\n");
     334       13865 :             return false;
     335             :         }
     336             :     }
     337         464 :     voutMasternodePaymentsRet.emplace_back(GetMasternodePayment(nHeight), payee);
     338         464 :     return true;
     339             : }
     340             : 
     341         587 : static void SubtractMnPaymentFromCoinstake(CMutableTransaction& txCoinstake, CAmount masternodePayment, int stakerOuts)
     342             : {
     343         587 :     assert (stakerOuts >= 2);
     344             :     //subtract mn payment from the stake reward
     345         587 :     if (stakerOuts == 2) {
     346             :         // Majority of cases; do it quick and move on
     347         587 :         txCoinstake.vout[1].nValue -= masternodePayment;
     348             :     } else {
     349             :         // special case, stake is split between (stakerOuts-1) outputs
     350           0 :         unsigned int outputs = stakerOuts-1;
     351           0 :         CAmount mnPaymentSplit = masternodePayment / outputs;
     352           0 :         CAmount mnPaymentRemainder = masternodePayment - (mnPaymentSplit * outputs);
     353           0 :         for (unsigned int j=1; j<=outputs; j++) {
     354           0 :             txCoinstake.vout[j].nValue -= mnPaymentSplit;
     355             :         }
     356             :         // in case it's not an even division, take the last bit of dust from the last one
     357           0 :         txCoinstake.vout[outputs].nValue -= mnPaymentRemainder;
     358             :     }
     359         587 : }
     360             : 
     361       15315 : void CMasternodePayments::FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const CBlockIndex* pindexPrev, bool fProofOfStake) const
     362             : {
     363       16752 :     std::vector<CTxOut> vecMnOuts;
     364       15315 :     if (!GetMasternodeTxOuts(pindexPrev, vecMnOuts)) {
     365       13878 :         return;
     366             :     }
     367             : 
     368             :     // Starting from PIVX v6.0 masternode and budgets are paid in the coinbase tx
     369        1437 :     const int nHeight = pindexPrev->nHeight + 1;
     370        1437 :     bool fPayCoinstake = fProofOfStake && !Params().GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_V6_0);
     371             : 
     372             :     // if PoS block pays the coinbase, clear it first
     373        1437 :     if (fProofOfStake && !fPayCoinstake) txCoinbase.vout.clear();
     374             : 
     375        1437 :     const int initial_cstake_outs = txCoinstake.vout.size();
     376             : 
     377        1437 :     CAmount masternodePayment{0};
     378        2887 :     for (const CTxOut& mnOut: vecMnOuts) {
     379             :         // Add the mn payment to the coinstake/coinbase tx
     380        1450 :         if (fPayCoinstake) {
     381          53 :             txCoinstake.vout.emplace_back(mnOut);
     382             :         } else {
     383        1397 :             txCoinbase.vout.emplace_back(mnOut);
     384             :         }
     385        1450 :         masternodePayment += mnOut.nValue;
     386        2900 :         CTxDestination payeeDest;
     387        1450 :         ExtractDestination(mnOut.scriptPubKey, payeeDest);
     388        3716 :         LogPrint(BCLog::MASTERNODE,"Masternode payment of %s to %s\n", FormatMoney(mnOut.nValue), EncodeDestination(payeeDest));
     389             :     }
     390             : 
     391             :     // Subtract mn payment value from the block reward
     392        1437 :     if (fProofOfStake) {
     393         587 :         SubtractMnPaymentFromCoinstake(txCoinstake, masternodePayment, initial_cstake_outs);
     394             :     } else {
     395         850 :         txCoinbase.vout[0].nValue = GetBlockValue(nHeight) - masternodePayment;
     396             :     }
     397             : }
     398             : 
     399       55744 : bool CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CValidationState& state)
     400             : {
     401       55744 :     if (!g_tiertwo_sync_state.IsBlockchainSynced()) return true;
     402             : 
     403             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     404       55734 :     if (deterministicMNManager->LegacyMNObsolete()) {
     405         878 :         LogPrint(BCLog::MASTERNODE, "mnw - skip obsolete message %s\n", strCommand);
     406         878 :         return true;
     407             :     }
     408             : 
     409       54856 :     if (strCommand == NetMsgType::GETMNWINNERS) {
     410             :         //Masternode Payments Request Sync
     411         756 :         int nCountNeeded;
     412         756 :         vRecv >> nCountNeeded;
     413             : 
     414         756 :         if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
     415           0 :             if (g_netfulfilledman.HasFulfilledRequest(pfrom->addr, NetMsgType::GETMNWINNERS)) {
     416           0 :                 LogPrint(BCLog::MASTERNODE, "%s: mnget - peer already asked me for the list\n", __func__);
     417           0 :                 return state.DoS(20, false, REJECT_INVALID, "getmnwinners-request-already-fulfilled");
     418             :             }
     419             :         }
     420             : 
     421         756 :         g_netfulfilledman.AddFulfilledRequest(pfrom->addr, NetMsgType::GETMNWINNERS);
     422         756 :         Sync(pfrom, nCountNeeded);
     423         756 :         LogPrint(BCLog::MASTERNODE, "mnget - Sent Masternode winners to peer %i\n", pfrom->GetId());
     424       54100 :     } else if (strCommand == NetMsgType::MNWINNER) {
     425             :         //Masternode Payments Declare Winner
     426        1864 :         CMasternodePaymentWinner winner;
     427         932 :         vRecv >> winner;
     428         932 :         if (pfrom->nVersion < ActiveProtocol()) return false;
     429             : 
     430         932 :         {
     431             :             // Clear inv request
     432         932 :             LOCK(cs_main);
     433         932 :             g_connman->RemoveAskFor(winner.GetHash(), MSG_MASTERNODE_WINNER);
     434             :         }
     435             : 
     436         932 :         ProcessMNWinner(winner, pfrom, state);
     437         932 :         return state.IsValid();
     438             :     }
     439             : 
     440             :     return true;
     441             : }
     442             : 
     443        1832 : bool CMasternodePayments::ProcessMNWinner(CMasternodePaymentWinner& winner, CNode* pfrom, CValidationState& state)
     444             : {
     445        1832 :     int nHeight = mnodeman.GetBestHeight();
     446             : 
     447        1832 :     if (mapMasternodePayeeVotes.count(winner.GetHash())) {
     448           0 :         LogPrint(BCLog::MASTERNODE, "mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), nHeight);
     449           0 :         g_tiertwo_sync_state.AddedMasternodeWinner(winner.GetHash());
     450           0 :         return false;
     451             :     }
     452             : 
     453        1832 :     int nFirstBlock = nHeight - (mnodeman.CountEnabled() * 1.25);
     454        1832 :     if (winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > nHeight + 20) {
     455           2 :         LogPrint(BCLog::MASTERNODE, "mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, nHeight);
     456           6 :         return state.Error("block height out of range");
     457             :     }
     458             : 
     459             :     // reject old signature version
     460        1830 :     if (winner.nMessVersion != MessageVersion::MESS_VER_HASH) {
     461           0 :         LogPrint(BCLog::MASTERNODE, "mnw - rejecting old message version %d\n", winner.nMessVersion);
     462           0 :         return state.Error("mnw old message version");
     463             :     }
     464             : 
     465             :     // See if the mnw signer exists, and whether it's a legacy or DMN masternode
     466        1830 :     const CMasternode* pmn{nullptr};
     467        3662 :     auto dmn = deterministicMNManager->GetListAtChainTip().GetMNByCollateral(winner.vinMasternode.prevout);
     468        1830 :     if (dmn == nullptr) {
     469             :         // legacy masternode
     470        1156 :         pmn = mnodeman.Find(winner.vinMasternode.prevout);
     471        1156 :         if (pmn == nullptr) {
     472             :             // it could be a non-synced masternode. ask for the mnb
     473           9 :             LogPrint(BCLog::MASTERNODE, "mnw - unknown masternode %s\n", winner.vinMasternode.prevout.hash.ToString());
     474             :             // Only ask for missing items after the initial mnlist sync is complete
     475           5 :             if (pfrom && g_tiertwo_sync_state.IsMasternodeListSynced()) mnodeman.AskForMN(pfrom, winner.vinMasternode);
     476          15 :             return state.Error("Non-existent mnwinner voter");
     477             :         }
     478             :     }
     479             :     // either deterministic or legacy. not both
     480        1825 :     assert((dmn && !pmn) || (!dmn && pmn));
     481             : 
     482             :     // See if the masternode is in the quorum (top-MNPAYMENTS_SIGNATURES_TOTAL)
     483        1825 :     if (!winner.IsValid(pfrom, state, nHeight)) {
     484             :         // error cause set internally
     485             :         return false;
     486             :     }
     487             : 
     488             :     // See if this masternode has already voted for this block height
     489        1819 :     if (!CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)) {
     490           0 :         return state.Error("MN already voted");
     491             :     }
     492             : 
     493             :     // Check signature
     494        1819 :     bool is_valid_sig = dmn ? winner.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())
     495        1819 :                             : winner.CheckSignature(pmn->pubKeyMasternode.GetID());
     496             : 
     497        1819 :     if (!is_valid_sig) {
     498           7 :         LogPrint(BCLog::MASTERNODE, "%s : mnw - invalid signature for %s masternode: %s\n",
     499             :                 __func__, (dmn ? "deterministic" : "legacy"), winner.vinMasternode.prevout.hash.ToString());
     500          12 :         return state.DoS(20, false, REJECT_INVALID, "invalid voter mnwinner signature");
     501             :     }
     502             : 
     503             :     // Record vote
     504        1815 :     RecordWinnerVote(winner.vinMasternode.prevout, winner.nBlockHeight);
     505             : 
     506             :     // Add winner
     507        1815 :     AddWinningMasternode(winner);
     508             : 
     509             :     // Relay only if we are synchronized.
     510             :     // Makes no sense to relay MNWinners to the peers from where we are syncing them.
     511        1815 :     if (g_tiertwo_sync_state.IsSynced()) winner.Relay();
     512        1815 :     g_tiertwo_sync_state.AddedMasternodeWinner(winner.GetHash());
     513             : 
     514             :     // valid
     515        1815 :     return true;
     516             : }
     517             : 
     518       14329 : bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee) const
     519             : {
     520       14329 :     const auto it = mapMasternodeBlocks.find(nBlockHeight);
     521       14329 :     if (it != mapMasternodeBlocks.end()) {
     522         207 :         return it->second.GetPayee(payee);
     523             :     }
     524             : 
     525             :     return false;
     526             : }
     527             : 
     528             : // Is this masternode scheduled to get paid soon?
     529             : // -- Only look ahead up to 8 blocks to allow for propagation of the latest 2 winners
     530        1549 : bool CMasternodePayments::IsScheduled(const CMasternode& mn, int nNotBlockHeight)
     531             : {
     532        3098 :     LOCK(cs_mapMasternodeBlocks);
     533             : 
     534        1549 :     int nHeight = mnodeman.GetBestHeight();
     535             : 
     536        3098 :     const CScript& mnpayee = mn.GetPayeeScript();
     537        3098 :     CScript payee;
     538        9998 :     for (int64_t h = nHeight; h <= nHeight + 8; h++) {
     539        9552 :         if (h == nNotBlockHeight) continue;
     540       13999 :         if (mapMasternodeBlocks.count(h)) {
     541        4685 :             if (mapMasternodeBlocks[h].GetPayee(payee)) {
     542        4685 :                 if (mnpayee == payee) {
     543             :                     return true;
     544             :                 }
     545             :             }
     546             :         }
     547             :     }
     548             : 
     549             :     return false;
     550             : }
     551             : 
     552        1985 : void CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
     553             : {
     554        1985 :     {
     555        3970 :         LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
     556             : 
     557        1985 :         mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;
     558             : 
     559        3260 :         if (!mapMasternodeBlocks.count(winnerIn.nBlockHeight)) {
     560        1420 :             CMasternodeBlockPayees blockPayees(winnerIn.nBlockHeight);
     561         710 :             mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
     562             :         }
     563             :     }
     564             : 
     565        1985 :     CTxDestination addr;
     566        1985 :     ExtractDestination(winnerIn.payee, addr);
     567        3077 :     LogPrint(BCLog::MASTERNODE, "mnw - Adding winner %s for block %d\n", EncodeDestination(addr), winnerIn.nBlockHeight);
     568        1985 :     mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, 1);
     569        1985 : }
     570             : 
     571         826 : bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
     572             : {
     573        1652 :     LOCK(cs_vecPayments);
     574             : 
     575             :     //require at least 6 signatures
     576         826 :     int nMaxSignatures = 0;
     577        1663 :     for (CMasternodePayee& payee : vecPayments)
     578         837 :         if (payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED)
     579         254 :             nMaxSignatures = payee.nVotes;
     580             : 
     581             :     // if we don't have at least 6 signatures on a payee, approve whichever is the longest chain
     582         826 :     if (nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true;
     583             : 
     584        1080 :     std::string strPayeesPossible = "";
     585         254 :     CAmount requiredMasternodePayment = GetMasternodePayment(nBlockHeight);
     586             : 
     587         256 :     for (CMasternodePayee& payee : vecPayments) {
     588         255 :         bool found = false;
     589         765 :         for (CTxOut out : txNew.vout) {
     590         510 :             if (payee.scriptPubKey == out.scriptPubKey) {
     591         254 :                 if(out.nValue == requiredMasternodePayment)
     592             :                     found = true;
     593             :                 else
     594           0 :                     LogPrintf("%s : Masternode payment value (%s) different from required value (%s).\n",
     595           0 :                             __func__, FormatMoney(out.nValue).c_str(), FormatMoney(requiredMasternodePayment).c_str());
     596             :             }
     597             :         }
     598             : 
     599         255 :         if (payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) {
     600         254 :             if (found) return true;
     601             : 
     602           2 :             CTxDestination address1;
     603           1 :             ExtractDestination(payee.scriptPubKey, address1);
     604             : 
     605           1 :             if (strPayeesPossible != "")
     606           0 :                 strPayeesPossible += ",";
     607             : 
     608           3 :             strPayeesPossible += EncodeDestination(address1);
     609             :         }
     610             :     }
     611             : 
     612           1 :     LogPrint(BCLog::MASTERNODE,"CMasternodePayments::IsTransactionValid - Missing required payment of %s to %s\n", FormatMoney(requiredMasternodePayment).c_str(), strPayeesPossible.c_str());
     613             :     return false;
     614             : }
     615             : 
     616          15 : std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
     617             : {
     618          15 :     LOCK(cs_vecPayments);
     619             : 
     620          30 :     std::string ret = "";
     621             : 
     622          30 :     for (CMasternodePayee& payee : vecPayments) {
     623          30 :         CTxDestination address1;
     624          15 :         ExtractDestination(payee.scriptPubKey, address1);
     625          15 :         if (ret != "") {
     626           0 :             ret += ", ";
     627             :         }
     628          45 :         ret += EncodeDestination(address1) + ":" + std::to_string(payee.nVotes);
     629             :     }
     630             : 
     631          45 :     return ret.empty() ? "Unknown" : ret;
     632             : }
     633             : 
     634          30 : std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight)
     635             : {
     636          60 :     LOCK(cs_mapMasternodeBlocks);
     637             : 
     638          30 :     if (mapMasternodeBlocks.count(nBlockHeight)) {
     639          15 :         return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
     640             :     }
     641             : 
     642          15 :     return "Unknown";
     643             : }
     644             : 
     645       19319 : bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, const CBlockIndex* pindexPrev)
     646             : {
     647       19319 :     const int nBlockHeight = pindexPrev->nHeight + 1;
     648       19319 :     if (deterministicMNManager->LegacyMNObsolete(nBlockHeight)) {
     649       14458 :         std::vector<CTxOut> vecMnOuts;
     650        7229 :         if (!GetMasternodeTxOuts(pindexPrev, vecMnOuts)) {
     651             :             // No masternode scheduled to be paid.
     652             :             return true;
     653             :         }
     654             : 
     655       14343 :         for (const CTxOut& o : vecMnOuts) {
     656        7224 :             if (std::find(txNew.vout.begin(), txNew.vout.end(), o) == txNew.vout.end()) {
     657           4 :                 CTxDestination mnDest;
     658           2 :                 const std::string& payee = ExtractDestination(o.scriptPubKey, mnDest) ? EncodeDestination(mnDest)
     659           4 :                                                                                       : HexStr(o.scriptPubKey);
     660           3 :                 LogPrint(BCLog::MASTERNODE, "%s: Failed to find expected payee %s in block at height %d (tx %s)\n",
     661             :                                             __func__, payee, pindexPrev->nHeight + 1, txNew.GetHash().ToString());
     662           2 :                 return false;
     663             :             }
     664             :         }
     665             :         // all the expected payees have been found in txNew outputs
     666        7119 :         return true;
     667             :     }
     668             : 
     669             :     // Legacy payment logic. !TODO: remove when transition to DMN is complete
     670       31409 :     LOCK(cs_mapMasternodeBlocks);
     671             : 
     672       23354 :     if (mapMasternodeBlocks.count(nBlockHeight)) {
     673         826 :         return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew, nBlockHeight);
     674             :     }
     675             : 
     676             :     return true;
     677             : }
     678             : 
     679        3620 : void CMasternodePayments::CleanPaymentList(int mnCount, int nHeight)
     680             : {
     681        7240 :     LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
     682             : 
     683             :     //keep up to five cycles for historical sake
     684        3620 :     int nLimit = std::max(int(mnCount * 1.25), 1000);
     685             : 
     686        3620 :     std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
     687       21525 :     while (it != mapMasternodePayeeVotes.end()) {
     688       17905 :         CMasternodePaymentWinner winner = (*it).second;
     689             : 
     690       17905 :         if (nHeight - winner.nBlockHeight > nLimit) {
     691           0 :             LogPrint(BCLog::MASTERNODE, "CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", winner.nBlockHeight);
     692           0 :             g_tiertwo_sync_state.EraseSeenMNW((*it).first);
     693           0 :             mapMasternodePayeeVotes.erase(it++);
     694           0 :             mapMasternodeBlocks.erase(winner.nBlockHeight);
     695             :         } else {
     696       17905 :             ++it;
     697             :         }
     698             :     }
     699        3620 : }
     700             : 
     701       38612 : void CMasternodePayments::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
     702             : {
     703       38612 :     if (g_tiertwo_sync_state.GetSyncPhase() > MASTERNODE_SYNC_LIST) {
     704       19566 :         ProcessBlock(pindexNew->nHeight + 10);
     705             :     }
     706       38612 : }
     707             : 
     708       19566 : void CMasternodePayments::ProcessBlock(int nBlockHeight)
     709             : {
     710             :     // No more mnw messages after transition to DMN
     711       19566 :     if (deterministicMNManager->LegacyMNObsolete(nBlockHeight)) {
     712       19396 :         return;
     713             :     }
     714       12909 :     if (!fMasterNode) return;
     715             : 
     716             :     // Get the active masternode (operator) key
     717        1163 :     CTxIn mnVin;
     718        1163 :     Optional<CKey> mnKey{nullopt};
     719        1163 :     CBLSSecretKey blsKey;
     720         993 :     if (!GetActiveMasternodeKeys(mnVin, mnKey, blsKey)) {
     721         823 :         return;
     722             :     }
     723             : 
     724             :     //reference node - hybrid mode
     725         670 :     int n = mnodeman.GetMasternodeRank(mnVin, nBlockHeight - 100);
     726             : 
     727         670 :     if (n == -1) {
     728         324 :         LogPrintf("%s: ERROR: active masternode is not registered yet\n", __func__);
     729             :         return;
     730             :     }
     731             : 
     732         346 :     if (n > MNPAYMENTS_SIGNATURES_TOTAL) {
     733           0 :         LogPrintf("%s: active masternode not in the top %d (%d)\n", __func__, MNPAYMENTS_SIGNATURES_TOTAL, n);
     734           0 :         return;
     735             :     }
     736             : 
     737         346 :     if (nBlockHeight <= nLastBlockHeight) return;
     738             : 
     739         346 :     if (g_budgetman.IsBudgetPaymentBlock(nBlockHeight)) {
     740             :         //is budget payment block -- handled by the budgeting software
     741             :         return;
     742             :     }
     743             : 
     744             :     // check winner height
     745         346 :     if (nBlockHeight - 100 > mnodeman.GetBestHeight() + 1) {
     746           0 :         LogPrintf("%s: mnw - invalid height %d > %d\n", __func__, nBlockHeight - 100, mnodeman.GetBestHeight() + 1);
     747           0 :         return;
     748             :     }
     749             : 
     750             :     // pay to the oldest MN that still had no payment but its input is old enough and it was active long enough
     751         346 :     int nCount = 0;
     752         516 :     MasternodeRef pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount);
     753             : 
     754         346 :     if (pmn == nullptr) {
     755         176 :         LogPrintf("%s: Failed to find masternode to pay\n", __func__);
     756         823 :         return;
     757             :     }
     758             : 
     759         340 :     CMasternodePaymentWinner newWinner(mnVin, nBlockHeight);
     760         340 :     newWinner.AddPayee(pmn->GetPayeeScript());
     761         170 :     if (mnKey != nullopt) {
     762             :         // Legacy MN
     763         102 :         if (!newWinner.Sign(*mnKey, mnKey->GetPubKey().GetID())) {
     764           0 :             LogPrintf("%s: Failed to sign masternode winner\n", __func__);
     765           0 :             return;
     766             :         }
     767             :     } else {
     768             :         // DMN
     769         119 :         if (!newWinner.Sign(blsKey)) {
     770           0 :             LogPrintf("%s: Failed to sign masternode winner with DMN\n", __func__);
     771             :             return;
     772             :         }
     773             :     }
     774             : 
     775         170 :     AddWinningMasternode(newWinner);
     776         170 :     newWinner.Relay();
     777         170 :     LogPrintf("%s: Relayed winner %s\n", __func__, newWinner.GetHash().ToString());
     778         170 :     nLastBlockHeight = nBlockHeight;
     779             : }
     780             : 
     781         756 : void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
     782             : {
     783         756 :     LOCK(cs_mapMasternodePayeeVotes);
     784             : 
     785         756 :     int nHeight = mnodeman.GetBestHeight();
     786         756 :     int nCount = (mnodeman.CountEnabled() * 1.25);
     787         756 :     if (nCountNeeded > nCount) nCountNeeded = nCount;
     788             : 
     789         756 :     int nInvCount = 0;
     790         756 :     std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
     791         943 :     while (it != mapMasternodePayeeVotes.end()) {
     792         374 :         CMasternodePaymentWinner winner = (*it).second;
     793         187 :         if (winner.nBlockHeight >= nHeight - nCountNeeded && winner.nBlockHeight <= nHeight + 20) {
     794          59 :             node->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash()));
     795          59 :             nInvCount++;
     796             :         }
     797         187 :         ++it;
     798             :     }
     799         756 :     g_connman->PushMessage(node, CNetMsgMaker(node->GetSendVersion()).Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_MNW, nInvCount));
     800         756 : }
     801             : 
     802          82 : std::string CMasternodePayments::ToString() const
     803             : {
     804          82 :     std::ostringstream info;
     805             : 
     806          82 :     info << "Votes: " << (int)mapMasternodePayeeVotes.size() << ", Blocks: " << (int)mapMasternodeBlocks.size();
     807             : 
     808          82 :     return info.str();
     809             : }
     810             : 
     811        1819 : bool CMasternodePayments::CanVote(const COutPoint& outMasternode, int nBlockHeight) const
     812             : {
     813        1819 :     LOCK(cs_mapMasternodePayeeVotes);
     814        1819 :     const auto it = mapMasternodesLastVote.find(outMasternode);
     815        3552 :     return it == mapMasternodesLastVote.end() || it->second != nBlockHeight;
     816             : }
     817             : 
     818        1815 : void CMasternodePayments::RecordWinnerVote(const COutPoint& outMasternode, int nBlockHeight)
     819             : {
     820        1815 :     LOCK(cs_mapMasternodePayeeVotes);
     821        1815 :     mapMasternodesLastVote[outMasternode] = nBlockHeight;
     822        1815 : }
     823             : 
     824        4568 : bool IsCoinbaseValueValid(const CTransactionRef& tx, CAmount nBudgetAmt, CValidationState& _state)
     825             : {
     826        4568 :     assert(tx->IsCoinBase());
     827        4568 :     if (g_tiertwo_sync_state.IsSynced()) {
     828        4308 :         const CAmount nCBaseOutAmt = tx->GetValueOut();
     829        4308 :         if (nBudgetAmt > 0) {
     830             :             // Superblock
     831          13 :             if (nCBaseOutAmt != nBudgetAmt) {
     832           4 :                 const std::string strError = strprintf("%s: invalid coinbase payment for budget (%s vs expected=%s)",
     833          12 :                                                        __func__, FormatMoney(nCBaseOutAmt), FormatMoney(nBudgetAmt));
     834          12 :                 return _state.DoS(100, error(strError.c_str()), REJECT_INVALID, "bad-superblock-cb-amt");
     835             :             }
     836             :             return true;
     837             :         } else {
     838             :             // regular block
     839        4295 :             int nHeight = mnodeman.GetBestHeight();
     840        4295 :             CAmount nMnAmt = GetMasternodePayment(nHeight);
     841             :             // if enforcement is disabled, there could be no masternode payment
     842        4295 :             bool sporkEnforced = sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT);
     843        4295 :             const std::string strError = strprintf("%s: invalid coinbase payment for masternode (%s vs expected=%s)",
     844       12885 :                                                    __func__, FormatMoney(nCBaseOutAmt), FormatMoney(nMnAmt));
     845        4295 :             if (sporkEnforced && nCBaseOutAmt != nMnAmt) {
     846           8 :                 return _state.DoS(100, error(strError.c_str()), REJECT_INVALID, "bad-cb-amt");
     847             :             }
     848        4291 :             if (!sporkEnforced && nCBaseOutAmt > nMnAmt) {
     849           6 :                 return _state.DoS(100, error(strError.c_str()), REJECT_INVALID, "bad-cb-amt-spork8-disabled");
     850             :             }
     851             :             return true;
     852             :         }
     853             :     }
     854             :     return true;
     855             : }

Generated by: LCOV version 1.14