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

infernoman's avatar
infernoman committed
5
6
7
8
#include "throne-payments.h"
#include "throne-budget.h"
#include "throne-sync.h"
#include "throneman.h"
Alastair Clark's avatar
Alastair Clark committed
9
#include "legacysigner.h"
10
11
#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

/** Object for who's going to get paid on which blocks */
Alastair Clark's avatar
Alastair Clark committed
18
CMasternodePayments thronePayments;
19

20
CCriticalSection cs_vecPayments;
Alastair Clark's avatar
Alastair Clark committed
21
22
CCriticalSection cs_mapMasternodeBlocks;
CCriticalSection cs_mapMasternodePayeeVotes;
23

24
//
Alastair Clark's avatar
Alastair Clark committed
25
// CMasternodePaymentDB
26
27
//

Alastair Clark's avatar
Alastair Clark committed
28
CMasternodePaymentDB::CMasternodePaymentDB()
29
30
{
    pathDB = GetDataDir() / "mnpayments.dat";
Alastair Clark's avatar
Alastair Clark committed
31
    strMagicMessage = "MasternodePayments";
32
33
}

Alastair Clark's avatar
Alastair Clark committed
34
bool CMasternodePaymentDB::Write(const CMasternodePayments& objToSave)
35
36
37
38
39
{
    int64_t nStart = GetTimeMillis();

    // serialize, checksum data up to that point, then append checksum
    CDataStream ssObj(SER_DISK, CLIENT_VERSION);
infernoman's avatar
infernoman committed
40
    ssObj << strMagicMessage; // throne cache file specific magic message
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
    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;
}

Alastair Clark's avatar
Alastair Clark committed
66
CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& objToLoad, bool fDryRun)
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
{

    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 {
infernoman's avatar
infernoman committed
114
        // de-serialize file header (throne cache file specific magic message) and ..
115
116
117
118
119
        ssObj >> strMagicMessageTmp;

        // ... verify the message matches predefined one
        if (strMagicMessage != strMagicMessageTmp)
        {
infernoman's avatar
infernoman committed
120
            error("%s : Invalid throne payement cache magic message", __func__);
121
122
123
124
125
126
127
128
129
130
131
132
133
134
            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;
        }

Alastair Clark's avatar
Alastair Clark committed
135
        // de-serialize data into CMasternodePayments object
136
137
138
139
140
141
142
143
144
145
146
        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) {
Alastair Clark's avatar
Alastair Clark committed
147
        LogPrintf("Masternode payments manager - cleaning....\n");
148
        objToLoad.CleanPaymentList();
Alastair Clark's avatar
Alastair Clark committed
149
        LogPrintf("Masternode payments manager - result:\n");
150
151
152
153
154
155
        LogPrintf("  %s\n", objToLoad.ToString());
    }

    return Ok;
}

Alastair Clark's avatar
Alastair Clark committed
156
void DumpMasternodePayments()
157
158
159
{
    int64_t nStart = GetTimeMillis();

Alastair Clark's avatar
Alastair Clark committed
160
161
    CMasternodePaymentDB paymentdb;
    CMasternodePayments tempPayments;
162
163

    LogPrintf("Verifying mnpayments.dat format...\n");
Alastair Clark's avatar
Alastair Clark committed
164
    CMasternodePaymentDB::ReadResult readResult = paymentdb.Read(tempPayments, true);
165
    // there was an error and it was not an error on file opening => do not proceed
Alastair Clark's avatar
Alastair Clark committed
166
    if (readResult == CMasternodePaymentDB::FileError)
167
        LogPrintf("Missing budgets file - mnpayments.dat, will try to recreate\n");
Alastair Clark's avatar
Alastair Clark committed
168
    else if (readResult != CMasternodePaymentDB::Ok)
169
170
    {
        LogPrintf("Error reading mnpayments.dat: ");
Alastair Clark's avatar
Alastair Clark committed
171
        if(readResult == CMasternodePaymentDB::IncorrectFormat)
172
173
174
175
176
177
178
179
            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");
infernoman's avatar
infernoman committed
180
    paymentdb.Write(thronePayments);
181
182
183

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

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

189
190
191
192
193
194
195
196
197
198
199
200
201
202
    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");
    }

infernoman's avatar
infernoman committed
203
    if(!throneSync.IsSynced()) { //there is no budget data to use to check anything
204
        //super blocks will always be on these blocks, max 100 per budgeting
205
        if(nHeight % GetBudgetPaymentCycleBlocks() < 100){
206
207
            return true;
        } else {
208
            if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
209
        }
210
    } else { // we're synced and have data so check the budget schedule
Evan Duffield's avatar
Evan Duffield committed
211
212
213
214
215
216

        //are these blocks even enabled
        if(!IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
            return block.vtx[0].GetValueOut() <= nExpectedValue;
        }
        
217
        if(budget.IsBudgetPaymentBlock(nHeight)){
218
219
220
            //the value of the block is evaluated in CheckBlock
            return true;
        } else {
221
            if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
222
223
224
225
226
227
        }
    }

    return true;
}

