masternode-payments.cpp 25.7 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
#include "addrman.h"
#include <boost/lexical_cast.hpp>
15
#include <boost/filesystem.hpp>
16
17
18
19
20

CCriticalSection cs_masternodepayments;

/** Object for who's going to get paid on which blocks */
CMasternodePayments masternodePayments;
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

//
// CMasternodePaymentDB
//

CMasternodePaymentDB::CMasternodePaymentDB()
{
    pathDB = GetDataDir() / "mnpayments.dat";
    strMagicMessage = "MasternodePayments";
}

bool CMasternodePaymentDB::Write(const CMasternodePayments& objToSave)
{
    int64_t nStart = GetTimeMillis();

    // serialize, checksum data up to that point, then append checksum
    CDataStream ssObj(SER_DISK, CLIENT_VERSION);
    ssObj << strMagicMessage; // masternode cache file specific magic message
    ssObj << FLATDATA(Params().MessageStart()); // network specific magic number
    ssObj << objToSave;
    uint256 hash = Hash(ssObj.begin(), ssObj.end());
    ssObj << hash;

    // open output file, and associate with CAutoFile
    FILE *file = fopen(pathDB.string().c_str(), "wb");
    CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
    if (fileout.IsNull())
        return error("%s : Failed to open file %s", __func__, pathDB.string());

    // Write and commit header, data
    try {
        fileout << ssObj;
    }
    catch (std::exception &e) {
        return error("%s : Serialize or I/O error - %s", __func__, e.what());
    }
    fileout.fclose();

    LogPrintf("Written info to mnpayments.dat  %dms\n", GetTimeMillis() - nStart);

    return true;
}

CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& objToLoad, bool fDryRun)
{

    int64_t nStart = GetTimeMillis();
    // open input file, and associate with CAutoFile
    FILE *file = fopen(pathDB.string().c_str(), "rb");
    CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
    if (filein.IsNull())
    {
        error("%s : Failed to open file %s", __func__, pathDB.string());
        return FileError;
    }

    // use file size to size memory buffer
    int fileSize = boost::filesystem::file_size(pathDB);
    int dataSize = fileSize - sizeof(uint256);
    // Don't try to resize to a negative number if file is small
    if (dataSize < 0)
        dataSize = 0;
    vector<unsigned char> vchData;
    vchData.resize(dataSize);
    uint256 hashIn;

    // read data and checksum from file
    try {
        filein.read((char *)&vchData[0], dataSize);
        filein >> hashIn;
    }
    catch (std::exception &e) {
        error("%s : Deserialize or I/O error - %s", __func__, e.what());
        return HashReadError;
    }
    filein.fclose();

    CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION);

    // verify stored checksum matches input data
    uint256 hashTmp = Hash(ssObj.begin(), ssObj.end());
    if (hashIn != hashTmp)
    {
        error("%s : Checksum mismatch, data corrupted", __func__);
        return IncorrectHash;
    }


    unsigned char pchMsgTmp[4];
    std::string strMagicMessageTmp;
    try {
        // de-serialize file header (masternode cache file specific magic message) and ..
        ssObj >> strMagicMessageTmp;

        // ... verify the message matches predefined one
        if (strMagicMessage != strMagicMessageTmp)
        {
            error("%s : Invalid masternode payement cache magic message", __func__);
            return IncorrectMagicMessage;
        }


        // de-serialize file header (network specific magic number) and ..
        ssObj >> FLATDATA(pchMsgTmp);

        // ... verify the network matches ours
        if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
        {
            error("%s : Invalid network magic number", __func__);
            return IncorrectMagicNumber;
        }

        // de-serialize data into CMasternodePayments object
        ssObj >> objToLoad;
    }
    catch (std::exception &e) {
        objToLoad.Clear();
        error("%s : Deserialize or I/O error - %s", __func__, e.what());
        return IncorrectFormat;
    }

    LogPrintf("Loaded info from mnpayments.dat  %dms\n", GetTimeMillis() - nStart);
    LogPrintf("  %s\n", objToLoad.ToString());
    if(!fDryRun) {
        LogPrintf("Masternode payments manager - cleaning....\n");
        objToLoad.CleanPaymentList();
        LogPrintf("Masternode payments manager - result:\n");
        LogPrintf("  %s\n", objToLoad.ToString());
    }

    return Ok;
}

