Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 489 Lines • ▼ Show 20 Lines | static uint32_t GetStandardScriptFlags(const Consensus::Params ¶ms, | ||||
return flags; | return flags; | ||||
} | } | ||||
// Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool | // Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool | ||||
// were somehow broken and returning the wrong scriptPubKeys | // were somehow broken and returning the wrong scriptPubKeys | ||||
static bool CheckInputsFromMempoolAndCache( | static bool CheckInputsFromMempoolAndCache( | ||||
const CTransaction &tx, CValidationState &state, | const CTransaction &tx, CValidationState &state, | ||||
const CCoinsViewCache &view, const CTxMemPool &pool, const uint32_t flags, | const CCoinsViewCache &view, const CTxMemPool &pool, const uint32_t flags, | ||||
bool cacheSigStore, PrecomputedTransactionData &txdata) | bool cacheSigStore, PrecomputedTransactionData &txdata, int &nSigChecksOut) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
// pool.cs should be locked already, but go ahead and re-take the lock here | // pool.cs should be locked already, but go ahead and re-take the lock here | ||||
// to enforce that mempool doesn't change between when we check the view and | // to enforce that mempool doesn't change between when we check the view and | ||||
// when we actually call through to CheckInputs | // when we actually call through to CheckInputs | ||||
LOCK(pool.cs); | LOCK(pool.cs); | ||||
Show All 17 Lines | for (const CTxIn &txin : tx.vin) { | ||||
} else { | } else { | ||||
const Coin &coinFromDisk = pcoinsTip->AccessCoin(txin.prevout); | const Coin &coinFromDisk = pcoinsTip->AccessCoin(txin.prevout); | ||||
assert(!coinFromDisk.IsSpent()); | assert(!coinFromDisk.IsSpent()); | ||||
assert(coinFromDisk.GetTxOut() == coin.GetTxOut()); | assert(coinFromDisk.GetTxOut() == coin.GetTxOut()); | ||||
} | } | ||||
} | } | ||||
return CheckInputs(tx, state, view, true, flags, cacheSigStore, true, | return CheckInputs(tx, state, view, true, flags, cacheSigStore, true, | ||||
txdata); | txdata, nSigChecksOut); | ||||
} | } | ||||
static bool | static bool | ||||
AcceptToMemoryPoolWorker(const Config &config, CTxMemPool &pool, | AcceptToMemoryPoolWorker(const Config &config, CTxMemPool &pool, | ||||
CValidationState &state, const CTransactionRef &ptx, | CValidationState &state, const CTransactionRef &ptx, | ||||
bool *pfMissingInputs, int64_t nAcceptTime, | bool *pfMissingInputs, int64_t nAcceptTime, | ||||
bool bypass_limits, const Amount nAbsurdFee, | bool bypass_limits, const Amount nAbsurdFee, | ||||
std::vector<COutPoint> &coins_to_uncache, | std::vector<COutPoint> &coins_to_uncache, | ||||
▲ Show 20 Lines • Show All 210 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
} | } | ||||
const uint32_t scriptVerifyFlags = | const uint32_t scriptVerifyFlags = | ||||
GetStandardScriptFlags(consensusParams, chainActive.Tip()); | GetStandardScriptFlags(consensusParams, chainActive.Tip()); | ||||
// Check against previous transactions. This is done last to help | // Check against previous transactions. This is done last to help | ||||
// prevent CPU exhaustion denial-of-service attacks. | // prevent CPU exhaustion denial-of-service attacks. | ||||
PrecomputedTransactionData txdata(tx); | PrecomputedTransactionData txdata(tx); | ||||
int nSigChecksStandard; | |||||
if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, false, | if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, false, | ||||
txdata)) { | txdata, nSigChecksStandard)) { | ||||
// State filled in by CheckInputs. | // State filled in by CheckInputs. | ||||
return false; | return false; | ||||
} | } | ||||
// Check again against the next block's script verification flags | // Check again against the next block's script verification flags | ||||
// to cache our script execution flags. | // to cache our script execution flags. | ||||
// | // | ||||
// This is also useful in case of bugs in the standard flags that cause | // This is also useful in case of bugs in the standard flags that cause | ||||
// transactions to pass as valid when they're actually invalid. For | // transactions to pass as valid when they're actually invalid. For | ||||
// instance the STRICTENC flag was incorrectly allowing certain CHECKSIG | // instance the STRICTENC flag was incorrectly allowing certain CHECKSIG | ||||
// NOT scripts to pass, even though they were invalid. | // NOT scripts to pass, even though they were invalid. | ||||
// | // | ||||
// There is a similar check in CreateNewBlock() to prevent creating | // There is a similar check in CreateNewBlock() to prevent creating | ||||
// invalid blocks (using TestBlockValidity), however allowing such | // invalid blocks (using TestBlockValidity), however allowing such | ||||
// transactions into the mempool can be exploited as a DoS attack. | // transactions into the mempool can be exploited as a DoS attack. | ||||
int nSigChecksConsensus; | |||||
if (!CheckInputsFromMempoolAndCache(tx, state, view, pool, | if (!CheckInputsFromMempoolAndCache(tx, state, view, pool, | ||||
nextBlockScriptVerifyFlags, true, | nextBlockScriptVerifyFlags, true, | ||||
txdata)) { | txdata, nSigChecksConsensus)) { | ||||
// This can occur under some circumstances, if the node receives an | // This can occur under some circumstances, if the node receives an | ||||
// unrequested tx which is invalid due to new consensus rules not | // unrequested tx which is invalid due to new consensus rules not | ||||
// being activated yet (during IBD). | // being activated yet (during IBD). | ||||
return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed " | return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed " | ||||
"against next-block but not STANDARD flags %s, %s", | "against next-block but not STANDARD flags %s, %s", | ||||
__func__, txid.ToString(), FormatStateMessage(state)); | __func__, txid.ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 413 Lines • ▼ Show 20 Lines | int GetSpendHeight(const CCoinsViewCache &inputs) { | ||||
CBlockIndex *pindexPrev = LookupBlockIndex(inputs.GetBestBlock()); | CBlockIndex *pindexPrev = LookupBlockIndex(inputs.GetBestBlock()); | ||||
return pindexPrev->nHeight + 1; | return pindexPrev->nHeight + 1; | ||||
} | } | ||||
bool CheckInputs(const CTransaction &tx, CValidationState &state, | bool CheckInputs(const CTransaction &tx, CValidationState &state, | ||||
const CCoinsViewCache &inputs, bool fScriptChecks, | const CCoinsViewCache &inputs, bool fScriptChecks, | ||||
const uint32_t flags, bool sigCacheStore, | const uint32_t flags, bool sigCacheStore, | ||||
bool scriptCacheStore, | bool scriptCacheStore, | ||||
const PrecomputedTransactionData &txdata, | const PrecomputedTransactionData &txdata, int &nSigChecksOut, | ||||
std::vector<CScriptCheck> *pvChecks) { | std::vector<CScriptCheck> *pvChecks) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(!tx.IsCoinBase()); | assert(!tx.IsCoinBase()); | ||||
if (pvChecks) { | if (pvChecks) { | ||||
pvChecks->reserve(tx.vin.size()); | pvChecks->reserve(tx.vin.size()); | ||||
} | } | ||||
// Skip script verification when connecting blocks under the assumevalid | // Skip script verification when connecting blocks under the assumevalid | ||||
// block. Assuming the assumevalid block is valid this is safe because | // block. Assuming the assumevalid block is valid this is safe because | ||||
// block merkle hashes are still computed and checked, of course, if an | // block merkle hashes are still computed and checked, of course, if an | ||||
// assumed valid block is invalid due to false scriptSigs this optimization | // assumed valid block is invalid due to false scriptSigs this optimization | ||||
// would allow an invalid chain to be accepted. | // would allow an invalid chain to be accepted. | ||||
if (!fScriptChecks) { | if (!fScriptChecks) { | ||||
return true; | return true; | ||||
} | } | ||||
// First check if script executions have been cached with the same flags. | // First check if script executions have been cached with the same flags. | ||||
// Note that this assumes that the inputs provided are correct (ie that the | // Note that this assumes that the inputs provided are correct (ie that the | ||||
// transaction hash which is in tx's prevouts properly commits to the | // transaction hash which is in tx's prevouts properly commits to the | ||||
// scriptPubKey in the inputs view of that transaction). | // scriptPubKey in the inputs view of that transaction). | ||||
ScriptCacheKey hashCacheEntry(tx, flags); | ScriptCacheKey hashCacheEntry(tx, flags); | ||||
int nSigChecksDummy; | if (IsKeyInScriptCache(hashCacheEntry, !scriptCacheStore, nSigChecksOut)) { | ||||
if (IsKeyInScriptCache(hashCacheEntry, !scriptCacheStore, | |||||
nSigChecksDummy)) { | |||||
return true; | return true; | ||||
} | } | ||||
int nSigChecksTotal = 0; | |||||
for (size_t i = 0; i < tx.vin.size(); i++) { | for (size_t i = 0; i < tx.vin.size(); i++) { | ||||
const COutPoint &prevout = tx.vin[i].prevout; | const COutPoint &prevout = tx.vin[i].prevout; | ||||
const Coin &coin = inputs.AccessCoin(prevout); | const Coin &coin = inputs.AccessCoin(prevout); | ||||
assert(!coin.IsSpent()); | assert(!coin.IsSpent()); | ||||
// We very carefully only pass in things to CScriptCheck which are | // We very carefully only pass in things to CScriptCheck which are | ||||
// clearly committed to by tx's hash. This provides a sanity | // clearly committed to by tx's hash. This provides a sanity | ||||
// check that our caching is not introducing consensus failures through | // check that our caching is not introducing consensus failures through | ||||
Show All 38 Lines | for (size_t i = 0; i < tx.vin.size(); i++) { | ||||
// careful thought should be taken as to the correct behavior - we | // careful thought should be taken as to the correct behavior - we | ||||
// may want to continue peering with non-upgraded nodes even after | // may want to continue peering with non-upgraded nodes even after | ||||
// soft-fork super-majority signaling has occurred. | // soft-fork super-majority signaling has occurred. | ||||
return state.DoS( | return state.DoS( | ||||
100, false, REJECT_INVALID, | 100, false, REJECT_INVALID, | ||||
strprintf("mandatory-script-verify-flag-failed (%s)", | strprintf("mandatory-script-verify-flag-failed (%s)", | ||||
ScriptErrorString(scriptError))); | ScriptErrorString(scriptError))); | ||||
} | } | ||||
nSigChecksTotal += check.GetScriptExecutionMetrics().nSigChecks; | |||||
} | } | ||||
nSigChecksOut = nSigChecksTotal; | |||||
if (scriptCacheStore && !pvChecks) { | if (scriptCacheStore && !pvChecks) { | ||||
// We executed all of the provided scripts, and were told to cache the | // We executed all of the provided scripts, and were told to cache the | ||||
// result. Do so now. | // result. Do so now. | ||||
AddKeyInScriptCache(hashCacheEntry, 0); | AddKeyInScriptCache(hashCacheEntry, nSigChecksTotal); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
namespace { | namespace { | ||||
bool UndoWriteToDisk(const CBlockUndo &blockundo, FlatFilePos &pos, | bool UndoWriteToDisk(const CBlockUndo &blockundo, FlatFilePos &pos, | ||||
▲ Show 20 Lines • Show All 578 Lines • ▼ Show 20 Lines | for (const auto &ptx : block.vtx) { | ||||
REJECT_INVALID, "bad-txns-nonfinal"); | REJECT_INVALID, "bad-txns-nonfinal"); | ||||
} | } | ||||
// Don't cache results if we're actually connecting blocks (still | // Don't cache results if we're actually connecting blocks (still | ||||
// consult the cache, though). | // consult the cache, though). | ||||
bool fCacheResults = fJustCheck; | bool fCacheResults = fJustCheck; | ||||
std::vector<CScriptCheck> vChecks; | std::vector<CScriptCheck> vChecks; | ||||
// metricsRet may be accurate (found in cache) or 0 (checks were | |||||
// deferred into vChecks). | |||||
int nSigChecksRet; | |||||
if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, | if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, | ||||
fCacheResults, PrecomputedTransactionData(tx), | fCacheResults, PrecomputedTransactionData(tx), | ||||
&vChecks)) { | nSigChecksRet, &vChecks)) { | ||||
return error("ConnectBlock(): CheckInputs on %s failed with %s", | return error("ConnectBlock(): CheckInputs on %s failed with %s", | ||||
tx.GetId().ToString(), FormatStateMessage(state)); | tx.GetId().ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
control.Add(vChecks); | control.Add(vChecks); | ||||
blockundo.vtxundo.push_back(CTxUndo()); | blockundo.vtxundo.push_back(CTxUndo()); | ||||
SpendCoins(view, tx, blockundo.vtxundo.back(), pindex->nHeight); | SpendCoins(view, tx, blockundo.vtxundo.back(), pindex->nHeight); | ||||
▲ Show 20 Lines • Show All 3,814 Lines • Show Last 20 Lines |