UdjinM6's avatar
UdjinM6 committed
228
bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight)
229
{
infernoman's avatar
infernoman committed
230
    if(!throneSync.IsSynced()) { //there is no budget data to use to check anything -- find the longest chain
231
        LogPrint("mnpayments", "Client not synced, skipping block payee checks\n");
232
233
234
        return true;
    }

235
    //check if it's a budget block
236
237
238
    if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
        if(budget.IsBudgetPaymentBlock(nBlockHeight)){
            if(budget.IsTransactionValid(txNew, nBlockHeight)){
239
                return true;
240
241
            } else {
                LogPrintf("Invalid budget payment detected %s\n", txNew.ToString().c_str());
Alastair Clark's avatar
Alastair Clark committed
242
                if(IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)){
243
244
245
246
247
                    return false;
                } else {
                    LogPrintf("Budget enforcement is disabled, accepting block\n");
                    return true;
                }
248
            }
249
250
251
        }
    }

infernoman's avatar
infernoman committed
252
253
    //check for throne payee
    if(thronePayments.IsTransactionValid(txNew, nBlockHeight))
254
255
    {
        return true;
256
257
    } else {
        LogPrintf("Invalid mn payment detected %s\n", txNew.ToString().c_str());
Alastair Clark's avatar
Alastair Clark committed
258
        if(IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)){
259
260
            return false;
        } else {
Alastair Clark's avatar
Alastair Clark committed
261
            LogPrintf("Masternode payment enforcement is disabled, accepting block\n");
262
263
            return true;
        }
264
265
266
267
268
    }

    return false;
}

Alastair Clark's avatar
Alastair Clark committed
269
bool CMasternodePayments::CanVote(COutPoint outMasternode, int nBlockHeight)
270
{
Alastair Clark's avatar
Alastair Clark committed
271
    LOCK(cs_mapMasternodePayeeVotes);
272

Alastair Clark's avatar
Alastair Clark committed
273
    if (mapMasternodesLastVote.count(outMasternode) && mapMasternodesLastVote[outMasternode] == nBlockHeight) {
274
275
276
        return false;
    }

Infernoman's avatar
Infernoman committed
277
    //record this throne voted
Alastair Clark's avatar
Alastair Clark committed
278
    mapMasternodesLastVote[outMasternode] = nBlockHeight;
279
280
    return true;
}
281
282
283
284
285

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

287
    if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(pindexPrev->nHeight+1)){
288
289
        budget.FillBlockPayee(txNew, nFees);
    } else {
infernoman's avatar
infernoman committed
290
        thronePayments.FillBlockPayee(txNew, nFees);
291
292
293
    }
}

UdjinM6's avatar
UdjinM6 committed
294
std::string GetRequiredPaymentsString(int nBlockHeight)
295
{
296
    if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(nBlockHeight)){
297
298
        return budget.GetRequiredPaymentsString(nBlockHeight);
    } else {
infernoman's avatar
infernoman committed
299
        return thronePayments.GetRequiredPaymentsString(nBlockHeight);
300
301
302
    }
}

