Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Validation] Improve coinstake and coinbase validation for non-synced nodes #2875

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions src/masternode-payments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@

#include "masternode-payments.h"

#include "budget/budgetmanager.h"
#include "chainparams.h"
#include "evo/deterministicmns.h"
#include "fs.h"
#include "budget/budgetmanager.h"
#include "masternodeman.h"
#include "netmessagemaker.h"
#include "tiertwo/netfulfilledman.h"
#include "spork.h"
#include "sporkid.h"
#include "sync.h"
#include "tiertwo/netfulfilledman.h"
#include "tiertwo/tiertwo_sync_state.h"
#include "util/system.h"
#include "utilmoneystr.h"
Expand Down Expand Up @@ -228,16 +229,25 @@ bool IsBlockPayeeValid(const CBlock& block, const CBlockIndex* pindexPrev)
{
int nBlockHeight = pindexPrev->nHeight + 1;
TrxValidationStatus transactionStatus = TrxValidationStatus::InValid;
const bool isV6UpgradeEnforced = Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_V6_0);
const bool isLegacyObsolete = deterministicMNManager->LegacyMNObsolete(nBlockHeight);

const bool fPayCoinstake = Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_POS) &&
!isV6UpgradeEnforced;
const CTransaction& txNew = *(fPayCoinstake ? block.vtx[1] : block.vtx[0]);

// If v6 is enforced and legacy mns are obsolete even not-synced nodes can check dmns reward
if (!g_tiertwo_sync_state.IsSynced() && isV6UpgradeEnforced && isLegacyObsolete) {
// This is a possible superblock cannot check anything: (TODO: update for single superblock payment)
if (nBlockHeight % Params().GetConsensus().nBudgetCycleBlocks < 100) return true;
return CheckMasternodePayee(txNew, pindexPrev);
}

if (!g_tiertwo_sync_state.IsSynced()) { //there is no budget data to use to check anything -- find the longest chain
LogPrint(BCLog::MASTERNODE, "Client not synced, skipping block payee checks\n");
return true;
}

const bool fPayCoinstake = Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_POS) &&
!Params().GetConsensus().NetworkUpgradeActive(nBlockHeight, Consensus::UPGRADE_V6_0);
const CTransaction& txNew = *(fPayCoinstake ? block.vtx[1] : block.vtx[0]);

//check if it's a budget block
if (sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) {
if (g_budgetman.IsBudgetPaymentBlock(nBlockHeight)) {
Expand All @@ -262,17 +272,21 @@ bool IsBlockPayeeValid(const CBlock& block, const CBlockIndex* pindexPrev)
// In all cases a masternode will get the payment for this block

//check for masternode payee
return CheckMasternodePayee(txNew, pindexPrev);
}

bool CheckMasternodePayee(const CTransaction& txNew, const CBlockIndex* pindexPrev)
{
if (masternodePayments.IsTransactionValid(txNew, pindexPrev))
return true;
LogPrint(BCLog::MASTERNODE,"Invalid mn payment detected %s\n", txNew.ToString().c_str());
LogPrint(BCLog::MASTERNODE, "Invalid mn payment detected %s\n", txNew.ToString().c_str());

if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT))
return false;
LogPrint(BCLog::MASTERNODE,"Masternode payment enforcement is disabled, accepting block\n");
LogPrint(BCLog::MASTERNODE, "Masternode payment enforcement is disabled, accepting block\n");
return true;
}


void FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const CBlockIndex* pindexPrev, bool fProofOfStake)
{
if (!sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) || // if superblocks are not enabled
Expand Down
1 change: 1 addition & 0 deletions src/masternode-payments.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ extern CMasternodePayments masternodePayments;
#define MNPAYMENTS_SIGNATURES_TOTAL 10

bool IsBlockPayeeValid(const CBlock& block, const CBlockIndex* pindexPrev);
bool CheckMasternodePayee(const CTransaction& txNew, const CBlockIndex* pindexPrev);
std::string GetRequiredPaymentsString(int nBlockHeight);
bool IsBlockValueValid(int nHeight, CAmount& nExpectedValue, CAmount nMinted, CAmount& nBudgetAmt);
void FillBlockPayee(CMutableTransaction& txCoinbase, CMutableTransaction& txCoinstake, const CBlockIndex* pindexPrev, bool fProofOfStake);
Expand Down
33 changes: 27 additions & 6 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "validation.h"

#include "addrman.h"
#include "amount.h"
#include "blocksignature.h"
#include "budget/budgetmanager.h"
#include "chainparams.h"
Expand All @@ -21,6 +22,7 @@
#include "consensus/tx_verify.h"
#include "consensus/validation.h"
#include "consensus/zerocoin_verify.h"
#include "evo/deterministicmns.h"
#include "evo/evodb.h"
#include "evo/specialtx_validation.h"
#include "flatfile.h"
Expand Down Expand Up @@ -1567,6 +1569,28 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
CAmount txValueOut = tx.GetValueOut();
if (!tx.IsCoinBase()) {
CAmount txValueIn = view.GetValueIn(tx);
// Once v6 is enforced and legacy mns are obsolete check that CoinStake does not overmint
if (tx.IsCoinStake() && isV6UpgradeEnforced && deterministicMNManager->LegacyMNObsolete(pindex->nHeight)) {
CAmount stakeMint = txValueOut - txValueIn;
// This is a possible superblock: coinstake cannot pay more than the blockvalue (TODO: update for single superblock payment)
if (pindex->nHeight % consensus.nBudgetCycleBlocks < 100) {
CAmount maxStakeMint = GetBlockValue(pindex->nHeight);
if (stakeMint > maxStakeMint) {
return state.DoS(100, error("%s: coinstake pays too much (actual=%s vs limit=%s)", __func__, FormatMoney(stakeMint), FormatMoney(maxStakeMint)),
REJECT_INVALID, "bad-blk-stake-amount");
}
} else {
// Masternode found, subtract its reward from the expected stake reward
CAmount nExpectedStakeMint = GetBlockValue(pindex->nHeight);
if (deterministicMNManager->GetListForBlock(pindex->pprev).GetMNPayee()) {
nExpectedStakeMint -= GetMasternodePayment(pindex->nHeight);
}
if (stakeMint != nExpectedStakeMint) {
return state.DoS(100, error("%s: coinstake pays too much (actual=%s vs limit=%s)", __func__, FormatMoney(stakeMint), FormatMoney(nExpectedStakeMint)),
REJECT_INVALID, "bad-blk-stake-amount");
}
}
}
if (!tx.IsCoinStake())
nFees += txValueIn - txValueOut;
nValueIn += txValueIn;
Expand Down Expand Up @@ -1637,12 +1661,9 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
}

// Masternode/Budget payments
// !TODO: after transition to DMN is complete, check this also during IBD
if (!fInitialBlockDownload) {
if (!IsBlockPayeeValid(block, pindex->pprev)) {
mapRejectedBlocks.emplace(block.GetHash(), GetTime());
return state.DoS(0, false, REJECT_INVALID, "bad-cb-payee", false, "Couldn't find masternode/budget payment");
}
if (!IsBlockPayeeValid(block, pindex->pprev)) {
mapRejectedBlocks.emplace(block.GetHash(), GetTime());
return state.DoS(0, false, REJECT_INVALID, "bad-cb-payee", false, "Couldn't find masternode/budget payment");
}

// After v6 enforcement: Check that the coinbase pays the exact amount
Expand Down
1 change: 1 addition & 0 deletions test/lint/lint-circular-dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
"chain -> legacy/stakemodifier -> validation -> pow -> chain"
"evo/deterministicmns -> masternodeman -> net -> tiertwo/net_masternodes -> evo/deterministicmns"
"evo/deterministicmns -> masternodeman -> validation -> validationinterface -> evo/deterministicmns"
"evo/deterministicmns -> masternodeman -> validation -> evo/deterministicmns"
)

EXIT_CODE=0
Expand Down