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