masternode-payments.cpp 18.1 KB
Newer Older
1
2
3
4
5
// Copyright (c) 2014-2015 The Dash developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "masternode-payments.h"
6
#include "masternode-budget.h"
7
#include "masternode-sync.h"
8
9
10
11
#include "masternodeman.h"
#include "darksend.h"
#include "util.h"
#include "sync.h"
12
#include "spork.h"
13
14
15
16
17
18
19
#include "addrman.h"
#include <boost/lexical_cast.hpp>

CCriticalSection cs_masternodepayments;

/** Object for who's going to get paid on which blocks */
CMasternodePayments masternodePayments;
20
21
map<uint256, CMasternodePaymentWinner> mapMasternodePayeeVotes;
map<uint256, CMasternodeBlockPayees> mapMasternodeBlocks;
22

23
bool IsBlockValueValid(const CBlock& block, int64_t nExpectedValue){
24
25
26
    CBlockIndex* pindexPrev = chainActive.Tip();
    if(pindexPrev == NULL) return true;

27
28
29
30
31
32
33
34
35
36
37
38
39
40
    int nHeight = 0;
    if(pindexPrev->GetBlockHash() == block.hashPrevBlock)
    {
        nHeight = pindexPrev->nHeight+1;
    } else { //out of order
        BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
        if (mi != mapBlockIndex.end() && (*mi).second)
            nHeight = (*mi).second->nHeight+1;
    }

    if(nHeight == 0){
        LogPrintf("IsBlockValueValid() : WARNING: Couldn't find previous block");
    }

Evan Duffield's avatar
Evan Duffield committed
41
42
43
44
45
46
47
48
49
50
    //are these blocks even enabled?
    if(!IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
        if(block.vtx[0].GetValueOut() > nExpectedValue) {
            return false;
        } else {
            return true;
        }
    }

    if(!masternodeSync.IsSynced()) { //there is no budget data to use to check anything
51
        //super blocks will always be on these blocks, max 100 per budgeting
52
        if(nHeight % GetBudgetPaymentCycleBlocks() < 100){
53
54
            return true;
        } else {
55
            if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
56
        }
57
    } else { // we're synced and have data so check the budget schedule
58
        if(budget.IsBudgetPaymentBlock(nHeight)){
59
60
61
            //the value of the block is evaluated in CheckBlock
            return true;
        } else {
62
            if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
63
64
65
66
67
68
        }
    }

    return true;
}

69
70
71
bool IsBlockPayeeValid(const CTransaction& txNew, int64_t nBlockHeight)
{
    //check if it's a budget block
72
    if(budget.IsBudgetPaymentBlock(nBlockHeight)){
73
74
        if(budget.IsTransactionValid(txNew, nBlockHeight)){
            return true;
75
76
77
78
79
        } else {
            LogPrintf("Invalid budget payment detected %s\n", txNew.ToString().c_str());
            if(IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)){
                return false;
            } else {
UdjinM6's avatar
UdjinM6 committed
80
                LogPrintf("Budget enforcement is disabled, accepting block\n");
81
82
                return true;
            }
83
84
85
86
87
88
89
        }
    }

    //check for masternode payee
    if(masternodePayments.IsTransactionValid(txNew, nBlockHeight))
    {
        return true;
90
91
92
93
94
    } else {
        LogPrintf("Invalid mn payment detected %s\n", txNew.ToString().c_str());
        if(IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)){
            return false;
        } else {
UdjinM6's avatar
UdjinM6 committed
95
            LogPrintf("Masternode payment enforcement is disabled, accepting block\n");
96
97
            return true;
        }
98
99
100
101
102
    }

    return false;
}

103
104
105
106
107

void FillBlockPayee(CMutableTransaction& txNew, int64_t nFees)
{
    CBlockIndex* pindexPrev = chainActive.Tip();
    if(!pindexPrev) return;
Evan Duffield's avatar
Evan Duffield committed
108

109
110
111
112
113
114
115
    if(budget.IsBudgetPaymentBlock(pindexPrev->nHeight+1)){
        budget.FillBlockPayee(txNew, nFees);
    } else {
        masternodePayments.FillBlockPayee(txNew, nFees);
    }
}

