neobytes/src/masternode-payments.cpp
Evan Duffield 402d821529 Fix memory leak / reduce mnw memory
- mapSeenMasternodePing & mapSeenMasternodeBroadcast were not getting cleaned, so the pinging of 3000 masternode was accumulating over time. This patch has the clean clean the lists every few minutes and removes anything older than 20 minutes for pings and 2.5 hours for broadcasts.
- v48
2015-08-24 19:27:10 -07:00

839 lines
27 KiB
C++

// 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 "masternode-budget.h"
#include "masternode-sync.h"
#include "masternodeman.h"
#include "darksend.h"
#include "util.h"
#include "sync.h"
#include "spork.h"
#include "addrman.h"
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
/** Object for who's going to get paid on which blocks */
CMasternodePayments masternodePayments;
CCriticalSection cs_vecPayments;
CCriticalSection cs_mapMasternodeBlocks;
CCriticalSection cs_mapMasternodePayeeVotes;
//
// CMasternodePaymentDB
//
CMasternodePaymentDB::CMasternodePaymentDB()
{
pathDB = GetDataDir() / "mnpayments.dat";
strMagicMessage = "MasternodePayments";
}
bool CMasternodePaymentDB::Write(const CMasternodePayments& objToSave)
{
int64_t nStart = GetTimeMillis();
// serialize, checksum data up to that point, then append checksum
CDataStream ssObj(SER_DISK, CLIENT_VERSION);
ssObj << strMagicMessage; // masternode cache file specific magic message
ssObj << FLATDATA(Params().MessageStart()); // network specific magic number
ssObj << objToSave;
uint256 hash = Hash(ssObj.begin(), ssObj.end());
ssObj << hash;
// open output file, and associate with CAutoFile
FILE *file = fopen(pathDB.string().c_str(), "wb");
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
if (fileout.IsNull())
return error("%s : Failed to open file %s", __func__, pathDB.string());
// Write and commit header, data
try {
fileout << ssObj;
}
catch (std::exception &e) {
return error("%s : Serialize or I/O error - %s", __func__, e.what());
}
fileout.fclose();
LogPrintf("Written info to mnpayments.dat %dms\n", GetTimeMillis() - nStart);
return true;
}
CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& objToLoad, bool fDryRun)
{
int64_t nStart = GetTimeMillis();
// open input file, and associate with CAutoFile
FILE *file = fopen(pathDB.string().c_str(), "rb");
CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
{
error("%s : Failed to open file %s", __func__, pathDB.string());
return FileError;
}
// use file size to size memory buffer
int fileSize = boost::filesystem::file_size(pathDB);
int dataSize = fileSize - sizeof(uint256);
// Don't try to resize to a negative number if file is small
if (dataSize < 0)
dataSize = 0;
vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
// read data and checksum from file
try {
filein.read((char *)&vchData[0], dataSize);
filein >> hashIn;
}
catch (std::exception &e) {
error("%s : Deserialize or I/O error - %s", __func__, e.what());
return HashReadError;
}
filein.fclose();
CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION);
// verify stored checksum matches input data
uint256 hashTmp = Hash(ssObj.begin(), ssObj.end());
if (hashIn != hashTmp)
{
error("%s : Checksum mismatch, data corrupted", __func__);
return IncorrectHash;
}
unsigned char pchMsgTmp[4];
std::string strMagicMessageTmp;
try {
// de-serialize file header (masternode cache file specific magic message) and ..
ssObj >> strMagicMessageTmp;
// ... verify the message matches predefined one
if (strMagicMessage != strMagicMessageTmp)
{
error("%s : Invalid masternode payement cache magic message", __func__);
return IncorrectMagicMessage;
}
// de-serialize file header (network specific magic number) and ..
ssObj >> FLATDATA(pchMsgTmp);
// ... verify the network matches ours
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
{
error("%s : Invalid network magic number", __func__);
return IncorrectMagicNumber;
}
// de-serialize data into CMasternodePayments object
ssObj >> objToLoad;
}
catch (std::exception &e) {
objToLoad.Clear();
error("%s : Deserialize or I/O error - %s", __func__, e.what());
return IncorrectFormat;
}
LogPrintf("Loaded info from mnpayments.dat %dms\n", GetTimeMillis() - nStart);
LogPrintf(" %s\n", objToLoad.ToString());
if(!fDryRun) {
LogPrintf("Masternode payments manager - cleaning....\n");
objToLoad.CleanPaymentList();
LogPrintf("Masternode payments manager - result:\n");
LogPrintf(" %s\n", objToLoad.ToString());
}
return Ok;
}
void DumpMasternodePayments()
{
int64_t nStart = GetTimeMillis();
CMasternodePaymentDB paymentdb;
CMasternodePayments tempPayments;
LogPrintf("Verifying mnpayments.dat format...\n");
CMasternodePaymentDB::ReadResult readResult = paymentdb.Read(tempPayments, true);
// there was an error and it was not an error on file opening => do not proceed
if (readResult == CMasternodePaymentDB::FileError)
LogPrintf("Missing budgets file - mnpayments.dat, will try to recreate\n");
else if (readResult != CMasternodePaymentDB::Ok)
{
LogPrintf("Error reading mnpayments.dat: ");
if(readResult == CMasternodePaymentDB::IncorrectFormat)
LogPrintf("magic is ok but data has invalid format, will try to recreate\n");
else
{
LogPrintf("file format is unknown or invalid, please fix it manually\n");
return;
}
}
LogPrintf("Writting info to mnpayments.dat...\n");
paymentdb.Write(masternodePayments);
LogPrintf("Budget dump finished %dms\n", GetTimeMillis() - nStart);
}
bool IsBlockValueValid(const CBlock& block, int64_t nExpectedValue){
CBlockIndex* pindexPrev = chainActive.Tip();
if(pindexPrev == NULL) return true;
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");
}
if(!masternodeSync.IsSynced()) { //there is no budget data to use to check anything
//super blocks will always be on these blocks, max 100 per budgeting
if(nHeight % GetBudgetPaymentCycleBlocks() < 100){
return true;
} else {
if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
}
} else { // we're synced and have data so check the budget schedule
//are these blocks even enabled
if(!IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
return block.vtx[0].GetValueOut() <= nExpectedValue;
}
if(budget.IsBudgetPaymentBlock(nHeight)){
//the value of the block is evaluated in CheckBlock
return true;
} else {
if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
}
}
return true;
}
bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight)
{
if(!masternodeSync.IsSynced()) { //there is no budget data to use to check anything -- find the longest chain
LogPrint("mnpayments", "Client not synced, skipping block payee checks\n");
return true;
}
//check if it's a budget block
if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
if(budget.IsBudgetPaymentBlock(nBlockHeight)){
if(budget.IsTransactionValid(txNew, nBlockHeight)){
return true;
} else {
LogPrintf("Invalid budget payment detected %s\n", txNew.ToString().c_str());
if(IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)){
return false;
} else {
LogPrintf("Budget enforcement is disabled, accepting block\n");
return true;
}
}
}
}
//check for masternode payee
if(masternodePayments.IsTransactionValid(txNew, nBlockHeight))
{
return true;
} else {
LogPrintf("Invalid mn payment detected %s\n", txNew.ToString().c_str());
if(IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)){
return false;
} else {
LogPrintf("Masternode payment enforcement is disabled, accepting block\n");
return true;
}
}
return false;
}
void FillBlockPayee(CMutableTransaction& txNew, int64_t nFees)
{
CBlockIndex* pindexPrev = chainActive.Tip();
if(!pindexPrev) return;
if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(pindexPrev->nHeight+1)){
budget.FillBlockPayee(txNew, nFees);
} else {
masternodePayments.FillBlockPayee(txNew, nFees);
}
}
std::string GetRequiredPaymentsString(int nBlockHeight)
{
if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(nBlockHeight)){
return budget.GetRequiredPaymentsString(nBlockHeight);
} else {
return masternodePayments.GetRequiredPaymentsString(nBlockHeight);
}
}
void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFees)
{
CBlockIndex* pindexPrev = chainActive.Tip();
if(!pindexPrev) return;
bool hasPayment = true;
CScript payee;
//spork
if(!masternodePayments.GetBlockPayee(pindexPrev->nHeight+1, payee)){
//no masternode detected
CMasternode* winningNode = mnodeman.GetCurrentMasterNode(1);
if(winningNode){
payee = GetScriptForDestination(winningNode->pubkey.GetID());
} else {
LogPrintf("CreateNewBlock: Failed to detect masternode to pay\n");
hasPayment = false;
}
}
CAmount blockValue = GetBlockValue(pindexPrev->nBits, pindexPrev->nHeight, nFees);
CAmount masternodePayment = GetMasternodePayment(pindexPrev->nHeight+1, blockValue);
txNew.vout[0].nValue = blockValue;
if(hasPayment){
txNew.vout.resize(2);
txNew.vout[1].scriptPubKey = payee;
txNew.vout[1].nValue = masternodePayment;
txNew.vout[0].nValue -= masternodePayment;
CTxDestination address1;
ExtractDestination(payee, address1);
CBitcoinAddress address2(address1);
LogPrintf("Masternode payment to %s\n", address2.ToString().c_str());
}
}
int CMasternodePayments::GetMinMasternodePaymentsProto() {
return IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)
? MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2
: MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1;
}
void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
if(!masternodeSync.IsBlockchainSynced()) return;
if(fLiteMode) return; //disable all Darksend/Masternode related functionality
if (strCommand == "mnget") { //Masternode Payments Request Sync
if(fLiteMode) return; //disable all Darksend/Masternode related functionality
int nCountNeeded;
vRecv >> nCountNeeded;
if(Params().NetworkID() == CBaseChainParams::MAIN){
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, nCountNeeded);
LogPrintf("mnget - Sent Masternode winners to %s\n", pfrom->addr.ToString().c_str());
}
else if (strCommand == "mnw") { //Masternode Payments Declare Winner
//this is required in litemodef
CMasternodePaymentWinner winner;
vRecv >> winner;
if(pfrom->nVersion < MIN_MNW_PEER_PROTO_VERSION) return;
if(chainActive.Tip() == NULL) return;
if(masternodePayments.mapMasternodePayeeVotes.count(winner.GetHash())){
LogPrint("mnpayments", "mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), chainActive.Tip()->nHeight);
masternodeSync.AddedMasternodeWinner(winner.GetHash());
return;
}
int nFirstBlock = chainActive.Tip()->nHeight - (mnodeman.CountEnabled()*2);
if(winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > chainActive.Tip()->nHeight+20){
LogPrintf("mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, chainActive.Tip()->nHeight);
return;
}
std::string strError = "";
if(!winner.IsValid(pfrom, strError)){
LogPrintf("mnw - invalid message - %s\n", strError);
return;
}
if(!masternodePayments.CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)){
LogPrintf("mnw - masternode already voted - %s\n", winner.vinMasternode.prevout.ToStringShort());
return;
}
if(!winner.SignatureValid()){
LogPrintf("mnw - invalid signature\n");
Misbehaving(pfrom->GetId(), 20);
// it could just be a non-synced masternode
mnodeman.AskForMN(pfrom, winner.vinMasternode);
return;
}
CTxDestination address1;
ExtractDestination(winner.payee, address1);
CBitcoinAddress address2(address1);
LogPrint("mnpayments", "mnw - winning vote - Addr %s Height %d bestHeight %d - %s\n", address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight, winner.vinMasternode.prevout.ToStringShort());
if(masternodePayments.AddWinningMasternode(winner)){
winner.Relay();
masternodeSync.AddedMasternodeWinner(winner.GetHash());
}
}
}
bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
{
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;
}
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) {
LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
return false;
}
return true;
}
bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
{
if(mapMasternodeBlocks.count(nBlockHeight)){
return mapMasternodeBlocks[nBlockHeight].GetPayee(payee);
}
return false;
}
// Is this masternode scheduled to get paid soon?
// -- Only look ahead up to 8 blocks to allow for propagation of the latest 2 winners
bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight)
{
LOCK(cs_mapMasternodeBlocks);
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+8; h++){
if(h == nNotBlockHeight) continue;
if(mapMasternodeBlocks.count(h)){
if(mapMasternodeBlocks[h].GetPayee(payee)){
if(mnpayee == payee) {
return true;
}
}
}
}
return false;
}
bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
{
uint256 blockHash = 0;
if(!GetBlockHash(blockHash, winnerIn.nBlockHeight-100)) {
return false;
}
{
LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
if(mapMasternodePayeeVotes.count(winnerIn.GetHash())){
return false;
}
mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;
if(!mapMasternodeBlocks.count(winnerIn.nBlockHeight)){
CMasternodeBlockPayees blockPayees(winnerIn.nBlockHeight);
mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
}
}
int n = 1;
if(IsReferenceNode(winnerIn.vinMasternode)) n = 100;
mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, n);
return true;
}
bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
{
LOCK(cs_vecPayments);
int nMaxSignatures = 0;
std::string strPayeesPossible = "";
CAmount masternodePayment = GetMasternodePayment(nBlockHeight, txNew.GetValueOut());
//require at least 6 signatures
BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
if(payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED)
nMaxSignatures = payee.nVotes;
// if we don't have at least 6 signatures on a payee, approve whichever is the longest chain
if(nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true;
BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
{
bool found = false;
BOOST_FOREACH(CTxOut out, txNew.vout){
if(payee.scriptPubKey == out.scriptPubKey && masternodePayment == out.nValue){
found = true;
}
}
if(payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED){
if(found) return true;
CTxDestination address1;
ExtractDestination(payee.scriptPubKey, address1);
CBitcoinAddress address2(address1);
if(strPayeesPossible == ""){
strPayeesPossible += address2.ToString();
} else {
strPayeesPossible += "," + address2.ToString();
}
}
}
LogPrintf("CMasternodePayments::IsTransactionValid - Missing required payment - %s\n", strPayeesPossible.c_str());
return false;
}
std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
{
LOCK(cs_vecPayments);
std::string ret = "Unknown";
BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
{
CTxDestination address1;
ExtractDestination(payee.scriptPubKey, address1);
CBitcoinAddress address2(address1);
if(ret != "Unknown"){
ret += ", " + address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
} else {
ret = address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
}
}
return ret;
}
std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight)
{
LOCK(cs_mapMasternodeBlocks);
if(mapMasternodeBlocks.count(nBlockHeight)){
return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
}
return "Unknown";
}
bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
{
LOCK(cs_mapMasternodeBlocks);
if(mapMasternodeBlocks.count(nBlockHeight)){
return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew);
}
return true;
}
void CMasternodePayments::CleanPaymentList()
{
LOCK(cs_mapMasternodePayeeVotes);
if(chainActive.Tip() == NULL) return;
//keep up to five cycles for historical sake
int nLimit = std::max(((int)mnodeman.size())*2, 1000);
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
while(it != mapMasternodePayeeVotes.end()) {
CMasternodePaymentWinner winner = (*it).second;
if(chainActive.Tip()->nHeight - winner.nBlockHeight > nLimit){
LogPrint("mnpayments", "CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", winner.nBlockHeight);
masternodeSync.mapSeenSyncMNW.erase((*it).first);
mapMasternodePayeeVotes.erase(it++);
} else {
++it;
}
}
}
bool IsReferenceNode(CTxIn& vin)
{
//reference node - hybrid mode
if(vin.prevout.ToStringShort() == "099c01bea63abd1692f60806bb646fa1d288e2d049281225f17e499024084e28-0") return true; // mainnet
if(vin.prevout.ToStringShort() == "fbc16ae5229d6d99181802fd76a4feee5e7640164dcebc7f8feb04a7bea026f8-0") return true; // testnet
if(vin.prevout.ToStringShort() == "e466f5d8beb4c2d22a314310dc58e0ea89505c95409754d0d68fb874952608cc-1") return true; // regtest
return false;
}
bool CMasternodePaymentWinner::IsValid(CNode* pnode, std::string& strError)
{
if(IsReferenceNode(vinMasternode)) return true;
CMasternode* pmn = mnodeman.Find(vinMasternode);
if(!pmn)
{
strError = strprintf("Unknown Masternode %s", vinMasternode.prevout.ToStringShort());
LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
mnodeman.AskForMN(pnode, vinMasternode);
return false;
}
if(pmn->protocolVersion < MIN_MNW_PEER_PROTO_VERSION)
{
strError = strprintf("Masternode protocol too old %d - req %d", pmn->protocolVersion, MIN_MNW_PEER_PROTO_VERSION);
LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
return false;
}
int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight-100, MIN_MNW_PEER_PROTO_VERSION);
if(n > MNPAYMENTS_SIGNATURES_TOTAL)
{
strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL, n);
LogPrintf("CMasternodePaymentWinner::IsValid - %s\n", strError);
return false;
}
return true;
}
bool CMasternodePayments::ProcessBlock(int nBlockHeight)
{
if(!fMasterNode) return false;
//reference node - hybrid mode
if(!IsReferenceNode(activeMasternode.vin)){
int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight-100, MIN_MNW_PEER_PROTO_VERSION);
if(n == -1)
{
LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Unknown Masternode\n");
return false;
}
if(n > MNPAYMENTS_SIGNATURES_TOTAL)
{
LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
return false;
}
}
if(nBlockHeight <= nLastBlockHeight) return false;
CMasternodePaymentWinner newWinner(activeMasternode.vin);
if(budget.IsBudgetPaymentBlock(nBlockHeight)){
//is budget payment block -- handled by the budgeting software
} else {
LogPrintf("CMasternodePayments::ProcessBlock() Start nHeight %d - vin %s. \n", nBlockHeight, activeMasternode.vin.ToString().c_str());
// pay to the oldest MN that still had no payment but its input is old enough and it was active long enough
int nCount = 0;
CMasternode *pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount);
if(pmn != NULL)
{
LogPrintf("CMasternodePayments::ProcessBlock() Found by FindOldestNotInVec \n");
newWinner.nBlockHeight = nBlockHeight;
CScript payee = GetScriptForDestination(pmn->pubkey.GetID());
newWinner.AddPayee(payee);
CTxDestination address1;
ExtractDestination(payee, address1);
CBitcoinAddress address2(address1);
LogPrintf("CMasternodePayments::ProcessBlock() Winner payee %s nHeight %d. \n", address2.ToString().c_str(), newWinner.nBlockHeight);
} else {
LogPrintf("CMasternodePayments::ProcessBlock() Failed to find masternode to pay\n");
}
}
std::string errorMessage;
CPubKey pubKeyMasternode;
CKey keyMasternode;
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
{
LogPrintf("CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str());
return false;
}
LogPrintf("CMasternodePayments::ProcessBlock() - Signing Winner\n");
if(newWinner.Sign(keyMasternode, pubKeyMasternode))
{
LogPrintf("CMasternodePayments::ProcessBlock() - AddWinningMasternode\n");
if(AddWinningMasternode(newWinner))
{
newWinner.Relay();
nLastBlockHeight = nBlockHeight;
return true;
}
}
return false;
}
void CMasternodePaymentWinner::Relay()
{
CInv inv(MSG_MASTERNODE_WINNER, GetHash());
RelayInv(inv);
}
bool CMasternodePaymentWinner::SignatureValid()
{
CMasternode* pmn = mnodeman.Find(vinMasternode);
if(pmn != NULL)
{
std::string strMessage = vinMasternode.prevout.ToStringShort() +
boost::lexical_cast<std::string>(nBlockHeight) +
payee.ToString();
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());
}
return true;
}
return false;
}
void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
{
LOCK(cs_mapMasternodePayeeVotes);
if(chainActive.Tip() == NULL) return;
int nCount = (mnodeman.CountEnabled()*2);
if(nCountNeeded > nCount) nCountNeeded = nCount;
vector<CInv> vInv;
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
while(it != mapMasternodePayeeVotes.end()) {
CMasternodePaymentWinner winner = (*it).second;
if(winner.nBlockHeight >= chainActive.Tip()->nHeight-nCountNeeded && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20) {
CInv inv(MSG_MASTERNODE_WINNER, winner.GetHash());
vInv.push_back(inv);
}
++it;
}
node->PushMessage("ssc", MASTERNODE_SYNC_MNW, (int)vInv.size());
if(vInv.size() > 0) node->PushMessage("inv", vInv);
}
std::string CMasternodePayments::ToString() const
{
std::ostringstream info;
info << "Votes: " << (int)mapMasternodePayeeVotes.size() <<
", Blocks: " << (int)mapMasternodeBlocks.size();
return info.str();
}
int CMasternodePayments::GetOldestBlock()
{
LOCK(cs_mapMasternodeBlocks);
int nOldestBlock = std::numeric_limits<int>::max();
std::map<int, CMasternodeBlockPayees>::iterator it = mapMasternodeBlocks.begin();
while(it != mapMasternodeBlocks.end()) {
if((*it).first < nOldestBlock) {
nOldestBlock = (*it).first;
}
it++;
}
return nOldestBlock;
}
int CMasternodePayments::GetNewestBlock()
{
LOCK(cs_mapMasternodeBlocks);
int nNewestBlock = 0;
std::map<int, CMasternodeBlockPayees>::iterator it = mapMasternodeBlocks.begin();
while(it != mapMasternodeBlocks.end()) {
if((*it).first > nNewestBlock) {
nNewestBlock = (*it).first;
}
it++;
}
return nNewestBlock;
}