void DumpMasternodePayments()
{
    int64_t nStart = GetTimeMillis();

    CMasternodePaymentDB paymentdb;
    CMasternodePayments tempPayments;

    LogPrintf("Verifying mnpayments.dat format...\n");
    CMasternodePaymentDB::ReadResult readResult = paymentdb.Read(tempPayments, true);
    // there was an error and it was not an error on file opening => do not proceed
    if (readResult == CMasternodePaymentDB::FileError)
        LogPrintf("Missing budgets file - mnpayments.dat, will try to recreate\n");
    else if (readResult != CMasternodePaymentDB::Ok)
    {
        LogPrintf("Error reading mnpayments.dat: ");
        if(readResult == CMasternodePaymentDB::IncorrectFormat)
            LogPrintf("magic is ok but data has invalid format, will try to recreate\n");
        else
        {
            LogPrintf("file format is unknown or invalid, please fix it manually\n");
            return;
        }
    }
    LogPrintf("Writting info to mnpayments.dat...\n");
    paymentdb.Write(masternodePayments);

    LogPrintf("Budget dump finished  %dms\n", GetTimeMillis() - nStart);
}
182

183
bool IsBlockValueValid(const CBlock& block, int64_t nExpectedValue){
184
185
186
    CBlockIndex* pindexPrev = chainActive.Tip();
    if(pindexPrev == NULL) return true;

187
188
189
190
191
192
193
194
195
196
197
198
199
200
    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
201
202
    //are these blocks even enabled?
    if(!IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
UdjinM6's avatar
UdjinM6 committed
203
        return block.vtx[0].GetValueOut() > nExpectedValue;
Evan Duffield's avatar
Evan Duffield committed
204
205
206
    }

    if(!masternodeSync.IsSynced()) { //there is no budget data to use to check anything
207
        //super blocks will always be on these blocks, max 100 per budgeting
208
        if(nHeight % GetBudgetPaymentCycleBlocks() < 100){
209
210
            return true;
        } else {
211
            if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
212
        }
213
    } else { // we're synced and have data so check the budget schedule
214
        if(budget.IsBudgetPaymentBlock(nHeight)){
215
216
217
            //the value of the block is evaluated in CheckBlock
            return true;
        } else {
218
            if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
219
220
221
222
223
224
        }
    }

    return true;
}

UdjinM6's avatar
UdjinM6 committed
225
bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight)
226
{
227
    if(!masternodeSync.IsSynced()) { //there is no budget data to use to check anything -- find the longest chain
Evan Duffield's avatar
Evan Duffield committed
228
        if(fDebug) LogPrintf("Client not synced, skipping block payee checks\n");
229
230
231
        return true;
    }

232
    //check if it's a budget block
233
    if(budget.IsBudgetPaymentBlock(nBlockHeight)){
234
235
        if(budget.IsTransactionValid(txNew, nBlockHeight)){
            return true;
236
237
238
239
240
        } 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
241
                LogPrintf("Budget enforcement is disabled, accepting block\n");
242
243
                return true;
            }
244
245
246
247
248
249
250
        }
    }

    //check for masternode payee
    if(masternodePayments.IsTransactionValid(txNew, nBlockHeight))
    {
        return true;
251
252
253
254
255
    } 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
256
            LogPrintf("Masternode payment enforcement is disabled, accepting block\n");
257
258
            return true;
        }
259
260
261
262
263
    }

    return false;
}

264
265
266
267
268

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

270
271
272
273
274
275
276
    if(budget.IsBudgetPaymentBlock(pindexPrev->nHeight+1)){
        budget.FillBlockPayee(txNew, nFees);
    } else {
        masternodePayments.FillBlockPayee(txNew, nFees);
    }
}