116
117
118
119
120
121
122
123
124
std::string GetRequiredPaymentsString(int64_t nBlockHeight)
{
    if(budget.IsBudgetPaymentBlock(nBlockHeight)){
        return budget.GetRequiredPaymentsString(nBlockHeight);
    } else {
        return masternodePayments.GetRequiredPaymentsString(nBlockHeight);
    }
}

125
126
127
128
129
130
131
void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFees)
{
    CBlockIndex* pindexPrev = chainActive.Tip();
    if(!pindexPrev) return;

    bool hasPayment = true;
    CScript payee;
Evan Duffield's avatar
Evan Duffield committed
132

133
134
135
136
137
138
139
140
141
142
143
144
145
146
    //spork
    if(!masternodePayments.GetBlockPayee(pindexPrev->nHeight+1, payee)){
        //no masternode detected
        CMasternode* winningNode = mnodeman.GetCurrentMasterNode(1);
        if(winningNode){
            payee = GetScriptForDestination(winningNode->pubkey.GetID());
        } else {
            LogPrintf("CreateNewBlock: Failed to detect masternode to pay\n");
            hasPayment = false;
        }
    }

    CAmount blockValue = GetBlockValue(pindexPrev->nBits, pindexPrev->nHeight, nFees);
    CAmount masternodePayment = GetMasternodePayment(pindexPrev->nHeight+1, blockValue);
Evan Duffield's avatar
Evan Duffield committed
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
    txNew.vout[0].nValue = blockValue;

    if(hasPayment){
        txNew.vout.resize(2);

        txNew.vout[1].scriptPubKey = payee;
        txNew.vout[1].nValue = masternodePayment;

        txNew.vout[0].nValue -= masternodePayment;

        CTxDestination address1;
        ExtractDestination(payee, address1);
        CBitcoinAddress address2(address1);

        LogPrintf("Masternode payment to %s\n", address2.ToString().c_str());
    }
}

166
167
168
169
170
171
int CMasternodePayments::GetMinMasternodePaymentsProto() {
    return IsSporkActive(SPORK_10_MASTERNODE_PAY_NEWEST_NODES)
            ? MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2
            : MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1;
}

172
void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
173
174
175
176
177
178
{
    if(IsInitialBlockDownload()) return;

    if (strCommand == "mnget") { //Masternode Payments Request Sync
        if(fLiteMode) return; //disable all Darksend/Masternode related functionality

179
180
181
182
        if(pfrom->HasFulfilledRequest("mnget")) {
            LogPrintf("mnget - peer already asked me for the list\n");
            Misbehaving(pfrom->GetId(), 20);
            return;
183
        }
184
        
185
186
187
188
189
190
191
        pfrom->FulfilledRequest("mnget");
        masternodePayments.Sync(pfrom);
        LogPrintf("mnget - Sent Masternode winners to %s\n", pfrom->addr.ToString().c_str());
    }
    else if (strCommand == "mnw") { //Masternode Payments Declare Winner
        LOCK(cs_masternodepayments);

192
        //this is required in litemodef
193
194
195
196
197
        CMasternodePaymentWinner winner;
        vRecv >> winner;

        if(chainActive.Tip() == NULL) return;

198
199
        if(mapMasternodePayeeVotes.count(winner.GetHash())){
           if(fDebug) LogPrintf("mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), chainActive.Tip()->nHeight);
Evan Duffield's avatar
Evan Duffield committed
200
           return;
201
202
203
        }

        if(winner.nBlockHeight < chainActive.Tip()->nHeight - 10 || winner.nBlockHeight > chainActive.Tip()->nHeight+20){
204
            LogPrintf("mnw - winner out of range - Height %d bestHeight %d\n", winner.nBlockHeight, chainActive.Tip()->nHeight);
205
206
207
            return;
        }

208
209
        if(!winner.IsValid()){
            LogPrintf("mnw - invalid message\n");
210
211
212
            return;
        }

213
        if(!winner.SignatureValid()){
214
215
216
217
218
            LogPrintf("mnw - invalid signature\n");
            Misbehaving(pfrom->GetId(), 100);
            return;
        }

219
        CTxDestination address1;
220
        ExtractDestination(winner.payee, address1);
221
222
223
        CBitcoinAddress address2(address1);

        if(fDebug) LogPrintf("mnw - winning vote - Addr %s Height %d bestHeight %d\n", address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight);
224
225

        if(masternodePayments.AddWinningMasternode(winner)){
226
            winner.Relay();
227
            masternodeSync.AddedMasternodeWinner();
228
229
230
231
        }
    }
}

232
bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
233
{
234
235
236
237
    std::string errorMessage;
    std::string strMasterNodeSignMessage;

    std::string strMessage =  vinMasternode.prevout.ToStringShort() +
Evan Duffield's avatar
Evan Duffield committed
238
                boost::lexical_cast<std::string>(nBlockHeight) +
239
                payee.ToString();
Evan Duffield's avatar
Evan Duffield committed
240

241
242
243
244
    if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) {
        LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
        return false;
    }
245

246
247
    if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) {
        LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
248
249
250
251
252
253
        return false;
    }

    return true;
}

