Skip to content

Commit

Permalink
[Consensus] Stricter checks for coinbase for v10+
Browse files Browse the repository at this point in the history
  • Loading branch information
random-zebra committed May 3, 2021
1 parent e8c35ee commit c14870b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 9 deletions.
34 changes: 30 additions & 4 deletions src/masternode-payments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ void DumpMasternodePayments()
LogPrint(BCLog::MASTERNODE,"Budget dump finished %dms\n", GetTimeMillis() - nStart);
}

bool IsBlockValueValid(int nHeight, CAmount& nExpectedValue, CAmount nMinted)
bool IsBlockValueValid(int nHeight, CAmount& nExpectedValue, CAmount nMinted, CAmount& nBudgetAmt)
{
if (!masternodeSync.IsSynced()) {
//there is no budget data to use to check anything
Expand All @@ -227,9 +227,8 @@ bool IsBlockValueValid(int nHeight, CAmount& nExpectedValue, CAmount nMinted)
// if the superblock spork is enabled
if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) {
// add current payee amount to the expected block value
CAmount expectedPayAmount;
if (g_budgetman.GetExpectedPayeeAmount(nHeight, expectedPayAmount)) {
nExpectedValue += expectedPayAmount;
if (g_budgetman.GetExpectedPayeeAmount(nHeight, nBudgetAmt)) {
nExpectedValue += nBudgetAmt;
}
}
}
Expand Down Expand Up @@ -726,3 +725,30 @@ std::string CMasternodePayments::ToString() const

return info.str();
}

bool IsCoinbaseValueValid(const CTransactionRef& tx, CAmount nBudgetAmt)
{
assert(tx->IsCoinBase());
if (masternodeSync.IsSynced()) {
const CAmount nCBaseOutAmt = tx->GetValueOut();
if (nBudgetAmt > 0) {
// Superblock
if (nCBaseOutAmt != nBudgetAmt) {
return error("%s: invalid coinbase payment for budget (%s vs expected=%s)",
__func__, FormatMoney(nCBaseOutAmt), FormatMoney(nBudgetAmt));
}
return true;
} else {
// regular block
CAmount nMnAmt = GetMasternodePayment();
// if enforcement is disabled, there could be no masternode payment
bool sporkEnforced = sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT);
if ((sporkEnforced && nCBaseOutAmt != nMnAmt) || (!sporkEnforced && nCBaseOutAmt > nMnAmt)) {
return error("%s: invalid coinbase payment for masternode (%s vs expected=%s)",
__func__, FormatMoney(nCBaseOutAmt), FormatMoney(nMnAmt));
}
return true;
}
}
return true;
}
8 changes: 7 additions & 1 deletion src/masternode-payments.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ extern CMasternodePayments masternodePayments;
void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
bool IsBlockPayeeValid(const CBlock& block, int nBlockHeight);
std::string GetRequiredPaymentsString(int nBlockHeight);
bool IsBlockValueValid(int nHeight, CAmount& nExpectedValue, CAmount nMinted);
bool IsBlockValueValid(int nHeight, CAmount& nExpectedValue, CAmount nMinted, CAmount& nBudgetAmt);
void FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const int nHeight, bool fProofOfStake);

/**
* Check coinbase output value for blocks v10+.
* It must pay the masternode for regular blocks and a proposal during superblocks.
*/
bool IsCoinbaseValueValid(const CTransactionRef& tx, CAmount nBudgetAmt);

void DumpMasternodePayments();

/** Save Masternode Payment Data (mnpayments.dat)
Expand Down
14 changes: 10 additions & 4 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1740,10 +1740,16 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
nExpectedMint += nFees;

//Check that the block does not overmint
if (!IsBlockValueValid(pindex->nHeight, nExpectedMint, nMint)) {
return state.DoS(100, error("ConnectBlock() : reward pays too much (actual=%s vs limit=%s)",
FormatMoney(nMint), FormatMoney(nExpectedMint)),
REJECT_INVALID, "bad-cb-amount");
CAmount nBudgetAmt = 0; // If this is a superblock, amount to be paid to the winning proposal, otherwise 0
if (!IsBlockValueValid(pindex->nHeight, nExpectedMint, nMint, nBudgetAmt)) {
return state.DoS(100, error("%s: reward pays too much (actual=%s vs limit=%s)",
__func__, FormatMoney(nMint), FormatMoney(nExpectedMint)),
REJECT_INVALID, "bad-blk-amount");
}

// For blocks v10+: Check that the coinbase pays the exact amount
if (isPoSActive && pindex->nVersion >= 10 && !IsCoinbaseValueValid(block.vtx[0], nBudgetAmt)) {
return state.DoS(100, false, REJECT_INVALID, "bad-cb-amount");
}

if (!control.Wait())
Expand Down

0 comments on commit c14870b

Please sign in to comment.