|
|
@ -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) |
|
|
|