254
bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
255
{
256
    if(mapMasternodeBlocks.count(nBlockHeight)){
257
258
        return mapMasternodeBlocks[nBlockHeight].GetPayee(payee);
    }
259

260
261
    return false;
}
262

Evan Duffield's avatar
Evan Duffield committed
263
bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight)
264
265
266
267
268
269
270
271
272
{
    CBlockIndex* pindexPrev = chainActive.Tip();
    if(pindexPrev == NULL) return false;

    CScript mnpayee;
    mnpayee = GetScriptForDestination(mn.pubkey.GetID());

    CScript payee;
    for(int64_t h = pindexPrev->nHeight; h <= pindexPrev->nHeight+10; h++){
Evan Duffield's avatar
Evan Duffield committed
273
        if(h == nNotBlockHeight) continue;
274
        if(mapMasternodeBlocks.count(h)){
275
            if(mapMasternodeBlocks[h].GetPayee(payee)){
276
                if(mnpayee == payee) {
277
278
279
                    return true;
                }
            }
280
281
282
283
284
285
        }
    }

    return false;
}

286
287
288
bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
{
    uint256 blockHash = 0;
289
    if(!GetBlockHash(blockHash, winnerIn.nBlockHeight-100)) {
290
291
292
        return false;
    }

293
    if(mapMasternodePayeeVotes.count(winnerIn.GetHash())){
Evan Duffield's avatar
Evan Duffield committed
294
       return false;
295
296
    }

297
298
299
    mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;

    if(!mapMasternodeBlocks.count(winnerIn.nBlockHeight)){
300
       CMasternodeBlockPayees blockPayees(winnerIn.nBlockHeight);
301
       mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
302
303
    }

304
305
    int n = 1;
    if(IsReferenceNode(winnerIn.vinMasternode)) n = 100;
306
    mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, n);
307

308
309
310
    return true;
}

311
bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
312
{
313
314
315
    int nMaxSignatures = 0;
    std::string strPayeesPossible = "";

316
317
    CAmount masternodePayment = GetMasternodePayment(nBlockHeight, txNew.GetValueOut());

318
319
320
    //require at least 6 signatures

    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
UdjinM6's avatar
UdjinM6 committed
321
        if(payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED)
322
            nMaxSignatures = payee.nVotes;
Evan Duffield's avatar
Evan Duffield committed
323

324
    // if we don't have at least 6 signatures on a payee, approve whichever is the longest chain
325
    if(nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true;
326
327

    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
328
329
    {
        bool found = false;
Evan Duffield's avatar
Evan Duffield committed
330
        BOOST_FOREACH(CTxOut out, txNew.vout){
331
            if(payee.scriptPubKey == out.scriptPubKey && masternodePayment == out.nValue){
332
                found = true;
Evan Duffield's avatar
Evan Duffield committed
333
334
            }
        }
335

Evan Duffield's avatar
Evan Duffield committed
336
        if(payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED){
337
            if(found) return true;
338

339
340
341
            CTxDestination address1;
            ExtractDestination(payee.scriptPubKey, address1);
            CBitcoinAddress address2(address1);
342

343
            if(strPayeesPossible == ""){
344
                strPayeesPossible += address2.ToString();
345
            } else {
346
                strPayeesPossible += "," + address2.ToString();
347
            }
348
349
        }
    }
350
351
352
353


    LogPrintf("CMasternodePayments::IsTransactionValid - Missing required payment - %s\n", strPayeesPossible.c_str());
    return false;
354
355
}

356
std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
357
{
358
359
    std::string ret = "Unknown";

360
    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
361
    {
362
363
364
        CTxDestination address1;
        ExtractDestination(payee.scriptPubKey, address1);
        CBitcoinAddress address2(address1);
365

366
        if(ret != "Unknown"){
367
            ret += ", " + address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
368
        } else {
Evan Duffield's avatar
Evan Duffield committed
369
            ret = address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
370
371
        }
    }
372

373
    return ret;
374
375
}

376
std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight)
377
{
378
379
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
380
381
    }