Alastair Clark's avatar
Alastair Clark committed
303
void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFees)
304
305
306
307
308
309
{
    CBlockIndex* pindexPrev = chainActive.Tip();
    if(!pindexPrev) return;

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

311
    //spork
infernoman's avatar
infernoman committed
312
313
    if(!thronePayments.GetBlockPayee(pindexPrev->nHeight+1, payee)){
        //no throne detected
Alastair Clark's avatar
Alastair Clark committed
314
        CMasternode* winningNode = mnodeman.GetCurrentMasterNode(1);
315
316
317
        if(winningNode){
            payee = GetScriptForDestination(winningNode->pubkey.GetID());
        } else {
infernoman's avatar
infernoman committed
318
            LogPrintf("CreateNewBlock: Failed to detect throne to pay\n");
319
320
321
322
323
            hasPayment = false;
        }
    }

    CAmount blockValue = GetBlockValue(pindexPrev->nBits, pindexPrev->nHeight, nFees);
Alastair Clark's avatar
Alastair Clark committed
324
    CAmount thronePayment = GetMasternodePayment(pindexPrev->nHeight+1, blockValue);
Evan Duffield's avatar
Evan Duffield committed
325

326
327
328
329
330
331
    txNew.vout[0].nValue = blockValue;

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

        txNew.vout[1].scriptPubKey = payee;
infernoman's avatar
infernoman committed
332
        txNew.vout[1].nValue = thronePayment;
333

infernoman's avatar
infernoman committed
334
        txNew.vout[0].nValue -= thronePayment;
335
336
337
338
339

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

Alastair Clark's avatar
Alastair Clark committed
340
        LogPrintf("Masternode payment to %s\n", address2.ToString().c_str());
341
342
343
    }
}

Alastair Clark's avatar
Alastair Clark committed
344
int CMasternodePayments::GetMinMasternodePaymentsProto() {
Alastair Clark's avatar
Alastair Clark committed
345
346
347
    return IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)
            ? MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2
            : MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1;
348
349
}

