"src/git@gitlab.crownplatform.com:nihilian/crown-core.git" did not exist on "bba9f1f5be3e57b6588b71ebe0e189a85c33eeee"
masternode-payments.cpp 14.8 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
8
9
10
11
12
13
14
15
16
17
#include "masternodeman.h"
#include "darksend.h"
#include "util.h"
#include "sync.h"
#include "addrman.h"
#include <boost/lexical_cast.hpp>

CCriticalSection cs_masternodepayments;

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

21
22
23
bool IsBlockPayeeValid(const CTransaction& txNew, int64_t nBlockHeight)
{
    //check if it's a budget block
24
    if(budget.IsBudgetPaymentBlock(nBlockHeight)){
25
26
27
28
29
30
31
32
33
34
35
36
37
38
        if(budget.IsTransactionValid(txNew, nBlockHeight)){
            return true;
        }
    }

    //check for masternode payee
    if(masternodePayments.IsTransactionValid(txNew, nBlockHeight))
    {
        return true;
    }

    return false;
}

39
40
41
42
43
44
45
46
47
std::string GetRequiredPaymentsString(int64_t nBlockHeight)
{
    if(budget.IsBudgetPaymentBlock(nBlockHeight)){
        return budget.GetRequiredPaymentsString(nBlockHeight);
    } else {
        return masternodePayments.GetRequiredPaymentsString(nBlockHeight);
    }
}

48
void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
{
    if(IsInitialBlockDownload()) return;

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

        if(pfrom->HasFulfilledRequest("mnget")) {
            LogPrintf("mnget - peer already asked me for the list\n");
            Misbehaving(pfrom->GetId(), 20);
            return;
        }

        pfrom->FulfilledRequest("mnget");
        masternodePayments.Sync(pfrom);
        LogPrintf("mnget - Sent Masternode winners to %s\n", pfrom->addr.ToString().c_str());
    }
    else if (strCommand == "mnw") { //Masternode Payments Declare Winner
        LOCK(cs_masternodepayments);

68
        //this is required in litemodef
69
70
71
72
73
        CMasternodePaymentWinner winner;
        vRecv >> winner;

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

74
75
76
        if(mapMasternodePayeeVotes.count(winner.GetHash())){
           if(fDebug) LogPrintf("mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), chainActive.Tip()->nHeight);
           return; 
77
78
79
        }

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

84
85
        if(!winner.IsValid()){
            LogPrintf("mnw - invalid message\n");
86
87
88
            return;
        }

89
        if(!winner.SignatureValid()){
90
91
92
93
94
            LogPrintf("mnw - invalid signature\n");
            Misbehaving(pfrom->GetId(), 100);
            return;
        }

95
96
97
98
99
        CTxDestination address1;
        ExtractDestination(winner.payee.scriptPubKey, address1);
        CBitcoinAddress address2(address1);

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

        if(masternodePayments.AddWinningMasternode(winner)){
102
            winner.Relay();
103
104
105
106
        }
    }
}

107
bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
108
{
109
110
111
112
113
114
115
116
117
118
119
    std::string errorMessage;
    std::string strMasterNodeSignMessage;

    std::string strMessage =  vinMasternode.prevout.ToStringShort() +
                boost::lexical_cast<std::string>(nBlockHeight) + 
                payee.ToString();
                
    if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) {
        LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
        return false;
    }
120

121
122
    if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) {
        LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
123
124
125
126
127
128
        return false;
    }

    return true;
}

129
bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
130
{
131
132
133
    if(!mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].GetPayee(payee);
    }
134

135
136
    return false;
}
137

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
bool CMasternodePayments::IsScheduled(CMasternode& mn)
{
    CBlockIndex* pindexPrev = chainActive.Tip();
    if(pindexPrev == NULL) return false;

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

    CScript payee;
    for(int64_t h = pindexPrev->nHeight; h <= pindexPrev->nHeight+10; h++){
        if(mapMasternodeBlocks.count(h)){
            mapMasternodeBlocks[h].GetPayee(payee);
            if(payee != CScript() && mnpayee == payee) return true;
            if(mn.donationAddress != CScript() && mn.donationAddress == payee) return true;
        }
    }

    return false;
}

