PIVX Core  5.6.99
P2P Digital Currency
masternode-payments.cpp
Go to the documentation of this file.
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"
15 #include "spork.h"
16 #include "sync.h"
18 #include "util/system.h"
19 #include "utilmoneystr.h"
20 #include "validation.h"
21 
22 
25 
29 
30 static const int MNPAYMENTS_DB_VERSION = 1;
31 
32 //
33 // CMasternodePaymentDB
34 //
35 
37 {
38  pathDB = GetDataDir() / "mnpayments.dat";
39  strMagicMessage = "MasternodePayments";
40 }
41 
43 {
44  int64_t nStart = GetTimeMillis();
45 
46  // serialize, checksum data up to that point, then append checksum
47  CDataStream ssObj(SER_DISK, CLIENT_VERSION);
48  ssObj << MNPAYMENTS_DB_VERSION;
49  ssObj << strMagicMessage; // masternode cache file specific magic message
50  ssObj << Params().MessageStart(); // network specific magic number
51  ssObj << objToSave;
52  uint256 hash = Hash(ssObj.begin(), ssObj.end());
53  ssObj << hash;
54 
55  // open output file, and associate with CAutoFile
56  FILE* file = fsbridge::fopen(pathDB, "wb");
57  CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
58  if (fileout.IsNull())
59  return error("%s : Failed to open file %s", __func__, pathDB.string());
60 
61  // Write and commit header, data
62  try {
63  fileout << ssObj;
64  } catch (const std::exception& e) {
65  return error("%s : Serialize or I/O error - %s", __func__, e.what());
66  }
67  fileout.fclose();
68 
69  LogPrint(BCLog::MASTERNODE,"Written info to mnpayments.dat %dms\n", GetTimeMillis() - nStart);
70 
71  return true;
72 }
73 
75 {
76  int64_t nStart = GetTimeMillis();
77  // open input file, and associate with CAutoFile
78  FILE* file = fsbridge::fopen(pathDB, "rb");
79  CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
80  if (filein.IsNull()) {
81  error("%s : Failed to open file %s", __func__, pathDB.string());
82  return FileError;
83  }
84 
85  // use file size to size memory buffer
86  int fileSize = fs::file_size(pathDB);
87  int dataSize = fileSize - sizeof(uint256);
88  // Don't try to resize to a negative number if file is small
89  if (dataSize < 0)
90  dataSize = 0;
91  std::vector<unsigned char> vchData;
92  vchData.resize(dataSize);
93  uint256 hashIn;
94 
95  // read data and checksum from file
96  try {
97  filein.read((char*)vchData.data(), dataSize);
98  filein >> hashIn;
99  } catch (const std::exception& e) {
100  error("%s : Deserialize or I/O error - %s", __func__, e.what());
101  return HashReadError;
102  }
103  filein.fclose();
104 
105  CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION);
106 
107  // verify stored checksum matches input data
108  uint256 hashTmp = Hash(ssObj.begin(), ssObj.end());
109  if (hashIn != hashTmp) {
110  error("%s : Checksum mismatch, data corrupted", __func__);
111  return IncorrectHash;
112  }
113 
114  int version;
115  std::string strMagicMessageTmp;
116  try {
117  // de-serialize file header
118  ssObj >> version;
119  ssObj >> strMagicMessageTmp;
120 
121  // ... verify the message matches predefined one
122  if (strMagicMessage != strMagicMessageTmp) {
123  error("%s : Invalid masternode payement cache magic message", __func__);
124  return IncorrectMagicMessage;
125  }
126 
127  // de-serialize file header (network specific magic number) and ..
128  std::vector<unsigned char> pchMsgTmp(4);
129  ssObj >> MakeSpan(pchMsgTmp);
130 
131  // ... verify the network matches ours
132  if (memcmp(pchMsgTmp.data(), Params().MessageStart(), pchMsgTmp.size()) != 0) {
133  error("%s : Invalid network magic number", __func__);
134  return IncorrectMagicNumber;
135  }
136 
137  // de-serialize data into CMasternodePayments object
138  ssObj >> objToLoad;
139  } catch (const std::exception& e) {
140  objToLoad.Clear();
141  error("%s : Deserialize or I/O error - %s", __func__, e.what());
142  return IncorrectFormat;
143  }
144 
145  LogPrint(BCLog::MASTERNODE,"Loaded info from mnpayments.dat (dbversion=%d) %dms\n", version, GetTimeMillis() - nStart);
146  LogPrint(BCLog::MASTERNODE," %s\n", objToLoad.ToString());
147 
148  return Ok;
149 }
150 
152 {
153  CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
154  ss << std::vector<unsigned char>(payee.begin(), payee.end());
155  ss << nBlockHeight;
156  ss << vinMasternode.prevout;
157  return ss.GetHash();
158 }
159 
161 {
162  return vinMasternode.prevout.ToStringShort() + std::to_string(nBlockHeight) + HexStr(payee);
163 }
164 
165 bool CMasternodePaymentWinner::IsValid(CNode* pnode, CValidationState& state, int chainHeight)
166 {
168  if (n < 1 || n > MNPAYMENTS_SIGNATURES_TOTAL) {
169  return state.Error(strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL, n));
170  }
171 
172  // Must be a P2PKH
173  if (!payee.IsPayToPublicKeyHash()) {
174  return state.Error("payee must be a P2PKH");
175  }
176 
177  return true;
178 }
179 
181 {
183  g_connman->RelayInv(inv);
184 }
185 
187 {
188  int64_t nStart = GetTimeMillis();
189 
190  CMasternodePaymentDB paymentdb;
191  LogPrint(BCLog::MASTERNODE,"Writing info to mnpayments.dat...\n");
192  paymentdb.Write(masternodePayments);
193 
194  LogPrint(BCLog::MASTERNODE,"Budget dump finished %dms\n", GetTimeMillis() - nStart);
195 }
196 
197 bool IsBlockValueValid(int nHeight, CAmount& nExpectedValue, CAmount nMinted, CAmount& nBudgetAmt)
198 {
199  const Consensus::Params& consensus = Params().GetConsensus();
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  if (nHeight % consensus.nBudgetCycleBlocks < 100) {
204  if (Params().IsTestnet()) {
205  return true;
206  }
207  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
213  // add current payee amount to the expected block value
214  if (g_budgetman.GetExpectedPayeeAmount(nHeight, nBudgetAmt)) {
215  nExpectedValue += nBudgetAmt;
216  }
217  }
218  }
219 
220  if (nMinted < 0 && consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_V5_3)) {
221  return false;
222  }
223 
224  return nMinted <= nExpectedValue;
225 }
226 
227 bool IsBlockPayeeValid(const CBlock& block, const CBlockIndex* pindexPrev)
228 {
229  int nBlockHeight = pindexPrev->nHeight + 1;
231 
232  if (!g_tiertwo_sync_state.IsSynced()) { //there is no budget data to use to check anything -- find the longest chain
233  LogPrint(BCLog::MASTERNODE, "Client not synced, skipping block payee checks\n");
234  return true;
235  }
236 
237  const bool fPayCoinstake = Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_POS) &&
239  const CTransaction& txNew = *(fPayCoinstake ? block.vtx[1] : block.vtx[0]);
240 
241  //check if it's a budget block
243  if (g_budgetman.IsBudgetPaymentBlock(nBlockHeight)) {
244  transactionStatus = g_budgetman.IsTransactionValid(txNew, block.GetHash(), nBlockHeight);
245  if (transactionStatus == TrxValidationStatus::Valid) {
246  return true;
247  }
248 
249  if (transactionStatus == TrxValidationStatus::InValid) {
250  LogPrint(BCLog::MASTERNODE,"Invalid budget payment detected %s\n", txNew.ToString().c_str());
252  return false;
253 
254  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  if (masternodePayments.IsTransactionValid(txNew, pindexPrev))
266  return true;
267  LogPrint(BCLog::MASTERNODE,"Invalid mn payment detected %s\n", txNew.ToString().c_str());
268 
270  return false;
271  LogPrint(BCLog::MASTERNODE,"Masternode payment enforcement is disabled, accepting block\n");
272  return true;
273 }
274 
275 
276 void FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const CBlockIndex* pindexPrev, bool fProofOfStake)
277 {
278  if (!sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) || // if superblocks are not enabled
279  // ... or this is not a superblock
280  !g_budgetman.FillBlockPayee(txCoinbase, txCoinstake, pindexPrev->nHeight + 1, fProofOfStake) ) {
281  // ... or there's no budget with enough votes, then pay a masternode
282  masternodePayments.FillBlockPayee(txCoinbase, txCoinstake, pindexPrev, fProofOfStake);
283  }
284 }
285 
286 std::string GetRequiredPaymentsString(int nBlockHeight)
287 {
289  return g_budgetman.GetRequiredPaymentsString(nBlockHeight);
290  } else {
291  return masternodePayments.GetRequiredPaymentsString(nBlockHeight);
292  }
293 }
294 
295 bool CMasternodePayments::GetMasternodeTxOuts(const CBlockIndex* pindexPrev, std::vector<CTxOut>& voutMasternodePaymentsRet) const
296 {
297  if (deterministicMNManager->LegacyMNObsolete(pindexPrev->nHeight + 1)) {
298  CAmount masternodeReward = GetMasternodePayment(pindexPrev->nHeight + 1);
299  auto dmnPayee = deterministicMNManager->GetListForBlock(pindexPrev).GetMNPayee();
300  if (!dmnPayee) {
301  return error("%s: Failed to get payees for block at height %d", __func__, pindexPrev->nHeight + 1);
302  }
304  if (dmnPayee->nOperatorReward != 0 && !dmnPayee->pdmnState->scriptOperatorPayout.empty()) {
305  operatorReward = (masternodeReward * dmnPayee->nOperatorReward) / 10000;
306  masternodeReward -= operatorReward;
307  }
308  if (masternodeReward > 0) {
309  voutMasternodePaymentsRet.emplace_back(masternodeReward, dmnPayee->pdmnState->scriptPayout);
310  }
311  if (operatorReward > 0) {
312  voutMasternodePaymentsRet.emplace_back(operatorReward, dmnPayee->pdmnState->scriptOperatorPayout);
313  }
314  return true;
315  }
316 
317  // Legacy payment logic. !TODO: remove when transition to DMN is complete
318  return GetLegacyMasternodeTxOut(pindexPrev->nHeight + 1, voutMasternodePaymentsRet);
319 }
320 
321 bool CMasternodePayments::GetLegacyMasternodeTxOut(int nHeight, std::vector<CTxOut>& voutMasternodePaymentsRet) const
322 {
323  voutMasternodePaymentsRet.clear();
324 
325  CScript payee;
326  if (!GetBlockPayee(nHeight, payee)) {
327  //no masternode detected
328  const uint256& hash = mnodeman.GetHashAtHeight(nHeight - 1);
329  MasternodeRef winningNode = mnodeman.GetCurrentMasterNode(hash);
330  if (winningNode) {
331  payee = winningNode->GetPayeeScript();
332  } else {
333  LogPrint(BCLog::MASTERNODE,"CreateNewBlock: Failed to detect masternode to pay\n");
334  return false;
335  }
336  }
337  voutMasternodePaymentsRet.emplace_back(GetMasternodePayment(nHeight), payee);
338  return true;
339 }
340 
341 static void SubtractMnPaymentFromCoinstake(CMutableTransaction& txCoinstake, CAmount masternodePayment, int stakerOuts)
342 {
343  assert (stakerOuts >= 2);
344  //subtract mn payment from the stake reward
345  if (stakerOuts == 2) {
346  // Majority of cases; do it quick and move on
347  txCoinstake.vout[1].nValue -= masternodePayment;
348  } else {
349  // special case, stake is split between (stakerOuts-1) outputs
350  unsigned int outputs = stakerOuts-1;
351  CAmount mnPaymentSplit = masternodePayment / outputs;
352  CAmount mnPaymentRemainder = masternodePayment - (mnPaymentSplit * outputs);
353  for (unsigned int j=1; j<=outputs; j++) {
354  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  txCoinstake.vout[outputs].nValue -= mnPaymentRemainder;
358  }
359 }
360 
361 void CMasternodePayments::FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const CBlockIndex* pindexPrev, bool fProofOfStake) const
362 {
363  std::vector<CTxOut> vecMnOuts;
364  if (!GetMasternodeTxOuts(pindexPrev, vecMnOuts)) {
365  return;
366  }
367 
368  // Starting from PIVX v6.0 masternode and budgets are paid in the coinbase tx
369  const int nHeight = pindexPrev->nHeight + 1;
370  bool fPayCoinstake = fProofOfStake && !Params().GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_V6_0);
371 
372  // if PoS block pays the coinbase, clear it first
373  if (fProofOfStake && !fPayCoinstake) txCoinbase.vout.clear();
374 
375  const int initial_cstake_outs = txCoinstake.vout.size();
376 
377  CAmount masternodePayment{0};
378  for (const CTxOut& mnOut: vecMnOuts) {
379  // Add the mn payment to the coinstake/coinbase tx
380  if (fPayCoinstake) {
381  txCoinstake.vout.emplace_back(mnOut);
382  } else {
383  txCoinbase.vout.emplace_back(mnOut);
384  }
385  masternodePayment += mnOut.nValue;
386  CTxDestination payeeDest;
387  ExtractDestination(mnOut.scriptPubKey, payeeDest);
388  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  if (fProofOfStake) {
393  SubtractMnPaymentFromCoinstake(txCoinstake, masternodePayment, initial_cstake_outs);
394  } else {
395  txCoinbase.vout[0].nValue = GetBlockValue(nHeight) - masternodePayment;
396  }
397 }
398 
400 {
401  if (!g_tiertwo_sync_state.IsBlockchainSynced()) return true;
402 
403  // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
404  if (deterministicMNManager->LegacyMNObsolete()) {
405  LogPrint(BCLog::MASTERNODE, "mnw - skip obsolete message %s\n", strCommand);
406  return true;
407  }
408 
409  if (strCommand == NetMsgType::GETMNWINNERS) {
410  //Masternode Payments Request Sync
411  int nCountNeeded;
412  vRecv >> nCountNeeded;
413 
414  if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
416  LogPrint(BCLog::MASTERNODE, "%s: mnget - peer already asked me for the list\n", __func__);
417  return state.DoS(20, false, REJECT_INVALID, "getmnwinners-request-already-fulfilled");
418  }
419  }
420 
422  Sync(pfrom, nCountNeeded);
423  LogPrint(BCLog::MASTERNODE, "mnget - Sent Masternode winners to peer %i\n", pfrom->GetId());
424  } else if (strCommand == NetMsgType::MNWINNER) {
425  //Masternode Payments Declare Winner
427  vRecv >> winner;
428  if (pfrom->nVersion < ActiveProtocol()) return false;
429 
430  {
431  // Clear inv request
432  LOCK(cs_main);
433  g_connman->RemoveAskFor(winner.GetHash(), MSG_MASTERNODE_WINNER);
434  }
435 
436  ProcessMNWinner(winner, pfrom, state);
437  return state.IsValid();
438  }
439 
440  return true;
441 }
442 
444 {
445  int nHeight = mnodeman.GetBestHeight();
446 
447  if (mapMasternodePayeeVotes.count(winner.GetHash())) {
448  LogPrint(BCLog::MASTERNODE, "mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), nHeight);
450  return false;
451  }
452 
453  int nFirstBlock = nHeight - (mnodeman.CountEnabled() * 1.25);
454  if (winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > nHeight + 20) {
455  LogPrint(BCLog::MASTERNODE, "mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, nHeight);
456  return state.Error("block height out of range");
457  }
458 
459  // reject old signature version
461  LogPrint(BCLog::MASTERNODE, "mnw - rejecting old message version %d\n", winner.nMessVersion);
462  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  const CMasternode* pmn{nullptr};
467  auto dmn = deterministicMNManager->GetListAtChainTip().GetMNByCollateral(winner.vinMasternode.prevout);
468  if (dmn == nullptr) {
469  // legacy masternode
470  pmn = mnodeman.Find(winner.vinMasternode.prevout);
471  if (pmn == nullptr) {
472  // it could be a non-synced masternode. ask for the mnb
473  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
476  return state.Error("Non-existent mnwinner voter");
477  }
478  }
479  // either deterministic or legacy. not both
480  assert((dmn && !pmn) || (!dmn && pmn));
481 
482  // See if the masternode is in the quorum (top-MNPAYMENTS_SIGNATURES_TOTAL)
483  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  if (!CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)) {
490  return state.Error("MN already voted");
491  }
492 
493  // Check signature
494  bool is_valid_sig = dmn ? winner.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())
495  : winner.CheckSignature(pmn->pubKeyMasternode.GetID());
496 
497  if (!is_valid_sig) {
498  LogPrint(BCLog::MASTERNODE, "%s : mnw - invalid signature for %s masternode: %s\n",
499  __func__, (dmn ? "deterministic" : "legacy"), winner.vinMasternode.prevout.hash.ToString());
500  return state.DoS(20, false, REJECT_INVALID, "invalid voter mnwinner signature");
501  }
502 
503  // Record vote
505 
506  // Add winner
507  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  if (g_tiertwo_sync_state.IsSynced()) winner.Relay();
513 
514  // valid
515  return true;
516 }
517 
518 bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee) const
519 {
520  const auto it = mapMasternodeBlocks.find(nBlockHeight);
521  if (it != mapMasternodeBlocks.end()) {
522  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 bool CMasternodePayments::IsScheduled(const CMasternode& mn, int nNotBlockHeight)
531 {
533 
534  int nHeight = mnodeman.GetBestHeight();
535 
536  const CScript& mnpayee = mn.GetPayeeScript();
537  CScript payee;
538  for (int64_t h = nHeight; h <= nHeight + 8; h++) {
539  if (h == nNotBlockHeight) continue;
540  if (mapMasternodeBlocks.count(h)) {
541  if (mapMasternodeBlocks[h].GetPayee(payee)) {
542  if (mnpayee == payee) {
543  return true;
544  }
545  }
546  }
547  }
548 
549  return false;
550 }
551 
553 {
554  {
556 
557  mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;
558 
559  if (!mapMasternodeBlocks.count(winnerIn.nBlockHeight)) {
560  CMasternodeBlockPayees blockPayees(winnerIn.nBlockHeight);
561  mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
562  }
563  }
564 
565  CTxDestination addr;
566  ExtractDestination(winnerIn.payee, addr);
567  LogPrint(BCLog::MASTERNODE, "mnw - Adding winner %s for block %d\n", EncodeDestination(addr), winnerIn.nBlockHeight);
568  mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, 1);
569 }
570 
571 bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
572 {
574 
575  //require at least 6 signatures
576  int nMaxSignatures = 0;
577  for (CMasternodePayee& payee : vecPayments)
578  if (payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED)
579  nMaxSignatures = payee.nVotes;
580 
581  // if we don't have at least 6 signatures on a payee, approve whichever is the longest chain
582  if (nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true;
583 
584  std::string strPayeesPossible = "";
585  CAmount requiredMasternodePayment = GetMasternodePayment(nBlockHeight);
586 
587  for (CMasternodePayee& payee : vecPayments) {
588  bool found = false;
589  for (CTxOut out : txNew.vout) {
590  if (payee.scriptPubKey == out.scriptPubKey) {
591  if(out.nValue == requiredMasternodePayment)
592  found = true;
593  else
594  LogPrintf("%s : Masternode payment value (%s) different from required value (%s).\n",
595  __func__, FormatMoney(out.nValue).c_str(), FormatMoney(requiredMasternodePayment).c_str());
596  }
597  }
598 
599  if (payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) {
600  if (found) return true;
601 
602  CTxDestination address1;
603  ExtractDestination(payee.scriptPubKey, address1);
604 
605  if (strPayeesPossible != "")
606  strPayeesPossible += ",";
607 
608  strPayeesPossible += EncodeDestination(address1);
609  }
610  }
611 
612  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 
617 {
619 
620  std::string ret = "";
621 
622  for (CMasternodePayee& payee : vecPayments) {
623  CTxDestination address1;
624  ExtractDestination(payee.scriptPubKey, address1);
625  if (ret != "") {
626  ret += ", ";
627  }
628  ret += EncodeDestination(address1) + ":" + std::to_string(payee.nVotes);
629  }
630 
631  return ret.empty() ? "Unknown" : ret;
632 }
633 
635 {
637 
638  if (mapMasternodeBlocks.count(nBlockHeight)) {
639  return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
640  }
641 
642  return "Unknown";
643 }
644 
646 {
647  const int nBlockHeight = pindexPrev->nHeight + 1;
648  if (deterministicMNManager->LegacyMNObsolete(nBlockHeight)) {
649  std::vector<CTxOut> vecMnOuts;
650  if (!GetMasternodeTxOuts(pindexPrev, vecMnOuts)) {
651  // No masternode scheduled to be paid.
652  return true;
653  }
654 
655  for (const CTxOut& o : vecMnOuts) {
656  if (std::find(txNew.vout.begin(), txNew.vout.end(), o) == txNew.vout.end()) {
657  CTxDestination mnDest;
658  const std::string& payee = ExtractDestination(o.scriptPubKey, mnDest) ? EncodeDestination(mnDest)
659  : HexStr(o.scriptPubKey);
660  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  return false;
663  }
664  }
665  // all the expected payees have been found in txNew outputs
666  return true;
667  }
668 
669  // Legacy payment logic. !TODO: remove when transition to DMN is complete
671 
672  if (mapMasternodeBlocks.count(nBlockHeight)) {
673  return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew, nBlockHeight);
674  }
675 
676  return true;
677 }
678 
679 void CMasternodePayments::CleanPaymentList(int mnCount, int nHeight)
680 {
682 
683  //keep up to five cycles for historical sake
684  int nLimit = std::max(int(mnCount * 1.25), 1000);
685 
686  std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
687  while (it != mapMasternodePayeeVotes.end()) {
688  CMasternodePaymentWinner winner = (*it).second;
689 
690  if (nHeight - winner.nBlockHeight > nLimit) {
691  LogPrint(BCLog::MASTERNODE, "CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", winner.nBlockHeight);
692  g_tiertwo_sync_state.EraseSeenMNW((*it).first);
693  mapMasternodePayeeVotes.erase(it++);
694  mapMasternodeBlocks.erase(winner.nBlockHeight);
695  } else {
696  ++it;
697  }
698  }
699 }
700 
701 void CMasternodePayments::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
702 {
704  ProcessBlock(pindexNew->nHeight + 10);
705  }
706 }
707 
708 void CMasternodePayments::ProcessBlock(int nBlockHeight)
709 {
710  // No more mnw messages after transition to DMN
711  if (deterministicMNManager->LegacyMNObsolete(nBlockHeight)) {
712  return;
713  }
714  if (!fMasterNode) return;
715 
716  // Get the active masternode (operator) key
717  CTxIn mnVin;
718  Optional<CKey> mnKey{nullopt};
719  CBLSSecretKey blsKey;
720  if (!GetActiveMasternodeKeys(mnVin, mnKey, blsKey)) {
721  return;
722  }
723 
724  //reference node - hybrid mode
725  int n = mnodeman.GetMasternodeRank(mnVin, nBlockHeight - 100);
726 
727  if (n == -1) {
728  LogPrintf("%s: ERROR: active masternode is not registered yet\n", __func__);
729  return;
730  }
731 
732  if (n > MNPAYMENTS_SIGNATURES_TOTAL) {
733  LogPrintf("%s: active masternode not in the top %d (%d)\n", __func__, MNPAYMENTS_SIGNATURES_TOTAL, n);
734  return;
735  }
736 
737  if (nBlockHeight <= nLastBlockHeight) return;
738 
739  if (g_budgetman.IsBudgetPaymentBlock(nBlockHeight)) {
740  //is budget payment block -- handled by the budgeting software
741  return;
742  }
743 
744  // check winner height
745  if (nBlockHeight - 100 > mnodeman.GetBestHeight() + 1) {
746  LogPrintf("%s: mnw - invalid height %d > %d\n", __func__, nBlockHeight - 100, mnodeman.GetBestHeight() + 1);
747  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  int nCount = 0;
752  MasternodeRef pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount);
753 
754  if (pmn == nullptr) {
755  LogPrintf("%s: Failed to find masternode to pay\n", __func__);
756  return;
757  }
758 
759  CMasternodePaymentWinner newWinner(mnVin, nBlockHeight);
760  newWinner.AddPayee(pmn->GetPayeeScript());
761  if (mnKey != nullopt) {
762  // Legacy MN
763  if (!newWinner.Sign(*mnKey, mnKey->GetPubKey().GetID())) {
764  LogPrintf("%s: Failed to sign masternode winner\n", __func__);
765  return;
766  }
767  } else {
768  // DMN
769  if (!newWinner.Sign(blsKey)) {
770  LogPrintf("%s: Failed to sign masternode winner with DMN\n", __func__);
771  return;
772  }
773  }
774 
775  AddWinningMasternode(newWinner);
776  newWinner.Relay();
777  LogPrintf("%s: Relayed winner %s\n", __func__, newWinner.GetHash().ToString());
778  nLastBlockHeight = nBlockHeight;
779 }
780 
781 void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
782 {
784 
785  int nHeight = mnodeman.GetBestHeight();
786  int nCount = (mnodeman.CountEnabled() * 1.25);
787  if (nCountNeeded > nCount) nCountNeeded = nCount;
788 
789  int nInvCount = 0;
790  std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
791  while (it != mapMasternodePayeeVotes.end()) {
792  CMasternodePaymentWinner winner = (*it).second;
793  if (winner.nBlockHeight >= nHeight - nCountNeeded && winner.nBlockHeight <= nHeight + 20) {
795  nInvCount++;
796  }
797  ++it;
798  }
800 }
801 
802 std::string CMasternodePayments::ToString() const
803 {
804  std::ostringstream info;
805 
806  info << "Votes: " << (int)mapMasternodePayeeVotes.size() << ", Blocks: " << (int)mapMasternodeBlocks.size();
807 
808  return info.str();
809 }
810 
811 bool CMasternodePayments::CanVote(const COutPoint& outMasternode, int nBlockHeight) const
812 {
814  const auto it = mapMasternodesLastVote.find(outMasternode);
815  return it == mapMasternodesLastVote.end() || it->second != nBlockHeight;
816 }
817 
818 void CMasternodePayments::RecordWinnerVote(const COutPoint& outMasternode, int nBlockHeight)
819 {
821  mapMasternodesLastVote[outMasternode] = nBlockHeight;
822 }
823 
824 bool IsCoinbaseValueValid(const CTransactionRef& tx, CAmount nBudgetAmt, CValidationState& _state)
825 {
826  assert(tx->IsCoinBase());
828  const CAmount nCBaseOutAmt = tx->GetValueOut();
829  if (nBudgetAmt > 0) {
830  // Superblock
831  if (nCBaseOutAmt != nBudgetAmt) {
832  const std::string strError = strprintf("%s: invalid coinbase payment for budget (%s vs expected=%s)",
833  __func__, FormatMoney(nCBaseOutAmt), FormatMoney(nBudgetAmt));
834  return _state.DoS(100, error(strError.c_str()), REJECT_INVALID, "bad-superblock-cb-amt");
835  }
836  return true;
837  } else {
838  // regular block
839  int nHeight = mnodeman.GetBestHeight();
840  CAmount nMnAmt = GetMasternodePayment(nHeight);
841  // if enforcement is disabled, there could be no masternode payment
843  const std::string strError = strprintf("%s: invalid coinbase payment for masternode (%s vs expected=%s)",
844  __func__, FormatMoney(nCBaseOutAmt), FormatMoney(nMnAmt));
845  if (sporkEnforced && nCBaseOutAmt != nMnAmt) {
846  return _state.DoS(100, error(strError.c_str()), REJECT_INVALID, "bad-cb-amt");
847  }
848  if (!sporkEnforced && nCBaseOutAmt > nMnAmt) {
849  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 }
bool GetActiveMasternodeKeys(CTxIn &vin, Optional< CKey > &key, CBLSSecretKey &blsKey)
int64_t CAmount
Amount in PIV (Can be negative)
Definition: amount.h:13
CBudgetManager g_budgetman
const CChainParams & Params()
Return the currently selected parameters.
uint256 hash
Definition: transaction.h:35
std::string ToStringShort() const
Definition: transaction.cpp:13
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:452
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:501
void fclose()
Definition: streams.h:474
void read(char *pch, size_t nSize)
Definition: streams.h:509
static const std::string MAIN
Chain name strings.
const_iterator end() const
Definition: streams.h:163
const_iterator begin() const
Definition: streams.h:161
uint256 GetHash() const
Definition: block.cpp:15
Definition: block.h:80
std::vector< CTransactionRef > vtx
Definition: block.h:83
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:139
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
TrxValidationStatus IsTransactionValid(const CTransaction &txNew, const uint256 &nBlockHash, int nBlockHeight) const
static CAmount GetTotalBudget(int nHeight)
bool FillBlockPayee(CMutableTransaction &txCoinbase, CMutableTransaction &txCoinstake, const int nHeight, bool fProofOfStake) const
std::string GetRequiredPaymentsString(int nBlockHeight)
bool GetExpectedPayeeAmount(int chainHeight, CAmount &nAmountRet) const
bool IsBudgetPaymentBlock(int nBlockHeight) const
const CMessageHeader::MessageStartChars & MessageStart() const
Definition: chainparams.h:73
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:72
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:216
uint256 GetHash()
Definition: hash.h:236
inv message data
Definition: protocol.h:466
std::string GetRequiredPaymentsString()
std::vector< CMasternodePayee > vecPayments
bool IsTransactionValid(const CTransaction &txNew, int nBlockHeight)
CScript GetPayeeScript() const
Definition: masternode.h:231
int CountEnabled(bool only_legacy=false) const
void AskForMN(CNode *pnode, const CTxIn &vin)
Ask (source) node for mnb.
uint256 GetHashAtHeight(int nHeight) const
MasternodeRef GetNextMasternodeInQueueForPayment(int nBlockHeight, bool fFilterSigTime, int &nCount, const CBlockIndex *pChainTip=nullptr) const
Find an entry in the masternode list that is next to be paid.
int GetBestHeight() const
int GetMasternodeRank(const CTxIn &vin, int64_t nBlockHeight) const
CMasternode * Find(const COutPoint &collateralOut)
Find an entry.
MasternodeRef GetCurrentMasterNode(const uint256 &hash) const
Get the winner for this block hash.
Save Masternode Payment Data (mnpayments.dat)
bool Write(const CMasternodePayments &objToSave)
ReadResult Read(CMasternodePayments &objToLoad)
void AddPayee(const CScript &payeeIn)
bool IsValid(CNode *pnode, CValidationState &state, int chainHeight)
std::string GetStrMessage() const override
bool CanVote(const COutPoint &outMasternode, int nBlockHeight) const
void ProcessBlock(int nBlockHeight)
void AddWinningMasternode(CMasternodePaymentWinner &winner)
void CleanPaymentList(int mnCount, int nHeight)
bool GetMasternodeTxOuts(const CBlockIndex *pindexPrev, std::vector< CTxOut > &voutMasternodePaymentsRet) const
bool IsTransactionValid(const CTransaction &txNew, const CBlockIndex *pindexPrev)
std::string GetRequiredPaymentsString(int nBlockHeight)
void RecordWinnerVote(const COutPoint &outMasternode, int nBlockHeight)
std::map< int, CMasternodeBlockPayees > mapMasternodeBlocks
void Sync(CNode *node, int nCountNeeded)
bool IsScheduled(const CMasternode &mn, int nNotBlockHeight)
std::map< COutPoint, int > mapMasternodesLastVote
bool GetBlockPayee(int nBlockHeight, CScript &payee) const
void FillBlockPayee(CMutableTransaction &txCoinbase, CMutableTransaction &txCoinstake, const CBlockIndex *pindexPrev, bool fProofOfStake) const
std::map< uint256, CMasternodePaymentWinner > mapMasternodePayeeVotes
std::string ToString() const
bool ProcessMNWinner(CMasternodePaymentWinner &winner, CNode *pfrom, CValidationState &state)
bool ProcessMessageMasternodePayments(CNode *pfrom, std::string &strCommand, CDataStream &vRecv, CValidationState &state)
bool GetLegacyMasternodeTxOut(int nHeight, std::vector< CTxOut > &voutMasternodePaymentsRet) const
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override
Notifies listeners when the block chain tip advances.
void AddFulfilledRequest(const CService &addr, const std::string &strRequest)
bool HasFulfilledRequest(const CService &addr, const std::string &strRequest) const
CSerializedNetMsg Make(int nFlags, std::string sCommand, Args &&... args)
Information about a peer.
Definition: net.h:669
std::atomic< int > nVersion
Definition: net.h:699
NodeId GetId() const
Definition: net.h:825
int GetSendVersion() const
Definition: net.cpp:789
const CAddress addr
Definition: net.h:698
void PushInventory(const CInv &inv)
Definition: net.h:914
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:72
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
bool IsPayToPublicKeyHash() const
Definition: script.cpp:212
bool Sign(const CKey &key, const CKeyID &keyID)
CSignedMessage Class Functions inherited by network signed-messages.
bool CheckSignature(const CKeyID &keyID) const
bool IsSporkActive(SporkId nSporkID)
Definition: spork.cpp:220
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:244
const uint256 & GetHash() const
Definition: transaction.h:301
std::string ToString() const
std::vector< CTxOut > vout
Definition: transaction.h:271
An input of a transaction.
Definition: transaction.h:94
COutPoint prevout
Definition: transaction.h:96
An output of a transaction.
Definition: transaction.h:137
CScript scriptPubKey
Definition: transaction.h:140
CAmount nValue
Definition: transaction.h:139
Capture information about block/transaction validation.
Definition: validation.h:24
bool DoS(int level, bool ret=false, unsigned int chRejectCodeIn=0, std::string strRejectReasonIn="", bool corruptionIn=false, const std::string &strDebugMessageIn="")
Definition: validation.h:39
bool IsValid() const
Definition: validation.h:69
bool Error(std::string strRejectReasonIn="")
Definition: validation.h:62
bool IsBlockchainSynced() const
void AddedMasternodeWinner(const uint256 &hash)
bool IsSynced() const
bool IsMasternodeListSynced() const
void EraseSeenMNW(const uint256 &hash)
int GetSyncPhase() const
std::string ToString() const
Definition: uint256.cpp:65
iterator begin()
Definition: prevector.h:285
iterator end()
Definition: prevector.h:287
256-bit opaque blob.
Definition: uint256.h:138
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
TrxValidationStatus
@ Valid
Transaction verification failed.
uint256 Hash(const T1 pbegin, const T1 pend)
Compute the 256-bit hash of an object.
Definition: hash.h:173
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:90
@ LOCK
Definition: lockunlock.h:16
#define LogPrint(category,...)
Definition: logging.h:163
RecursiveMutex cs_mapMasternodePayeeVotes
bool IsBlockValueValid(int nHeight, CAmount &nExpectedValue, CAmount nMinted, CAmount &nBudgetAmt)
std::string GetRequiredPaymentsString(int nBlockHeight)
RecursiveMutex cs_mapMasternodeBlocks
CMasternodePayments masternodePayments
Object for who's going to get paid on which blocks.
void DumpMasternodePayments()
bool IsCoinbaseValueValid(const CTransactionRef &tx, CAmount nBudgetAmt, CValidationState &_state)
Check coinbase output value for blocks after v6.0 enforcement.
bool IsBlockPayeeValid(const CBlock &block, const CBlockIndex *pindexPrev)
RecursiveMutex cs_vecPayments
void FillBlockPayee(CMutableTransaction &txCoinbase, CMutableTransaction &txCoinstake, const CBlockIndex *pindexPrev, bool fProofOfStake)
#define MNPAYMENTS_SIGNATURES_TOTAL
#define MNPAYMENTS_SIGNATURES_REQUIRED
std::shared_ptr< CMasternode > MasternodeRef
Definition: masternode.h:24
CMasternodeMan mnodeman
Masternode manager.
@ MESS_VER_HASH
Definition: messagesigner.h:17
@ MASTERNODE
Definition: logging.h:59
@ UPGRADE_V6_0
Definition: params.h:41
@ UPGRADE_V5_3
Definition: params.h:38
@ UPGRADE_POS
Definition: params.h:28
const char * MNWINNER
The mnwinner message is used to relay and distribute consensus for masternode payout ordering.
Definition: protocol.cpp:47
const char * GETMNWINNERS
The getmnwinners message is used to request winning masternode data from connected peers.
Definition: protocol.cpp:48
const char * SYNCSTATUSCOUNT
The syncstatuscount message is used to track the layer 2 syncing process.
Definition: protocol.cpp:54
std::string EncodeDestination(const CWDestination &address, const CChainParams::Base58Type addrType)
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:23
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:80
CNetFulfilledRequestManager g_netfulfilledman(DEFAULT_ITEMS_FILTER_SIZE)
boost::optional< T > Optional
Substitute for C++17 std::optional.
Definition: optional.h:12
@ MSG_MASTERNODE_WINNER
Definition: protocol.h:444
@ operatorReward
Definition: rpcevo.cpp:46
@ SER_DISK
Definition: serialize.h:175
@ SER_GETHASH
Definition: serialize.h:176
constexpr Span< A > MakeSpan(A(&a)[N])
MakeSpan for arrays:
Definition: span.h:221
CSporkManager sporkManager
Definition: spork.cpp:29
@ SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT
Definition: sporkid.h:19
@ SPORK_13_ENABLE_SUPERBLOCKS
Definition: sporkid.h:20
@ SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT
Definition: sporkid.h:18
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet, bool fColdStake)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:162
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:72
A mutable version of CTransaction.
Definition: transaction.h:409
std::vector< CTxOut > vout
Definition: transaction.h:411
Parameters that influence chain consensus.
Definition: params.h:171
bool NetworkUpgradeActive(int nHeight, Consensus::UpgradeIndex idx) const
Returns true if the given network upgrade is active as of the given block height.
Definition: params.cpp:12
int nBudgetCycleBlocks
Definition: params.h:178
#define LOCK2(cs1, cs2)
Definition: sync.h:221
const fs::path & GetDataDir(bool fNetSpecific)
Definition: system.cpp:724
std::atomic< bool > fMasterNode
Definition: system.cpp:87
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
TierTwoSyncState g_tiertwo_sync_state
#define MASTERNODE_SYNC_MNW
#define MASTERNODE_SYNC_LIST
#define strprintf
Definition: tinyformat.h:1056
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:456
std::string FormatMoney(const CAmount &n, bool fPlus)
Money parsing/formatting utilities.
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: utiltime.cpp:61
int ActiveProtocol()
See whether the protocol update is enforced for connected nodes.
int64_t GetMasternodePayment(int nHeight)
Definition: validation.cpp:852
CAmount GetBlockValue(int nHeight)
Definition: validation.cpp:816