Alastair Clark's avatar
Alastair Clark committed
350
void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
351
{
infernoman's avatar
infernoman committed
352
    if(!throneSync.IsBlockchainSynced()) return;
353

Alastair Clark's avatar
Alastair Clark committed
354
    if(fLiteMode) return; //disable all Masternode related functionality
355
356


Alastair Clark's avatar
Alastair Clark committed
357
358
    if (strCommand == "mnget") { //Masternode Payments Request Sync
        if(fLiteMode) return; //disable all Masternode related functionality
359

360
361
362
        int nCountNeeded;
        vRecv >> nCountNeeded;

363
364
365
366
367
368
        if(Params().NetworkID() == CBaseChainParams::MAIN){
            if(pfrom->HasFulfilledRequest("mnget")) {
                LogPrintf("mnget - peer already asked me for the list\n");
                Misbehaving(pfrom->GetId(), 20);
                return;
            }
369
        }
370

371
        pfrom->FulfilledRequest("mnget");
infernoman's avatar
infernoman committed
372
        thronePayments.Sync(pfrom, nCountNeeded);
Alastair Clark's avatar
Alastair Clark committed
373
        LogPrintf("mnget - Sent Masternode winners to %s\n", pfrom->addr.ToString().c_str());
374
    }
Alastair Clark's avatar
Alastair Clark committed
375
    else if (strCommand == "mnw") { //Masternode Payments Declare Winner
376
        //this is required in litemodef
Alastair Clark's avatar
Alastair Clark committed
377
        CMasternodePaymentWinner winner;
378
379
        vRecv >> winner;

Evan Duffield's avatar
Evan Duffield committed
380
381
        if(pfrom->nVersion < MIN_MNW_PEER_PROTO_VERSION) return;

382
383
384
385
386
387
        int nHeight;
        {
            TRY_LOCK(cs_main, locked);
            if(!locked || chainActive.Tip() == NULL) return;
            nHeight = chainActive.Tip()->nHeight;
        }
388

Alastair Clark's avatar
Alastair Clark committed
389
        if(thronePayments.mapMasternodePayeeVotes.count(winner.GetHash())){
390
            LogPrint("mnpayments", "mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), nHeight);
Alastair Clark's avatar
Alastair Clark committed
391
            throneSync.AddedMasternodeWinner(winner.GetHash());
UdjinM6's avatar
UdjinM6 committed
392
            return;
393
394
        }

395
396
397
        int nFirstBlock = nHeight - (mnodeman.CountEnabled()*1.25);
        if(winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > nHeight+20){
            LogPrint("mnpayments", "mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, nHeight);
398
399
400
            return;
        }

401
        std::string strError = "";
402
        if(!winner.IsValid(pfrom, strError)){
403
            if(strError != "") LogPrintf("mnw - invalid message - %s\n", strError);
404
405
406
            return;
        }

Alastair Clark's avatar
Alastair Clark committed
407
408
        if(!thronePayments.CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)){
            LogPrintf("mnw - throne already voted - %s\n", winner.vinMasternode.prevout.ToStringShort());
Evan Duffield's avatar
Evan Duffield committed
409
410
411
            return;
        }

412
        if(!winner.SignatureValid()){
413
            LogPrintf("mnw - invalid signature\n");
infernoman's avatar
infernoman committed
414
415
            if(throneSync.IsSynced()) Misbehaving(pfrom->GetId(), 20);
            // it could just be a non-synced throne
Alastair Clark's avatar
Alastair Clark committed
416
            mnodeman.AskForMN(pfrom, winner.vinMasternode);
417
418
419
            return;
        }

420
        CTxDestination address1;
421
        ExtractDestination(winner.payee, address1);
422
423
        CBitcoinAddress address2(address1);

Alastair Clark's avatar
Alastair Clark committed
424
        LogPrint("mnpayments", "mnw - winning vote - Addr %s Height %d bestHeight %d - %s\n", address2.ToString().c_str(), winner.nBlockHeight, nHeight, winner.vinMasternode.prevout.ToStringShort());
425

Alastair Clark's avatar
Alastair Clark committed
426
        if(thronePayments.AddWinningMasternode(winner)){
427
            winner.Relay();
Alastair Clark's avatar
Alastair Clark committed
428
            throneSync.AddedMasternodeWinner(winner.GetHash());
429
430
431
432
        }
    }
}

Alastair Clark's avatar
Alastair Clark committed
433
bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
434
{
435
    std::string errorMessage;
Alastair Clark's avatar
Alastair Clark committed
436
    std::string strMasterNodeSignMessage;
437

Alastair Clark's avatar
Alastair Clark committed
438
    std::string strMessage =  vinMasternode.prevout.ToStringShort() +
Evan Duffield's avatar
Evan Duffield committed
439
                boost::lexical_cast<std::string>(nBlockHeight) +
440
                payee.ToString();
Evan Duffield's avatar
Evan Duffield committed
441

Alastair Clark's avatar
Alastair Clark committed
442
443
    if(!legacySigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) {
        LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
444
445
        return false;
    }
446

Alastair Clark's avatar
Alastair Clark committed
447
448
    if(!legacySigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) {
        LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
449
450
451
452
453
454
        return false;
    }

    return true;
}

Alastair Clark's avatar
Alastair Clark committed
455
bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
456
{
Alastair Clark's avatar
Alastair Clark committed
457
458
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].GetPayee(payee);
459
    }
460

461
462
    return false;
}
463

infernoman's avatar
infernoman committed
464
// Is this throne scheduled to get paid soon? 
465
// -- Only look ahead up to 8 blocks to allow for propagation of the latest 2 winners
Alastair Clark's avatar
Alastair Clark committed
466
bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight)
467
{
Alastair Clark's avatar
Alastair Clark committed
468
    LOCK(cs_mapMasternodeBlocks);
469

470
471
472
473
474
475
    int nHeight;
    {
        TRY_LOCK(cs_main, locked);
        if(!locked || chainActive.Tip() == NULL) return false;
        nHeight = chainActive.Tip()->nHeight;
    }
476
477
478
479
480

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

    CScript payee;
481
    for(int64_t h = nHeight; h <= nHeight+8; h++){
Evan Duffield's avatar
Evan Duffield committed
482
        if(h == nNotBlockHeight) continue;
Alastair Clark's avatar
Alastair Clark committed
483
484
        if(mapMasternodeBlocks.count(h)){
            if(mapMasternodeBlocks[h].GetPayee(payee)){
485
                if(mnpayee == payee) {
486
487
488
                    return true;
                }
            }
489
490
491
492
493
494
        }
    }

    return false;
}