158
159
160
bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
{
    uint256 blockHash = 0;
161
    if(!GetBlockHash(blockHash, winnerIn.nBlockHeight-100)) {
162
163
164
        return false;
    }

165
166
    if(mapMasternodePayeeVotes.count(winnerIn.GetHash())){
       return false; 
167
168
    }

169
170
171
172
173
    mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;

    if(!mapMasternodeBlocks.count(winnerIn.nBlockHeight)){
       CMasternodeBlockPayees blockPayees;
       mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
174
175
    }

176
177
178
179
    int n = 1;
    if(IsReferenceNode(winnerIn.vinMasternode)) n = 100;
    mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee.scriptPubKey, winnerIn.payee.nValue, n);

180
181
182
    return true;
}

183
bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
184
{
185
186
187
188
189
190
    int nMaxSignatures = 0;
    std::string strPayeesPossible = "";

    //require at least 6 signatures

    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
UdjinM6's avatar
UdjinM6 committed
191
        if(payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED)
192
193
194
195
196
197
            nMaxSignatures = payee.nVotes;

    // if we don't have at least 6 signatures on a payee, approve whichever is the longest chain
    if(nMaxSignatures == 0) return true;

    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
198
199
    {
        bool found = false;
200
        BOOST_FOREACH(CTxOut out, txNew.vout)
201
202
            if(payee.scriptPubKey == out.scriptPubKey && payee.nValue == out.nValue) 
                found = true;
203

204
205
206
207
208
209
        //if 2 contenders are within +/- 20%, take either 
        // If nMaxSignatures == 6, the min signatures = 2
        // If nMaxSignatures == 10, the min signatures = 6
        // If nMaxSignatures == 15, the min signatures = 11
        if(payee.nVotes >= nMaxSignatures-(MNPAYMENTS_SIGNATURES_TOTAL/5)){            
            if(found) return true;
210

211
212
213
            CTxDestination address1;
            ExtractDestination(payee.scriptPubKey, address1);
            CBitcoinAddress address2(address1);
214

215
216
217
218
219
            if(strPayeesPossible == ""){
                strPayeesPossible += address2.ToString()  + ":" + boost::lexical_cast<std::string>(payee.nValue);
            } else {
                strPayeesPossible += "," + address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nValue);
            }
220
221
        }
    }
222
223
224
225


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

228
std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
229
{
230
231
    std::string ret = "Unknown";

232
    BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
233
    {
234
235
236
        CTxDestination address1;
        ExtractDestination(payee.scriptPubKey, address1);
        CBitcoinAddress address2(address1);
237

238
239
240
241
        if(ret != "Unknown"){
            ret += ", " + address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nValue);
        } else {
            ret = address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nValue);
242
243
        }
    }
244

245
    return ret;
246
247
}

248
std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight)
249
{
250
251
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
252
253
    }

254
255
    return "Unknown";
}
256

257
258
259
260
bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
{
    if(mapMasternodeBlocks.count(nBlockHeight)){
        return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew);
261
262
    }

263
    return true;
264
265
266
267
268
269
270
271
272
273
}

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

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

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

274
275
276
277
278
279
280
281
282
    std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
    while(it != mapMasternodePayeeVotes.end()) {
        CMasternodePaymentWinner winner = (*it).second;
   
        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;
283
        }
284
    }
285
286
}

287
bool IsReferenceNode(CTxIn& vin)
288
{
289
290
291
292
    //reference node - hybrid mode
    if(vin.prevout.ToStringShort() == "099c01bea63abd1692f60806bb646fa1d288e2d049281225f17e499024084e28-0") return true; // mainnet
    if(vin.prevout.ToStringShort() == "testnet-0") return true; // testnet
    if(vin.prevout.ToStringShort() == "regtest-0") return true; // regtest
293

294
295
    return false;
}
296

297
298
299
bool CMasternodePaymentWinner::IsValid()
{
    if(IsReferenceNode(vinMasternode)) return true;
300

301
    int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight-100, MIN_MNPAYMENTS_PROTO_VERSION);
302

303
    if(n == -1)
304
    {
305
306
        if(fDebug) LogPrintf("CMasternodePaymentWinner::IsValid - Unknown Masternode\n");
        return false;
307
308
    }

309
    if(n > MNPAYMENTS_SIGNATURES_TOTAL)
310
    {
311
312
313
314
315
316
317
318
319
320
        if(fDebug) LogPrintf("CMasternodePaymentWinner::IsValid - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
        return false;
    }

    return true;
}

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

322
323
324
325
326
    if(!fMasterNode) return false;

    //reference node - hybrid mode

    if(!IsReferenceNode(activeMasternode.vin)){
327
        int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight-100, MIN_MNPAYMENTS_PROTO_VERSION);
