diff --git a/src/Makefile.am b/src/Makefile.am index 64a8c7687d..3f0be328eb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -107,6 +107,7 @@ BITCOIN_CORE_H = \ limitedmap.h \ main.h \ masternode.h \ + masternode-payments.h \ masternode-pos.h \ masternodeman.h \ masternodeconfig.h \ @@ -278,6 +279,7 @@ libbitcoin_common_a_SOURCES = \ darksend.cpp \ darksend-relay.cpp \ masternode.cpp \ + masternode-payments.cpp \ masternode-pos.cpp \ masternodeman.cpp \ masternodeconfig.cpp \ diff --git a/src/darksend.h b/src/darksend.h index 927a5bb998..59797766a6 100644 --- a/src/darksend.h +++ b/src/darksend.h @@ -9,6 +9,7 @@ #include "sync.h" #include "activemasternode.h" #include "masternodeman.h" +#include "masternode-payments.h" #include "darksend-relay.h" class CTxIn; diff --git a/src/init.cpp b/src/init.cpp index a82d07909e..f2d115862c 100755 --- a/src/init.cpp +++ b/src/init.cpp @@ -24,6 +24,7 @@ #include "ui_interface.h" #include "util.h" #include "activemasternode.h" +#include "masternode-payments.h" #include "masternodeman.h" #include "spork.h" #include "utilmoneystr.h" diff --git a/src/main.cpp b/src/main.cpp index a1a0b5bb47..5a34f068dc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,7 @@ #include "instantx.h" #include "darksend.h" #include "masternodeman.h" +#include "masternode-payments.h" #include "merkleblock.h" #include "net.h" #include "pow.h" diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp new file mode 100644 index 0000000000..0a0170c7ee --- /dev/null +++ b/src/masternode-payments.cpp @@ -0,0 +1,359 @@ +// 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" +#include "masternodeman.h" +#include "darksend.h" +#include "util.h" +#include "sync.h" +#include "addrman.h" +#include + +CCriticalSection cs_masternodepayments; + +/** Object for who's going to get paid on which blocks */ +CMasternodePayments masternodePayments; +// keep track of Masternode votes I've seen +map mapSeenMasternodeVotes; + +void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) +{ + 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); + + //this is required in litemode + CMasternodePaymentWinner winner; + vRecv >> winner; + + if(chainActive.Tip() == NULL) return; + + CTxDestination address1; + ExtractDestination(winner.payee, address1); + CBitcoinAddress address2(address1); + + uint256 hash = winner.GetHash(); + if(mapSeenMasternodeVotes.count(hash)) { + if(fDebug) LogPrintf("mnw - seen vote %s Addr %s Height %d bestHeight %d\n", hash.ToString().c_str(), address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight); + return; + } + + if(winner.nBlockHeight < chainActive.Tip()->nHeight - 10 || winner.nBlockHeight > chainActive.Tip()->nHeight+20){ + LogPrintf("mnw - winner out of range %s Addr %s Height %d bestHeight %d\n", winner.vin.ToString().c_str(), address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight); + return; + } + + if(winner.vin.nSequence != std::numeric_limits::max()){ + LogPrintf("mnw - invalid nSequence\n"); + Misbehaving(pfrom->GetId(), 100); + return; + } + + LogPrintf("mnw - winning vote - Vin %s Addr %s Height %d bestHeight %d\n", winner.vin.ToString().c_str(), address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight); + + if(!masternodePayments.CheckSignature(winner)){ + LogPrintf("mnw - invalid signature\n"); + Misbehaving(pfrom->GetId(), 100); + return; + } + + mapSeenMasternodeVotes.insert(make_pair(hash, winner)); + + if(masternodePayments.AddWinningMasternode(winner)){ + masternodePayments.Relay(winner); + } + } +} + + +bool CMasternodePayments::CheckSignature(CMasternodePaymentWinner& winner) +{ + //note: need to investigate why this is failing + std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast(winner.nBlockHeight) + winner.payee.ToString(); + CPubKey pubkey(ParseHex(Params().MasternodePaymentPubKey())); + + std::string errorMessage = ""; + if(!darkSendSigner.VerifyMessage(pubkey, winner.vchSig, strMessage, errorMessage)){ + return false; + } + + return true; +} + +bool CMasternodePayments::Sign(CMasternodePaymentWinner& winner) +{ + std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast(winner.nBlockHeight) + winner.payee.ToString(); + + CKey key2; + CPubKey pubkey2; + std::string errorMessage = ""; + + if(!darkSendSigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2)) + { + LogPrintf("CMasternodePayments::Sign - ERROR: Invalid Masternodeprivkey: '%s'\n", errorMessage.c_str()); + return false; + } + + if(!darkSendSigner.SignMessage(strMessage, errorMessage, winner.vchSig, key2)) { + LogPrintf("CMasternodePayments::Sign - Sign message failed"); + return false; + } + + if(!darkSendSigner.VerifyMessage(pubkey2, winner.vchSig, strMessage, errorMessage)) { + LogPrintf("CMasternodePayments::Sign - Verify message failed"); + return false; + } + + return true; +} + +uint64_t CMasternodePayments::CalculateScore(uint256 blockHash, CTxIn& vin) +{ + uint256 n1 = blockHash; + uint256 n2 = HashX11(BEGIN(n1), END(n1)); + uint256 n3 = HashX11(BEGIN(vin.prevout.hash), END(vin.prevout.hash)); + uint256 n4 = n3 > n2 ? (n3 - n2) : (n2 - n3); + + //printf(" -- CMasternodePayments CalculateScore() n2 = %d \n", n2.Get64()); + //printf(" -- CMasternodePayments CalculateScore() n3 = %d \n", n3.Get64()); + //printf(" -- CMasternodePayments CalculateScore() n4 = %d \n", n4.Get64()); + + return n4.Get64(); +} + +bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee) +{ + BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){ + if(winner.nBlockHeight == nBlockHeight) { + payee = winner.payee; + return true; + } + } + + return false; +} + +bool CMasternodePayments::GetWinningMasternode(int nBlockHeight, CTxIn& vinOut) +{ + BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){ + if(winner.nBlockHeight == nBlockHeight) { + vinOut = winner.vin; + return true; + } + } + + return false; +} + +bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn) +{ + uint256 blockHash = 0; + if(!GetBlockHash(blockHash, winnerIn.nBlockHeight-576)) { + return false; + } + + winnerIn.score = CalculateScore(blockHash, winnerIn.vin); + + bool foundBlock = false; + BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){ + if(winner.nBlockHeight == winnerIn.nBlockHeight) { + foundBlock = true; + if(winner.score < winnerIn.score){ + winner.score = winnerIn.score; + winner.vin = winnerIn.vin; + winner.payee = winnerIn.payee; + winner.vchSig = winnerIn.vchSig; + + mapSeenMasternodeVotes.insert(make_pair(winnerIn.GetHash(), winnerIn)); + + return true; + } + } + } + + // if it's not in the vector + if(!foundBlock){ + vWinning.push_back(winnerIn); + mapSeenMasternodeVotes.insert(make_pair(winnerIn.GetHash(), winnerIn)); + + return true; + } + + return false; +} + +void CMasternodePayments::CleanPaymentList() +{ + LOCK(cs_masternodepayments); + + if(chainActive.Tip() == NULL) return; + + int nLimit = std::max(((int)mnodeman.size())*2, 1000); + + vector::iterator it; + for(it=vWinning.begin();itnHeight - (*it).nBlockHeight > nLimit){ + if(fDebug) LogPrintf("CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", (*it).nBlockHeight); + vWinning.erase(it); + break; + } + } +} + +bool CMasternodePayments::ProcessBlock(int nBlockHeight) +{ + LOCK(cs_masternodepayments); + + if(nBlockHeight <= nLastBlockHeight) return false; + if(!enabled) return false; + CMasternodePaymentWinner newWinner; + int nMinimumAge = mnodeman.CountEnabled(); + CScript payeeSource; + + uint256 hash; + if(!GetBlockHash(hash, nBlockHeight-10)) return false; + unsigned int nHash; + memcpy(&nHash, &hash, 2); + + LogPrintf(" ProcessBlock Start nHeight %d. \n", nBlockHeight); + + std::vector vecLastPayments; + BOOST_REVERSE_FOREACH(CMasternodePaymentWinner& winner, vWinning) + { + //if we already have the same vin - we have one full payment cycle, break + if(vecLastPayments.size() > nMinimumAge) break; + vecLastPayments.push_back(winner.vin); + } + + // pay to the oldest MN that still had no payment but its input is old enough and it was active long enough + CMasternode *pmn = mnodeman.FindOldestNotInVec(vecLastPayments, nMinimumAge); + if(pmn != NULL) + { + LogPrintf(" Found by FindOldestNotInVec \n"); + + newWinner.score = 0; + newWinner.nBlockHeight = nBlockHeight; + newWinner.vin = pmn->vin; + pmn->nLastPaid = GetAdjustedTime(); + + if(pmn->donationPercentage > 0 && (nHash % 100) <= (unsigned int)pmn->donationPercentage) { + newWinner.payee = pmn->donationAddress; + } else { + newWinner.payee = GetScriptForDestination(pmn->pubkey.GetID()); + } + + payeeSource = GetScriptForDestination(pmn->pubkey.GetID()); + } + + //if we can't find new MN to get paid, pick first active MN counting back from the end of vecLastPayments list + if(newWinner.nBlockHeight == 0 && nMinimumAge > 0) + { + LogPrintf(" Find by reverse \n"); + + BOOST_REVERSE_FOREACH(CTxIn& vinLP, vecLastPayments) + { + CMasternode* pmn = mnodeman.Find(vinLP); + if(pmn != NULL) + { + pmn->Check(); + if(!pmn->IsEnabled()) continue; + + newWinner.score = 0; + newWinner.nBlockHeight = nBlockHeight; + newWinner.vin = pmn->vin; + pmn->nLastPaid = GetAdjustedTime(); + + if(pmn->donationPercentage > 0 && (nHash % 100) <= (unsigned int)pmn->donationPercentage) { + newWinner.payee = pmn->donationAddress; + } else { + newWinner.payee = GetScriptForDestination(pmn->pubkey.GetID()); + } + + payeeSource = GetScriptForDestination(pmn->pubkey.GetID()); + + break; // we found active MN + } + } + } + + if(newWinner.nBlockHeight == 0) return false; + + CTxDestination address1; + ExtractDestination(newWinner.payee, address1); + CBitcoinAddress address2(address1); + + CTxDestination address3; + ExtractDestination(payeeSource, address3); + CBitcoinAddress address4(address3); + + LogPrintf("Winner payee %s nHeight %d vin source %s. \n", address2.ToString().c_str(), newWinner.nBlockHeight, address4.ToString().c_str()); + + if(Sign(newWinner)) + { + if(AddWinningMasternode(newWinner)) + { + Relay(newWinner); + nLastBlockHeight = nBlockHeight; + return true; + } + } + + return false; +} + + +void CMasternodePayments::Relay(CMasternodePaymentWinner& winner) +{ + CInv inv(MSG_MASTERNODE_WINNER, winner.GetHash()); + + vector vInv; + vInv.push_back(inv); + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes){ + pnode->PushMessage("inv", vInv); + } +} + +void CMasternodePayments::Sync(CNode* node) +{ + LOCK(cs_masternodepayments); + + BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning) + if(winner.nBlockHeight >= chainActive.Tip()->nHeight-10 && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20) + node->PushMessage("mnw", winner); +} + + +bool CMasternodePayments::SetPrivKey(std::string strPrivKey) +{ + CMasternodePaymentWinner winner; + + // Test signing successful, proceed + strMasterPrivKey = strPrivKey; + + Sign(winner); + + if(CheckSignature(winner)){ + LogPrintf("CMasternodePayments::SetPrivKey - Successfully initialized as Masternode payments master\n"); + enabled = true; + return true; + } else { + return false; + } +} diff --git a/src/masternode-payments.h b/src/masternode-payments.h new file mode 100644 index 0000000000..ff1ce6149e --- /dev/null +++ b/src/masternode-payments.h @@ -0,0 +1,109 @@ + + +// 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. +#ifndef MASTERNODE_PAYMENTS_H +#define MASTERNODE_PAYMENTS_H + +#include "sync.h" +#include "net.h" +#include "key.h" +#include "util.h" +#include "base58.h" +#include "main.h" +#include "masternode.h" +#include "masternode-pos.h" +#include "timedata.h" + +using namespace std; + +class CMasternodePayments; +class CMasternodePaymentWinner; + +extern CMasternodePayments masternodePayments; +extern map mapSeenMasternodeVotes; + +void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); + + +// for storing the winning payments +class CMasternodePaymentWinner +{ +public: + int nBlockHeight; + CTxIn vin; + CScript payee; + std::vector vchSig; + uint64_t score; + + CMasternodePaymentWinner() { + nBlockHeight = 0; + score = 0; + vin = CTxIn(); + payee = CScript(); + } + + uint256 GetHash(){ + uint256 n2 = HashX11(BEGIN(nBlockHeight), END(nBlockHeight)); + uint256 n3 = vin.prevout.hash > n2 ? (vin.prevout.hash - n2) : (n2 - vin.prevout.hash); + + return n3; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(nBlockHeight); + READWRITE(payee); + READWRITE(vin); + READWRITE(score); + READWRITE(vchSig); + } +}; + +// +// Masternode Payments Class +// Keeps track of who should get paid for which blocks +// + +class CMasternodePayments +{ +private: + std::vector vWinning; + int nSyncedFromPeer; + std::string strMasterPrivKey; + bool enabled; + int nLastBlockHeight; + +public: + + CMasternodePayments() { + enabled = false; + } + + bool SetPrivKey(std::string strPrivKey); + bool CheckSignature(CMasternodePaymentWinner& winner); + bool Sign(CMasternodePaymentWinner& winner); + + // Deterministically calculate a given "score" for a masternode depending on how close it's hash is + // to the blockHeight. The further away they are the better, the furthest will win the election + // and get paid this block + // + + uint64_t CalculateScore(uint256 blockHash, CTxIn& vin); + bool GetWinningMasternode(int nBlockHeight, CTxIn& vinOut); + bool AddWinningMasternode(CMasternodePaymentWinner& winner); + bool ProcessBlock(int nBlockHeight); + void Relay(CMasternodePaymentWinner& winner); + void Sync(CNode* node); + void CleanPaymentList(); + int LastPayment(CMasternode& mn); + + //slow + bool GetBlockPayee(int nBlockHeight, CScript& payee); +}; + + +#endif \ No newline at end of file diff --git a/src/masternode.cpp b/src/masternode.cpp index ef083d9624..029ed4d250 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -10,80 +10,11 @@ #include "addrman.h" #include -CCriticalSection cs_masternodepayments; - -/** Object for who's going to get paid on which blocks */ -CMasternodePayments masternodePayments; -// keep track of Masternode votes I've seen -map mapSeenMasternodeVotes; // keep track of the scanning errors I've seen map mapSeenMasternodeScanningErrors; // cache block hashes as we calculate them std::map mapCacheBlockHashes; -void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) -{ - 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); - - //this is required in litemode - CMasternodePaymentWinner winner; - vRecv >> winner; - - if(chainActive.Tip() == NULL) return; - - CTxDestination address1; - ExtractDestination(winner.payee, address1); - CBitcoinAddress address2(address1); - - uint256 hash = winner.GetHash(); - if(mapSeenMasternodeVotes.count(hash)) { - if(fDebug) LogPrintf("mnw - seen vote %s Addr %s Height %d bestHeight %d\n", hash.ToString().c_str(), address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight); - return; - } - - if(winner.nBlockHeight < chainActive.Tip()->nHeight - 10 || winner.nBlockHeight > chainActive.Tip()->nHeight+20){ - LogPrintf("mnw - winner out of range %s Addr %s Height %d bestHeight %d\n", winner.vin.ToString().c_str(), address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight); - return; - } - - if(winner.vin.nSequence != std::numeric_limits::max()){ - LogPrintf("mnw - invalid nSequence\n"); - Misbehaving(pfrom->GetId(), 100); - return; - } - - LogPrintf("mnw - winning vote - Vin %s Addr %s Height %d bestHeight %d\n", winner.vin.ToString().c_str(), address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight); - - if(!masternodePayments.CheckSignature(winner)){ - LogPrintf("mnw - invalid signature\n"); - Misbehaving(pfrom->GetId(), 100); - return; - } - - mapSeenMasternodeVotes.insert(make_pair(hash, winner)); - - if(masternodePayments.AddWinningMasternode(winner)){ - masternodePayments.Relay(winner); - } - } -} struct CompareValueOnly { @@ -277,280 +208,4 @@ void CMasternode::Check() } activeState = MASTERNODE_ENABLED; // OK -} - -bool CMasternodePayments::CheckSignature(CMasternodePaymentWinner& winner) -{ - //note: need to investigate why this is failing - std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast(winner.nBlockHeight) + winner.payee.ToString(); - CPubKey pubkey(ParseHex(Params().MasternodePaymentPubKey())); - - std::string errorMessage = ""; - if(!darkSendSigner.VerifyMessage(pubkey, winner.vchSig, strMessage, errorMessage)){ - return false; - } - - return true; -} - -bool CMasternodePayments::Sign(CMasternodePaymentWinner& winner) -{ - std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast(winner.nBlockHeight) + winner.payee.ToString(); - - CKey key2; - CPubKey pubkey2; - std::string errorMessage = ""; - - if(!darkSendSigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2)) - { - LogPrintf("CMasternodePayments::Sign - ERROR: Invalid Masternodeprivkey: '%s'\n", errorMessage.c_str()); - return false; - } - - if(!darkSendSigner.SignMessage(strMessage, errorMessage, winner.vchSig, key2)) { - LogPrintf("CMasternodePayments::Sign - Sign message failed"); - return false; - } - - if(!darkSendSigner.VerifyMessage(pubkey2, winner.vchSig, strMessage, errorMessage)) { - LogPrintf("CMasternodePayments::Sign - Verify message failed"); - return false; - } - - return true; -} - -uint64_t CMasternodePayments::CalculateScore(uint256 blockHash, CTxIn& vin) -{ - uint256 n1 = blockHash; - uint256 n2 = HashX11(BEGIN(n1), END(n1)); - uint256 n3 = HashX11(BEGIN(vin.prevout.hash), END(vin.prevout.hash)); - uint256 n4 = n3 > n2 ? (n3 - n2) : (n2 - n3); - - //printf(" -- CMasternodePayments CalculateScore() n2 = %d \n", n2.Get64()); - //printf(" -- CMasternodePayments CalculateScore() n3 = %d \n", n3.Get64()); - //printf(" -- CMasternodePayments CalculateScore() n4 = %d \n", n4.Get64()); - - return n4.Get64(); -} - -bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee) -{ - BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){ - if(winner.nBlockHeight == nBlockHeight) { - payee = winner.payee; - return true; - } - } - - return false; -} - -bool CMasternodePayments::GetWinningMasternode(int nBlockHeight, CTxIn& vinOut) -{ - BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){ - if(winner.nBlockHeight == nBlockHeight) { - vinOut = winner.vin; - return true; - } - } - - return false; -} - -bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn) -{ - uint256 blockHash = 0; - if(!GetBlockHash(blockHash, winnerIn.nBlockHeight-576)) { - return false; - } - - winnerIn.score = CalculateScore(blockHash, winnerIn.vin); - - bool foundBlock = false; - BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){ - if(winner.nBlockHeight == winnerIn.nBlockHeight) { - foundBlock = true; - if(winner.score < winnerIn.score){ - winner.score = winnerIn.score; - winner.vin = winnerIn.vin; - winner.payee = winnerIn.payee; - winner.vchSig = winnerIn.vchSig; - - mapSeenMasternodeVotes.insert(make_pair(winnerIn.GetHash(), winnerIn)); - - return true; - } - } - } - - // if it's not in the vector - if(!foundBlock){ - vWinning.push_back(winnerIn); - mapSeenMasternodeVotes.insert(make_pair(winnerIn.GetHash(), winnerIn)); - - return true; - } - - return false; -} - -void CMasternodePayments::CleanPaymentList() -{ - LOCK(cs_masternodepayments); - - if(chainActive.Tip() == NULL) return; - - int nLimit = std::max(((int)mnodeman.size())*2, 1000); - - vector::iterator it; - for(it=vWinning.begin();itnHeight - (*it).nBlockHeight > nLimit){ - if(fDebug) LogPrintf("CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", (*it).nBlockHeight); - vWinning.erase(it); - break; - } - } -} - -bool CMasternodePayments::ProcessBlock(int nBlockHeight) -{ - LOCK(cs_masternodepayments); - - if(nBlockHeight <= nLastBlockHeight) return false; - if(!enabled) return false; - CMasternodePaymentWinner newWinner; - int nMinimumAge = mnodeman.CountEnabled(); - CScript payeeSource; - - uint256 hash; - if(!GetBlockHash(hash, nBlockHeight-10)) return false; - unsigned int nHash; - memcpy(&nHash, &hash, 2); - - LogPrintf(" ProcessBlock Start nHeight %d. \n", nBlockHeight); - - std::vector vecLastPayments; - BOOST_REVERSE_FOREACH(CMasternodePaymentWinner& winner, vWinning) - { - //if we already have the same vin - we have one full payment cycle, break - if(vecLastPayments.size() > nMinimumAge) break; - vecLastPayments.push_back(winner.vin); - } - - // pay to the oldest MN that still had no payment but its input is old enough and it was active long enough - CMasternode *pmn = mnodeman.FindOldestNotInVec(vecLastPayments, nMinimumAge); - if(pmn != NULL) - { - LogPrintf(" Found by FindOldestNotInVec \n"); - - newWinner.score = 0; - newWinner.nBlockHeight = nBlockHeight; - newWinner.vin = pmn->vin; - pmn->nLastPaid = GetAdjustedTime(); - - if(pmn->donationPercentage > 0 && (nHash % 100) <= (unsigned int)pmn->donationPercentage) { - newWinner.payee = pmn->donationAddress; - } else { - newWinner.payee = GetScriptForDestination(pmn->pubkey.GetID()); - } - - payeeSource = GetScriptForDestination(pmn->pubkey.GetID()); - } - - //if we can't find new MN to get paid, pick first active MN counting back from the end of vecLastPayments list - if(newWinner.nBlockHeight == 0 && nMinimumAge > 0) - { - LogPrintf(" Find by reverse \n"); - - BOOST_REVERSE_FOREACH(CTxIn& vinLP, vecLastPayments) - { - CMasternode* pmn = mnodeman.Find(vinLP); - if(pmn != NULL) - { - pmn->Check(); - if(!pmn->IsEnabled()) continue; - - newWinner.score = 0; - newWinner.nBlockHeight = nBlockHeight; - newWinner.vin = pmn->vin; - pmn->nLastPaid = GetAdjustedTime(); - - if(pmn->donationPercentage > 0 && (nHash % 100) <= (unsigned int)pmn->donationPercentage) { - newWinner.payee = pmn->donationAddress; - } else { - newWinner.payee = GetScriptForDestination(pmn->pubkey.GetID()); - } - - payeeSource = GetScriptForDestination(pmn->pubkey.GetID()); - - break; // we found active MN - } - } - } - - if(newWinner.nBlockHeight == 0) return false; - - CTxDestination address1; - ExtractDestination(newWinner.payee, address1); - CBitcoinAddress address2(address1); - - CTxDestination address3; - ExtractDestination(payeeSource, address3); - CBitcoinAddress address4(address3); - - LogPrintf("Winner payee %s nHeight %d vin source %s. \n", address2.ToString().c_str(), newWinner.nBlockHeight, address4.ToString().c_str()); - - if(Sign(newWinner)) - { - if(AddWinningMasternode(newWinner)) - { - Relay(newWinner); - nLastBlockHeight = nBlockHeight; - return true; - } - } - - return false; -} - - -void CMasternodePayments::Relay(CMasternodePaymentWinner& winner) -{ - CInv inv(MSG_MASTERNODE_WINNER, winner.GetHash()); - - vector vInv; - vInv.push_back(inv); - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes){ - pnode->PushMessage("inv", vInv); - } -} - -void CMasternodePayments::Sync(CNode* node) -{ - LOCK(cs_masternodepayments); - - BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning) - if(winner.nBlockHeight >= chainActive.Tip()->nHeight-10 && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20) - node->PushMessage("mnw", winner); -} - - -bool CMasternodePayments::SetPrivKey(std::string strPrivKey) -{ - CMasternodePaymentWinner winner; - - // Test signing successful, proceed - strMasterPrivKey = strPrivKey; - - Sign(winner); - - if(CheckSignature(winner)){ - LogPrintf("CMasternodePayments::SetPrivKey - Successfully initialized as Masternode payments master\n"); - enabled = true; - return true; - } else { - return false; - } -} +} \ No newline at end of file diff --git a/src/masternode.h b/src/masternode.h index 83a27e8e1a..933f5cdddf 100644 --- a/src/masternode.h +++ b/src/masternode.h @@ -11,6 +11,7 @@ #include "util.h" #include "base58.h" #include "main.h" +#include "masternode.h" #include "masternode-pos.h" #include "timedata.h" @@ -34,14 +35,8 @@ using namespace std; class CMasternode; -class CMasternodePayments; -class CMasternodePaymentWinner; - -extern CMasternodePayments masternodePayments; -extern map mapSeenMasternodeVotes; extern map mapCacheBlockHashes; -void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); bool GetBlockHash(uint256& hash, int nBlockHeight); // @@ -248,83 +243,4 @@ public: }; -// for storing the winning payments -class CMasternodePaymentWinner -{ -public: - int nBlockHeight; - CTxIn vin; - CScript payee; - std::vector vchSig; - uint64_t score; - - CMasternodePaymentWinner() { - nBlockHeight = 0; - score = 0; - vin = CTxIn(); - payee = CScript(); - } - - uint256 GetHash(){ - uint256 n2 = HashX11(BEGIN(nBlockHeight), END(nBlockHeight)); - uint256 n3 = vin.prevout.hash > n2 ? (vin.prevout.hash - n2) : (n2 - vin.prevout.hash); - - return n3; - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(nBlockHeight); - READWRITE(payee); - READWRITE(vin); - READWRITE(score); - READWRITE(vchSig); - } -}; - -// -// Masternode Payments Class -// Keeps track of who should get paid for which blocks -// - -class CMasternodePayments -{ -private: - std::vector vWinning; - int nSyncedFromPeer; - std::string strMasterPrivKey; - bool enabled; - int nLastBlockHeight; - -public: - - CMasternodePayments() { - enabled = false; - } - - bool SetPrivKey(std::string strPrivKey); - bool CheckSignature(CMasternodePaymentWinner& winner); - bool Sign(CMasternodePaymentWinner& winner); - - // Deterministically calculate a given "score" for a masternode depending on how close it's hash is - // to the blockHeight. The further away they are the better, the furthest will win the election - // and get paid this block - // - - uint64_t CalculateScore(uint256 blockHash, CTxIn& vin); - bool GetWinningMasternode(int nBlockHeight, CTxIn& vinOut); - bool AddWinningMasternode(CMasternodePaymentWinner& winner); - bool ProcessBlock(int nBlockHeight); - void Relay(CMasternodePaymentWinner& winner); - void Sync(CNode* node); - void CleanPaymentList(); - int LastPayment(CMasternode& mn); - - //slow - bool GetBlockPayee(int nBlockHeight, CScript& payee); -}; - - #endif diff --git a/src/miner.cpp b/src/miner.cpp index 407c48a1f0..46f416f45e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -20,6 +20,7 @@ #include "wallet.h" #endif #include "masternodeman.h" +#include "masternode-payments.h" #include #include diff --git a/src/rpcdarksend.cpp b/src/rpcdarksend.cpp index 6632a1bfcb..d06c9f435f 100644 --- a/src/rpcdarksend.cpp +++ b/src/rpcdarksend.cpp @@ -8,6 +8,7 @@ #include "init.h" #include "activemasternode.h" #include "masternodeman.h" +#include "masternode-payments.h" #include "masternodeconfig.h" #include "rpcserver.h" #include "utilmoneystr.h"