Alastair Clark's avatar
Alastair Clark committed
495
bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
496
{
497
    uint256 blockHash = uint256();
498
    if(!GetBlockHash(blockHash, winnerIn.nBlockHeight-100)) {
499
500
501
        return false;
    }

502
    {
Alastair Clark's avatar
Alastair Clark committed
503
        LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
504
    
Alastair Clark's avatar
Alastair Clark committed
505
        if(mapMasternodePayeeVotes.count(winnerIn.GetHash())){
506
507
           return false;
        }
508

Alastair Clark's avatar
Alastair Clark committed
509
        mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;
510

Alastair Clark's avatar
Alastair Clark committed
511
512
513
        if(!mapMasternodeBlocks.count(winnerIn.nBlockHeight)){
           CMasternodeBlockPayees blockPayees(winnerIn.nBlockHeight);
           mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
514
        }
515
516
    }

517
    int n = 1;
Alastair Clark's avatar
Alastair Clark committed
518
519
    if(IsReferenceNode(winnerIn.vinMasternode)) n = 100;
    mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, n);
520

521
522
523
    return true;
}

Alastair Clark's avatar
Alastair Clark committed
524
bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
525
{
526
527
    LOCK(cs_vecPayments);

528
529
530
    int nMaxSignatures = 0;
    std::string strPayeesPossible = "";

Alastair Clark's avatar
Alastair Clark committed
531
    CAmount thronePayment = GetMasternodePayment(nBlockHeight, txNew.GetValueOut());
532

533
534
    //require at least 6 signatures

Alastair Clark's avatar
Alastair Clark committed
535
    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
UdjinM6's avatar
UdjinM6 committed
536
        if(payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED)
537
            nMaxSignatures = payee.nVotes;
Evan Duffield's avatar
Evan Duffield committed
538

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

Alastair Clark's avatar
Alastair Clark committed
542
    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
543
544
    {
        bool found = false;
Evan Duffield's avatar
Evan Duffield committed
545
        BOOST_FOREACH(CTxOut out, txNew.vout){
infernoman's avatar
infernoman committed
546
            if(payee.scriptPubKey == out.scriptPubKey && thronePayment == out.nValue){
547
                found = true;
Evan Duffield's avatar
Evan Duffield committed
548
549
            }
        }
550

Evan Duffield's avatar
Evan Duffield committed
551
        if(payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED){
552
            if(found) return true;
553

554
555
556
            CTxDestination address1;
            ExtractDestination(payee.scriptPubKey, address1);
            CBitcoinAddress address2(address1);
557

558
            if(strPayeesPossible == ""){
559
                strPayeesPossible += address2.ToString();
560
            } else {
561
                strPayeesPossible += "," + address2.ToString();
562
            }
563
564
        }
    }
565
566


Alastair Clark's avatar
Alastair Clark committed
567
    LogPrintf("CMasternodePayments::IsTransactionValid - Missing required payment - %s\n", strPayeesPossible.c_str());
568
    return false;
569
570
}

Alastair Clark's avatar
Alastair Clark committed
571
std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
572
{
573
574
    LOCK(cs_vecPayments);

575
576
    std::string ret = "Unknown";

Alastair Clark's avatar
Alastair Clark committed
577
    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
578
    {
579
580
581
        CTxDestination address1;
        ExtractDestination(payee.scriptPubKey, address1);
        CBitcoinAddress address2(address1);
582

583
        if(ret != "Unknown"){
584
            ret += ", " + address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
585
        } else {
Evan Duffield's avatar
Evan Duffield committed
586
            ret = address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
587
588
        }
    }
589

590
    return ret;
591
592
}

Alastair Clark's avatar
Alastair Clark committed
593
std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight)
594
{
Alastair Clark's avatar
Alastair Clark committed
595
    LOCK(cs_mapMasternodeBlocks);
596

Alastair Clark's avatar
Alastair Clark committed
597
598
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
599
600
    }

601
602
    return "Unknown";
}
603

Alastair Clark's avatar
Alastair Clark committed
604
bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
605
{
Alastair Clark's avatar
Alastair Clark committed
606
    LOCK(cs_mapMasternodeBlocks);
607

Alastair Clark's avatar
Alastair Clark committed
608
609
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew);
610
611
    }

612
    return true;
613
614
}