328
329
330
331
332

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

335
336
337
338
339
        if(n > MNPAYMENTS_SIGNATURES_TOTAL)
        {
            if(fDebug) LogPrintf("CMasternodePayments::ProcessBlock - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
            return false;
        }
340
341
    }

342
343
    if(nBlockHeight <= nLastBlockHeight) return false;
    
344
345
346
347
    CBlockIndex* pindexPrev = chainActive.Tip();
    if(pindexPrev == NULL) return false;
    CAmount blockValue = GetBlockValue(pindexPrev->nBits, pindexPrev->nHeight, 0);
    CAmount masternodePayment = GetMasternodePayment(pindexPrev->nHeight+1, blockValue);
348

349
    CMasternodePaymentWinner newWinner(activeMasternode.vin);
350

351
    if(budget.IsBudgetPaymentBlock(nBlockHeight)){
352
        //is budget payment block -- handled by the budgeting software
353
354
    } else {
        CScript payeeSource;
355
        uint256 hash;
356
        if(!GetBlockHash(hash, nBlockHeight-100)) return false;
357
358
359
360
361
362
        unsigned int nHash;
        memcpy(&nHash, &hash, 2);

        LogPrintf(" ProcessBlock Start nHeight %d. \n", nBlockHeight);

        // pay to the oldest MN that still had no payment but its input is old enough and it was active long enough
363
        CMasternode *pmn = mnodeman.GetNextMasternodeInQueueForPayment();
364
365
366
        if(pmn != NULL)
        {
            LogPrintf(" Found by FindOldestNotInVec \n");
367

368
            newWinner.nBlockHeight = nBlockHeight;
369

370
371
372
373
374
375
            CScript payee;
            if(pmn->donationPercentage > 0 && (nHash % 100) <= (unsigned int)pmn->donationPercentage) {
                payee = pmn->donationAddress;
            } else {
                payee = GetScriptForDestination(pmn->pubkey.GetID());
            }
376
            
377
378
379
380
381
382
            payeeSource = GetScriptForDestination(pmn->pubkey.GetID());
            newWinner.AddPayee(payee, masternodePayment);
            
            CTxDestination address1;
            ExtractDestination(payee, address1);
            CBitcoinAddress address2(address1);
383

384
385
386
            CTxDestination address3;
            ExtractDestination(payeeSource, address3);
            CBitcoinAddress address4(address3);
387

388
389
390
391
            LogPrintf("Winner payee %s nHeight %d vin source %s. \n", address2.ToString().c_str(), newWinner.nBlockHeight, address4.ToString().c_str());
        } else {
            LogPrintf(" Failed to find masternode to pay\n");
        }
392

393
    }
394

395
396
397
    std::string errorMessage;
    CPubKey pubKeyMasternode;
    CKey keyMasternode;
398

399
400
401
402
403
    if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
    {
        LogPrintf("CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str());
        return false;
    }
404

405
    if(newWinner.Sign(keyMasternode, pubKeyMasternode))
406
407
408
    {
        if(AddWinningMasternode(newWinner))
        {
409
            newWinner.Relay();
410
411
412
413
            nLastBlockHeight = nBlockHeight;
            return true;
        }
    }
414

415
416
417
    return false;
}

418
void CMasternodePaymentWinner::Relay()
419
{
420
    CInv inv(MSG_MASTERNODE_WINNER, GetHash());
421
422
423
424
425
426
427
428
429

    vector<CInv> vInv;
    vInv.push_back(inv);
    LOCK(cs_vNodes);
    BOOST_FOREACH(CNode* pnode, vNodes){
        pnode->PushMessage("inv", vInv);
    }
}

430
bool CMasternodePaymentWinner::SignatureValid()
431
432
{

433
    CMasternode* pmn = mnodeman.Find(vinMasternode);
434

435
436
437
438
439
    if(pmn != NULL)
    {
        std::string strMessage =  vinMasternode.prevout.ToStringShort() +
                    boost::lexical_cast<std::string>(nBlockHeight) + 
                    payee.ToString();
440
441


442
443
444
445
        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());
        }
446
447
448

        return true;
    }
449
450

    return false;
451
}
452
453
454
455

void CMasternodePayments::Sync(CNode* node)
{
    LOCK(cs_masternodepayments);
456
457
458
459
460
461

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

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