UdjinM6's avatar
UdjinM6 committed
277
std::string GetRequiredPaymentsString(int nBlockHeight)
278
279
280
281
282
283
284
285
{
    if(budget.IsBudgetPaymentBlock(nBlockHeight)){
        return budget.GetRequiredPaymentsString(nBlockHeight);
    } else {
        return masternodePayments.GetRequiredPaymentsString(nBlockHeight);
    }
}

286
287
288
289
290
291
292
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
293

294
295
296
297
298
299
300
301
302
303
304
305
306
307
    //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
308

309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
    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());
    }
}

327
int CMasternodePayments::GetMinMasternodePaymentsProto() {
328
329
330
    return IsSporkActive(SPORK_10_MASTERNODE_PAY_NEWEST_NODES)
            ? MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2
            : MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1;
331
332
}

333
void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
334
335
336
337
338
339
{
    if(IsInitialBlockDownload()) return;

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

340
341
342
        int nCountNeeded;
        vRecv >> nCountNeeded;

343
344
345
346
347
348
        if(Params().NetworkID() == CBaseChainParams::MAIN){
            if(pfrom->HasFulfilledRequest("mnget")) {
                LogPrintf("mnget - peer already asked me for the list\n");
                Misbehaving(pfrom->GetId(), 20);
                return;
            }
349
        }
350

351
        pfrom->FulfilledRequest("mnget");
352
        masternodePayments.Sync(pfrom, nCountNeeded);
353
354
355
        LogPrintf("mnget - Sent Masternode winners to %s\n", pfrom->addr.ToString().c_str());
    }
    else if (strCommand == "mnw") { //Masternode Payments Declare Winner
Evan Duffield's avatar
Evan Duffield committed
356
357
        // disabled due to locking issues
        //LOCK(cs_masternodepayments);
358

359
        //this is required in litemodef
360
361
362
363
364
        CMasternodePaymentWinner winner;
        vRecv >> winner;

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

365
        if(masternodePayments.mapMasternodePayeeVotes.count(winner.GetHash())){
366
           if(fDebug) LogPrintf("mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), chainActive.Tip()->nHeight);
367
           masternodeSync.AddedMasternodeWinner();
Evan Duffield's avatar
Evan Duffield committed
368
           return;
369
370
        }

371
        int nFirstBlock = chainActive.Tip()->nHeight - (mnodeman.CountEnabled()*2);
372
373
        if(winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > chainActive.Tip()->nHeight+20){
            LogPrintf("mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, chainActive.Tip()->nHeight);
374
375
376
            return;
        }

377
378
379
        std::string strError = "";
        if(!winner.IsValid(strError)){
            LogPrintf("mnw - invalid message - %s\n", strError);
380
381
382
            return;
        }

Evan Duffield's avatar
Evan Duffield committed
383
384
385
386
387
        if(!masternodePayments.CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)){
            LogPrintf("mnw - masternode already voted - %s\n", winner.vinMasternode.prevout.ToStringShort());
            return;
        }

388
        if(!winner.SignatureValid()){
389
390
391
392
393
            LogPrintf("mnw - invalid signature\n");
            Misbehaving(pfrom->GetId(), 100);
            return;
        }

394
        CTxDestination address1;
395
        ExtractDestination(winner.payee, address1);
396
397
        CBitcoinAddress address2(address1);

Evan Duffield's avatar
Evan Duffield committed
398
        if(fDebug) LogPrintf("mnw - winning vote - Addr %s Height %d bestHeight %d - %s\n", address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight, winner.vinMasternode.prevout.ToStringShort());
399
400

        if(masternodePayments.AddWinningMasternode(winner)){
401
            winner.Relay();
402
            masternodeSync.AddedMasternodeWinner();
403
404
405
406
        }
    }
}

407
bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
408
{
409
410
411
412
    std::string errorMessage;
    std::string strMasterNodeSignMessage;

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

416
417
418
419
    if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) {
        LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
        return false;
    }
420

421
422
    if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) {
        LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
423
424
425
426
427
428
        return false;
    }

    return true;
}