Alastair Clark's avatar
Alastair Clark committed
615
void CMasternodePayments::CleanPaymentList()
616
{
Alastair Clark's avatar
Alastair Clark committed
617
    LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
618

619
620
621
622
623
624
    int nHeight;
    {
        TRY_LOCK(cs_main, locked);
        if(!locked || chainActive.Tip() == NULL) return;
        nHeight = chainActive.Tip()->nHeight;
    }
625

626
    //keep up to five cycles for historical sake
Evan Duffield's avatar
Evan Duffield committed
627
    int nLimit = std::max(int(mnodeman.size()*1.25), 1000);
628

Alastair Clark's avatar
Alastair Clark committed
629
630
631
    std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
    while(it != mapMasternodePayeeVotes.end()) {
        CMasternodePaymentWinner winner = (*it).second;
Evan Duffield's avatar
Evan Duffield committed
632

633
        if(nHeight - winner.nBlockHeight > nLimit){
Alastair Clark's avatar
Alastair Clark committed
634
            LogPrint("mnpayments", "CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", winner.nBlockHeight);
infernoman's avatar
infernoman committed
635
            throneSync.mapSeenSyncMNW.erase((*it).first);
Alastair Clark's avatar
Alastair Clark committed
636
637
            mapMasternodePayeeVotes.erase(it++);
            mapMasternodeBlocks.erase(winner.nBlockHeight);
638
639
        } else {
            ++it;
640
        }
641
    }
642
643
}

644
bool IsReferenceNode(CTxIn& vin)
645
{
646
647
    //reference node - hybrid mode
    if(vin.prevout.ToStringShort() == "099c01bea63abd1692f60806bb646fa1d288e2d049281225f17e499024084e28-0") return true; // mainnet
648
649
    if(vin.prevout.ToStringShort() == "fbc16ae5229d6d99181802fd76a4feee5e7640164dcebc7f8feb04a7bea026f8-0") return true; // testnet
    if(vin.prevout.ToStringShort() == "e466f5d8beb4c2d22a314310dc58e0ea89505c95409754d0d68fb874952608cc-1") return true; // regtest
650

651
652
    return false;
}
653

Alastair Clark's avatar
Alastair Clark committed
654
bool CMasternodePaymentWinner::IsValid(CNode* pnode, std::string& strError)
655
{
Alastair Clark's avatar
Alastair Clark committed
656
    if(IsReferenceNode(vinMasternode)) return true;
657

Alastair Clark's avatar
Alastair Clark committed
658
    CMasternode* pmn = mnodeman.Find(vinMasternode);
659

660
    if(!pmn)
661
    {
Alastair Clark's avatar
Alastair Clark committed
662
663
664
        strError = strprintf("Unknown Masternode %s", vinMasternode.prevout.ToStringShort());
        LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
        mnodeman.AskForMN(pnode, vinMasternode);
665
        return false;
666
667
    }

668
    if(pmn->protocolVersion < MIN_MNW_PEER_PROTO_VERSION)
669
    {
Alastair Clark's avatar
Alastair Clark committed
670
671
        strError = strprintf("Masternode protocol too old %d - req %d", pmn->protocolVersion, MIN_MNW_PEER_PROTO_VERSION);
        LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
672
673
674
        return false;
    }

Alastair Clark's avatar
Alastair Clark committed
675
    int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight-100, MIN_MNW_PEER_PROTO_VERSION);
676

677
    if(n > MNPAYMENTS_SIGNATURES_TOTAL)
678
    {    
infernoman's avatar
infernoman committed
679
        //It's common to have thrones mistakenly think they are in the top 10
680
        // We don't want to print all of these messages, or punish them unless they're way off
681
        if(n > MNPAYMENTS_SIGNATURES_TOTAL*2)
682
        {
Alastair Clark's avatar
Alastair Clark committed
683
684
            strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL, n);
            LogPrintf("CMasternodePaymentWinner::IsValid - %s\n", strError);
infernoman's avatar
infernoman committed
685
            if(throneSync.IsSynced()) Misbehaving(pnode->GetId(), 20);
686
        }
687
688
689
690
691
692
        return false;
    }

    return true;
}

Alastair Clark's avatar
Alastair Clark committed
693
bool CMasternodePayments::ProcessBlock(int nBlockHeight)
694
{
Alastair Clark's avatar
Alastair Clark committed
695
    if(!fMasterNode) return false;
696
697
698

    //reference node - hybrid mode

Alastair Clark's avatar
Alastair Clark committed
699
700
    if(!IsReferenceNode(activeMasternode.vin)){
        int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight-100, MIN_MNW_PEER_PROTO_VERSION);
701

702
        if(n == -1)
703
        {
Alastair Clark's avatar
Alastair Clark committed
704
            LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Unknown Masternode\n");
705
            return false;
706
707
        }

708
        if(n > MNPAYMENTS_SIGNATURES_TOTAL)
709
        {
Alastair Clark's avatar
Alastair Clark committed
710
            LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
711
712
            return false;
        }
713
714
    }

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

Alastair Clark's avatar
Alastair Clark committed
717
    CMasternodePaymentWinner newWinner(activeMasternode.vin);
718

719
    if(budget.IsBudgetPaymentBlock(nBlockHeight)){
720
        //is budget payment block -- handled by the budgeting software
721
    } else {
Alastair Clark's avatar
Alastair Clark committed
722
        LogPrintf("CMasternodePayments::ProcessBlock() Start nHeight %d - vin %s. \n", nBlockHeight, activeMasternode.vin.ToString().c_str());
723
724

        // pay to the oldest MN that still had no payment but its input is old enough and it was active long enough
725
        int nCount = 0;
Alastair Clark's avatar
Alastair Clark committed
726
        CMasternode *pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount);
727
        
728
729
        if(pmn != NULL)
        {
Alastair Clark's avatar
Alastair Clark committed
730
            LogPrintf("CMasternodePayments::ProcessBlock() Found by FindOldestNotInVec \n");
731

732
            newWinner.nBlockHeight = nBlockHeight;
733

734
            CScript payee = GetScriptForDestination(pmn->pubkey.GetID());
735
            newWinner.AddPayee(payee);
Evan Duffield's avatar
Evan Duffield committed
736

737
738
739
            CTxDestination address1;
            ExtractDestination(payee, address1);
            CBitcoinAddress address2(address1);
740

Alastair Clark's avatar
Alastair Clark committed
741
            LogPrintf("CMasternodePayments::ProcessBlock() Winner payee %s nHeight %d. \n", address2.ToString().c_str(), newWinner.nBlockHeight);
742
        } else {
Alastair Clark's avatar
Alastair Clark committed
743
            LogPrintf("CMasternodePayments::ProcessBlock() Failed to find throne to pay\n");
744
        }
745

746
    }
747

748
    std::string errorMessage;
Alastair Clark's avatar
Alastair Clark committed
749
750
    CPubKey pubKeyMasternode;
    CKey keyMasternode;
751

Alastair Clark's avatar
Alastair Clark committed
752
    if(!legacySigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
753
    {
Alastair Clark's avatar
Alastair Clark committed
754
        LogPrintf("CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str());
755
756
        return false;
    }
757

Alastair Clark's avatar
Alastair Clark committed
758
759
    LogPrintf("CMasternodePayments::ProcessBlock() - Signing Winner\n");
    if(newWinner.Sign(keyMasternode, pubKeyMasternode))
760
    {
Alastair Clark's avatar
Alastair Clark committed
761
        LogPrintf("CMasternodePayments::ProcessBlock() - AddWinningMasternode\n");
Evan Duffield's avatar
Evan Duffield committed
762

Alastair Clark's avatar
Alastair Clark committed
763
        if(AddWinningMasternode(newWinner))
764
        {
765
            newWinner.Relay();
766
767
768
769
            nLastBlockHeight = nBlockHeight;
            return true;
        }
    }
770

771
772
773
    return false;
}

Alastair Clark's avatar
Alastair Clark committed
774
void CMasternodePaymentWinner::Relay()
775
{
Alastair Clark's avatar
Alastair Clark committed
776
    CInv inv(MSG_MASTERNODE_WINNER, GetHash());
UdjinM6's avatar
UdjinM6 committed
777
    RelayInv(inv);
778
779
}

Alastair Clark's avatar
Alastair Clark committed
780
bool CMasternodePaymentWinner::SignatureValid()
781
782
{

Alastair Clark's avatar
Alastair Clark committed
783
    CMasternode* pmn = mnodeman.Find(vinMasternode);
784

785
786
    if(pmn != NULL)
    {
Alastair Clark's avatar
Alastair Clark committed
787
        std::string strMessage =  vinMasternode.prevout.ToStringShort() +
Evan Duffield's avatar
Evan Duffield committed
788
                    boost::lexical_cast<std::string>(nBlockHeight) +
789
                    payee.ToString();
790

791
        std::string errorMessage = "";
Alastair Clark's avatar
renames    
Alastair Clark committed
792
        if(!legacySigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)){
Alastair Clark's avatar
Alastair Clark committed
793
            return error("CMasternodePaymentWinner::SignatureValid() - Got bad Masternode address signature %s \n", vinMasternode.ToString().c_str());
794
        }
795
796
797

        return true;
    }
798
799

    return false;
800
}
801

