Consensus: Refactor: Separate Consensus::CheckTxInputs and GetSpendHeight in CheckInputs
Zcash: - Replaces some of the refactoring performed in #1017 - Exposed Consensus::CheckTxInputs for testing
This commit is contained in:
parent
fbbd3cc638
commit
e079f010bf
67
src/main.cpp
67
src/main.cpp
|
@ -1607,13 +1607,16 @@ bool CScriptCheck::operator()() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
|
||||
int GetSpendHeight(const CCoinsViewCache& inputs)
|
||||
{
|
||||
if (!tx.IsCoinBase())
|
||||
{
|
||||
if (pvChecks)
|
||||
pvChecks->reserve(tx.vin.size());
|
||||
LOCK(cs_main);
|
||||
CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
|
||||
return pindexPrev->nHeight + 1;
|
||||
}
|
||||
|
||||
namespace Consensus {
|
||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams)
|
||||
{
|
||||
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
|
||||
// for an attacker to attempt to split the network.
|
||||
if (!inputs.HaveInputs(tx))
|
||||
|
@ -1632,6 +1635,13 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
|
|||
assert(coins);
|
||||
|
||||
if (coins->IsCoinBase()) {
|
||||
// Ensure that coinbases are matured
|
||||
if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) {
|
||||
return state.Invalid(
|
||||
error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),
|
||||
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
|
||||
}
|
||||
|
||||
// Ensure that coinbases cannot be spent to transparent outputs
|
||||
// Disabled on regtest
|
||||
if (fCoinbaseEnforcedProtectionEnabled &&
|
||||
|
@ -1670,6 +1680,19 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
|
|||
if (!MoneyRange(nFees))
|
||||
return state.DoS(100, error("CheckInputs(): nFees out of range"),
|
||||
REJECT_INVALID, "bad-txns-fee-outofrange");
|
||||
return true;
|
||||
}
|
||||
}// namespace Consensus
|
||||
|
||||
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
|
||||
{
|
||||
if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs), consensusParams))
|
||||
return false;
|
||||
|
||||
if (!tx.IsCoinBase())
|
||||
{
|
||||
if (pvChecks)
|
||||
pvChecks->reserve(tx.vin.size());
|
||||
|
||||
// The first loop above does all the inexpensive checks.
|
||||
// Only if ALL inputs pass do we perform expensive ECDSA signature checks.
|
||||
|
@ -1718,40 +1741,6 @@ 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, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
|
||||
{
|
||||
if (!NonContextualCheckInputs(tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tx.IsCoinBase())
|
||||
{
|
||||
// While checking, GetBestBlock() refers to the parent block.
|
||||
// This is also true for mempool checks.
|
||||
CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
|
||||
int nSpendHeight = pindexPrev->nHeight + 1;
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
{
|
||||
const COutPoint &prevout = tx.vin[i].prevout;
|
||||
const CCoins *coins = inputs.AccessCoins(prevout.hash);
|
||||
// Assertion is okay because NonContextualCheckInputs ensures the inputs
|
||||
// are available.
|
||||
assert(coins);
|
||||
|
||||
// If prev is coinbase, check that it's matured
|
||||
if (coins->IsCoinBase()) {
|
||||
if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) {
|
||||
return state.Invalid(
|
||||
error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),
|
||||
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
|
||||
|
|
15
src/main.h
15
src/main.h
|
@ -332,10 +332,6 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
|
|||
unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams,
|
||||
std::vector<CScriptCheck> *pvChecks = NULL);
|
||||
|
||||
bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
|
||||
unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams,
|
||||
std::vector<CScriptCheck> *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);
|
||||
|
||||
|
@ -520,4 +516,15 @@ extern CCoinsViewCache *pcoinsTip;
|
|||
/** Global variable that points to the active block tree (protected by cs_main) */
|
||||
extern CBlockTreeDB *pblocktree;
|
||||
|
||||
/**
|
||||
* Return the spend height, which is one more than the inputs.GetBestBlock().
|
||||
* While checking, GetBestBlock() refers to the parent block. (protected by cs_main)
|
||||
* This is also true for mempool checks.
|
||||
*/
|
||||
int GetSpendHeight(const CCoinsViewCache& inputs);
|
||||
|
||||
namespace Consensus {
|
||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams);
|
||||
}
|
||||
|
||||
#endif // BITCOIN_MAIN_H
|
||||
|
|
|
@ -756,7 +756,7 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends)
|
|||
|
||||
{
|
||||
CTransaction tx2(mtx2);
|
||||
BOOST_CHECK(NonContextualCheckInputs(tx2, state, cache, false, SCRIPT_VERIFY_NONE, false, Params().GetConsensus()));
|
||||
BOOST_CHECK(Consensus::CheckTxInputs(tx2, state, cache, 100+COINBASE_MATURITY, Params().GetConsensus()));
|
||||
}
|
||||
|
||||
mtx2.vout.resize(1);
|
||||
|
@ -765,7 +765,7 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends)
|
|||
|
||||
{
|
||||
CTransaction tx2(mtx2);
|
||||
BOOST_CHECK(!NonContextualCheckInputs(tx2, state, cache, false, SCRIPT_VERIFY_NONE, false, Params().GetConsensus()));
|
||||
BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, cache, 100+COINBASE_MATURITY, Params().GetConsensus()));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-coinbase-spend-has-transparent-outputs");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue