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

Alastair Clark's avatar
Alastair Clark committed
6
7
8
9
#include "masternode-payments.h"
#include "masternode-budget.h"
#include "masternode-sync.h"
#include "masternodeman.h"
Alastair Clark's avatar
Alastair Clark committed
10
#include "legacysigner.h"
11
12
#include "util.h"
#include "sync.h"
13
#include "spork.h"
14
15
#include "addrman.h"
#include <boost/lexical_cast.hpp>
16
#include <boost/filesystem.hpp>
17
18

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

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

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

29
30
31
32
33
34
35
36
37
38
39
40
41
42
    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");
    }

Alastair Clark's avatar
Alastair Clark committed
43
    if(!masternodeSync.IsSynced()) { //there is no budget data to use to check anything
44
        //super blocks will always be on these blocks, max 100 per budgeting
Volodymyr Shamray's avatar
Volodymyr Shamray committed
45
        if(nHeight % GetBudgetPaymentCycleBlocks() < 100){
46
47
            return true;
        } else {
48
            if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
49
        }
50
    } else { // we're synced and have data so check the budget schedule
Evan Duffield's avatar
Evan Duffield committed
51
52
53
54
55
56

        //are these blocks even enabled
        if(!IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
            return block.vtx[0].GetValueOut() <= nExpectedValue;
        }
        
57
        if(budget.IsBudgetPaymentBlock(nHeight)){
58
59
60
            //the value of the block is evaluated in CheckBlock
            return true;
        } else {
61
            if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
62
63
64
65
66
67
        }
    }

    return true;
}

UdjinM6's avatar
UdjinM6 committed
68
bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight)
69
{
Alastair Clark's avatar
Alastair Clark committed
70
    if(!masternodeSync.IsSynced()) { //there is no budget data to use to check anything -- find the longest chain
71
        LogPrint("mnpayments", "Client not synced, skipping block payee checks\n");
72
73
74
        return true;
    }

75
    //check if it's a budget block
76
77
78
    if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
        if(budget.IsBudgetPaymentBlock(nBlockHeight)){
            if(budget.IsTransactionValid(txNew, nBlockHeight)){
79
                return true;
80
81
            } else {
                LogPrintf("Invalid budget payment detected %s\n", txNew.ToString().c_str());
Alastair Clark's avatar
Alastair Clark committed
82
                if(IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)){
83
84
85
86
87
                    return false;
                } else {
                    LogPrintf("Budget enforcement is disabled, accepting block\n");
                    return true;
                }
88
            }
89
90
91
        }
    }

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

    return false;
}

Alastair Clark's avatar
Alastair Clark committed
109
bool CMasternodePayments::CanVote(COutPoint outMasternode, int nBlockHeight)
110
{
Alastair Clark's avatar
Alastair Clark committed
111
    LOCK(cs_mapMasternodePayeeVotes);
112

Alastair Clark's avatar
Alastair Clark committed
113
    if (mapMasternodesLastVote.count(outMasternode) && mapMasternodesLastVote[outMasternode] == nBlockHeight) {
114
115
116
        return false;
    }

Alastair Clark's avatar
Alastair Clark committed
117
    //record this masternode voted
Alastair Clark's avatar
Alastair Clark committed
118
    mapMasternodesLastVote[outMasternode] = nBlockHeight;
119
120
    return true;
}
121
122
123
124
125

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

127
    if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(pindexPrev->nHeight+1)){
128
129
        budget.FillBlockPayee(txNew, nFees);
    } else {
Alastair Clark's avatar
Alastair Clark committed
130
        masternodePayments.FillBlockPayee(txNew, nFees);
131
132
133
    }
}

UdjinM6's avatar
UdjinM6 committed
134
std::string GetRequiredPaymentsString(int nBlockHeight)
135
{
136
    if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(nBlockHeight)){
137
138
        return budget.GetRequiredPaymentsString(nBlockHeight);
    } else {
Alastair Clark's avatar
Alastair Clark committed
139
        return masternodePayments.GetRequiredPaymentsString(nBlockHeight);
140
141
142
    }
}

Alastair Clark's avatar
Alastair Clark committed
143
void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFees)
144
145
146
147
148
149
{
    CBlockIndex* pindexPrev = chainActive.Tip();
    if(!pindexPrev) return;

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

151
    //spork
Alastair Clark's avatar
Alastair Clark committed
152
153
    if(!masternodePayments.GetBlockPayee(pindexPrev->nHeight+1, payee)){
        //no masternode detected
Alastair Clark's avatar
Alastair Clark committed
154
        CMasternode* winningNode = mnodeman.GetCurrentMasterNode(1);
155
156
157
        if(winningNode){
            payee = GetScriptForDestination(winningNode->pubkey.GetID());
        } else {
Alastair Clark's avatar
Alastair Clark committed
158
            LogPrintf("CreateNewBlock: Failed to detect masternode to pay\n");
159
160
161
162
            hasPayment = false;
        }
    }

163
    CAmount blockValue = GetBlockValue(pindexPrev->nHeight, nFees);
Alastair Clark's avatar
Alastair Clark committed
164
    CAmount masternodePayment = GetMasternodePayment(pindexPrev->nHeight+1, blockValue);
Evan Duffield's avatar
Evan Duffield committed
165

166
167
168
169
170
171
    txNew.vout[0].nValue = blockValue;

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

        txNew.vout[1].scriptPubKey = payee;
Alastair Clark's avatar
Alastair Clark committed
172
        txNew.vout[1].nValue = masternodePayment;
173

Alastair Clark's avatar
Alastair Clark committed
174
        txNew.vout[0].nValue -= masternodePayment;
175
176
177
178
179

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

Alastair Clark's avatar
Alastair Clark committed
180
        LogPrintf("Masternode payment to %s\n", address2.ToString().c_str());
181
182
183
    }
}

Alastair Clark's avatar
Alastair Clark committed
184
int CMasternodePayments::GetMinMasternodePaymentsProto() {
185
186
187
    return IsSporkActive(SPORK_10_MASTERNODE_DONT_PAY_OLD_NODES)
            ? MIN_MASTERNODE_PAYMENT_PROTO_VERSION_CURR
            : MIN_MASTERNODE_PAYMENT_PROTO_VERSION_PREV;
188
189
}

Alastair Clark's avatar
Alastair Clark committed
190
void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
191
{
Alastair Clark's avatar
Alastair Clark committed
192
    if(!masternodeSync.IsBlockchainSynced()) return;
193

Alastair Clark's avatar
Alastair Clark committed
194
    if(fLiteMode) return; //disable all Masternode related functionality
195
196


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

200
201
202
        int nCountNeeded;
        vRecv >> nCountNeeded;

203
204
205
206
207
208
        if(Params().NetworkID() == CBaseChainParams::MAIN){
            if(pfrom->HasFulfilledRequest("mnget")) {
                LogPrintf("mnget - peer already asked me for the list\n");
                Misbehaving(pfrom->GetId(), 20);
                return;
            }
209
        }
210

211
        pfrom->FulfilledRequest("mnget");
Alastair Clark's avatar
Alastair Clark committed
212
        masternodePayments.Sync(pfrom, nCountNeeded);
Alastair Clark's avatar
Alastair Clark committed
213
        LogPrintf("mnget - Sent Masternode winners to %s\n", pfrom->addr.ToString().c_str());
214
    }
Alastair Clark's avatar
Alastair Clark committed
215
    else if (strCommand == "mnw") { //Masternode Payments Declare Winner
216
        //this is required in litemodef
Alastair Clark's avatar
Alastair Clark committed
217
        CMasternodePaymentWinner winner;
218
219
        vRecv >> winner;

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

222
223
224
225
226
227
        int nHeight;
        {
            TRY_LOCK(cs_main, locked);
            if(!locked || chainActive.Tip() == NULL) return;
            nHeight = chainActive.Tip()->nHeight;
        }
228

Alastair Clark's avatar
Alastair Clark committed
229
        if(masternodePayments.mapMasternodePayeeVotes.count(winner.GetHash())){
230
            LogPrint("mnpayments", "mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), nHeight);
Alastair Clark's avatar
Alastair Clark committed
231
            masternodeSync.AddedMasternodeWinner(winner.GetHash());
UdjinM6's avatar
UdjinM6 committed
232
            return;
233
234
        }

235
236
237
        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);
238
239
240
            return;
        }

241
        std::string strError = "";
242
        if(!winner.IsValid(pfrom, strError)){
243
            if(strError != "") LogPrintf("mnw - invalid message - %s\n", strError);
244
245
246
            return;
        }

Alastair Clark's avatar
Alastair Clark committed
247
248
        if(!masternodePayments.CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)){
            LogPrintf("mnw - masternode already voted - %s\n", winner.vinMasternode.prevout.ToStringShort());
Evan Duffield's avatar
Evan Duffield committed
249
250
251
            return;
        }

252
        if(!winner.SignatureValid()){
253
            LogPrintf("mnw - invalid signature\n");
Alastair Clark's avatar
Alastair Clark committed
254
255
            if(masternodeSync.IsSynced()) Misbehaving(pfrom->GetId(), 20);
            // it could just be a non-synced masternode
Alastair Clark's avatar
Alastair Clark committed
256
            mnodeman.AskForMN(pfrom, winner.vinMasternode);
257
258
259
            return;
        }

260
        CTxDestination address1;
261
        ExtractDestination(winner.payee, address1);
262
263
        CBitcoinAddress address2(address1);

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

Alastair Clark's avatar
Alastair Clark committed
266
        if(masternodePayments.AddWinningMasternode(winner)){
267
            winner.Relay();
Alastair Clark's avatar
Alastair Clark committed
268
            masternodeSync.AddedMasternodeWinner(winner.GetHash());
269
270
271
272
        }
    }
}

Alastair Clark's avatar
Alastair Clark committed
273
bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
274
{
275
    std::string errorMessage;
Alastair Clark's avatar
Alastair Clark committed
276
    std::string strMasterNodeSignMessage;
277

Alastair Clark's avatar
Alastair Clark committed
278
    std::string strMessage =  vinMasternode.prevout.ToStringShort() +
Evan Duffield's avatar
Evan Duffield committed
279
                boost::lexical_cast<std::string>(nBlockHeight) +
280
                payee.ToString();
Evan Duffield's avatar
Evan Duffield committed
281

Alastair Clark's avatar
Alastair Clark committed
282
283
    if(!legacySigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) {
        LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
284
285
        return false;
    }
286

Alastair Clark's avatar
Alastair Clark committed
287
288
    if(!legacySigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) {
        LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
289
290
291
292
293
294
        return false;
    }

    return true;
}

Alastair Clark's avatar
Alastair Clark committed
295
bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
296
{
Alastair Clark's avatar
Alastair Clark committed
297
298
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].GetPayee(payee);
299
    }
300

301
302
    return false;
}
303

Alastair Clark's avatar
Alastair Clark committed
304
// Is this masternode scheduled to get paid soon? 
305
// -- Only look ahead up to 8 blocks to allow for propagation of the latest 2 winners
Alastair Clark's avatar
Alastair Clark committed
306
bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight)
307
{
Alastair Clark's avatar
Alastair Clark committed
308
    LOCK(cs_mapMasternodeBlocks);
309

310
311
312
313
314
315
    int nHeight;
    {
        TRY_LOCK(cs_main, locked);
        if(!locked || chainActive.Tip() == NULL) return false;
        nHeight = chainActive.Tip()->nHeight;
    }
316
317
318
319
320

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

    CScript payee;
321
    for(int64_t h = nHeight; h <= nHeight+8; h++){
Evan Duffield's avatar
Evan Duffield committed
322
        if(h == nNotBlockHeight) continue;
Alastair Clark's avatar
Alastair Clark committed
323
324
        if(mapMasternodeBlocks.count(h)){
            if(mapMasternodeBlocks[h].GetPayee(payee)){
325
                if(mnpayee == payee) {
326
327
328
                    return true;
                }
            }
329
330
331
332
333
334
        }
    }

    return false;
}

Alastair Clark's avatar
Alastair Clark committed
335
bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
336
{
337
    uint256 blockHash = uint256();
338
    if(!GetBlockHash(blockHash, winnerIn.nBlockHeight-100)) {
339
340
341
        return false;
    }

342
    {
Alastair Clark's avatar
Alastair Clark committed
343
        LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
344
    
Alastair Clark's avatar
Alastair Clark committed
345
        if(mapMasternodePayeeVotes.count(winnerIn.GetHash())){
346
347
           return false;
        }
348

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

Alastair Clark's avatar
Alastair Clark committed
351
352
353
        if(!mapMasternodeBlocks.count(winnerIn.nBlockHeight)){
           CMasternodeBlockPayees blockPayees(winnerIn.nBlockHeight);
           mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
354
        }
355
356
    }

357
    int n = 1;
Alastair Clark's avatar
Alastair Clark committed
358
359
    if(IsReferenceNode(winnerIn.vinMasternode)) n = 100;
    mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, n);
360

361
362
363
    return true;
}

Alastair Clark's avatar
Alastair Clark committed
364
bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
365
{
366
367
    LOCK(cs_vecPayments);

368
369
370
    int nMaxSignatures = 0;
    std::string strPayeesPossible = "";

Alastair Clark's avatar
Alastair Clark committed
371
    CAmount masternodePayment = GetMasternodePayment(nBlockHeight, txNew.GetValueOut());
372

373
374
    //require at least 6 signatures

Alastair Clark's avatar
Alastair Clark committed
375
    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
UdjinM6's avatar
UdjinM6 committed
376
        if(payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED)
377
            nMaxSignatures = payee.nVotes;
Evan Duffield's avatar
Evan Duffield committed
378

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

Alastair Clark's avatar
Alastair Clark committed
382
    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
383
384
    {
        bool found = false;
Evan Duffield's avatar
Evan Duffield committed
385
        BOOST_FOREACH(CTxOut out, txNew.vout){
Alastair Clark's avatar
Alastair Clark committed
386
            if(payee.scriptPubKey == out.scriptPubKey && masternodePayment == out.nValue){
387
                found = true;
Evan Duffield's avatar
Evan Duffield committed
388
389
            }
        }
390

Evan Duffield's avatar
Evan Duffield committed
391
        if(payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED){
392
            if(found) return true;
393

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

398
            if(strPayeesPossible == ""){
399
                strPayeesPossible += address2.ToString();
400
            } else {
401
                strPayeesPossible += "," + address2.ToString();
402
            }
403
404
        }
    }
405
406


Alastair Clark's avatar
Alastair Clark committed
407
    LogPrintf("CMasternodePayments::IsTransactionValid - Missing required payment - %s\n", strPayeesPossible.c_str());
408
    return false;
409
410
}

Alastair Clark's avatar
Alastair Clark committed
411
std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
412
{
413
414
    LOCK(cs_vecPayments);

415
416
    std::string ret = "Unknown";

Alastair Clark's avatar
Alastair Clark committed
417
    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
418
    {
419
420
421
        CTxDestination address1;
        ExtractDestination(payee.scriptPubKey, address1);
        CBitcoinAddress address2(address1);
422

423
        if(ret != "Unknown"){
424
            ret += ", " + address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
425
        } else {
Evan Duffield's avatar
Evan Duffield committed
426
            ret = address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
427
428
        }
    }
429

430
    return ret;
431
432
}

Alastair Clark's avatar
Alastair Clark committed
433
std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight)
434
{
Alastair Clark's avatar
Alastair Clark committed
435
    LOCK(cs_mapMasternodeBlocks);
436

Alastair Clark's avatar
Alastair Clark committed
437
438
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
439
440
    }

441
442
    return "Unknown";
}
443

Alastair Clark's avatar
Alastair Clark committed
444
bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
445
{
Alastair Clark's avatar
Alastair Clark committed
446
    LOCK(cs_mapMasternodeBlocks);
447

Alastair Clark's avatar
Alastair Clark committed
448
449
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew);
450
451
    }

452
    return true;
453
454
}

455
void CMasternodePayments::CheckAndRemove()
456
{
Alastair Clark's avatar
Alastair Clark committed
457
    LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
458

459
460
461
462
463
464
    int nHeight;
    {
        TRY_LOCK(cs_main, locked);
        if(!locked || chainActive.Tip() == NULL) return;
        nHeight = chainActive.Tip()->nHeight;
    }
465

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

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

473
        if(nHeight - winner.nBlockHeight > nLimit){
Alastair Clark's avatar
Alastair Clark committed
474
            LogPrint("mnpayments", "CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", winner.nBlockHeight);
Alastair Clark's avatar
Alastair Clark committed
475
            masternodeSync.mapSeenSyncMNW.erase((*it).first);
Alastair Clark's avatar
Alastair Clark committed
476
477
            mapMasternodePayeeVotes.erase(it++);
            mapMasternodeBlocks.erase(winner.nBlockHeight);
478
479
        } else {
            ++it;
480
        }
481
    }
482
483
}

484
bool IsReferenceNode(CTxIn& vin)
485
{
486
487
    //reference node - hybrid mode
    if(vin.prevout.ToStringShort() == "099c01bea63abd1692f60806bb646fa1d288e2d049281225f17e499024084e28-0") return true; // mainnet
488
489
    if(vin.prevout.ToStringShort() == "fbc16ae5229d6d99181802fd76a4feee5e7640164dcebc7f8feb04a7bea026f8-0") return true; // testnet
    if(vin.prevout.ToStringShort() == "e466f5d8beb4c2d22a314310dc58e0ea89505c95409754d0d68fb874952608cc-1") return true; // regtest
490

491
492
    return false;
}
493

Alastair Clark's avatar
Alastair Clark committed
494
bool CMasternodePaymentWinner::IsValid(CNode* pnode, std::string& strError)
495
{
Alastair Clark's avatar
Alastair Clark committed
496
    if(IsReferenceNode(vinMasternode)) return true;
497

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

500
    if(!pmn)
501
    {
Alastair Clark's avatar
Alastair Clark committed
502
503
504
        strError = strprintf("Unknown Masternode %s", vinMasternode.prevout.ToStringShort());
        LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
        mnodeman.AskForMN(pnode, vinMasternode);
505
        return false;
506
507
    }

508
    if(pmn->protocolVersion < MIN_MNW_PEER_PROTO_VERSION)
509
    {
Alastair Clark's avatar
Alastair Clark committed
510
511
        strError = strprintf("Masternode protocol too old %d - req %d", pmn->protocolVersion, MIN_MNW_PEER_PROTO_VERSION);
        LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
512
513
514
        return false;
    }

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

517
    if(n > MNPAYMENTS_SIGNATURES_TOTAL)
518
    {    
Alastair Clark's avatar
Alastair Clark committed
519
        //It's common to have masternodes mistakenly think they are in the top 10
520
        // We don't want to print all of these messages, or punish them unless they're way off
521
        if(n > MNPAYMENTS_SIGNATURES_TOTAL*2)
522
        {
Alastair Clark's avatar
Alastair Clark committed
523
524
            strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL, n);
            LogPrintf("CMasternodePaymentWinner::IsValid - %s\n", strError);
Alastair Clark's avatar
Alastair Clark committed
525
            if(masternodeSync.IsSynced()) Misbehaving(pnode->GetId(), 20);
526
        }
527
528
529
530
531
532
        return false;
    }

    return true;
}

