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 608 : CMasternodePaymentDB::CMasternodePaymentDB()
37 : {
38 608 : pathDB = GetDataDir() / "mnpayments.dat";
39 608 : strMagicMessage = "MasternodePayments";
40 608 : }
41 :
42 315 : bool CMasternodePaymentDB::Write(const CMasternodePayments& objToSave)
43 : {
44 315 : int64_t nStart = GetTimeMillis();
45 :
46 : // serialize, checksum data up to that point, then append checksum
47 630 : CDataStream ssObj(SER_DISK, CLIENT_VERSION);
48 315 : ssObj << MNPAYMENTS_DB_VERSION;
49 315 : ssObj << strMagicMessage; // masternode cache file specific magic message
50 315 : ssObj << Params().MessageStart(); // network specific magic number
51 315 : ssObj << objToSave;
52 315 : uint256 hash = Hash(ssObj.begin(), ssObj.end());
53 315 : ssObj << hash;
54 :
55 : // open output file, and associate with CAutoFile
56 315 : FILE* file = fsbridge::fopen(pathDB, "wb");
57 630 : CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
58 315 : if (fileout.IsNull())
59 0 : return error("%s : Failed to open file %s", __func__, pathDB.string());
60 :
61 : // Write and commit header, data
62 315 : try {
63 315 : 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 315 : fileout.fclose();
68 :
69 315 : LogPrint(BCLog::MASTERNODE,"Written info to mnpayments.dat %dms\n", GetTimeMillis() - nStart);
70 :
71 : return true;
72 : }
73 :
74 293 : CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& objToLoad)
75 : {
76 293 : int64_t nStart = GetTimeMillis();
77 : // open input file, and associate with CAutoFile
78 293 : FILE* file = fsbridge::fopen(pathDB, "rb");
79 586 : CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
80 293 : if (filein.IsNull()) {
81 217 : error("%s : Failed to open file %s", __func__, pathDB.string());
82 : return FileError;
83 : }
84 :
85 : // use file size to size memory buffer
86 76 : int fileSize = fs::file_size(pathDB);
87 76 : int dataSize = fileSize - sizeof(uint256);
88 : // Don't try to resize to a negative number if file is small
89 76 : if (dataSize < 0)
90 0 : dataSize = 0;
91 369 : std::vector<unsigned char> vchData;
92 76 : vchData.resize(dataSize);
93 76 : uint256 hashIn;
94 :
95 : // read data and checksum from file
96 76 : try {
97 76 : filein.read((char*)vchData.data(), dataSize);
98 76 : 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 76 : filein.fclose();
104 :
105 152 : CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION);
106 :
107 : // verify stored checksum matches input data
108 76 : uint256 hashTmp = Hash(ssObj.begin(), ssObj.end());
109 76 : if (hashIn != hashTmp) {
110 0 : error("%s : Checksum mismatch, data corrupted", __func__);
111 : return IncorrectHash;
112 : }
113 :
114 76 : int version;
115 152 : std::string strMagicMessageTmp;
116 76 : try {
117 : // de-serialize file header
118 76 : ssObj >> version;
119 76 : ssObj >> strMagicMessageTmp;
120 :
121 : // ... verify the message matches predefined one
122 76 : 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 76 : std::vector<unsigned char> pchMsgTmp(4);
129 76 : ssObj >> MakeSpan(pchMsgTmp);
130 :
131 : // ... verify the network matches ours
132 76 : 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 152 : 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 76 : LogPrint(BCLog::MASTERNODE,"Loaded info from mnpayments.dat (dbversion=%d) %dms\n", version, GetTimeMillis() - nStart);
146 152 : LogPrint(BCLog::MASTERNODE," %s\n", objToLoad.ToString());
147 :
148 : return Ok;
149 : }
150 :
151 5595 : uint256 CMasternodePaymentWinner::GetHash() const
152 : {
153 5595 : CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
154 22380 : ss << std::vector<unsigned char>(payee.begin(), payee.end());
155 5595 : ss << nBlockHeight;
156 5595 : ss << vinMasternode.prevout;
157 11190 : 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 931 : bool CMasternodePaymentWinner::IsValid(CNode* pnode, CValidationState& state, int chainHeight)
166 : {
167 931 : int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight - 100);
168 931 : if (n < 1 || n > MNPAYMENTS_SIGNATURES_TOTAL) {
169 21 : return state.Error(strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL, n));
170 : }
171 :
172 : // Must be a P2PKH
173 924 : if (!payee.IsPayToPublicKeyHash()) {
174 3 : return state.Error("payee must be a P2PKH");
175 : }
176 :
177 : return true;
178 : }
179 :
180 929 : void CMasternodePaymentWinner::Relay()
181 : {
182 929 : CInv inv(MSG_MASTERNODE_WINNER, GetHash());
183 929 : g_connman->RelayInv(inv);
184 929 : }
185 :
186 315 : void DumpMasternodePayments()
187 : {
188 315 : int64_t nStart = GetTimeMillis();
189 :
190 630 : CMasternodePaymentDB paymentdb;
191 315 : LogPrint(BCLog::MASTERNODE,"Writing info to mnpayments.dat...\n");
192 315 : paymentdb.Write(masternodePayments);
193 :
194 315 : LogPrint(BCLog::MASTERNODE,"Budget dump finished %dms\n", GetTimeMillis() - nStart);
195 315 : }
196 :
197 34685 : bool IsBlockValueValid(int nHeight, CAmount& nExpectedValue, CAmount nMinted, CAmount& nBudgetAmt)
198 : {
199 34685 : const Consensus::Params& consensus = Params().GetConsensus();
200 34685 : 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 28639 : if (nHeight % consensus.nBudgetCycleBlocks < 100) {
204 22954 : if (Params().IsTestnet()) {
205 : return true;
206 : }
207 22954 : 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 6046 : if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) {
213 : // add current payee amount to the expected block value
214 849 : if (g_budgetman.GetExpectedPayeeAmount(nHeight, nBudgetAmt)) {
215 26 : nExpectedValue += nBudgetAmt;
216 : }
217 : }
218 : }
219 :
220 34685 : if (nMinted < 0 && consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_V5_3)) {
221 : return false;
222 : }
223 :
224 34684 : return nMinted <= nExpectedValue;
225 : }
226 :
227 34018 : bool IsBlockPayeeValid(const CBlock& block, const CBlockIndex* pindexPrev)
228 : {
229 34018 : int nBlockHeight = pindexPrev->nHeight + 1;
230 34018 : TrxValidationStatus transactionStatus = TrxValidationStatus::InValid;
231 :
232 34018 : if (!g_tiertwo_sync_state.IsSynced()) { //there is no budget data to use to check anything -- find the longest chain
233 27988 : LogPrint(BCLog::MASTERNODE, "Client not synced, skipping block payee checks\n");
234 27988 : return true;
235 : }
236 :
237 7120 : const bool fPayCoinstake = Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_POS) &&
238 1090 : !Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_V6_0);
239 6030 : const CTransaction& txNew = *(fPayCoinstake ? block.vtx[1] : block.vtx[0]);
240 :
241 : //check if it's a budget block
242 6030 : if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) {
243 840 : if (g_budgetman.IsBudgetPaymentBlock(nBlockHeight)) {
244 21 : transactionStatus = g_budgetman.IsTransactionValid(txNew, block.GetHash(), nBlockHeight);
245 21 : 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 6009 : if (masternodePayments.IsTransactionValid(txNew, pindexPrev))
266 : return true;
267 1 : LogPrint(BCLog::MASTERNODE,"Invalid mn payment detected %s\n", txNew.ToString().c_str());
268 :
269 1 : 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 10235 : void FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const CBlockIndex* pindexPrev, bool fProofOfStake)
277 : {
278 10568 : if (!sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) || // if superblocks are not enabled
279 : // ... or this is not a superblock
280 333 : !g_budgetman.FillBlockPayee(txCoinbase, txCoinstake, pindexPrev->nHeight + 1, fProofOfStake) ) {
281 : // ... or there's no budget with enough votes, then pay a masternode
282 10228 : masternodePayments.FillBlockPayee(txCoinbase, txCoinstake, pindexPrev, fProofOfStake);
283 : }
284 10235 : }
285 :
286 0 : std::string GetRequiredPaymentsString(int nBlockHeight)
287 : {
288 0 : if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && g_budgetman.IsBudgetPaymentBlock(nBlockHeight)) {
289 0 : return g_budgetman.GetRequiredPaymentsString(nBlockHeight);
290 : } else {
291 0 : return masternodePayments.GetRequiredPaymentsString(nBlockHeight);
292 : }
293 : }
294 :
295 10682 : bool CMasternodePayments::GetMasternodeTxOuts(const CBlockIndex* pindexPrev, std::vector<CTxOut>& voutMasternodePaymentsRet) const
296 : {
297 10682 : if (deterministicMNManager->LegacyMNObsolete(pindexPrev->nHeight + 1)) {
298 672 : CAmount masternodeReward = GetMasternodePayment(pindexPrev->nHeight + 1);
299 1344 : auto dmnPayee = deterministicMNManager->GetListForBlock(pindexPrev).GetMNPayee();
300 672 : if (!dmnPayee) {
301 21 : return error("%s: Failed to get payees for block at height %d", __func__, pindexPrev->nHeight + 1);
302 : }
303 651 : CAmount operatorReward = 0;
304 651 : if (dmnPayee->nOperatorReward != 0 && !dmnPayee->pdmnState->scriptOperatorPayout.empty()) {
305 6 : operatorReward = (masternodeReward * dmnPayee->nOperatorReward) / 10000;
306 6 : masternodeReward -= operatorReward;
307 : }
308 651 : if (masternodeReward > 0) {
309 651 : voutMasternodePaymentsRet.emplace_back(masternodeReward, dmnPayee->pdmnState->scriptPayout);
310 : }
311 651 : if (operatorReward > 0) {
312 6 : voutMasternodePaymentsRet.emplace_back(operatorReward, dmnPayee->pdmnState->scriptOperatorPayout);
313 : }
314 651 : return true;
315 : }
316 :
317 : // Legacy payment logic. !TODO: remove when transition to DMN is complete
318 10010 : return GetLegacyMasternodeTxOut(pindexPrev->nHeight + 1, voutMasternodePaymentsRet);
319 : }
320 :
321 10010 : bool CMasternodePayments::GetLegacyMasternodeTxOut(int nHeight, std::vector<CTxOut>& voutMasternodePaymentsRet) const
322 : {
323 10010 : voutMasternodePaymentsRet.clear();
324 :
325 20020 : CScript payee;
326 10010 : if (!GetBlockPayee(nHeight, payee)) {
327 : //no masternode detected
328 9882 : const uint256& hash = mnodeman.GetHashAtHeight(nHeight - 1);
329 9953 : MasternodeRef winningNode = mnodeman.GetCurrentMasterNode(hash);
330 9882 : if (winningNode) {
331 71 : payee = winningNode->GetPayeeScript();
332 : } else {
333 9811 : LogPrint(BCLog::MASTERNODE,"CreateNewBlock: Failed to detect masternode to pay\n");
334 9811 : return false;
335 : }
336 : }
337 199 : voutMasternodePaymentsRet.emplace_back(GetMasternodePayment(nHeight), payee);
338 199 : return true;
339 : }
340 :
341 60 : static void SubtractMnPaymentFromCoinstake(CMutableTransaction& txCoinstake, CAmount masternodePayment, int stakerOuts)
342 : {
343 60 : assert (stakerOuts >= 2);
344 : //subtract mn payment from the stake reward
345 60 : if (stakerOuts == 2) {
346 : // Majority of cases; do it quick and move on
347 60 : 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 60 : }
360 :
361 10228 : void CMasternodePayments::FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const CBlockIndex* pindexPrev, bool fProofOfStake) const
362 : {
363 10642 : std::vector<CTxOut> vecMnOuts;
364 10228 : if (!GetMasternodeTxOuts(pindexPrev, vecMnOuts)) {
365 9814 : return;
366 : }
367 :
368 : // Starting from PIVX v6.0 masternode and budgets are paid in the coinbase tx
369 414 : const int nHeight = pindexPrev->nHeight + 1;
370 414 : bool fPayCoinstake = fProofOfStake && !Params().GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_V6_0);
371 :
372 : // if PoS block pays the coinbase, clear it first
373 414 : if (fProofOfStake && !fPayCoinstake) txCoinbase.vout.clear();
374 :
375 414 : const int initial_cstake_outs = txCoinstake.vout.size();
376 :
377 414 : CAmount masternodePayment{0};
378 830 : for (const CTxOut& mnOut: vecMnOuts) {
379 : // Add the mn payment to the coinstake/coinbase tx
380 416 : if (fPayCoinstake) {
381 53 : txCoinstake.vout.emplace_back(mnOut);
382 : } else {
383 363 : txCoinbase.vout.emplace_back(mnOut);
384 : }
385 416 : masternodePayment += mnOut.nValue;
386 832 : CTxDestination payeeDest;
387 416 : ExtractDestination(mnOut.scriptPubKey, payeeDest);
388 614 : 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 414 : if (fProofOfStake) {
393 60 : SubtractMnPaymentFromCoinstake(txCoinstake, masternodePayment, initial_cstake_outs);
394 : } else {
395 354 : txCoinbase.vout[0].nValue = GetBlockValue(nHeight) - masternodePayment;
396 : }
397 : }
398 :
399 51037 : bool CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CValidationState& state)
400 : {
401 51037 : if (!g_tiertwo_sync_state.IsBlockchainSynced()) return true;
402 :
403 : // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
404 51036 : if (deterministicMNManager->LegacyMNObsolete()) {
405 19 : LogPrint(BCLog::MASTERNODE, "mnw - skip obsolete message %s\n", strCommand);
406 19 : return true;
407 : }
408 :
409 51017 : if (strCommand == NetMsgType::GETMNWINNERS) {
410 : //Masternode Payments Request Sync
411 264 : int nCountNeeded;
412 264 : vRecv >> nCountNeeded;
413 :
414 264 : 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 264 : g_netfulfilledman.AddFulfilledRequest(pfrom->addr, NetMsgType::GETMNWINNERS);
422 264 : Sync(pfrom, nCountNeeded);
423 264 : LogPrint(BCLog::MASTERNODE, "mnget - Sent Masternode winners to peer %i\n", pfrom->GetId());
424 50753 : } else if (strCommand == NetMsgType::MNWINNER) {
425 : //Masternode Payments Declare Winner
426 66 : CMasternodePaymentWinner winner;
427 33 : vRecv >> winner;
428 33 : if (pfrom->nVersion < ActiveProtocol()) return false;
429 :
430 33 : {
431 : // Clear inv request
432 33 : LOCK(cs_main);
433 33 : g_connman->RemoveAskFor(winner.GetHash(), MSG_MASTERNODE_WINNER);
434 : }
435 :
436 33 : ProcessMNWinner(winner, pfrom, state);
437 33 : return state.IsValid();
438 : }
439 :
440 : return true;
441 : }
442 :
443 933 : bool CMasternodePayments::ProcessMNWinner(CMasternodePaymentWinner& winner, CNode* pfrom, CValidationState& state)
444 : {
445 933 : int nHeight = mnodeman.GetBestHeight();
446 :
447 933 : 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 933 : int nFirstBlock = nHeight - (mnodeman.CountEnabled() * 1.25);
454 933 : if (winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > nHeight + 20) {
455 1 : LogPrint(BCLog::MASTERNODE, "mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, nHeight);
456 3 : return state.Error("block height out of range");
457 : }
458 :
459 : // reject old signature version
460 932 : 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 932 : const CMasternode* pmn{nullptr};
467 1865 : auto dmn = deterministicMNManager->GetListAtChainTip().GetMNByCollateral(winner.vinMasternode.prevout);
468 932 : if (dmn == nullptr) {
469 : // legacy masternode
470 905 : pmn = mnodeman.Find(winner.vinMasternode.prevout);
471 905 : if (pmn == nullptr) {
472 : // it could be a non-synced masternode. ask for the mnb
473 1 : 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 1 : if (pfrom && g_tiertwo_sync_state.IsMasternodeListSynced()) mnodeman.AskForMN(pfrom, winner.vinMasternode);
476 3 : return state.Error("Non-existent mnwinner voter");
477 : }
478 : }
479 : // either deterministic or legacy. not both
480 931 : assert((dmn && !pmn) || (!dmn && pmn));
481 :
482 : // See if the masternode is in the quorum (top-MNPAYMENTS_SIGNATURES_TOTAL)
483 931 : 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 923 : if (!CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)) {
490 0 : return state.Error("MN already voted");
491 : }
492 :
493 : // Check signature
494 923 : bool is_valid_sig = dmn ? winner.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())
495 923 : : winner.CheckSignature(pmn->pubKeyMasternode.GetID());
496 :
497 923 : if (!is_valid_sig) {
498 1 : LogPrint(BCLog::MASTERNODE, "%s : mnw - invalid signature for %s masternode: %s\n",
499 : __func__, (dmn ? "deterministic" : "legacy"), winner.vinMasternode.prevout.hash.ToString());
500 3 : return state.DoS(20, false, REJECT_INVALID, "invalid voter mnwinner signature");
501 : }
502 :
503 : // Record vote
504 922 : RecordWinnerVote(winner.vinMasternode.prevout, winner.nBlockHeight);
505 :
506 : // Add winner
507 922 : 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 922 : if (g_tiertwo_sync_state.IsSynced()) winner.Relay();
512 922 : g_tiertwo_sync_state.AddedMasternodeWinner(winner.GetHash());
513 :
514 : // valid
515 922 : return true;
516 : }
517 :
518 10010 : bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee) const
519 : {
520 10010 : const auto it = mapMasternodeBlocks.find(nBlockHeight);
521 10010 : if (it != mapMasternodeBlocks.end()) {
522 128 : 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 18 : bool CMasternodePayments::IsScheduled(const CMasternode& mn, int nNotBlockHeight)
531 : {
532 36 : LOCK(cs_mapMasternodeBlocks);
533 :
534 18 : int nHeight = mnodeman.GetBestHeight();
535 :
536 36 : const CScript& mnpayee = mn.GetPayeeScript();
537 36 : CScript payee;
538 156 : for (int64_t h = nHeight; h <= nHeight + 8; h++) {
539 148 : if (h == nNotBlockHeight) continue;
540 274 : if (mapMasternodeBlocks.count(h)) {
541 22 : if (mapMasternodeBlocks[h].GetPayee(payee)) {
542 22 : if (mnpayee == payee) {
543 : return true;
544 : }
545 : }
546 : }
547 : }
548 :
549 : return false;
550 : }
551 :
552 929 : void CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
553 : {
554 929 : {
555 1858 : LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
556 :
557 929 : mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;
558 :
559 1694 : if (!mapMasternodeBlocks.count(winnerIn.nBlockHeight)) {
560 328 : CMasternodeBlockPayees blockPayees(winnerIn.nBlockHeight);
561 164 : mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
562 : }
563 : }
564 :
565 929 : CTxDestination addr;
566 929 : ExtractDestination(winnerIn.payee, addr);
567 965 : LogPrint(BCLog::MASTERNODE, "mnw - Adding winner %s for block %d\n", EncodeDestination(addr), winnerIn.nBlockHeight);
568 929 : mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, 1);
569 929 : }
570 :
571 267 : bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
572 : {
573 534 : LOCK(cs_vecPayments);
574 :
575 : //require at least 6 signatures
576 267 : int nMaxSignatures = 0;
577 538 : for (CMasternodePayee& payee : vecPayments)
578 271 : 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 267 : if (nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true;
583 :
584 521 : 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 0 : std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
617 : {
618 0 : LOCK(cs_vecPayments);
619 :
620 0 : std::string ret = "";
621 :
622 0 : for (CMasternodePayee& payee : vecPayments) {
623 0 : CTxDestination address1;
624 0 : ExtractDestination(payee.scriptPubKey, address1);
625 0 : if (ret != "") {
626 0 : ret += ", ";
627 : }
628 0 : ret += EncodeDestination(address1) + ":" + std::to_string(payee.nVotes);
629 : }
630 :
631 0 : return ret.empty() ? "Unknown" : ret;
632 : }
633 :
634 0 : std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight)
635 : {
636 0 : LOCK(cs_mapMasternodeBlocks);
637 :
638 0 : if (mapMasternodeBlocks.count(nBlockHeight)) {
639 0 : return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
640 : }
641 :
642 0 : return "Unknown";
643 : }
644 :
645 6009 : bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, const CBlockIndex* pindexPrev)
646 : {
647 6009 : const int nBlockHeight = pindexPrev->nHeight + 1;
648 6009 : if (deterministicMNManager->LegacyMNObsolete(nBlockHeight)) {
649 904 : std::vector<CTxOut> vecMnOuts;
650 452 : if (!GetMasternodeTxOuts(pindexPrev, vecMnOuts)) {
651 : // No masternode scheduled to be paid.
652 : return true;
653 : }
654 :
655 872 : for (const CTxOut& o : vecMnOuts) {
656 438 : if (std::find(txNew.vout.begin(), txNew.vout.end(), o) == txNew.vout.end()) {
657 0 : CTxDestination mnDest;
658 0 : const std::string& payee = ExtractDestination(o.scriptPubKey, mnDest) ? EncodeDestination(mnDest)
659 0 : : HexStr(o.scriptPubKey);
660 0 : 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 0 : return false;
663 : }
664 : }
665 : // all the expected payees have been found in txNew outputs
666 434 : return true;
667 : }
668 :
669 : // Legacy payment logic. !TODO: remove when transition to DMN is complete
670 11566 : LOCK(cs_mapMasternodeBlocks);
671 :
672 10847 : if (mapMasternodeBlocks.count(nBlockHeight)) {
673 267 : return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew, nBlockHeight);
674 : }
675 :
676 : return true;
677 : }
678 :
679 1865 : void CMasternodePayments::CleanPaymentList(int mnCount, int nHeight)
680 : {
681 3730 : LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
682 :
683 : //keep up to five cycles for historical sake
684 1865 : int nLimit = std::max(int(mnCount * 1.25), 1000);
685 :
686 1865 : std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
687 2339 : while (it != mapMasternodePayeeVotes.end()) {
688 474 : CMasternodePaymentWinner winner = (*it).second;
689 :
690 474 : 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 474 : ++it;
697 : }
698 : }
699 1865 : }
700 :
701 21965 : void CMasternodePayments::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
702 : {
703 21965 : if (g_tiertwo_sync_state.GetSyncPhase() > MASTERNODE_SYNC_LIST) {
704 10961 : ProcessBlock(pindexNew->nHeight + 10);
705 : }
706 21965 : }
707 :
708 10961 : void CMasternodePayments::ProcessBlock(int nBlockHeight)
709 : {
710 : // No more mnw messages after transition to DMN
711 10961 : if (deterministicMNManager->LegacyMNObsolete(nBlockHeight)) {
712 10954 : return;
713 : }
714 10733 : if (!fMasterNode) return;
715 :
716 : // Get the active masternode (operator) key
717 144 : CTxIn mnVin;
718 144 : Optional<CKey> mnKey{nullopt};
719 144 : CBLSSecretKey blsKey;
720 137 : if (!GetActiveMasternodeKeys(mnVin, mnKey, blsKey)) {
721 130 : return;
722 : }
723 :
724 : //reference node - hybrid mode
725 130 : int n = mnodeman.GetMasternodeRank(mnVin, nBlockHeight - 100);
726 :
727 130 : if (n == -1) {
728 118 : LogPrintf("%s: ERROR: active masternode is not registered yet\n", __func__);
729 : return;
730 : }
731 :
732 12 : 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 12 : if (nBlockHeight <= nLastBlockHeight) return;
738 :
739 12 : if (g_budgetman.IsBudgetPaymentBlock(nBlockHeight)) {
740 : //is budget payment block -- handled by the budgeting software
741 : return;
742 : }
743 :
744 : // check winner height
745 12 : 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 12 : int nCount = 0;
752 19 : MasternodeRef pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount);
753 :
754 12 : if (pmn == nullptr) {
755 5 : LogPrintf("%s: Failed to find masternode to pay\n", __func__);
756 130 : return;
757 : }
758 :
759 14 : CMasternodePaymentWinner newWinner(mnVin, nBlockHeight);
760 14 : newWinner.AddPayee(pmn->GetPayeeScript());
761 7 : if (mnKey != nullopt) {
762 : // Legacy MN
763 10 : 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 2 : if (!newWinner.Sign(blsKey)) {
770 0 : LogPrintf("%s: Failed to sign masternode winner with DMN\n", __func__);
771 : return;
772 : }
773 : }
774 :
775 7 : AddWinningMasternode(newWinner);
776 7 : newWinner.Relay();
777 7 : LogPrintf("%s: Relayed winner %s\n", __func__, newWinner.GetHash().ToString());
778 7 : nLastBlockHeight = nBlockHeight;
779 : }
780 :
781 264 : void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
782 : {
783 264 : LOCK(cs_mapMasternodePayeeVotes);
784 :
785 264 : int nHeight = mnodeman.GetBestHeight();
786 264 : int nCount = (mnodeman.CountEnabled() * 1.25);
787 264 : if (nCountNeeded > nCount) nCountNeeded = nCount;
788 :
789 264 : int nInvCount = 0;
790 264 : std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
791 298 : while (it != mapMasternodePayeeVotes.end()) {
792 68 : CMasternodePaymentWinner winner = (*it).second;
793 34 : if (winner.nBlockHeight >= nHeight - nCountNeeded && winner.nBlockHeight <= nHeight + 20) {
794 12 : node->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash()));
795 12 : nInvCount++;
796 : }
797 34 : ++it;
798 : }
799 264 : g_connman->PushMessage(node, CNetMsgMaker(node->GetSendVersion()).Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_MNW, nInvCount));
800 264 : }
801 :
802 76 : std::string CMasternodePayments::ToString() const
803 : {
804 76 : std::ostringstream info;
805 :
806 76 : info << "Votes: " << (int)mapMasternodePayeeVotes.size() << ", Blocks: " << (int)mapMasternodeBlocks.size();
807 :
808 76 : return info.str();
809 : }
810 :
811 923 : bool CMasternodePayments::CanVote(const COutPoint& outMasternode, int nBlockHeight) const
812 : {
813 923 : LOCK(cs_mapMasternodePayeeVotes);
814 923 : const auto it = mapMasternodesLastVote.find(outMasternode);
815 1799 : return it == mapMasternodesLastVote.end() || it->second != nBlockHeight;
816 : }
817 :
818 922 : void CMasternodePayments::RecordWinnerVote(const COutPoint& outMasternode, int nBlockHeight)
819 : {
820 922 : LOCK(cs_mapMasternodePayeeVotes);
821 922 : mapMasternodesLastVote[outMasternode] = nBlockHeight;
822 922 : }
823 :
824 181 : bool IsCoinbaseValueValid(const CTransactionRef& tx, CAmount nBudgetAmt, CValidationState& _state)
825 : {
826 181 : assert(tx->IsCoinBase());
827 181 : if (g_tiertwo_sync_state.IsSynced()) {
828 164 : const CAmount nCBaseOutAmt = tx->GetValueOut();
829 164 : if (nBudgetAmt > 0) {
830 : // Superblock
831 7 : 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 157 : int nHeight = mnodeman.GetBestHeight();
840 157 : CAmount nMnAmt = GetMasternodePayment(nHeight);
841 : // if enforcement is disabled, there could be no masternode payment
842 157 : bool sporkEnforced = sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT);
843 157 : const std::string strError = strprintf("%s: invalid coinbase payment for masternode (%s vs expected=%s)",
844 471 : __func__, FormatMoney(nCBaseOutAmt), FormatMoney(nMnAmt));
845 157 : if (sporkEnforced && nCBaseOutAmt != nMnAmt) {
846 8 : return _state.DoS(100, error(strError.c_str()), REJECT_INVALID, "bad-cb-amt");
847 : }
848 153 : 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 : }
|