429
bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
430
{
431
    if(mapMasternodeBlocks.count(nBlockHeight)){
432
433
        return mapMasternodeBlocks[nBlockHeight].GetPayee(payee);
    }
434

435
436
    return false;
}
437

438
// Is this masternode scheduled to get paid soon? 
439
// -- Only look ahead up to 8 blocks to allow for propagation of the latest 2 winners
Evan Duffield's avatar
Evan Duffield committed
440
bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight)
441
442
443
444
445
446
447
448
{
    CBlockIndex* pindexPrev = chainActive.Tip();
    if(pindexPrev == NULL) return false;

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

    CScript payee;
449
    for(int64_t h = pindexPrev->nHeight; h <= pindexPrev->nHeight+8; h++){
Evan Duffield's avatar
Evan Duffield committed
450
        if(h == nNotBlockHeight) continue;
451
        if(mapMasternodeBlocks.count(h)){
452
            if(mapMasternodeBlocks[h].GetPayee(payee)){
453
                if(mnpayee == payee) {
454
455
456
                    return true;
                }
            }
457
458
459
460
461
462
        }
    }

    return false;
}

463
464
465
bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
{
    uint256 blockHash = 0;
466
    if(!GetBlockHash(blockHash, winnerIn.nBlockHeight-100)) {
467
468
469
        return false;
    }

470
    if(mapMasternodePayeeVotes.count(winnerIn.GetHash())){
Evan Duffield's avatar
Evan Duffield committed
471
       return false;
472
473
    }

474
475
476
    mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;

    if(!mapMasternodeBlocks.count(winnerIn.nBlockHeight)){
477
       CMasternodeBlockPayees blockPayees(winnerIn.nBlockHeight);
478
       mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
479
480
    }

481
482
    int n = 1;
    if(IsReferenceNode(winnerIn.vinMasternode)) n = 100;
483
    mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, n);
484

485
486
487
    return true;
}

488
bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
489
{
490
491
492
    int nMaxSignatures = 0;
    std::string strPayeesPossible = "";

493
494
    CAmount masternodePayment = GetMasternodePayment(nBlockHeight, txNew.GetValueOut());

495
496
497
    //require at least 6 signatures

    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
UdjinM6's avatar
UdjinM6 committed
498
        if(payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED)
499
            nMaxSignatures = payee.nVotes;
Evan Duffield's avatar
Evan Duffield committed
500

501
    // if we don't have at least 6 signatures on a payee, approve whichever is the longest chain
502
    if(nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true;
503
504

    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
505
506
    {
        bool found = false;
Evan Duffield's avatar
Evan Duffield committed
507
        BOOST_FOREACH(CTxOut out, txNew.vout){
508
            if(payee.scriptPubKey == out.scriptPubKey && masternodePayment == out.nValue){
509
                found = true;
Evan Duffield's avatar
Evan Duffield committed
510
511
            }
        }
512

Evan Duffield's avatar
Evan Duffield committed
513
        if(payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED){
514
            if(found) return true;
515

516
517
518
            CTxDestination address1;
            ExtractDestination(payee.scriptPubKey, address1);
            CBitcoinAddress address2(address1);
519

520
            if(strPayeesPossible == ""){
521
                strPayeesPossible += address2.ToString();
522
            } else {
523
                strPayeesPossible += "," + address2.ToString();
524
            }
525
526
        }
    }
527
528
529
530


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

533
std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
534
{
535
536
    std::string ret = "Unknown";

537
    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
538
    {
539
540
541
        CTxDestination address1;
        ExtractDestination(payee.scriptPubKey, address1);
        CBitcoinAddress address2(address1);
542

543
        if(ret != "Unknown"){
544
            ret += ", " + address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
545
        } else {
Evan Duffield's avatar
Evan Duffield committed
546
            ret = address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
547
548
        }
    }
549

550
    return ret;
551
552
}

553
std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight)
554
{
555
556
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
557
558
    }

559
560
    return "Unknown";
}
561

562
563
564
565
bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
{
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew);
566
567
    }

568
    return true;
569
570
571
572
573
574
575
576
}

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

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

577
578
    //keep up to five cycles for historical sake
    int nLimit = std::max(((int)mnodeman.size())*5, 1000);
579

580
581
582
    std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
    while(it != mapMasternodePayeeVotes.end()) {
        CMasternodePaymentWinner winner = (*it).second;
Evan Duffield's avatar
Evan Duffield committed
583

584
585
586
587
588
        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;
589
        }
590
    }
591
592
}

593
bool IsReferenceNode(CTxIn& vin)
594
{
595
596
    //reference node - hybrid mode
    if(vin.prevout.ToStringShort() == "099c01bea63abd1692f60806bb646fa1d288e2d049281225f17e499024084e28-0") return true; // mainnet
597
598
    if(vin.prevout.ToStringShort() == "fbc16ae5229d6d99181802fd76a4feee5e7640164dcebc7f8feb04a7bea026f8-0") return true; // testnet
    if(vin.prevout.ToStringShort() == "e466f5d8beb4c2d22a314310dc58e0ea89505c95409754d0d68fb874952608cc-1") return true; // regtest
599

600
601
    return false;
}
602

603
bool CMasternodePaymentWinner::IsValid(std::string& strError)
604
605
{
    if(IsReferenceNode(vinMasternode)) return true;
606

607
    CMasternode* pmn = mnodeman.Find(vinMasternode);
608

609
    if(!pmn)
610
    {
611
612
        strError = strprintf("Unknown Masternode %s", vinMasternode.prevout.ToStringShort());
        LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
613
        return false;
614
615
    }

616
    if(pmn->protocolVersion < MIN_MNW_PEER_PROTO_VERSION)
617
    {
618
        strError = strprintf("Masternode protocol too old %d - req %d", pmn->protocolVersion, MIN_MNW_PEER_PROTO_VERSION);
619
620
621
622
        LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
        return false;
    }

623
    int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight-100, MIN_MNW_PEER_PROTO_VERSION);
624

625
    if(n > MNPAYMENTS_SIGNATURES_TOTAL)
626
    {
627
628
        strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL, n);
        LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
629
630
631
632
633
634
635
636
637
        return false;
    }

    return true;
}

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

639
640
641
642
643
    if(!fMasterNode) return false;

    //reference node - hybrid mode

    if(!IsReferenceNode(activeMasternode.vin)){
644
        int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight-100, GetMinMasternodePaymentsProto());
645
646
647
648
649

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

652
653
654
655
656
        if(n > MNPAYMENTS_SIGNATURES_TOTAL)
        {
            if(fDebug) LogPrintf("CMasternodePayments::ProcessBlock - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
            return false;
        }
657
658
    }

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

661
    CMasternodePaymentWinner newWinner(activeMasternode.vin);
662

663
    if(budget.IsBudgetPaymentBlock(nBlockHeight)){
664
        //is budget payment block -- handled by the budgeting software
665
    } else {
666
        uint256 hash;
Evan Duffield's avatar
Evan Duffield committed
667

668
        if(!GetBlockHash(hash, nBlockHeight-100)) return false;
669
670
671
        unsigned int nHash;
        memcpy(&nHash, &hash, 2);

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

        // 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
675
        CMasternode *pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight);
676
677
        if(pmn != NULL)
        {
Evan Duffield's avatar
Evan Duffield committed
678
            LogPrintf("CMasternodePayments::ProcessBlock() Found by FindOldestNotInVec \n");
679

680
            newWinner.nBlockHeight = nBlockHeight;
681

682
            CScript payee = GetScriptForDestination(pmn->pubkey.GetID());
683
            newWinner.AddPayee(payee);
Evan Duffield's avatar
Evan Duffield committed
684

685
686
687
            CTxDestination address1;
            ExtractDestination(payee, address1);
            CBitcoinAddress address2(address1);
688

689
            LogPrintf("CMasternodePayments::ProcessBlock() Winner payee %s nHeight %d. \n", address2.ToString().c_str(), newWinner.nBlockHeight);
690
        } else {
Evan Duffield's avatar
Evan Duffield committed
691
            LogPrintf("CMasternodePayments::ProcessBlock() Failed to find masternode to pay\n");
692
        }
