diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7d303c1b..cb75808f 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -31,6 +31,7 @@ class CMainParams : public CChainParams { public: CMainParams() { strNetworkID = "main"; + consensus.coinbaseMustBeProtected = true; consensus.nSubsidySlowStartInterval = 20000; consensus.nSubsidyHalvingInterval = 840000; consensus.nMajorityEnforceBlockUpgrade = 750; @@ -210,6 +211,7 @@ class CRegTestParams : public CTestNetParams { public: CRegTestParams() { strNetworkID = "regtest"; + consensus.coinbaseMustBeProtected = false; consensus.nSubsidySlowStartInterval = 0; consensus.nSubsidyHalvingInterval = 150; consensus.nMajorityEnforceBlockUpgrade = 750; diff --git a/src/consensus/params.h b/src/consensus/params.h index 1dea7c47..8d2cb3af 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -14,6 +14,9 @@ namespace Consensus { */ struct Params { uint256 hashGenesisBlock; + + bool coinbaseMustBeProtected; + /** Needs to evenly divide MAX_SUBSIDY to avoid rounding errors. */ int nSubsidySlowStartInterval; /** diff --git a/src/main.cpp b/src/main.cpp index 72b3cabe..bda5d307 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1219,7 +1219,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. - if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true)) + if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus())) { return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString()); } @@ -1233,7 +1233,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // There is a similar check in CreateNewBlock() to prevent creating // invalid blocks, however allowing such transactions into the mempool // can be exploited as a DoS attack. - if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) + if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus())) { return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); } @@ -1604,7 +1604,7 @@ bool CScriptCheck::operator()() { return true; } -bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector *pvChecks) +bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector *pvChecks) { if (!tx.IsCoinBase()) { @@ -1630,7 +1630,8 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c if (coins->IsCoinBase()) { // Ensure that coinbases cannot be spent to transparent outputs - if (!tx.vout.empty()) { + // Disabled on regtest + if (consensusParams.coinbaseMustBeProtected && !tx.vout.empty()) { return state.Invalid( error("CheckInputs(): tried to spend coinbase with transparent outputs"), REJECT_INVALID, "bad-txns-coinbase-spend-has-transparent-outputs"); @@ -1712,7 +1713,7 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c return true; } -bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector *pvChecks) +bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector *pvChecks) { if (!tx.IsCoinBase()) { @@ -1737,7 +1738,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons } return NonContextualCheckInputs( - tx, state, inputs, fScriptChecks, flags, cacheStore, pvChecks + tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks ); } @@ -2154,7 +2155,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin nFees += view.GetValueIn(tx)-tx.GetValueOut(); std::vector vChecks; - if (!ContextualCheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL)) + if (!ContextualCheckInputs(tx, state, view, fScriptChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL)) return false; control.Add(vChecks); } diff --git a/src/main.h b/src/main.h index f1627e62..df5085a9 100644 --- a/src/main.h +++ b/src/main.h @@ -318,10 +318,12 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma * instead of being performed inline. */ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, - unsigned int flags, bool cacheStore, std::vector *pvChecks = NULL); + unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, + std::vector *pvChecks = NULL); bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, - unsigned int flags, bool cacheStore, std::vector *pvChecks = NULL); + unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, + std::vector *pvChecks = NULL); /** Apply the effects of this transaction on the UTXO set represented by view */ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight); diff --git a/src/miner.cpp b/src/miner.cpp index 475e9003..2f9caf02 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -282,7 +282,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // policy here, but we still have to ensure that the block we // create only contains transactions that are valid in new blocks. CValidationState state; - if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) + if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus())) continue; UpdateCoins(tx, state, view, nHeight); diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 9edf432e..8b0f7dd7 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -508,7 +508,7 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends) { CTransaction tx2(mtx2); - BOOST_CHECK(NonContextualCheckInputs(tx2, state, cache, false, SCRIPT_VERIFY_NONE, false, NULL)); + BOOST_CHECK(NonContextualCheckInputs(tx2, state, cache, false, SCRIPT_VERIFY_NONE, false, Params().GetConsensus())); } mtx2.vout.resize(1); @@ -517,7 +517,7 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends) { CTransaction tx2(mtx2); - BOOST_CHECK(!NonContextualCheckInputs(tx2, state, cache, false, SCRIPT_VERIFY_NONE, false, NULL)); + BOOST_CHECK(!NonContextualCheckInputs(tx2, state, cache, false, SCRIPT_VERIFY_NONE, false, Params().GetConsensus())); BOOST_CHECK(state.GetRejectReason() == "bad-txns-coinbase-spend-has-transparent-outputs"); } } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index e8ed8f82..669e35e3 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -327,7 +327,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const waitingOnDependants.push_back(&it->second); else { CValidationState state; - assert(ContextualCheckInputs(tx, state, mempoolDuplicate, false, 0, false, NULL)); + assert(ContextualCheckInputs(tx, state, mempoolDuplicate, false, 0, false, Params().GetConsensus(), NULL)); UpdateCoins(tx, state, mempoolDuplicate, 1000000); } } @@ -341,7 +341,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const stepsSinceLastRemove++; assert(stepsSinceLastRemove < waitingOnDependants.size()); } else { - assert(ContextualCheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, NULL)); + assert(ContextualCheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, Params().GetConsensus(), NULL)); UpdateCoins(entry->GetTx(), state, mempoolDuplicate, 1000000); stepsSinceLastRemove = 0; }