neobytes/src/masternode-payments.cpp

695 lines
23 KiB
C++
Raw Normal View History

// Copyright (c) 2014-2016 The Dash Core developers
2015-04-16 21:58:09 +02:00
// 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"
2016-04-15 04:54:11 +02:00
#include "governance.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 "activemasternode.h"
2015-04-16 21:58:09 +02:00
#include "util.h"
#include "sync.h"
#include "spork.h"
2015-04-16 21:58:09 +02:00
#include "addrman.h"
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
2015-04-16 21:58:09 +02:00
/** Object for who's going to get paid on which blocks */
CMasternodePayments mnpayments;
CCriticalSection cs_vecPayments;
CCriticalSection cs_mapMasternodeBlocks;
CCriticalSection cs_mapMasternodePayeeVotes;
bool IsBlockValueValid(const CBlock& block, CAmount nExpectedValue){
int nHeight = 0;
{
LOCK(cs_main);
if(!chainActive.Tip()) return true;
if(chainActive.Tip()->GetBlockHash() == block.hashPrevBlock)
{
nHeight = chainActive.Tip()->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 Params().GetConsensus().nBudgetPaymentsWindowBlocks per budgeting
if(nHeight >= Params().GetConsensus().nBudgetPaymentsStartBlock &&
nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks < Params().GetConsensus().nBudgetPaymentsWindowBlocks){
return true;
} else {
if(block.vtx[0].GetValueOut() > nExpectedValue) return false;
}
2015-07-02 01:46:03 +02:00
} else { // we're synced and have data so check the budget schedule
2015-08-11 23:54:42 +02:00
//are these blocks even enabled
if(!sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
2015-08-11 23:54:42 +02:00
return block.vtx[0].GetValueOut() <= nExpectedValue;
}
2016-04-15 04:54:11 +02:00
// 12.1
// if(nHeight >= Params().GetConsensus().nBudgetPaymentsStartBlock &&
// 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
// 12.1
// if(sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){
2016-04-15 04:54:11 +02:00
// if(budget.IsBudgetPaymentBlock(nBlockHeight)){
// if(budget.IsTransactionValid(txNew, nBlockHeight)){
// return true;
// } else {
// LogPrintf("Invalid budget payment detected %s", txNew.ToString());
// if(sporkManager.IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)){
2016-04-15 04:54:11 +02:00
// return false;
// } else {
// LogPrintf("Budget enforcement is disabled, accepting block\n");
// return true;
// }
// }
// }
// }
//check for masternode payee
if(mnpayments.IsTransactionValid(txNew, nBlockHeight))
{
return true;
} else {
LogPrintf("Invalid mn payment detected %s", txNew.ToString());
if(sporkManager.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");
return true;
}
}
return false;
}
void FillBlockPayee(CMutableTransaction& txNew, CAmount nFees)
{
AssertLockHeld(cs_main);
if(!chainActive.Tip()) return;
2016-04-15 04:54:11 +02:00
// 12.1
// if(sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(chainActive.Tip()->nHeight+1)){
2016-04-15 04:54:11 +02:00
// budget.FillBlockPayee(txNew, nFees);
// } else {
// mnpayments.FillBlockPayee(txNew, nFees);
// }
mnpayments.FillBlockPayee(txNew, nFees);
}
std::string GetRequiredPaymentsString(int nBlockHeight)
{
// 12.1 -- added triggered payments
// if(sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(nBlockHeight)){
2016-04-15 04:54:11 +02:00
// return budget.GetRequiredPaymentsString(nBlockHeight);
// } else {
// return mnpayments.GetRequiredPaymentsString(nBlockHeight);
// }
return mnpayments.GetRequiredPaymentsString(nBlockHeight);
}
void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, CAmount nFees)
{
AssertLockHeld(cs_main);
if(!chainActive.Tip()) return;
bool hasPayment = true;
CScript payee;
//spork
if(!mnpayments.GetBlockPayee(chainActive.Tip()->nHeight+1, payee)){
//no masternode detected
CMasternode* winningNode = mnodeman.GetCurrentMasterNode();
if(winningNode){
payee = GetScriptForDestination(winningNode->pubkey.GetID());
} else {
LogPrintf("CreateNewBlock: Failed to detect masternode to pay\n");
hasPayment = false;
}
}
CAmount blockValue = nFees + GetBlockSubsidy(chainActive.Tip()->nBits, chainActive.Tip()->nHeight, Params().GetConsensus());
CAmount masternodePayment = GetMasternodePayment(chainActive.Tip()->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 %d to %s\n", masternodePayment, address2.ToString());
}
}
int CMasternodePayments::GetMinMasternodePaymentsProto() {
return sporkManager.IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)
? MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2
: MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1;
}
void CMasternodePayments::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
2015-04-16 21:58:09 +02:00
{
if(!masternodeSync.IsBlockchainSynced()) return;
2015-04-16 21:58:09 +02:00
2015-08-25 00:01:02 +02:00
if(fLiteMode) return; //disable all Darksend/Masternode related functionality
if (strCommand == NetMsgType::MNWINNERSSYNC) { //Masternode Payments Request Sync
// ignore such request until we are fully synced
if (!masternodeSync.IsSynced()) return;
2015-04-16 21:58:09 +02:00
int nCountNeeded;
vRecv >> nCountNeeded;
if(Params().NetworkIDString() == CBaseChainParams::MAIN){
if(pfrom->HasFulfilledRequest(NetMsgType::MNWINNERSSYNC)) {
LogPrintf("mnget - peer already asked me for the list\n");
Misbehaving(pfrom->GetId(), 20);
return;
}
2015-04-16 21:58:09 +02:00
}
pfrom->FulfilledRequest(NetMsgType::MNWINNERSSYNC);
Sync(pfrom, nCountNeeded);
LogPrintf("mnget - Sent Masternode winners to %s\n", pfrom->addr.ToString());
2015-04-16 21:58:09 +02:00
}
else if (strCommand == NetMsgType::MNWINNER) { //Masternode Payments Declare Winner
//this is required in litemodef
2015-04-16 21:58:09 +02:00
CMasternodePaymentWinner winner;
vRecv >> winner;
2015-08-15 01:19:46 +02:00
if(pfrom->nVersion < MIN_MNW_PEER_PROTO_VERSION) return;
if(!pCurrentBlockIndex) return;
2015-04-16 21:58:09 +02:00
// can't really verify it until masternode list is synced, reject it for now
if (masternodeSync.RequestedMasternodeAssets < MASTERNODE_SYNC_MNW) return;
if(mapMasternodePayeeVotes.count(winner.GetHash())) {
LogPrint("mnpayments", "MNWINNER -- Already seen: hash=%s, nHeight=%d\n", winner.GetHash().ToString(), pCurrentBlockIndex->nHeight);
masternodeSync.AddedMasternodeWinner(winner.GetHash());
return;
2015-04-16 21:58:09 +02:00
}
int nFirstBlock = pCurrentBlockIndex->nHeight - mnodeman.CountEnabled()*1.25;
if(winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > pCurrentBlockIndex->nHeight+20) {
LogPrint("mnpayments", "MNWINNER -- winner out of range: nFirstBlock=%d, nBlockHeight=%d, nHeight=%d\n", nFirstBlock, winner.nBlockHeight, pCurrentBlockIndex->nHeight);
2015-04-16 21:58:09 +02:00
return;
}
std::string strError = "";
if(!winner.IsValid(pfrom, pCurrentBlockIndex->nHeight, strError)) {
LogPrint("mnpayments", "MNWINNER -- invalid message, error: %s\n", strError);
2015-04-16 21:58:09 +02:00
return;
}
if(!CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)){
LogPrintf("MNWINNER -- masternode already voted: prevout=%s\n", winner.vinMasternode.prevout.ToStringShort());
2015-07-24 16:12:48 +02:00
return;
}
if(!winner.SignatureValid()) {
// do not ban for old mnw, MN simply might be not active anymore
if(masternodeSync.IsSynced() && winner.nBlockHeight > pCurrentBlockIndex->nHeight) {
LogPrintf("MNWINNER -- invalid signature\n");
Misbehaving(pfrom->GetId(), 20);
}
2015-08-07 05:07:40 +02:00
// it could just be a non-synced masternode
mnodeman.AskForMN(pfrom, winner.vinMasternode);
2015-04-16 21:58:09 +02:00
return;
}
CTxDestination address1;
ExtractDestination(winner.payee, address1);
CBitcoinAddress address2(address1);
LogPrint("mnpayments", "MNWINNER -- winning vote: address=%s, nBlockHeight=%d, nHeight=%d, prevout=%s\n", address2.ToString(), winner.nBlockHeight, pCurrentBlockIndex->nHeight, winner.vinMasternode.prevout.ToStringShort());
2015-04-16 21:58:09 +02:00
if(AddWinningMasternode(winner)){
winner.Relay();
masternodeSync.AddedMasternodeWinner(winner.GetHash());
2015-04-16 21:58:09 +02:00
}
}
}
bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
2015-04-16 21:58:09 +02:00
{
std::string errorMessage;
std::string strMasterNodeSignMessage;
std::string strMessage = vinMasternode.prevout.ToStringShort() +
boost::lexical_cast<std::string>(nBlockHeight) +
ScriptToAsmStr(payee);
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) {
LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage);
return false;
}
2015-04-16 21:58:09 +02:00
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) {
LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage);
2015-04-16 21:58:09 +02:00
return false;
}
return true;
}
bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
2015-04-16 21:58:09 +02:00
{
if(mapMasternodeBlocks.count(nBlockHeight)){
return mapMasternodeBlocks[nBlockHeight].GetPayee(payee);
}
2015-04-16 21:58:09 +02:00
return false;
}
2015-04-16 21:58:09 +02:00
// 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);
if(!pCurrentBlockIndex) return false;
CScript mnpayee;
mnpayee = GetScriptForDestination(mn.pubkey.GetID());
CScript payee;
for(int64_t h = pCurrentBlockIndex->nHeight; h <= pCurrentBlockIndex->nHeight + 8; h++){
if(h == nNotBlockHeight) continue;
if(mapMasternodeBlocks.count(h)){
if(mapMasternodeBlocks[h].GetPayee(payee)){
if(mnpayee == payee) {
return true;
}
}
}
}
return false;
}
2015-08-30 01:48:19 +02:00
bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
{
uint256 blockHash = uint256();
if(!GetBlockHash(blockHash, winnerIn.nBlockHeight - 101)) return false;
2015-04-16 21:58:09 +02:00
{
LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
if(mapMasternodePayeeVotes.count(winnerIn.GetHash())){
return false;
}
2015-04-16 21:58:09 +02:00
mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;
if(!mapMasternodeBlocks.count(winnerIn.nBlockHeight)){
CMasternodeBlockPayees blockPayees(winnerIn.nBlockHeight);
mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
}
2015-04-16 21:58:09 +02:00
}
mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, 1);
2015-04-16 21:58:09 +02:00
return true;
}
bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
2015-04-16 21:58:09 +02:00
{
LOCK(cs_vecPayments);
int nMaxSignatures = 0;
std::string strPayeesPossible = "";
CAmount masternodePayment = GetMasternodePayment(nBlockHeight, txNew.GetValueOut());
//require at least MNPAYMENTS_SIGNATURES_REQUIRED signatures
BOOST_FOREACH(CMasternodePayee& payee, vecPayments)
2015-05-16 04:53:53 +02:00
if(payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED)
nMaxSignatures = payee.nVotes;
// if we don't have at least MNPAYMENTS_SIGNATURES_REQUIRED 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;
}
}
2015-04-16 21:58:09 +02:00
if(payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED){
if(found) return true;
2015-04-16 21:58:09 +02:00
CTxDestination address1;
ExtractDestination(payee.scriptPubKey, address1);
CBitcoinAddress address2(address1);
2015-04-16 21:58:09 +02:00
if(strPayeesPossible == ""){
strPayeesPossible += address2.ToString();
} else {
strPayeesPossible += "," + address2.ToString();
}
2015-04-16 21:58:09 +02:00
}
}
LogPrintf("CMasternodePayments::IsTransactionValid - Missing required payment - %s %d\n", strPayeesPossible, masternodePayment);
return false;
2015-04-16 21:58:09 +02:00
}
std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
2015-04-16 21:58:09 +02:00
{
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 {
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
}
}
return ret;
2015-04-16 21:58:09 +02:00
}
std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight)
2015-04-16 21:58:09 +02:00
{
LOCK(cs_mapMasternodeBlocks);
if(mapMasternodeBlocks.count(nBlockHeight)){
return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
2015-04-16 21:58:09 +02:00
}
return "Unknown";
}
2015-04-16 21:58:09 +02:00
bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
{
LOCK(cs_mapMasternodeBlocks);
if(mapMasternodeBlocks.count(nBlockHeight)){
return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew);
2015-04-16 21:58:09 +02:00
}
return true;
2015-04-16 21:58:09 +02:00
}
2016-04-13 19:49:47 +02:00
void CMasternodePayments::CheckAndRemove()
2015-04-16 21:58:09 +02:00
{
if(!pCurrentBlockIndex) return;
2015-04-16 21:58:09 +02:00
LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks);
2015-04-16 21:58:09 +02:00
2016-05-29 20:35:09 +02:00
// keep a bit more for historical sake but at least minBlocksToStore
int nLimit = std::max(int(mnodeman.size() * nStorageCoeff), nMinBlocksToStore);
2015-04-16 21:58:09 +02:00
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
while(it != mapMasternodePayeeVotes.end()) {
CMasternodePaymentWinner winner = (*it).second;
if(pCurrentBlockIndex->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++);
mapMasternodeBlocks.erase(winner.nBlockHeight);
} else {
++it;
2015-04-16 21:58:09 +02:00
}
}
LogPrintf("CMasternodePayments::CleanPaymentList() - %s mapSeenSyncMNW %lld\n", ToString(), masternodeSync.mapSeenSyncMNW.size());
2015-04-16 21:58:09 +02:00
}
bool CMasternodePaymentWinner::IsValid(CNode* pnode, int nValidationHeight, std::string& strError)
{
2015-07-21 17:09:17 +02:00
CMasternode* pmn = mnodeman.Find(vinMasternode);
2015-04-16 21:58:09 +02:00
if(!pmn) {
strError = strprintf("Unknown Masternode: prevout=%s", vinMasternode.prevout.ToStringShort());
// Only ask if we are already synced and still have no idea about that Masternode
if (masternodeSync.IsSynced()) mnodeman.AskForMN(pnode, vinMasternode);
return false;
2015-04-16 21:58:09 +02:00
}
if(pmn->protocolVersion < MIN_MNW_PEER_PROTO_VERSION) {
strError = strprintf("Masternode protocol is too old: protocolVersion=%d, MIN_MNW_PEER_PROTO_VERSION=%d", pmn->protocolVersion, MIN_MNW_PEER_PROTO_VERSION);
2015-07-21 17:09:17 +02:00
return false;
}
int nRank = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight - 101, MIN_MNW_PEER_PROTO_VERSION);
2015-07-21 17:09:17 +02:00
if(nRank > MNPAYMENTS_SIGNATURES_TOTAL) {
// It's common to have masternodes mistakenly think they are in the top 10
// We don't want to print all of these messages in normal mode, debug mode should print though
strError = strprintf("Masternode is not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, nRank);
// Only ban for new mnw which is out of bounds, for old mnw MN list itself might be way too much off
if(nRank > MNPAYMENTS_SIGNATURES_TOTAL*2 && nBlockHeight > nValidationHeight) {
LogPrintf("CMasternodePaymentWinner::IsValid -- Error: Masternode is not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL*2, nRank);
Misbehaving(pnode->GetId(), 20);
}
// Still invalid however
return false;
}
return true;
}
bool CMasternodePayments::ProcessBlock(int nBlockHeight)
{
// DETERMINE IF WE SHOULD BE VOTING FOR THE NEXT PAYEE
if(!fMasterNode) return false;
int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight - 101, 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;
}
2015-04-16 21:58:09 +02:00
// LOCATE THE NEXT MASTERNODE WHICH SHOULD BE PAID
CMasternodePaymentWinner newWinner(activeMasternode.vin);
{
LogPrintf("CMasternodePayments::ProcessBlock() Start nHeight %d - vin %s. \n", nBlockHeight, activeMasternode.vin.ToString());
2015-04-16 21:58:09 +02:00
// 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");
2015-04-16 21:58:09 +02:00
newWinner.nBlockHeight = nBlockHeight;
CScript payee = GetScriptForDestination(pmn->pubkey.GetID());
newWinner.AddPayee(payee);
CTxDestination address1;
ExtractDestination(payee, address1);
CBitcoinAddress address2(address1);
2015-04-16 21:58:09 +02:00
LogPrintf("CMasternodePayments::ProcessBlock() Winner payee %s nHeight %d. \n", address2.ToString(), newWinner.nBlockHeight);
} else {
LogPrintf("CMasternodePayments::ProcessBlock() Failed to find masternode to pay\n");
}
}
2015-04-16 21:58:09 +02:00
// SIGN MESSAGE TO NETWORK WITH OUR MASTERNODE KEYS
std::string errorMessage;
2015-04-16 21:58:09 +02:00
2015-06-22 15:50:33 +02:00
LogPrintf("CMasternodePayments::ProcessBlock() - Signing Winner\n");
if(newWinner.Sign(activeMasternode.keyMasternode, activeMasternode.pubKeyMasternode))
2015-04-16 21:58:09 +02:00
{
2015-06-22 15:50:33 +02:00
LogPrintf("CMasternodePayments::ProcessBlock() - AddWinningMasternode\n");
2015-08-30 01:48:19 +02:00
if(AddWinningMasternode(newWinner))
2015-04-16 21:58:09 +02:00
{
newWinner.Relay();
2015-04-16 21:58:09 +02:00
return true;
}
}
2015-04-16 21:58:09 +02:00
return false;
}
void CMasternodePaymentWinner::Relay()
2015-04-16 21:58:09 +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
}
bool CMasternodePaymentWinner::SignatureValid()
2015-04-16 21:58:09 +02:00
{
CMasternode* pmn = mnodeman.Find(vinMasternode);
2015-04-16 21:58:09 +02:00
if(pmn != NULL)
{
std::string strMessage = vinMasternode.prevout.ToStringShort() +
boost::lexical_cast<std::string>(nBlockHeight) +
ScriptToAsmStr(payee);
2015-04-16 21:58:09 +02:00
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)){
return error("CMasternodePaymentWinner::SignatureValid() - Got bad Masternode payment signature %s", vinMasternode.ToString().c_str());
}
2015-04-16 21:58:09 +02:00
return true;
}
return false;
2015-04-16 21:58:09 +02:00
}
void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
{
LOCK(cs_mapMasternodePayeeVotes);
if(!pCurrentBlockIndex) return;
2015-09-04 14:22:17 +02:00
int nCount = (mnodeman.CountEnabled()*1.25);
if(nCountNeeded > nCount) nCountNeeded = nCount;
int nInvCount = 0;
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
while(it != mapMasternodePayeeVotes.end()) {
2015-08-30 01:48:19 +02:00
CMasternodePaymentWinner winner = (*it).second;
if(winner.nBlockHeight >= pCurrentBlockIndex->nHeight - nCountNeeded && winner.nBlockHeight <= pCurrentBlockIndex->nHeight + 20) {
node->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash()));
nInvCount++;
}
++it;
}
node->PushMessage(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_MNW, nInvCount);
2015-05-16 04:53:53 +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_mapMasternodeBlocks);
2015-07-22 00:14:54 +02:00
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;
}
2016-05-29 20:35:09 +02:00
bool CMasternodePayments::IsEnoughData(int nMnCount) {
if(GetBlockCount() > nMnCount * nStorageCoeff && GetBlockCount() > nMinBlocksToStore)
2016-05-29 20:35:09 +02:00
{
float nAverageVotes = (MNPAYMENTS_SIGNATURES_TOTAL + MNPAYMENTS_SIGNATURES_REQUIRED) / 2;
if(GetVoteCount() > nMnCount * nStorageCoeff * nAverageVotes && GetVoteCount() > nMinBlocksToStore * nAverageVotes)
2016-05-29 20:35:09 +02:00
{
return true;
}
}
return false;
}
void CMasternodePayments::UpdatedBlockTip(const CBlockIndex *pindex)
{
pCurrentBlockIndex = pindex;
LogPrint("mnpayments", "pCurrentBlockIndex->nHeight: %d\n", pCurrentBlockIndex->nHeight);
if(!fLiteMode && masternodeSync.RequestedMasternodeAssets > MASTERNODE_SYNC_LIST)
ProcessBlock(pindex->nHeight+10);
}