Alastair Clark's avatar
Alastair Clark committed
802
void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
803
{
Alastair Clark's avatar
Alastair Clark committed
804
    LOCK(cs_mapMasternodePayeeVotes);
805

806
807
808
809
810
811
    int nHeight;
    {
        TRY_LOCK(cs_main, locked);
        if(!locked || chainActive.Tip() == NULL) return;
        nHeight = chainActive.Tip()->nHeight;
    }
812

UdjinM6's avatar
UdjinM6 committed
813
    int nCount = (mnodeman.CountEnabled()*1.25);
814
    if(nCountNeeded > nCount) nCountNeeded = nCount;
815

816
    int nInvCount = 0;
Alastair Clark's avatar
Alastair Clark committed
817
818
819
    std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
    while(it != mapMasternodePayeeVotes.end()) {
        CMasternodePaymentWinner winner = (*it).second;
820
        if(winner.nBlockHeight >= nHeight-nCountNeeded && winner.nBlockHeight <= nHeight + 20) {
Alastair Clark's avatar
Alastair Clark committed
821
            node->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash()));
822
            nInvCount++;
Evan Duffield's avatar
Evan Duffield committed
823
        }
824
825
        ++it;
    }
Alastair Clark's avatar
Alastair Clark committed
826
    node->PushMessage("ssc", MASTERNODE_SYNC_MNW, nInvCount);
UdjinM6's avatar
UdjinM6 committed
827
}
828

Alastair Clark's avatar
Alastair Clark committed
829
std::string CMasternodePayments::ToString() const
830
831
832
{
    std::ostringstream info;

Alastair Clark's avatar
Alastair Clark committed
833
834
    info << "Votes: " << (int)mapMasternodePayeeVotes.size() <<
            ", Blocks: " << (int)mapMasternodeBlocks.size();
835
836
837
838
839

    return info.str();
}


Evan Duffield's avatar
Evan Duffield committed
840

Alastair Clark's avatar
Alastair Clark committed
841
int CMasternodePayments::GetOldestBlock()
Evan Duffield's avatar
Evan Duffield committed
842
{
Alastair Clark's avatar
Alastair Clark committed
843
    LOCK(cs_mapMasternodeBlocks);
Evan Duffield's avatar
Evan Duffield committed
844
845
846

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

Alastair Clark's avatar
Alastair Clark committed
847
848
    std::map<int, CMasternodeBlockPayees>::iterator it = mapMasternodeBlocks.begin();
    while(it != mapMasternodeBlocks.end()) {
Evan Duffield's avatar
Evan Duffield committed
849
850
851
852
853
854
855
856
857
858
859
        if((*it).first < nOldestBlock) {
            nOldestBlock = (*it).first;
        }
        it++;
    }

    return nOldestBlock;
}



Alastair Clark's avatar
Alastair Clark committed
860
int CMasternodePayments::GetNewestBlock()
861
{
Alastair Clark's avatar
Alastair Clark committed
862
    LOCK(cs_mapMasternodeBlocks);
863
864
865

    int nNewestBlock = 0;

Alastair Clark's avatar
Alastair Clark committed
866
867
    std::map<int, CMasternodeBlockPayees>::iterator it = mapMasternodeBlocks.begin();
    while(it != mapMasternodeBlocks.end()) {
868
869
870
871
872
873
874
875
        if((*it).first > nNewestBlock) {
            nNewestBlock = (*it).first;
        }
        it++;
    }

    return nNewestBlock;
}