Merge pull request #2258 from codablock/pr_dip3_paymentlogic

DIP3 MN reward payment logic
This commit is contained in:
UdjinM6 2018-09-05 15:08:53 +03:00 committed by GitHub
commit f0166389bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 232 additions and 48 deletions

View File

@ -14,6 +14,8 @@
#include "spork.h"
#include "util.h"
#include "evo/deterministicmns.h"
#include <string>
/** Object for who's going to get paid on which blocks */
@ -150,7 +152,7 @@ bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockRewar
bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward)
{
if(!masternodeSync.IsSynced() || fLiteMode) {
if((!masternodeSync.IsSynced() && !deterministicMNManager->IsDeterministicMNsSporkActive(nBlockHeight)) || fLiteMode) {
//there is no budget data to use to check anything, let's just accept the longest chain
if(fDebug) LogPrintf("%s -- WARNING: Not enough data, skipping block payee checks\n", __func__);
return true;
@ -176,7 +178,10 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount bloc
if(CSuperblockManager::IsSuperblockTriggered(nBlockHeight)) {
if(CSuperblockManager::IsValid(txNew, nBlockHeight, blockReward)) {
LogPrint("gobject", "%s -- Valid superblock at height %d: %s", __func__, nBlockHeight, txNew.ToString());
// only allow superblock and masternode payments in the same block after spork15 activation
if (!deterministicMNManager->IsDeterministicMNsSporkActive(nBlockHeight))
return true;
// continue validation, should also pay MN
} else {
LogPrintf("%s -- ERROR: Invalid superblock detected at height %d: %s", __func__, nBlockHeight, txNew.ToString());
// should NOT allow such superblocks, when superblocks are enabled
@ -196,13 +201,18 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount bloc
return true;
}
if (deterministicMNManager->IsDeterministicMNsSporkActive(nBlockHeight)) {
// always enforce masternode payments when spork15 is active
return false;
} else {
if(sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) {
LogPrintf("%s -- ERROR: Invalid masternode payment detected at height %d: %s", __func__, nBlockHeight, txNew.ToString());
return false;
}
LogPrintf("%s -- WARNING: Masternode payment enforcement is disabled, accepting any payee\n", __func__);
LogPrintf("%s-- WARNING: Masternode payment enforcement is disabled, accepting any payee\n", __func__);
return true;
}
}
void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, std::vector<CTxOut>& voutMasternodePaymentsRet, std::vector<CTxOut>& voutSuperblockPaymentsRet)
@ -215,10 +225,7 @@ void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blo
CSuperblockManager::GetSuperblockPayments(nBlockHeight, voutSuperblockPaymentsRet);
}
// TODO this is a placeholder until DIP3 is merged, which will allow superblock payments and MN reward payments
// in the same block. We set this to false for now, which means that we'll always get into the next if statement
// when a superblock payment is present
bool allowSuperblockAndMNReward = false;
bool allowSuperblockAndMNReward = deterministicMNManager->IsDeterministicMNsSporkActive(nBlockHeight);
// don't allow payments to superblocks AND masternodes before spork15 activation
if (!voutSuperblockPaymentsRet.empty() && !allowSuperblockAndMNReward) {
@ -247,7 +254,7 @@ void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blo
nBlockHeight, blockReward, voutMasternodeStr, txNew.ToString());
}
std::string GetRequiredPaymentsString(int nBlockHeight)
std::string GetLegacyRequiredPaymentsString(int nBlockHeight)
{
// IF WE HAVE A ACTIVATED TRIGGER FOR THIS HEIGHT - IT IS A SUPERBLOCK, GET THE REQUIRED PAYEES
if(CSuperblockManager::IsSuperblockTriggered(nBlockHeight)) {
@ -258,6 +265,54 @@ std::string GetRequiredPaymentsString(int nBlockHeight)
return mnpayments.GetRequiredPaymentsString(nBlockHeight);
}
std::string GetRequiredPaymentsString(int nBlockHeight, const CDeterministicMNCPtr &payee)
{
std::string strPayee = "Unknown";
if (payee) {
CTxDestination dest;
if (!ExtractDestination(payee->pdmnState->scriptPayout, dest))
assert(false);
strPayee = CBitcoinAddress(dest).ToString();
}
if (CSuperblockManager::IsSuperblockTriggered(nBlockHeight)) {
strPayee += ", " + CSuperblockManager::GetRequiredPaymentsString(nBlockHeight);
}
return strPayee;
}
std::map<int, std::string> GetRequiredPaymentsStrings(int nStartHeight, int nEndHeight)
{
std::map<int, std::string> mapPayments;
LOCK(cs_main);
int nChainTipHeight = chainActive.Height();
bool doProjection = false;
for(int h = nStartHeight; h < nEndHeight; h++) {
if (deterministicMNManager->IsDeterministicMNsSporkActive(h)) {
if (h <= nChainTipHeight) {
auto payee = deterministicMNManager->GetListForBlock(chainActive[h - 1]->GetBlockHash()).GetMNPayee();
mapPayments.emplace(h, GetRequiredPaymentsString(h, payee));
} else {
doProjection = true;
break;
}
} else {
mapPayments.emplace(h, GetLegacyRequiredPaymentsString(h));
}
}
if (doProjection) {
auto projection = deterministicMNManager->GetListAtChainTip().GetProjectedMNPayees(nEndHeight - nChainTipHeight);
for (size_t i = 0; i < projection.size(); i++) {
auto payee = projection[i];
int h = nChainTipHeight + 1 + i;
mapPayments.emplace(h, GetRequiredPaymentsString(h, payee));
}
}
return mapPayments;
}
void CMasternodePayments::Clear()
{
LOCK2(cs_mapMasternodeBlocks, cs_mapMasternodePaymentVotes);
@ -267,6 +322,9 @@ void CMasternodePayments::Clear()
bool CMasternodePayments::UpdateLastVote(const CMasternodePaymentVote& vote)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return false;
LOCK(cs_mapMasternodePaymentVotes);
const auto it = mapMasternodesLastVote.find(vote.masternodeOutpoint);
@ -294,6 +352,8 @@ bool CMasternodePayments::GetMasternodeTxOuts(int nBlockHeight, CAmount blockRew
voutMasternodePaymentsRet.clear();
if(!GetBlockTxOuts(nBlockHeight, blockReward, voutMasternodePaymentsRet)) {
assert(!deterministicMNManager->IsDeterministicMNsSporkActive(nBlockHeight));
// no masternode detected...
int nCount = 0;
masternode_info_t mnInfo;
@ -327,6 +387,9 @@ int CMasternodePayments::GetMinMasternodePaymentsProto() const {
void CMasternodePayments::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
if(fLiteMode) return; // disable all Dash specific functionality
if (strCommand == NetMsgType::MASTERNODEPAYMENTSYNC) { //Masternode Payments Request Sync
@ -514,6 +577,28 @@ bool CMasternodePayments::GetBlockTxOuts(int nBlockHeight, CAmount blockReward,
CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockReward);
if (deterministicMNManager->IsDeterministicMNsSporkActive(nBlockHeight)) {
uint256 blockHash;
{
LOCK(cs_main);
blockHash = chainActive[nBlockHeight - 1]->GetBlockHash();
}
uint256 proTxHash;
auto dmnPayee = deterministicMNManager->GetListForBlock(blockHash).GetMNPayee();
if (!dmnPayee) {
return false;
}
if (dmnPayee->nOperatorReward == 0 || dmnPayee->pdmnState->scriptOperatorPayout == CScript()) {
voutMasternodePaymentsRet.emplace_back(masternodeReward, dmnPayee->pdmnState->scriptPayout);
} else {
CAmount operatorReward = (masternodeReward * dmnPayee->nOperatorReward) / 10000;
masternodeReward -= operatorReward;
voutMasternodePaymentsRet.emplace_back(masternodeReward, dmnPayee->pdmnState->scriptPayout);
voutMasternodePaymentsRet.emplace_back(operatorReward, dmnPayee->pdmnState->scriptOperatorPayout);
}
return true;
} else {
LOCK(cs_mapMasternodeBlocks);
auto it = mapMasternodeBlocks.find(nBlockHeight);
CScript payee;
@ -522,6 +607,7 @@ bool CMasternodePayments::GetBlockTxOuts(int nBlockHeight, CAmount blockReward,
}
voutMasternodePaymentsRet.emplace_back(masternodeReward, payee);
return true;
}
}
// Is this masternode scheduled to get paid soon?
@ -530,6 +616,16 @@ bool CMasternodePayments::IsScheduled(const masternode_info_t& mnInfo, int nNotB
{
LOCK(cs_mapMasternodeBlocks);
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
auto projectedPayees = deterministicMNManager->GetListAtChainTip().GetProjectedMNPayees(8);
for (const auto &dmn : projectedPayees) {
if (dmn->proTxHash == mnInfo.outpoint.hash) {
return true;
}
}
return false;
}
if(!masternodeSync.IsMasternodeListSynced()) return false;
CScript mnpayee;
@ -699,20 +795,49 @@ std::string CMasternodeBlockPayees::GetRequiredPaymentsString() const
std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight) const
{
LOCK(cs_mapMasternodeBlocks);
const auto it = mapMasternodeBlocks.find(nBlockHeight);
return it == mapMasternodeBlocks.end() ? "Unknown" : it->second.GetRequiredPaymentsString();
}
bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward) const
{
if (deterministicMNManager->IsDeterministicMNsSporkActive(nBlockHeight)) {
std::vector<CTxOut> voutMasternodePayments;
if (!GetBlockTxOuts(nBlockHeight, blockReward, voutMasternodePayments)) {
LogPrintf("CMasternodePayments::%s -- ERROR failed to get payees for block at height %s\n", __func__, nBlockHeight);
return true;
}
for (const auto& txout : voutMasternodePayments) {
bool found = false;
for (const auto& txout2 : txNew.vout) {
if (txout == txout2) {
found = true;
break;
}
}
if (!found) {
CTxDestination dest;
if (!ExtractDestination(txout.scriptPubKey, dest))
assert(false);
LogPrintf("CMasternodePayments::%s -- ERROR failed to find expected payee %s in block at height %s\n", __func__, CBitcoinAddress(dest).ToString(), nBlockHeight);
return false;
}
}
return true;
} else {
LOCK(cs_mapMasternodeBlocks);
const auto it = mapMasternodeBlocks.find(nBlockHeight);
return it == mapMasternodeBlocks.end() ? true : it->second.IsTransactionValid(txNew);
}
}
void CMasternodePayments::CheckAndRemove()
{
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
return;
}
if(!masternodeSync.IsBlockchainSynced()) return;
LOCK2(cs_mapMasternodeBlocks, cs_mapMasternodePaymentVotes);
@ -794,6 +919,10 @@ bool CMasternodePaymentVote::IsValid(CNode* pnode, int nValidationHeight, std::s
bool CMasternodePayments::ProcessBlock(int nBlockHeight, CConnman& connman)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive(nBlockHeight)) {
return true;
}
// DETERMINE IF WE SHOULD BE VOTING FOR THE NEXT PAYEE
if(fLiteMode || !fMasternodeMode) return false;
@ -929,6 +1058,10 @@ void CMasternodePayments::CheckBlockVotes(int nBlockHeight)
void CMasternodePaymentVote::Relay(CConnman& connman) const
{
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
return;
}
// Do not relay until fully synced
if(!masternodeSync.IsSynced()) {
LogPrint("mnpayments", "CMasternodePayments::%s -- won't relay until fully synced\n", __func__);
@ -1130,6 +1263,10 @@ void CMasternodePayments::UpdatedBlockTip(const CBlockIndex *pindex, CConnman& c
{
if(!pindex) return;
if (deterministicMNManager->IsDeterministicMNsSporkActive(pindex->nHeight)) {
return;
}
nCachedBlockHeight = pindex->nHeight;
LogPrint("mnpayments", "CMasternodePayments::%s -- nCachedBlockHeight=%d\n", __func__, nCachedBlockHeight);

View File

@ -36,7 +36,7 @@ extern CMasternodePayments mnpayments;
bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockReward, std::string& strErrorRet);
bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward);
void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, std::vector<CTxOut>& voutMasternodePaymentsRet, std::vector<CTxOut>& voutSuperblockPaymentsRet);
std::string GetRequiredPaymentsString(int nBlockHeight);
std::map<int, std::string> GetRequiredPaymentsStrings(int nStartHeight, int nEndHeight);
class CMasternodePayee
{

View File

@ -18,6 +18,8 @@
#include "wallet/wallet.h"
#endif // ENABLE_WALLET
#include "evo/deterministicmns.h"
#include <string>
@ -345,8 +347,22 @@ std::string CMasternode::GetStatus() const
void CMasternode::UpdateLastPaid(const CBlockIndex *pindex, int nMaxBlocksToScanBack)
{
AssertLockHeld(cs_main);
if(!pindex) return;
if (deterministicMNManager->IsDeterministicMNsSporkActive(pindex->nHeight)) {
auto dmn = deterministicMNManager->GetListForBlock(pindex->GetBlockHash()).GetMN(outpoint.hash);
if (!dmn || dmn->pdmnState->nLastPaidHeight == -1) {
LogPrint("masternode", "CMasternode::UpdateLastPaidBlock -- searching for block with payment to %s -- not found\n", outpoint.ToStringShort());
} else {
nBlockLastPaid = (int)dmn->pdmnState->nLastPaidHeight;
nTimeLastPaid = chainActive[nBlockLastPaid]->nTime;
LogPrint("masternode", "CMasternode::UpdateLastPaidBlock -- searching for block with payment to %s -- found new %d\n", outpoint.ToStringShort(), nBlockLastPaid);
}
return;
}
const CBlockIndex *BlockReading = pindex;
CScript mnpayee = GetScriptForDestination(keyIDCollateralAddress);

View File

@ -583,6 +583,14 @@ bool CMasternodeMan::Get(const COutPoint& outpoint, CMasternode& masternodeRet)
return true;
}
bool CMasternodeMan::GetMasternodeInfo(const uint256& proTxHash, masternode_info_t& mnInfoRet)
{
auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMN(proTxHash);
if (!dmn)
return false;
return GetMasternodeInfo(COutPoint(proTxHash, dmn->nCollateralIndex), mnInfoRet);
}
bool CMasternodeMan::GetMasternodeInfo(const COutPoint& outpoint, masternode_info_t& mnInfoRet)
{
LOCK(cs);
@ -654,6 +662,10 @@ bool CMasternodeMan::GetNextMasternodeInQueueForPayment(bool fFilterSigTime, int
bool CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight, bool fFilterSigTime, int& nCountRet, masternode_info_t& mnInfoRet)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive(nBlockHeight)) {
return false;
}
mnInfoRet = masternode_info_t();
nCountRet = 0;
@ -1805,7 +1817,7 @@ bool CMasternodeMan::CheckMnbAndUpdateMasternodeList(CNode* pfrom, CMasternodeBr
void CMasternodeMan::UpdateLastPaid(const CBlockIndex* pindex)
{
LOCK(cs);
LOCK2(cs_main, cs);
if(fLiteMode || !masternodeSync.IsWinnersListSynced() || mapMasternodes.empty()) return;

View File

@ -171,6 +171,7 @@ public:
bool Get(const COutPoint& outpoint, CMasternode& masternodeRet);
bool Has(const COutPoint& outpoint);
bool GetMasternodeInfo(const uint256& proTxHash, masternode_info_t& mnInfoRet);
bool GetMasternodeInfo(const COutPoint& outpoint, masternode_info_t& mnInfoRet);
bool GetMasternodeInfo(const CKeyID& keyIDOperator, masternode_info_t& mnInfoRet);
bool GetMasternodeInfo(const CPubKey& pubKeyOperator, masternode_info_t& mnInfoRet);

View File

@ -42,6 +42,7 @@
#endif // ENABLE_WALLET
#include "privatesend-server.h"
#include "evo/deterministicmns.h"
#include "evo/simplifiedmns.h"
#include <boost/thread.hpp>
@ -1178,13 +1179,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
if (!push && inv.type == MSG_MASTERNODE_PAYMENT_VOTE) {
if(mnpayments.HasVerifiedPaymentVote(inv.hash)) {
if (!deterministicMNManager->IsDeterministicMNsSporkActive()) {
if (mnpayments.HasVerifiedPaymentVote(inv.hash)) {
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MASTERNODEPAYMENTVOTE, mnpayments.mapMasternodePaymentVotes[inv.hash]));
push = true;
}
}
}
if (!push && inv.type == MSG_MASTERNODE_PAYMENT_BLOCK) {
if (!deterministicMNManager->IsDeterministicMNsSporkActive()) {
BlockMap::iterator mi = mapBlockIndex.find(inv.hash);
LOCK(cs_mapMasternodeBlocks);
if (mi != mapBlockIndex.end() && mnpayments.mapMasternodeBlocks.count(mi->second->nHeight)) {
@ -1199,6 +1203,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
push = true;
}
}
}
if (!push && inv.type == MSG_MASTERNODE_ANNOUNCE) {
if (!deterministicMNManager->IsDeterministicMNsSporkActive()) {

View File

@ -24,6 +24,8 @@
#include "evo/specialtx.h"
#include "evo/deterministicmns.h"
#include "evo/deterministicmns.h"
#include <fstream>
#include <iomanip>
#include <univalue.h>
@ -223,10 +225,15 @@ UniValue masternode_count(const JSONRPCRequest& request)
masternode_count_help();
int nCount;
int total;
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
nCount = total = mnodeman.CountEnabled();
} else {
masternode_info_t mnInfo;
mnodeman.GetNextMasternodeInQueueForPayment(true, nCount, mnInfo);
total = mnodeman.size();
}
int total = mnodeman.size();
int ps = mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION);
int enabled = mnodeman.CountEnabled();
@ -272,11 +279,18 @@ UniValue GetNextMasternodeForPayment(int heightShift)
LOCK(cs_main);
pindex = chainActive.Tip();
}
nHeight = pindex->nHeight + heightShift;
mnodeman.UpdateLastPaid(pindex);
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
auto payee = deterministicMNManager->GetListAtChainTip().GetMNPayee();
if (!payee || !mnodeman.GetMasternodeInfo(payee->proTxHash, mnInfo))
return "unknown";
} else {
if (!mnodeman.GetNextMasternodeInQueueForPayment(nHeight, true, nCount, mnInfo))
return "unknown";
}
UniValue obj(UniValue::VOBJ);
@ -787,11 +801,9 @@ UniValue masternode_winners(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'masternode winners ( \"count\" \"filter\" )'");
UniValue obj(UniValue::VOBJ);
for (int i = nHeight - nLast; i < nHeight + 20; i++) {
std::string strPayment = GetRequiredPaymentsString(i);
if (strFilter !="" && strPayment.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strprintf("%d", i), strPayment));
auto mapPayments = GetRequiredPaymentsStrings(nHeight - nLast, nHeight + 20);
for (const auto &p : mapPayments) {
obj.push_back(Pair(strprintf("%d", p.first), p.second));
}
return obj;

View File

@ -28,6 +28,7 @@
#include "masternode-payments.h"
#include "masternode-sync.h"
#include "evo/deterministicmns.h"
#include "evo/specialtx.h"
#include "evo/cbtx.h"
@ -720,7 +721,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
result.push_back(Pair("masternode", masternodeObj));
result.push_back(Pair("masternode_payments_started", pindexPrev->nHeight + 1 > consensusParams.nMasternodePaymentsStartBlock));
result.push_back(Pair("masternode_payments_enforced", sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)));
result.push_back(Pair("masternode_payments_enforced", deterministicMNManager->IsDeterministicMNsSporkActive() || sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)));
UniValue superblockObjArray(UniValue::VARR);
if(pblocktemplate->voutSuperblockPayments.size()) {