2015-04-16 21:58:09 +02:00
|
|
|
// 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"
|
2015-05-04 17:04:09 +02:00
|
|
|
#include "masternode-budget.h"
|
2015-07-15 04:44:58 +02:00
|
|
|
#include "masternode-sync.h"
|
2015-04-16 21:58:09 +02:00
|
|
|
#include "masternodeman.h"
|
|
|
|
#include "darksend.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "sync.h"
|
2015-05-30 19:27:51 +02:00
|
|
|
#include "spork.h"
|
2015-04-16 21:58:09 +02:00
|
|
|
#include "addrman.h"
|
|
|
|
#include <boost/lexical_cast.hpp>
|
2015-07-21 04:24:43 +02:00
|
|
|
#include <boost/filesystem.hpp>
|
2015-04-16 21:58:09 +02:00
|
|
|
|
|
|
|
CCriticalSection cs_masternodepayments;
|
|
|
|
|
|
|
|
/** Object for who's going to get paid on which blocks */
|
|
|
|
CMasternodePayments masternodePayments;
|
2015-07-21 04:24:43 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// 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);
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-07-04 16:49:49 +02:00
|
|
|
bool IsBlockValueValid(const CBlock& block, int64_t nExpectedValue){
|
2015-05-30 19:27:51 +02:00
|
|
|
CBlockIndex* pindexPrev = chainActive.Tip();
|
|
|
|
if(pindexPrev == NULL) return true;
|
|
|
|
|
2015-07-04 16:49:49 +02:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2015-07-17 05:03:42 +02:00
|
|
|
//are these blocks even enabled?
|
|
|
|
if(!IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
|
2015-07-17 17:07:07 +02:00
|
|
|
return block.vtx[0].GetValueOut() > nExpectedValue;
|
2015-07-17 05:03:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!masternodeSync.IsSynced()) { //there is no budget data to use to check anything
|
2015-05-30 19:27:51 +02:00
|
|
|
//super blocks will always be on these blocks, max 100 per budgeting
|
2015-07-04 16:49:49 +02:00
|
|
|
if(nHeight % GetBudgetPaymentCycleBlocks() < 100){
|
2015-05-30 19:27:51 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
2015-07-04 16:49:49 +02:00
|
|
|
if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
|
2015-05-30 19:27:51 +02:00
|
|
|
}
|
2015-07-02 01:46:03 +02:00
|
|
|
} else { // we're synced and have data so check the budget schedule
|
2015-07-04 16:49:49 +02:00
|
|
|
if(budget.IsBudgetPaymentBlock(nHeight)){
|
2015-05-30 19:27:51 +02:00
|
|
|
//the value of the block is evaluated in CheckBlock
|
|
|
|
return true;
|
|
|
|
} else {
|
2015-07-04 16:49:49 +02:00
|
|
|
if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
|
2015-05-30 19:27:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-07-17 17:07:07 +02:00
|
|
|
bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight)
|
2015-05-04 17:04:09 +02:00
|
|
|
{
|
2015-07-18 15:46:54 +02:00
|
|
|
if(!masternodeSync.IsSynced()) { //there is no budget data to use to check anything -- find the longest chain
|
2015-07-24 18:10:08 +02:00
|
|
|
if(fDebug) LogPrintf("Client not synced, skipping block payee checks\n");
|
2015-07-18 15:46:54 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
//check if it's a budget block
|
2015-05-26 16:56:51 +02:00
|
|
|
if(budget.IsBudgetPaymentBlock(nBlockHeight)){
|
2015-05-04 17:04:09 +02:00
|
|
|
if(budget.IsTransactionValid(txNew, nBlockHeight)){
|
|
|
|
return true;
|
2015-05-30 19:27:51 +02:00
|
|
|
} else {
|
|
|
|
LogPrintf("Invalid budget payment detected %s\n", txNew.ToString().c_str());
|
|
|
|
if(IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)){
|
|
|
|
return false;
|
|
|
|
} else {
|
2015-06-23 22:44:20 +02:00
|
|
|
LogPrintf("Budget enforcement is disabled, accepting block\n");
|
2015-05-30 19:27:51 +02:00
|
|
|
return true;
|
|
|
|
}
|
2015-05-04 17:04:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//check for masternode payee
|
|
|
|
if(masternodePayments.IsTransactionValid(txNew, nBlockHeight))
|
|
|
|
{
|
|
|
|
return true;
|
2015-05-30 19:27:51 +02:00
|
|
|
} else {
|
|
|
|
LogPrintf("Invalid mn payment detected %s\n", txNew.ToString().c_str());
|
|
|
|
if(IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)){
|
|
|
|
return false;
|
|
|
|
} else {
|
2015-06-23 22:44:20 +02:00
|
|
|
LogPrintf("Masternode payment enforcement is disabled, accepting block\n");
|
2015-05-30 19:27:51 +02:00
|
|
|
return true;
|
|
|
|
}
|
2015-05-04 17:04:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-05-30 19:27:51 +02:00
|
|
|
|
|
|
|
void FillBlockPayee(CMutableTransaction& txNew, int64_t nFees)
|
|
|
|
{
|
|
|
|
CBlockIndex* pindexPrev = chainActive.Tip();
|
|
|
|
if(!pindexPrev) return;
|
2015-06-25 17:17:53 +02:00
|
|
|
|
2015-05-30 19:27:51 +02:00
|
|
|
if(budget.IsBudgetPaymentBlock(pindexPrev->nHeight+1)){
|
|
|
|
budget.FillBlockPayee(txNew, nFees);
|
|
|
|
} else {
|
|
|
|
masternodePayments.FillBlockPayee(txNew, nFees);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-17 17:07:07 +02:00
|
|
|
std::string GetRequiredPaymentsString(int nBlockHeight)
|
2015-05-26 16:56:51 +02:00
|
|
|
{
|
|
|
|
if(budget.IsBudgetPaymentBlock(nBlockHeight)){
|
|
|
|
return budget.GetRequiredPaymentsString(nBlockHeight);
|
|
|
|
} else {
|
|
|
|
return masternodePayments.GetRequiredPaymentsString(nBlockHeight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-30 19:27:51 +02:00
|
|
|
void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFees)
|
|
|
|
{
|
|
|
|
CBlockIndex* pindexPrev = chainActive.Tip();
|
|
|
|
if(!pindexPrev) return;
|
|
|
|
|
|
|
|
bool hasPayment = true;
|
|
|
|
CScript payee;
|
2015-06-25 17:17:53 +02:00
|
|
|
|
2015-05-30 19:27:51 +02:00
|
|
|
//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);
|
2015-06-25 17:17:53 +02:00
|
|
|
|
2015-05-30 19:27:51 +02:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-08 03:57:32 +02:00
|
|
|
int CMasternodePayments::GetMinMasternodePaymentsProto() {
|
2015-07-22 01:11:49 +02:00
|
|
|
return IsSporkActive(SPORK_10_MASTERNODE_PAY_NEWEST_NODES)
|
|
|
|
? MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2
|
|
|
|
: MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1;
|
2015-07-08 03:57:32 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
|
|
|
if(IsInitialBlockDownload()) return;
|
|
|
|
|
|
|
|
if (strCommand == "mnget") { //Masternode Payments Request Sync
|
|
|
|
if(fLiteMode) return; //disable all Darksend/Masternode related functionality
|
|
|
|
|
2015-07-21 00:09:42 +02:00
|
|
|
int nCountNeeded;
|
|
|
|
vRecv >> nCountNeeded;
|
|
|
|
|
2015-07-21 04:24:43 +02:00
|
|
|
if(Params().NetworkID() == CBaseChainParams::MAIN){
|
|
|
|
if(pfrom->HasFulfilledRequest("mnget")) {
|
|
|
|
LogPrintf("mnget - peer already asked me for the list\n");
|
|
|
|
Misbehaving(pfrom->GetId(), 20);
|
|
|
|
return;
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
2015-07-21 04:24:43 +02:00
|
|
|
|
2015-04-16 21:58:09 +02:00
|
|
|
pfrom->FulfilledRequest("mnget");
|
2015-07-21 00:09:42 +02:00
|
|
|
masternodePayments.Sync(pfrom, nCountNeeded);
|
2015-04-16 21:58:09 +02:00
|
|
|
LogPrintf("mnget - Sent Masternode winners to %s\n", pfrom->addr.ToString().c_str());
|
|
|
|
}
|
|
|
|
else if (strCommand == "mnw") { //Masternode Payments Declare Winner
|
2015-07-23 23:35:14 +02:00
|
|
|
// disabled due to locking issues
|
|
|
|
//LOCK(cs_masternodepayments);
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-05-27 21:47:01 +02:00
|
|
|
//this is required in litemodef
|
2015-04-16 21:58:09 +02:00
|
|
|
CMasternodePaymentWinner winner;
|
|
|
|
vRecv >> winner;
|
|
|
|
|
|
|
|
if(chainActive.Tip() == NULL) return;
|
|
|
|
|
2015-07-21 04:24:43 +02:00
|
|
|
if(masternodePayments.mapMasternodePayeeVotes.count(winner.GetHash())){
|
2015-04-22 16:33:44 +02:00
|
|
|
if(fDebug) LogPrintf("mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), chainActive.Tip()->nHeight);
|
2015-07-24 20:35:11 +02:00
|
|
|
masternodeSync.AddedMasternodeWinner();
|
2015-06-25 17:17:53 +02:00
|
|
|
return;
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-07-22 05:07:23 +02:00
|
|
|
int nFirstBlock = chainActive.Tip()->nHeight - (mnodeman.CountEnabled()*2);
|
2015-07-21 00:09:42 +02:00
|
|
|
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);
|
2015-04-16 21:58:09 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-07-18 21:24:06 +02:00
|
|
|
std::string strError = "";
|
|
|
|
if(!winner.IsValid(strError)){
|
|
|
|
LogPrintf("mnw - invalid message - %s\n", strError);
|
2015-04-16 21:58:09 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-07-24 16:12:48 +02:00
|
|
|
if(!masternodePayments.CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)){
|
|
|
|
LogPrintf("mnw - masternode already voted - %s\n", winner.vinMasternode.prevout.ToStringShort());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
if(!winner.SignatureValid()){
|
2015-04-16 21:58:09 +02:00
|
|
|
LogPrintf("mnw - invalid signature\n");
|
|
|
|
Misbehaving(pfrom->GetId(), 100);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
CTxDestination address1;
|
2015-06-25 20:08:50 +02:00
|
|
|
ExtractDestination(winner.payee, address1);
|
2015-04-22 16:33:44 +02:00
|
|
|
CBitcoinAddress address2(address1);
|
|
|
|
|
2015-07-24 16:12:48 +02:00
|
|
|
if(fDebug) LogPrintf("mnw - winning vote - Addr %s Height %d bestHeight %d - %s\n", address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight, winner.vinMasternode.prevout.ToStringShort());
|
2015-04-16 21:58:09 +02:00
|
|
|
|
|
|
|
if(masternodePayments.AddWinningMasternode(winner)){
|
2015-04-22 16:33:44 +02:00
|
|
|
winner.Relay();
|
2015-07-15 04:44:58 +02:00
|
|
|
masternodeSync.AddedMasternodeWinner();
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
2015-04-22 16:33:44 +02:00
|
|
|
std::string errorMessage;
|
|
|
|
std::string strMasterNodeSignMessage;
|
|
|
|
|
|
|
|
std::string strMessage = vinMasternode.prevout.ToStringShort() +
|
2015-06-25 17:17:53 +02:00
|
|
|
boost::lexical_cast<std::string>(nBlockHeight) +
|
2015-04-22 16:33:44 +02:00
|
|
|
payee.ToString();
|
2015-06-25 17:17:53 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) {
|
|
|
|
LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
|
|
|
|
return false;
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) {
|
|
|
|
LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
|
2015-04-16 21:58:09 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
2015-05-28 19:45:31 +02:00
|
|
|
if(mapMasternodeBlocks.count(nBlockHeight)){
|
2015-04-22 16:33:44 +02:00
|
|
|
return mapMasternodeBlocks[nBlockHeight].GetPayee(payee);
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
return false;
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-07-22 05:07:23 +02:00
|
|
|
// Is this masternode scheduled to get paid soon?
|
2015-07-23 15:45:43 +02:00
|
|
|
// -- Only look ahead up to 8 blocks to allow for propagation of the latest 2 winners
|
2015-06-15 02:05:51 +02:00
|
|
|
bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight)
|
2015-05-27 21:47:01 +02:00
|
|
|
{
|
|
|
|
CBlockIndex* pindexPrev = chainActive.Tip();
|
|
|
|
if(pindexPrev == NULL) return false;
|
|
|
|
|
|
|
|
CScript mnpayee;
|
|
|
|
mnpayee = GetScriptForDestination(mn.pubkey.GetID());
|
|
|
|
|
|
|
|
CScript payee;
|
2015-07-23 15:45:43 +02:00
|
|
|
for(int64_t h = pindexPrev->nHeight; h <= pindexPrev->nHeight+8; h++){
|
2015-06-15 02:05:51 +02:00
|
|
|
if(h == nNotBlockHeight) continue;
|
2015-05-27 21:47:01 +02:00
|
|
|
if(mapMasternodeBlocks.count(h)){
|
2015-05-28 19:45:31 +02:00
|
|
|
if(mapMasternodeBlocks[h].GetPayee(payee)){
|
2015-06-23 18:38:28 +02:00
|
|
|
if(mnpayee == payee) {
|
2015-05-28 19:45:31 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2015-05-27 21:47:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
|
|
|
|
{
|
|
|
|
uint256 blockHash = 0;
|
2015-05-26 16:56:51 +02:00
|
|
|
if(!GetBlockHash(blockHash, winnerIn.nBlockHeight-100)) {
|
2015-04-16 21:58:09 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
if(mapMasternodePayeeVotes.count(winnerIn.GetHash())){
|
2015-06-25 17:17:53 +02:00
|
|
|
return false;
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;
|
|
|
|
|
|
|
|
if(!mapMasternodeBlocks.count(winnerIn.nBlockHeight)){
|
2015-05-28 19:45:31 +02:00
|
|
|
CMasternodeBlockPayees blockPayees(winnerIn.nBlockHeight);
|
2015-04-22 16:33:44 +02:00
|
|
|
mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
int n = 1;
|
|
|
|
if(IsReferenceNode(winnerIn.vinMasternode)) n = 100;
|
2015-06-25 20:08:50 +02:00
|
|
|
mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, n);
|
2015-04-22 16:33:44 +02:00
|
|
|
|
2015-04-16 21:58:09 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
2015-05-04 17:04:09 +02:00
|
|
|
int nMaxSignatures = 0;
|
|
|
|
std::string strPayeesPossible = "";
|
|
|
|
|
2015-06-25 20:08:50 +02:00
|
|
|
CAmount masternodePayment = GetMasternodePayment(nBlockHeight, txNew.GetValueOut());
|
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
//require at least 6 signatures
|
|
|
|
|
|
|
|
BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
|
2015-05-16 04:53:53 +02:00
|
|
|
if(payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED)
|
2015-05-04 17:04:09 +02:00
|
|
|
nMaxSignatures = payee.nVotes;
|
2015-06-25 17:17:53 +02:00
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
// if we don't have at least 6 signatures on a payee, approve whichever is the longest chain
|
2015-06-21 19:06:25 +02:00
|
|
|
if(nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true;
|
2015-05-04 17:04:09 +02:00
|
|
|
|
|
|
|
BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
|
2015-04-22 16:33:44 +02:00
|
|
|
{
|
|
|
|
bool found = false;
|
2015-06-25 17:17:53 +02:00
|
|
|
BOOST_FOREACH(CTxOut out, txNew.vout){
|
2015-06-25 20:08:50 +02:00
|
|
|
if(payee.scriptPubKey == out.scriptPubKey && masternodePayment == out.nValue){
|
2015-04-22 16:33:44 +02:00
|
|
|
found = true;
|
2015-06-25 17:17:53 +02:00
|
|
|
}
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-06-25 17:17:53 +02:00
|
|
|
if(payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED){
|
2015-05-04 17:04:09 +02:00
|
|
|
if(found) return true;
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
CTxDestination address1;
|
|
|
|
ExtractDestination(payee.scriptPubKey, address1);
|
|
|
|
CBitcoinAddress address2(address1);
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
if(strPayeesPossible == ""){
|
2015-06-25 20:08:50 +02:00
|
|
|
strPayeesPossible += address2.ToString();
|
2015-05-04 17:04:09 +02:00
|
|
|
} else {
|
2015-06-25 20:08:50 +02:00
|
|
|
strPayeesPossible += "," + address2.ToString();
|
2015-05-04 17:04:09 +02:00
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
}
|
2015-05-04 17:04:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
LogPrintf("CMasternodePayments::IsTransactionValid - Missing required payment - %s\n", strPayeesPossible.c_str());
|
|
|
|
return false;
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
2015-04-22 16:33:44 +02:00
|
|
|
std::string ret = "Unknown";
|
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
|
2015-04-22 16:33:44 +02:00
|
|
|
{
|
2015-05-26 16:56:51 +02:00
|
|
|
CTxDestination address1;
|
|
|
|
ExtractDestination(payee.scriptPubKey, address1);
|
|
|
|
CBitcoinAddress address2(address1);
|
2015-04-22 16:33:44 +02:00
|
|
|
|
2015-05-26 16:56:51 +02:00
|
|
|
if(ret != "Unknown"){
|
2015-06-25 20:08:50 +02:00
|
|
|
ret += ", " + address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
|
2015-05-26 16:56:51 +02:00
|
|
|
} else {
|
2015-06-25 20:22:11 +02:00
|
|
|
ret = address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes);
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
}
|
2015-05-04 17:04:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
return ret;
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight)
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
2015-04-22 16:33:44 +02:00
|
|
|
if(mapMasternodeBlocks.count(nBlockHeight)){
|
|
|
|
return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
return "Unknown";
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
|
|
|
|
{
|
|
|
|
if(mapMasternodeBlocks.count(nBlockHeight)){
|
|
|
|
return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew);
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
return true;
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CMasternodePayments::CleanPaymentList()
|
|
|
|
{
|
|
|
|
LOCK(cs_masternodepayments);
|
|
|
|
|
|
|
|
if(chainActive.Tip() == NULL) return;
|
|
|
|
|
2015-07-22 05:07:23 +02:00
|
|
|
//keep up to five cycles for historical sake
|
|
|
|
int nLimit = std::max(((int)mnodeman.size())*5, 1000);
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
|
|
|
|
while(it != mapMasternodePayeeVotes.end()) {
|
|
|
|
CMasternodePaymentWinner winner = (*it).second;
|
2015-06-25 17:17:53 +02:00
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
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;
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
2015-05-04 17:04:09 +02:00
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
bool IsReferenceNode(CTxIn& vin)
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
2015-04-22 16:33:44 +02:00
|
|
|
//reference node - hybrid mode
|
|
|
|
if(vin.prevout.ToStringShort() == "099c01bea63abd1692f60806bb646fa1d288e2d049281225f17e499024084e28-0") return true; // mainnet
|
2015-06-19 20:33:02 +02:00
|
|
|
if(vin.prevout.ToStringShort() == "fbc16ae5229d6d99181802fd76a4feee5e7640164dcebc7f8feb04a7bea026f8-0") return true; // testnet
|
|
|
|
if(vin.prevout.ToStringShort() == "e466f5d8beb4c2d22a314310dc58e0ea89505c95409754d0d68fb874952608cc-1") return true; // regtest
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
return false;
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-07-18 21:24:06 +02:00
|
|
|
bool CMasternodePaymentWinner::IsValid(std::string& strError)
|
2015-04-22 16:33:44 +02:00
|
|
|
{
|
|
|
|
if(IsReferenceNode(vinMasternode)) return true;
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-07-21 17:09:17 +02:00
|
|
|
CMasternode* pmn = mnodeman.Find(vinMasternode);
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-07-21 17:09:17 +02:00
|
|
|
if(!pmn)
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
2015-07-21 17:09:17 +02:00
|
|
|
strError = strprintf("Unknown Masternode %s", vinMasternode.prevout.ToStringShort());
|
|
|
|
LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
|
2015-04-22 16:33:44 +02:00
|
|
|
return false;
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-07-22 01:11:49 +02:00
|
|
|
if(pmn->protocolVersion < MIN_MNW_PEER_PROTO_VERSION)
|
2015-07-21 17:09:17 +02:00
|
|
|
{
|
2015-07-22 01:11:49 +02:00
|
|
|
strError = strprintf("Masternode protocol too old %d - req %d", pmn->protocolVersion, MIN_MNW_PEER_PROTO_VERSION);
|
2015-07-21 17:09:17 +02:00
|
|
|
LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-22 01:11:49 +02:00
|
|
|
int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight-100, MIN_MNW_PEER_PROTO_VERSION);
|
2015-07-21 17:09:17 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
if(n > MNPAYMENTS_SIGNATURES_TOTAL)
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
2015-07-21 17:09:17 +02:00
|
|
|
strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL, n);
|
|
|
|
LogPrintf ("CMasternodePaymentWinner::IsValid - %s\n", strError);
|
2015-04-22 16:33:44 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CMasternodePayments::ProcessBlock(int nBlockHeight)
|
|
|
|
{
|
|
|
|
LOCK(cs_masternodepayments);
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
if(!fMasterNode) return false;
|
|
|
|
|
|
|
|
//reference node - hybrid mode
|
|
|
|
|
|
|
|
if(!IsReferenceNode(activeMasternode.vin)){
|
2015-07-08 03:57:32 +02:00
|
|
|
int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight-100, GetMinMasternodePaymentsProto());
|
2015-04-22 16:33:44 +02:00
|
|
|
|
|
|
|
if(n == -1)
|
|
|
|
{
|
|
|
|
if(fDebug) LogPrintf("CMasternodePayments::ProcessBlock - Unknown Masternode\n");
|
|
|
|
return false;
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
if(n > MNPAYMENTS_SIGNATURES_TOTAL)
|
|
|
|
{
|
|
|
|
if(fDebug) LogPrintf("CMasternodePayments::ProcessBlock - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
|
|
|
|
return false;
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
if(nBlockHeight <= nLastBlockHeight) return false;
|
2015-06-25 17:17:53 +02:00
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
CMasternodePaymentWinner newWinner(activeMasternode.vin);
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
if(budget.IsBudgetPaymentBlock(nBlockHeight)){
|
2015-05-27 21:47:01 +02:00
|
|
|
//is budget payment block -- handled by the budgeting software
|
2015-05-04 17:04:09 +02:00
|
|
|
} else {
|
2015-04-22 16:33:44 +02:00
|
|
|
uint256 hash;
|
2015-06-15 02:05:51 +02:00
|
|
|
|
2015-05-26 16:56:51 +02:00
|
|
|
if(!GetBlockHash(hash, nBlockHeight-100)) return false;
|
2015-04-22 16:33:44 +02:00
|
|
|
unsigned int nHash;
|
|
|
|
memcpy(&nHash, &hash, 2);
|
|
|
|
|
2015-06-24 18:41:03 +02:00
|
|
|
LogPrintf("CMasternodePayments::ProcessBlock() Start nHeight %d - vin %s. \n", nBlockHeight, activeMasternode.vin.ToString().c_str());
|
2015-04-22 16:33:44 +02:00
|
|
|
|
|
|
|
// pay to the oldest MN that still had no payment but its input is old enough and it was active long enough
|
2015-07-25 01:10:44 +02:00
|
|
|
CMasternode *pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true);
|
|
|
|
if(pmn == NULL) pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, false); // if no results, look for any node with a newer sigTime
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
if(pmn != NULL)
|
|
|
|
{
|
2015-06-22 15:50:33 +02:00
|
|
|
LogPrintf("CMasternodePayments::ProcessBlock() Found by FindOldestNotInVec \n");
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
newWinner.nBlockHeight = nBlockHeight;
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-06-23 18:38:28 +02:00
|
|
|
CScript payee = GetScriptForDestination(pmn->pubkey.GetID());
|
2015-06-25 20:08:50 +02:00
|
|
|
newWinner.AddPayee(payee);
|
2015-06-25 17:17:53 +02:00
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
CTxDestination address1;
|
|
|
|
ExtractDestination(payee, address1);
|
|
|
|
CBitcoinAddress address2(address1);
|
2015-04-22 16:33:44 +02:00
|
|
|
|
2015-06-23 18:38:28 +02:00
|
|
|
LogPrintf("CMasternodePayments::ProcessBlock() Winner payee %s nHeight %d. \n", address2.ToString().c_str(), newWinner.nBlockHeight);
|
2015-05-04 17:04:09 +02:00
|
|
|
} else {
|
2015-06-22 15:50:33 +02:00
|
|
|
LogPrintf("CMasternodePayments::ProcessBlock() Failed to find masternode to pay\n");
|
2015-05-04 17:04:09 +02:00
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
std::string errorMessage;
|
|
|
|
CPubKey pubKeyMasternode;
|
|
|
|
CKey keyMasternode;
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
|
|
|
|
{
|
|
|
|
LogPrintf("CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str());
|
|
|
|
return false;
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-06-22 15:50:33 +02:00
|
|
|
LogPrintf("CMasternodePayments::ProcessBlock() - Signing Winner\n");
|
2015-05-04 17:04:09 +02:00
|
|
|
if(newWinner.Sign(keyMasternode, pubKeyMasternode))
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
2015-06-22 15:50:33 +02:00
|
|
|
LogPrintf("CMasternodePayments::ProcessBlock() - AddWinningMasternode\n");
|
|
|
|
|
2015-04-16 21:58:09 +02:00
|
|
|
if(AddWinningMasternode(newWinner))
|
|
|
|
{
|
2015-04-22 16:33:44 +02:00
|
|
|
newWinner.Relay();
|
2015-04-16 21:58:09 +02:00
|
|
|
nLastBlockHeight = nBlockHeight;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2015-05-04 17:04:09 +02:00
|
|
|
|
2015-04-16 21:58:09 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
void CMasternodePaymentWinner::Relay()
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
2015-04-22 16:33:44 +02:00
|
|
|
CInv inv(MSG_MASTERNODE_WINNER, GetHash());
|
2015-07-08 02:37:23 +02:00
|
|
|
RelayInv(inv);
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
bool CMasternodePaymentWinner::SignatureValid()
|
2015-04-16 21:58:09 +02:00
|
|
|
{
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
CMasternode* pmn = mnodeman.Find(vinMasternode);
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
if(pmn != NULL)
|
|
|
|
{
|
|
|
|
std::string strMessage = vinMasternode.prevout.ToStringShort() +
|
2015-06-25 17:17:53 +02:00
|
|
|
boost::lexical_cast<std::string>(nBlockHeight) +
|
2015-04-22 16:33:44 +02:00
|
|
|
payee.ToString();
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
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());
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2015-04-22 16:33:44 +02:00
|
|
|
|
|
|
|
return false;
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
2015-04-22 16:33:44 +02:00
|
|
|
|
2015-07-21 00:09:42 +02:00
|
|
|
void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
|
2015-04-22 16:33:44 +02:00
|
|
|
{
|
|
|
|
LOCK(cs_masternodepayments);
|
2015-05-04 17:04:09 +02:00
|
|
|
|
|
|
|
if(chainActive.Tip() == NULL) return;
|
|
|
|
|
2015-07-22 05:07:23 +02:00
|
|
|
int nCount = (mnodeman.CountEnabled()*2);
|
2015-07-21 00:09:42 +02:00
|
|
|
if(nCountNeeded > nCount) nCountNeeded = nCount;
|
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
|
|
|
|
while(it != mapMasternodePayeeVotes.end()) {
|
|
|
|
CMasternodePaymentWinner winner = (*it).second;
|
2015-07-23 23:35:14 +02:00
|
|
|
if(winner.nBlockHeight >= chainActive.Tip()->nHeight-nCountNeeded && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20) {
|
|
|
|
CInv inv(MSG_MASTERNODE_WINNER, winner.GetHash());
|
2015-07-25 21:07:30 +02:00
|
|
|
node->PushInventory(inv);
|
2015-07-23 23:35:14 +02:00
|
|
|
}
|
2015-05-04 17:04:09 +02:00
|
|
|
++it;
|
|
|
|
}
|
2015-05-16 04:53:53 +02:00
|
|
|
}
|
2015-07-21 04:24:43 +02:00
|
|
|
|
|
|
|
std::string CMasternodePayments::ToString() const
|
|
|
|
{
|
|
|
|
std::ostringstream info;
|
|
|
|
|
|
|
|
info << "Votes: " << (int)mapMasternodePayeeVotes.size() <<
|
|
|
|
", Blocks: " << (int)mapMasternodeBlocks.size();
|
|
|
|
|
|
|
|
return info.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-22 00:14:54 +02:00
|
|
|
|
|
|
|
int CMasternodePayments::GetOldestBlock()
|
|
|
|
{
|
|
|
|
LOCK(cs_masternodepayments);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-07-21 04:24:43 +02:00
|
|
|
int CMasternodePayments::GetNewestBlock()
|
|
|
|
{
|
|
|
|
LOCK(cs_masternodepayments);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|