382
383
    return "Unknown";
}
384

385
386
387
388
bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
{
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew);
389
390
    }

391
    return true;
392
393
394
395
396
397
398
399
400
401
}

void CMasternodePayments::CleanPaymentList()
{
    LOCK(cs_masternodepayments);

    if(chainActive.Tip() == NULL) return;

    int nLimit = std::max(((int)mnodeman.size())*2, 1000);

402
403
404
    std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
    while(it != mapMasternodePayeeVotes.end()) {
        CMasternodePaymentWinner winner = (*it).second;
Evan Duffield's avatar
Evan Duffield committed
405

406
407
408
409
410
        if(chainActive.Tip()->nHeight - winner.nBlockHeight > nLimit){
            if(fDebug) LogPrintf("CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", winner.nBlockHeight);
            mapMasternodePayeeVotes.erase(it++);
        } else {
            ++it;
411
        }
412
    }
413
414
}

415
bool IsReferenceNode(CTxIn& vin)
416
{
417
418
    //reference node - hybrid mode
    if(vin.prevout.ToStringShort() == "099c01bea63abd1692f60806bb646fa1d288e2d049281225f17e499024084e28-0") return true; // mainnet
419
420
    if(vin.prevout.ToStringShort() == "fbc16ae5229d6d99181802fd76a4feee5e7640164dcebc7f8feb04a7bea026f8-0") return true; // testnet
    if(vin.prevout.ToStringShort() == "e466f5d8beb4c2d22a314310dc58e0ea89505c95409754d0d68fb874952608cc-1") return true; // regtest
421

422
423
    return false;
}
424

425
426
427
bool CMasternodePaymentWinner::IsValid()
{
    if(IsReferenceNode(vinMasternode)) return true;
428

Evan Duffield's avatar
Evan Duffield committed
429
    int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight-100, masternodePayments.GetMinMasternodePaymentsProto());
430

431
    if(n == -1)
432
    {
Evan Duffield's avatar
Evan Duffield committed
433
        LogPrintf("CMasternodePaymentWinner::IsValid - Unknown Masternode - %s\n", vinMasternode.ToString().c_str());
434
        return false;
435
436
    }

437
    if(n > MNPAYMENTS_SIGNATURES_TOTAL)
438
    {
439
        LogPrintf("CMasternodePaymentWinner::IsValid - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
440
441
442
443
444
445
446
447
448
        return false;
    }

    return true;
}

