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-04-02 01:23:23 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       11591 : uint256 CMasternodePaymentWinner::GetHash() const
     152             : {
     153       11591 :     CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
     154       46364 :     ss << std::vector<unsigned char>(payee.begin(), payee.end());
     155       11591 :     ss << nBlockHeight;
     156       11591 :     ss << vinMasternode.prevout;
     157       23182 :     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        1814 : bool CMasternodePaymentWinner::IsValid(CNode* pnode, CValidationState& state, int chainHeight)
     166             : {
     167        1814 :     int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight - 100);
     168        1814 :     if (n < 1 || n > MNPAYMENTS_SIGNATURES_TOTAL) {
     169           9 :         return state.Error(strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL, n));
     170             :     }
     171             : 
     172             :     // Must be a P2PKH
     173        1811 :     if (!payee.IsPayToPublicKeyHash()) {
     174           3 :         return state.Error("payee must be a P2PKH");
     175             :     }
     176             : 
     177             :     return true;
     178             : }
     179             : 
     180        1967 : void CMasternodePaymentWinner::Relay()
     181             : {
     182        1967 :     CInv inv(MSG_MASTERNODE_WINNER, GetHash());
     183        1967 :     g_connman->RelayInv(inv);
     184        1967 : }
     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       55917 : bool IsBlockValueValid(int nHeight, CAmount& nExpectedValue, CAmount nMinted, CAmount& nBudgetAmt)
     198             : {
     199       55917 :     const Consensus::Params& consensus = Params().GetConsensus();
     200       55917 :     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       36874 :         if (nHeight % consensus.nBudgetCycleBlocks < 100) {
     204       29083 :             if (Params().IsTestnet()) {
     205             :                 return true;
     206             :             }
     207       29083 :             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       19043 :         if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) {
     213             :             // add current payee amount to the expected block value
     214        2386 :             if (g_budgetman.GetExpectedPayeeAmount(nHeight, nBudgetAmt)) {
     215          32 :                 nExpectedValue += nBudgetAmt;
     216             :             }
     217             :         }
     218             :     }
     219             : 
     220       55917 :     if (nMinted < 0 && consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_V5_3)) {
     221             :         return false;
     222             :     }
     223             : 
     224       55916 :     return nMinted <= nExpectedValue;
     225             : }
     226             : 
     227       55253 : bool IsBlockPayeeValid(const CBlock& block, const CBlockIndex* pindexPrev)
     228             : {
     229       55253 :     int nBlockHeight = pindexPrev->nHeight + 1;
     230       55253 :     TrxValidationStatus transactionStatus = TrxValidationStatus::InValid;
     231             : 
     232       55253 :     if (!g_tiertwo_sync_state.IsSynced()) { //there is no budget data to use to check anything -- find the longest chain
     233       36226 :         LogPrint(BCLog::MASTERNODE, "Client not synced, skipping block payee checks\n");
     234       36226 :         return true;
     235             :     }
     236             : 
     237       25195 :     const bool fPayCoinstake = Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_POS) &&
     238        6168 :                                !Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_V6_0);
     239       19027 :     const CTransaction& txNew = *(fPayCoinstake ? block.vtx[1] : block.vtx[0]);
     240             : 
     241             :     //check if it's a budget block
     242       19027 :     if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) {
     243        2377 :         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       19000 :     if (masternodePayments.IsTransactionValid(txNew, pindexPrev))
     266             :         return true;
     267           3 :     LogPrint(BCLog::MASTERNODE,"Invalid mn payment detected %s\n", txNew.ToString().c_str());
     268             : 
     269           2 :     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       15126 : void FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const CBlockIndex* pindexPrev, bool fProofOfStake)
     277             : {
     278       15684 :     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       15118 :         masternodePayments.FillBlockPayee(txCoinbase, txCoinstake, pindexPrev, fProofOfStake);
     283             :     }
     284       15126 : }
     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       22031 : bool CMasternodePayments::GetMasternodeTxOuts(const CBlockIndex* pindexPrev, std::vector<CTxOut>& voutMasternodePaymentsRet) const
     296             : {
     297       22031 :     if (deterministicMNManager->LegacyMNObsolete(pindexPrev->nHeight + 1)) {
     298        7859 :         CAmount masternodeReward = GetMasternodePayment(pindexPrev->nHeight + 1);
     299       15718 :         auto dmnPayee = deterministicMNManager->GetListForBlock(pindexPrev).GetMNPayee();
     300        7859 :         if (!dmnPayee) {
     301         121 :             return error("%s: Failed to get payees for block at height %d", __func__, pindexPrev->nHeight + 1);
     302             :         }
     303        7738 :         CAmount operatorReward = 0;
     304        7738 :         if (dmnPayee->nOperatorReward != 0 && !dmnPayee->pdmnState->scriptOperatorPayout.empty()) {
     305         117 :             operatorReward = (masternodeReward * dmnPayee->nOperatorReward) / 10000;
     306         117 :             masternodeReward -= operatorReward;
     307             :         }
     308        7738 :         if (masternodeReward > 0) {
     309        7738 :             voutMasternodePaymentsRet.emplace_back(masternodeReward, dmnPayee->pdmnState->scriptPayout);
     310             :         }
     311        7738 :         if (operatorReward > 0) {
     312         117 :             voutMasternodePaymentsRet.emplace_back(operatorReward, dmnPayee->pdmnState->scriptOperatorPayout);
     313             :         }
     314        7738 :         return true;
     315             :     }
     316             : 
     317             :     // Legacy payment logic. !TODO: remove when transition to DMN is complete
     318       14172 :     return GetLegacyMasternodeTxOut(pindexPrev->nHeight + 1, voutMasternodePaymentsRet);
     319             : }
     320             : 
     321       14172 : bool CMasternodePayments::GetLegacyMasternodeTxOut(int nHeight, std::vector<CTxOut>& voutMasternodePaymentsRet) const
     322             : {
     323       14172 :     voutMasternodePaymentsRet.clear();
     324             : 
     325       28344 :     CScript payee;
     326       14172 :     if (!GetBlockPayee(nHeight, payee)) {
     327             :         //no masternode detected
     328       13965 :         const uint256& hash = mnodeman.GetHashAtHeight(nHeight - 1);
     329       14222 :         MasternodeRef winningNode = mnodeman.GetCurrentMasterNode(hash);
     330       13965 :         if (winningNode) {
     331         257 :             payee = winningNode->GetPayeeScript();
     332             :         } else {
     333       13708 :             LogPrint(BCLog::MASTERNODE,"CreateNewBlock: Failed to detect masternode to pay\n");
     334       13708 :             return false;
     335             :         }
     336             :     }
     337         464 :     voutMasternodePaymentsRet.emplace_back(GetMasternodePayment(nHeight), payee);
     338         464 :     return true;
     339             : }
     340             : 
     341         566 : static void SubtractMnPaymentFromCoinstake(CMutableTransaction& txCoinstake, CAmount masternodePayment, int stakerOuts)
     342             : {
     343         566 :     assert (stakerOuts >= 2);
     344             :     //subtract mn payment from the stake reward
     345         566 :     if (stakerOuts == 2) {
     346             :         // Majority of cases; do it quick and move on
     347         566 :         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         566 : }
     360             : 
     361       15118 : void CMasternodePayments::FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const CBlockIndex* pindexPrev, bool fProofOfStake) const
     362             : {
     363       16515 :     std::vector<CTxOut> vecMnOuts;
     364       15118 :     if (!GetMasternodeTxOuts(pindexPrev, vecMnOuts)) {
     365       13721 :         return;
     366             :     }
     367             : 
     368             :     // Starting from PIVX v6.0 masternode and budgets are paid in the coinbase tx
     369        1397 :     const int nHeight = pindexPrev->nHeight + 1;
     370        1397 :     bool fPayCoinstake = fProofOfStake && !Params().GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_V6_0);
     371             : 
     372             :     // if PoS block pays the coinbase, clear it first
     373        1397 :     if (fProofOfStake && !fPayCoinstake) txCoinbase.vout.clear();
     374             : 
     375        1397 :     const int initial_cstake_outs = txCoinstake.vout.size();
     376             : 
     377        1397 :     CAmount masternodePayment{0};
     378        2807 :     for (const CTxOut& mnOut: vecMnOuts) {
     379             :         // Add the mn payment to the coinstake/coinbase tx
     380        1410 :         if (fPayCoinstake) {
     381          53 :             txCoinstake.vout.emplace_back(mnOut);
     382             :         } else {
     383        1357 :             txCoinbase.vout.emplace_back(mnOut);
     384             :         }
     385        1410 :         masternodePayment += mnOut.nValue;
     386        2820 :         CTxDestination payeeDest;
     387        1410 :         ExtractDestination(mnOut.scriptPubKey, payeeDest);
     388        3596 :         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        1397 :     if (fProofOfStake) {
     393         566 :         SubtractMnPaymentFromCoinstake(txCoinstake, masternodePayment, initial_cstake_outs);
     394             :     } else {
     395         831 :         txCoinbase.vout[0].nValue = GetBlockValue(nHeight) - masternodePayment;
     396             :     }
     397             : }
     398             : 
     399       55648 : bool CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CValidationState& state)
     400             : {
     401       55648 :     if (!g_tiertwo_sync_state.IsBlockchainSynced()) return true;
     402             : 
     403             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     404       55642 :     if (deterministicMNManager->LegacyMNObsolete()) {
     405         790 :         LogPrint(BCLog::MASTERNODE, "mnw - skip obsolete message %s\n", strCommand);
     406         790 :         return true;
     407             :     }
     408             : 
     409       54852 :     if (strCommand == NetMsgType::GETMNWINNERS) {
     410             :         //Masternode Payments Request Sync
     411         752 :         int nCountNeeded;
     412         752 :         vRecv >> nCountNeeded;
     413             : 
     414         752 :         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         752 :         g_netfulfilledman.AddFulfilledRequest(pfrom->addr, NetMsgType::GETMNWINNERS);
     422         752 :         Sync(pfrom, nCountNeeded);
     423         752 :         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        1842 :         CMasternodePaymentWinner winner;
     427         921 :         vRecv >> winner;
     428         921 :         if (pfrom->nVersion < ActiveProtocol()) return false;
     429             : 
     430         921 :         {
     431             :             // Clear inv request
     432         921 :             LOCK(cs_main);
     433         921 :             g_connman->RemoveAskFor(winner.GetHash(), MSG_MASTERNODE_WINNER);
     434             :         }
     435             : 
     436         921 :         ProcessMNWinner(winner, pfrom, state);
     437         921 :         return state.IsValid();
     438             :     }
     439             : 
     440             :     return true;
     441             : }
     442             : 
     443        1821 : bool CMasternodePayments::ProcessMNWinner(CMasternodePaymentWinner& winner, CNode* pfrom, CValidationState& state)
     444             : {
     445        1821 :     int nHeight = mnodeman.GetBestHeight();
     446             : 
     447        1821 :     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        1821 :     int nFirstBlock = nHeight - (mnodeman.CountEnabled() * 1.25);
     454        1821 :     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        1819 :     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        1819 :     const CMasternode* pmn{nullptr};
     467        3640 :     auto dmn = deterministicMNManager->GetListAtChainTip().GetMNByCollateral(winner.vinMasternode.prevout);
     468        1819 :     if (dmn == nullptr) {
     469             :         // legacy masternode
     470        1145 :         pmn = mnodeman.Find(winner.vinMasternode.prevout);
     471        1145 :         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        1814 :     assert((dmn && !pmn) || (!dmn && pmn));
     481             : 
     482             :     // See if the masternode is in the quorum (top-MNPAYMENTS_SIGNATURES_TOTAL)
     483        1814 :     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        1810 :     if (!CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)) {
     490           0 :         return state.Error("MN already voted");
     491             :     }
     492             : 
     493             :     // Check signature
     494        1810 :     bool is_valid_sig = dmn ? winner.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())
     495        1810 :                             : winner.CheckSignature(pmn->pubKeyMasternode.GetID());
     496             : 
     497        1810 :     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        1806 :     RecordWinnerVote(winner.vinMasternode.prevout, winner.nBlockHeight);
     505             : 
     506             :     // Add winner
     507        1806 :     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        1806 :     if (g_tiertwo_sync_state.IsSynced()) winner.Relay();
     512        1806 :     g_tiertwo_sync_state.AddedMasternodeWinner(winner.GetHash());
     513             : 
     514             :     // valid
     515        1806 :     return true;
     516             : }
     517             : 
     518       14172 : bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee) const
     519             : {
     520       14172 :     const auto it = mapMasternodeBlocks.find(nBlockHeight);
     521       14172 :     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        1493 : bool CMasternodePayments::IsScheduled(const CMasternode& mn, int nNotBlockHeight)
     531             : {
     532        2986 :     LOCK(cs_mapMasternodeBlocks);
     533             : 
     534        1493 :     int nHeight = mnodeman.GetBestHeight();
     535             : 
     536        2986 :     const CScript& mnpayee = mn.GetPayeeScript();
     537        2986 :     CScript payee;
     538        9542 :     for (int64_t h = nHeight; h <= nHeight + 8; h++) {
     539        9124 :         if (h == nNotBlockHeight) continue;
     540       13319 :         if (mapMasternodeBlocks.count(h)) {
     541        4509 :             if (mapMasternodeBlocks[h].GetPayee(payee)) {
     542        4509 :                 if (mnpayee == payee) {
     543             :                     return true;
     544             :                 }
     545             :             }
     546             :         }
     547             :     }
     548             : 
     549             :     return false;
     550             : }
     551             : 
     552        1973 : void CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
     553             : {
     554        1973 :     {
     555        3946 :         LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
     556             : 
     557        1973 :         mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;
     558             : 
     559        3236 :         if (!mapMasternodeBlocks.count(winnerIn.nBlockHeight)) {
     560        1420 :             CMasternodeBlockPayees blockPayees(winnerIn.nBlockHeight);
     561         710 :             mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
     562             :         }
     563             :     }
     564             : 
     565        1973 :     CTxDestination addr;
     566        1973 :     ExtractDestination(winnerIn.payee, addr);
     567        3053 :     LogPrint(BCLog::MASTERNODE, "mnw - Adding winner %s for block %d\n", EncodeDestination(addr), winnerIn.nBlockHeight);
     568        1973 :     mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, 1);
     569        1973 : }
     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        1656 :     for (CMasternodePayee& payee : vecPayments)
     578         830 :         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       19000 : bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, const CBlockIndex* pindexPrev)
     646             : {
     647       19000 :     const int nBlockHeight = pindexPrev->nHeight + 1;
     648       19000 :     if (deterministicMNManager->LegacyMNObsolete(nBlockHeight)) {
     649       13822 :         std::vector<CTxOut> vecMnOuts;
     650        6911 :         if (!GetMasternodeTxOuts(pindexPrev, vecMnOuts)) {
     651             :             // No masternode scheduled to be paid.
     652             :             return true;
     653             :         }
     654             : 
     655       13708 :         for (const CTxOut& o : vecMnOuts) {
     656        6906 :             if (std::find(txNew.vout.begin(), txNew.vout.end(), o) == txNew.vout.end()) {
     657           2 :                 CTxDestination mnDest;
     658           1 :                 const std::string& payee = ExtractDestination(o.scriptPubKey, mnDest) ? EncodeDestination(mnDest)
     659           2 :                                                                                       : HexStr(o.scriptPubKey);
     660           2 :                 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           1 :                 return false;
     663             :             }
     664             :         }
     665             :         // all the expected payees have been found in txNew outputs
     666        6802 :         return true;
     667             :     }
     668             : 
     669             :     // Legacy payment logic. !TODO: remove when transition to DMN is complete
     670       31089 :     LOCK(cs_mapMasternodeBlocks);
     671             : 
     672       23352 :     if (mapMasternodeBlocks.count(nBlockHeight)) {
     673         826 :         return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew, nBlockHeight);
     674             :     }
     675             : 
     676             :     return true;
     677             : }
     678             : 
     679        3421 : void CMasternodePayments::CleanPaymentList(int mnCount, int nHeight)
     680             : {
     681        6842 :     LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
     682             : 
     683             :     //keep up to five cycles for historical sake
     684        3421 :     int nLimit = std::max(int(mnCount * 1.25), 1000);
     685             : 
     686        3421 :     std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
     687       19393 :     while (it != mapMasternodePayeeVotes.end()) {
     688       15972 :         CMasternodePaymentWinner winner = (*it).second;
     689             : 
     690       15972 :         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       15972 :             ++it;
     697             :         }
     698             :     }
     699        3421 : }
     700             : 
     701       38317 : void CMasternodePayments::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
     702             : {
     703       38317 :     if (g_tiertwo_sync_state.GetSyncPhase() > MASTERNODE_SYNC_LIST) {
     704       21948 :         ProcessBlock(pindexNew->nHeight + 10);
     705             :     }
     706       38317 : }
     707             : 
     708       21948 : void CMasternodePayments::ProcessBlock(int nBlockHeight)
     709             : {
     710             :     // No more mnw messages after transition to DMN
     711       21948 :     if (deterministicMNManager->LegacyMNObsolete(nBlockHeight)) {
     712       21781 :         return;
     713             :     }
     714       15571 :     if (!fMasterNode) return;
     715             : 
     716             :     // Get the active masternode (operator) key
     717        1160 :     CTxIn mnVin;
     718        1160 :     Optional<CKey> mnKey{nullopt};
     719        1160 :     CBLSSecretKey blsKey;
     720         993 :     if (!GetActiveMasternodeKeys(mnVin, mnKey, blsKey)) {
     721         826 :         return;
     722             :     }
     723             : 
     724             :     //reference node - hybrid mode
     725         677 :     int n = mnodeman.GetMasternodeRank(mnVin, nBlockHeight - 100);
     726             : 
     727         677 :     if (n == -1) {
     728         337 :         LogPrintf("%s: ERROR: active masternode is not registered yet\n", __func__);
     729             :         return;
     730             :     }
     731             : 
     732         340 :     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         340 :     if (nBlockHeight <= nLastBlockHeight) return;
     738             : 
     739         340 :     if (g_budgetman.IsBudgetPaymentBlock(nBlockHeight)) {
     740             :         //is budget payment block -- handled by the budgeting software
     741             :         return;
     742             :     }
     743             : 
     744             :     // check winner height
     745         340 :     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         340 :     int nCount = 0;
     752         507 :     MasternodeRef pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount);
     753             : 
     754         340 :     if (pmn == nullptr) {
     755         173 :         LogPrintf("%s: Failed to find masternode to pay\n", __func__);
     756         826 :         return;
     757             :     }
     758             : 
     759         334 :     CMasternodePaymentWinner newWinner(mnVin, nBlockHeight);
     760         334 :     newWinner.AddPayee(pmn->GetPayeeScript());
     761         167 :     if (mnKey != nullopt) {
     762             :         // Legacy MN
     763          96 :         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         167 :     AddWinningMasternode(newWinner);
     776         167 :     newWinner.Relay();
     777         167 :     LogPrintf("%s: Relayed winner %s\n", __func__, newWinner.GetHash().ToString());
     778         167 :     nLastBlockHeight = nBlockHeight;
     779             : }
     780             : 
     781         752 : void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
     782             : {
     783         752 :     LOCK(cs_mapMasternodePayeeVotes);
     784             : 
     785         752 :     int nHeight = mnodeman.GetBestHeight();
     786         752 :     int nCount = (mnodeman.CountEnabled() * 1.25);
     787         752 :     if (nCountNeeded > nCount) nCountNeeded = nCount;
     788             : 
     789         752 :     int nInvCount = 0;
     790         752 :     std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
     791         919 :     while (it != mapMasternodePayeeVotes.end()) {
     792         334 :         CMasternodePaymentWinner winner = (*it).second;
     793         167 :         if (winner.nBlockHeight >= nHeight - nCountNeeded && winner.nBlockHeight <= nHeight + 20) {
     794          59 :             node->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash()));
     795          59 :             nInvCount++;
     796             :         }
     797         167 :         ++it;
     798             :     }
     799         752 :     g_connman->PushMessage(node, CNetMsgMaker(node->GetSendVersion()).Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_MNW, nInvCount));
     800         752 : }
     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        1810 : bool CMasternodePayments::CanVote(const COutPoint& outMasternode, int nBlockHeight) const
     812             : {
     813        1810 :     LOCK(cs_mapMasternodePayeeVotes);
     814        1810 :     const auto it = mapMasternodesLastVote.find(outMasternode);
     815        3540 :     return it == mapMasternodesLastVote.end() || it->second != nBlockHeight;
     816             : }
     817             : 
     818        1806 : void CMasternodePayments::RecordWinnerVote(const COutPoint& outMasternode, int nBlockHeight)
     819             : {
     820        1806 :     LOCK(cs_mapMasternodePayeeVotes);
     821        1806 :     mapMasternodesLastVote[outMasternode] = nBlockHeight;
     822        1806 : }
     823             : 
     824        4400 : bool IsCoinbaseValueValid(const CTransactionRef& tx, CAmount nBudgetAmt, CValidationState& _state)
     825             : {
     826        4400 :     assert(tx->IsCoinBase());
     827        4400 :     if (g_tiertwo_sync_state.IsSynced()) {
     828        4139 :         const CAmount nCBaseOutAmt = tx->GetValueOut();
     829        4139 :         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        4126 :             int nHeight = mnodeman.GetBestHeight();
     840        4126 :             CAmount nMnAmt = GetMasternodePayment(nHeight);
     841             :             // if enforcement is disabled, there could be no masternode payment
     842        4126 :             bool sporkEnforced = sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT);
     843        4126 :             const std::string strError = strprintf("%s: invalid coinbase payment for masternode (%s vs expected=%s)",
     844       12378 :                                                    __func__, FormatMoney(nCBaseOutAmt), FormatMoney(nMnAmt));
     845        4126 :             if (sporkEnforced && nCBaseOutAmt != nMnAmt) {
     846           8 :                 return _state.DoS(100, error(strError.c_str()), REJECT_INVALID, "bad-cb-amt");
     847             :             }
     848        4122 :             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