Alastair Clark's avatar
Alastair Clark committed
533
bool CMasternodePayments::ProcessBlock(int nBlockHeight)
534
{
Alastair Clark's avatar
Alastair Clark committed
535
    if(!fMasterNode) return false;
536
537
538

    //reference node - hybrid mode

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

542
        if(n == -1)
543
        {
Alastair Clark's avatar
Alastair Clark committed
544
            LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Unknown Masternode\n");
545
            return false;
546
547
        }

548
        if(n > MNPAYMENTS_SIGNATURES_TOTAL)
549
        {
Alastair Clark's avatar
Alastair Clark committed
550
            LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
551
552
            return false;
        }
553
554
    }

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

Alastair Clark's avatar
Alastair Clark committed
557
    CMasternodePaymentWinner newWinner(activeMasternode.vin);
558

559
    if(budget.IsBudgetPaymentBlock(nBlockHeight)){
560
        //is budget payment block -- handled by the budgeting software
561
    } else {
Alastair Clark's avatar
Alastair Clark committed
562
        LogPrintf("CMasternodePayments::ProcessBlock() Start nHeight %d - vin %s. \n", nBlockHeight, activeMasternode.vin.ToString().c_str());
563
564

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

572
            newWinner.nBlockHeight = nBlockHeight;
573

574
            CScript payee = GetScriptForDestination(pmn->pubkey.GetID());
575
            newWinner.AddPayee(payee);
Evan Duffield's avatar
Evan Duffield committed
576

577
578
579
            CTxDestination address1;
            ExtractDestination(payee, address1);
            CBitcoinAddress address2(address1);
580

Alastair Clark's avatar
Alastair Clark committed
581
            LogPrintf("CMasternodePayments::ProcessBlock() Winner payee %s nHeight %d. \n", address2.ToString().c_str(), newWinner.nBlockHeight);
582
        } else {
Alastair Clark's avatar
Alastair Clark committed
583
            LogPrintf("CMasternodePayments::ProcessBlock() Failed to find masternode to pay\n");
584
        }
585

586
    }
587

588
    std::string errorMessage;
Alastair Clark's avatar
Alastair Clark committed
589
590
    CPubKey pubKeyMasternode;
    CKey keyMasternode;
591

Alastair Clark's avatar
Alastair Clark committed
592
    if(!legacySigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
593
    {
Alastair Clark's avatar
Alastair Clark committed
594
        LogPrintf("CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str());
595
596
        return false;
    }
597

Alastair Clark's avatar
Alastair Clark committed
598
599
    LogPrintf("CMasternodePayments::ProcessBlock() - Signing Winner\n");
    if(newWinner.Sign(keyMasternode, pubKeyMasternode))
600
    {
Alastair Clark's avatar
Alastair Clark committed
601
        LogPrintf("CMasternodePayments::ProcessBlock() - AddWinningMasternode\n");
Evan Duffield's avatar
Evan Duffield committed
602

Alastair Clark's avatar
Alastair Clark committed
603
        if(AddWinningMasternode(newWinner))
604
        {
605
            newWinner.Relay();
606
607
608
609
            nLastBlockHeight = nBlockHeight;
            return true;
        }
    }
610

611
612
613
    return false;
}

Alastair Clark's avatar
Alastair Clark committed
614
void CMasternodePaymentWinner::Relay()
615
{
Alastair Clark's avatar
Alastair Clark committed
616
    CInv inv(MSG_MASTERNODE_WINNER, GetHash());
UdjinM6's avatar
UdjinM6 committed
617
    RelayInv(inv);
618
619
}

Alastair Clark's avatar
Alastair Clark committed
620
bool CMasternodePaymentWinner::SignatureValid()
621
622
{

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

625
626
    if(pmn != NULL)
    {
Alastair Clark's avatar
Alastair Clark committed
627
        std::string strMessage =  vinMasternode.prevout.ToStringShort() +
Evan Duffield's avatar
Evan Duffield committed
628
                    boost::lexical_cast<std::string>(nBlockHeight) +
629
                    payee.ToString();
630

631
        std::string errorMessage = "";
Alastair Clark's avatar
renames    
Alastair Clark committed
632
        if(!legacySigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)){
Alastair Clark's avatar
Alastair Clark committed
633
            return error("CMasternodePaymentWinner::SignatureValid() - Got bad Masternode address signature %s \n", vinMasternode.ToString().c_str());
634
        }
635
636
637

        return true;
    }
638
639

    return false;
640
}
641