bool CMasternodePayments::ProcessBlock(int nBlockHeight)
{
    LOCK(cs_masternodepayments);
449

450
451
452
453
454
    if(!fMasterNode) return false;

    //reference node - hybrid mode

    if(!IsReferenceNode(activeMasternode.vin)){
455
        int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight-100, GetMinMasternodePaymentsProto());
456
457
458
459
460

        if(n == -1)
        {
            if(fDebug) LogPrintf("CMasternodePayments::ProcessBlock - Unknown Masternode\n");
            return false;
461
462
        }

463
464
465
466
467
        if(n > MNPAYMENTS_SIGNATURES_TOTAL)
        {
            if(fDebug) LogPrintf("CMasternodePayments::ProcessBlock - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
            return false;
        }
468
469
    }

470
    if(nBlockHeight <= nLastBlockHeight) return false;
Evan Duffield's avatar
Evan Duffield committed
471

472
    CMasternodePaymentWinner newWinner(activeMasternode.vin);
473

474
    if(budget.IsBudgetPaymentBlock(nBlockHeight)){
475
        //is budget payment block -- handled by the budgeting software
476
    } else {
477
        uint256 hash;
Evan Duffield's avatar
Evan Duffield committed
478

479
        if(!GetBlockHash(hash, nBlockHeight-100)) return false;
480
481
482
        unsigned int nHash;
        memcpy(&nHash, &hash, 2);

Evan Duffield's avatar
Evan Duffield committed
483
        LogPrintf("CMasternodePayments::ProcessBlock() Start nHeight %d - vin %s. \n", nBlockHeight, activeMasternode.vin.ToString().c_str());
484
485

        // pay to the oldest MN that still had no payment but its input is old enough and it was active long enough
Evan Duffield's avatar
Evan Duffield committed
486
        CMasternode *pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight);
487
488
        if(pmn != NULL)
        {
Evan Duffield's avatar
Evan Duffield committed
489
            LogPrintf("CMasternodePayments::ProcessBlock() Found by FindOldestNotInVec \n");
490

491
            newWinner.nBlockHeight = nBlockHeight;
492

493
            CScript payee = GetScriptForDestination(pmn->pubkey.GetID());
494
            newWinner.AddPayee(payee);
Evan Duffield's avatar
Evan Duffield committed
495

496
497
498
            CTxDestination address1;
            ExtractDestination(payee, address1);
            CBitcoinAddress address2(address1);
499

500
            LogPrintf("CMasternodePayments::ProcessBlock() Winner payee %s nHeight %d. \n", address2.ToString().c_str(), newWinner.nBlockHeight);
501
        } else {
Evan Duffield's avatar
Evan Duffield committed
502
            LogPrintf("CMasternodePayments::ProcessBlock() Failed to find masternode to pay\n");
503
        }
504

505
    }
506

507
508
509
    std::string errorMessage;
    CPubKey pubKeyMasternode;
    CKey keyMasternode;
510

511
512
513
514
515
    if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
    {
        LogPrintf("CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str());
        return false;
    }
516

Evan Duffield's avatar
Evan Duffield committed
517
    LogPrintf("CMasternodePayments::ProcessBlock() - Signing Winner\n");
518
    if(newWinner.Sign(keyMasternode, pubKeyMasternode))
519
    {
Evan Duffield's avatar
Evan Duffield committed
520
521
        LogPrintf("CMasternodePayments::ProcessBlock() - AddWinningMasternode\n");

522
523
        if(AddWinningMasternode(newWinner))
        {
524
            newWinner.Relay();
525
526
527
528
            nLastBlockHeight = nBlockHeight;
            return true;
        }
    }
529

530
531
532
    return false;
}

533
void CMasternodePaymentWinner::Relay()
534
{
535
    CInv inv(MSG_MASTERNODE_WINNER, GetHash());
UdjinM6's avatar
UdjinM6 committed
536
    RelayInv(inv);
537
538
}

539
bool CMasternodePaymentWinner::SignatureValid()
540
541
{

542
    CMasternode* pmn = mnodeman.Find(vinMasternode);
543

544
545
546
    if(pmn != NULL)
    {
        std::string strMessage =  vinMasternode.prevout.ToStringShort() +
Evan Duffield's avatar
Evan Duffield committed
547
                    boost::lexical_cast<std::string>(nBlockHeight) +
548
                    payee.ToString();
549
550


551
552
553
554
        std::string errorMessage = "";
        if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)){
            return error("CMasternodePaymentWinner::SignatureValid() - Got bad Masternode address signature %s \n", vinMasternode.ToString().c_str());
        }
555
556
557

        return true;
    }
558
559

    return false;
560
}
561
562
563
564

void CMasternodePayments::Sync(CNode* node)
{
    LOCK(cs_masternodepayments);
565
566
567
568
569
570

    if(chainActive.Tip() == NULL) return;

    std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
    while(it != mapMasternodePayeeVotes.end()) {
        CMasternodePaymentWinner winner = (*it).second;
571
        if(winner.nBlockHeight >= chainActive.Tip()->nHeight-10 && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20)
572
573
574
            node->PushMessage("mnw", winner);
        ++it;
    }
UdjinM6's avatar
UdjinM6 committed
575
}