693

694
    }
695

696
697
698
    std::string errorMessage;
    CPubKey pubKeyMasternode;
    CKey keyMasternode;
699

700
701
702
703
704
    if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
    {
        LogPrintf("CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str());
        return false;
    }
705

Evan Duffield's avatar
Evan Duffield committed
706
    LogPrintf("CMasternodePayments::ProcessBlock() - Signing Winner\n");
707
    if(newWinner.Sign(keyMasternode, pubKeyMasternode))
708
    {
Evan Duffield's avatar
Evan Duffield committed
709
710
        LogPrintf("CMasternodePayments::ProcessBlock() - AddWinningMasternode\n");

711
712
        if(AddWinningMasternode(newWinner))
        {
713
            newWinner.Relay();
714
715
716
717
            nLastBlockHeight = nBlockHeight;
            return true;
        }
    }
718

719
720
721
    return false;
}

722
void CMasternodePaymentWinner::Relay()
723
{
724
    CInv inv(MSG_MASTERNODE_WINNER, GetHash());
UdjinM6's avatar
UdjinM6 committed
725
    RelayInv(inv);
726
727
}

728
bool CMasternodePaymentWinner::SignatureValid()
729
730
{

731
    CMasternode* pmn = mnodeman.Find(vinMasternode);
732

733
734
735
    if(pmn != NULL)
    {
        std::string strMessage =  vinMasternode.prevout.ToStringShort() +
Evan Duffield's avatar
Evan Duffield committed
736
                    boost::lexical_cast<std::string>(nBlockHeight) +
737
                    payee.ToString();
738

739
740
741
742
        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());
        }
743
744
745

        return true;
    }
746
747

    return false;
748
}
749

750
void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
751
752
{
    LOCK(cs_masternodepayments);
753
754
755

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

756
    int nCount = (mnodeman.CountEnabled()*2);
757
758
    if(nCountNeeded > nCount) nCountNeeded = nCount;

759
760
761
    std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
    while(it != mapMasternodePayeeVotes.end()) {
        CMasternodePaymentWinner winner = (*it).second;
Evan Duffield's avatar
Evan Duffield committed
762
763
764
765
        if(winner.nBlockHeight >= chainActive.Tip()->nHeight-nCountNeeded && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20) {
            CInv inv(MSG_MASTERNODE_WINNER, winner.GetHash());
            RelayInv(inv);
        }
766
767
        ++it;
    }
UdjinM6's avatar
UdjinM6 committed
768
}
769
770
771
772
773
774
775
776
777
778
779
780

std::string CMasternodePayments::ToString() const
{
    std::ostringstream info;

    info << "Votes: " << (int)mapMasternodePayeeVotes.size() <<
            ", Blocks: " << (int)mapMasternodeBlocks.size();

    return info.str();
}


Evan Duffield's avatar
Evan Duffield committed
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800

int CMasternodePayments::GetOldestBlock()
{
    LOCK(cs_masternodepayments);

    int nOldestBlock = std::numeric_limits<int>::max();

    std::map<int, CMasternodeBlockPayees>::iterator it = mapMasternodeBlocks.begin();
    while(it != mapMasternodeBlocks.end()) {
        if((*it).first < nOldestBlock) {
            nOldestBlock = (*it).first;
        }
        it++;
    }

    return nOldestBlock;
}



801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
int CMasternodePayments::GetNewestBlock()
{
    LOCK(cs_masternodepayments);

    int nNewestBlock = 0;

    std::map<int, CMasternodeBlockPayees>::iterator it = mapMasternodeBlocks.begin();
    while(it != mapMasternodeBlocks.end()) {
        if((*it).first > nNewestBlock) {
            nNewestBlock = (*it).first;
        }
        it++;
    }

    return nNewestBlock;
}