Alastair Clark's avatar
Alastair Clark committed
642
void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
643
{
Alastair Clark's avatar
Alastair Clark committed
644
    LOCK(cs_mapMasternodePayeeVotes);
645

646
647
648
649
650
651
    int nHeight;
    {
        TRY_LOCK(cs_main, locked);
        if(!locked || chainActive.Tip() == NULL) return;
        nHeight = chainActive.Tip()->nHeight;
    }
652

UdjinM6's avatar
UdjinM6 committed
653
    int nCount = (mnodeman.CountEnabled()*1.25);
654
    if(nCountNeeded > nCount) nCountNeeded = nCount;
655

656
    int nInvCount = 0;
Alastair Clark's avatar
Alastair Clark committed
657
658
659
    std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
    while(it != mapMasternodePayeeVotes.end()) {
        CMasternodePaymentWinner winner = (*it).second;
660
        if(winner.nBlockHeight >= nHeight-nCountNeeded && winner.nBlockHeight <= nHeight + 20) {
Alastair Clark's avatar
Alastair Clark committed
661
            node->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash()));
662
            nInvCount++;
Evan Duffield's avatar
Evan Duffield committed
663
        }
664
665
        ++it;
    }
Alastair Clark's avatar
Alastair Clark committed
666
    node->PushMessage("ssc", MASTERNODE_SYNC_MNW, nInvCount);
UdjinM6's avatar
UdjinM6 committed
667
}
668

Alastair Clark's avatar
Alastair Clark committed
669
std::string CMasternodePayments::ToString() const
670
671
672
{
    std::ostringstream info;

Alastair Clark's avatar
Alastair Clark committed
673
674
    info << "Votes: " << (int)mapMasternodePayeeVotes.size() <<
            ", Blocks: " << (int)mapMasternodeBlocks.size();
675
676
677
678
679

    return info.str();
}


Evan Duffield's avatar
Evan Duffield committed
680

Alastair Clark's avatar
Alastair Clark committed
681
int CMasternodePayments::GetOldestBlock()
Evan Duffield's avatar
Evan Duffield committed
682
{
Alastair Clark's avatar
Alastair Clark committed
683
    LOCK(cs_mapMasternodeBlocks);
Evan Duffield's avatar
Evan Duffield committed
684
685
686

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

Alastair Clark's avatar
Alastair Clark committed
687
688
    std::map<int, CMasternodeBlockPayees>::iterator it = mapMasternodeBlocks.begin();
    while(it != mapMasternodeBlocks.end()) {
Evan Duffield's avatar
Evan Duffield committed
689
690
691
692
693
694
695
696
697
698
699
        if((*it).first < nOldestBlock) {
            nOldestBlock = (*it).first;
        }
        it++;
    }

    return nOldestBlock;
}



Alastair Clark's avatar
Alastair Clark committed
700
int CMasternodePayments::GetNewestBlock()
701
{
Alastair Clark's avatar
Alastair Clark committed
702
    LOCK(cs_mapMasternodeBlocks);
703
704
705

    int nNewestBlock = 0;

Alastair Clark's avatar
Alastair Clark committed
706
707
    std::map<int, CMasternodeBlockPayees>::iterator it = mapMasternodeBlocks.begin();
    while(it != mapMasternodeBlocks.end()) {
708
709
710
711
712
713
714
715
        if((*it).first > nNewestBlock) {
            nNewestBlock = (*it).first;
        }
        it++;
    }

    return nNewestBlock;
}