Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 1,217 Lines • ▼ Show 20 Lines | |||||
bool CScriptCheck::operator()() { | bool CScriptCheck::operator()() { | ||||
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; | const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; | ||||
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, | if (!VerifyScript(scriptSig, scriptPubKey, nFlags, | ||||
CachingTransactionSignatureChecker(ptxTo, nIn, amount, | CachingTransactionSignatureChecker(ptxTo, nIn, amount, | ||||
cacheStore, txdata), | cacheStore, txdata), | ||||
metrics, &error)) { | metrics, &error)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (pLimitSigChecks && | if ((pTxLimitSigChecks && | ||||
!pLimitSigChecks->consume_and_check(metrics.nSigChecks)) { | !pTxLimitSigChecks->consume_and_check(metrics.nSigChecks)) || | ||||
(pBlockLimitSigChecks && | |||||
!pBlockLimitSigChecks->consume_and_check(metrics.nSigChecks))) { | |||||
// we can't assign a meaningful script error (since the script | // we can't assign a meaningful script error (since the script | ||||
// succeeded), but remove the ScriptError::OK which could be | // succeeded), but remove the ScriptError::OK which could be | ||||
// misinterpreted. | // misinterpreted. | ||||
error = ScriptError::SIGCHECKS_LIMIT_EXCEEDED; | error = ScriptError::SIGCHECKS_LIMIT_EXCEEDED; | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
int GetSpendHeight(const CCoinsViewCache &inputs) { | int GetSpendHeight(const CCoinsViewCache &inputs) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
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, int &nSigChecksOut, | const PrecomputedTransactionData &txdata, int &nSigChecksOut, | ||||
std::vector<CScriptCheck> *pvChecks /*= nullptr*/, | TxSigCheckLimiter &txLimitSigChecks, | ||||
CheckInputsLimiter *pLimitSigChecks /*= nullptr*/) { | CheckInputsLimiter *pBlockLimitSigChecks, | ||||
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); | ||||
if (IsKeyInScriptCache(hashCacheEntry, !scriptCacheStore, nSigChecksOut)) { | if (IsKeyInScriptCache(hashCacheEntry, !scriptCacheStore, nSigChecksOut)) { | ||||
if (pLimitSigChecks && | if (!txLimitSigChecks.consume_and_check(nSigChecksOut) || | ||||
!pLimitSigChecks->consume_and_check(nSigChecksOut)) { | (pBlockLimitSigChecks && | ||||
!pBlockLimitSigChecks->consume_and_check(nSigChecksOut))) { | |||||
return state.Invalid(false, REJECT_NONSTANDARD, | return state.Invalid(false, REJECT_NONSTANDARD, | ||||
strprintf("too-many-sigchecks")); | strprintf("too-many-sigchecks")); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
int nSigChecksTotal = 0; | 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 | ||||
// additional data in, eg, the coins being spent being checked as a part | // additional data in, eg, the coins being spent being checked as a part | ||||
// of CScriptCheck. | // of CScriptCheck. | ||||
const CScript &scriptPubKey = coin.GetTxOut().scriptPubKey; | const CScript &scriptPubKey = coin.GetTxOut().scriptPubKey; | ||||
const Amount amount = coin.GetTxOut().nValue; | const Amount amount = coin.GetTxOut().nValue; | ||||
// Verify signature | // Verify signature | ||||
CScriptCheck check(scriptPubKey, amount, tx, i, flags, sigCacheStore, | CScriptCheck check(scriptPubKey, amount, tx, i, flags, sigCacheStore, | ||||
txdata, pLimitSigChecks); | txdata, &txLimitSigChecks, pBlockLimitSigChecks); | ||||
if (pvChecks) { | if (pvChecks) { | ||||
pvChecks->push_back(std::move(check)); | pvChecks->push_back(std::move(check)); | ||||
} else if (!check()) { | } else if (!check()) { | ||||
ScriptError scriptError = check.GetScriptError(); | ScriptError scriptError = check.GetScriptError(); | ||||
// Compute flags without the optional standardness flags. | // Compute flags without the optional standardness flags. | ||||
// This differs from MANDATORY_SCRIPT_VERIFY_FLAGS as it contains | // This differs from MANDATORY_SCRIPT_VERIFY_FLAGS as it contains | ||||
// additional upgrade flags (see AcceptToMemoryPoolWorker variable | // additional upgrade flags (see AcceptToMemoryPoolWorker variable | ||||
// extraFlags). | // extraFlags). | ||||
▲ Show 20 Lines • Show All 594 Lines • ▼ Show 20 Lines | bool CChainState::ConnectBlock(const CBlock &block, CValidationState &state, | ||||
// Limit the total executed signature operations in the block, a consensus | // Limit the total executed signature operations in the block, a consensus | ||||
// rule. Tracking during the CPU-consuming part (validation of uncached | // rule. Tracking during the CPU-consuming part (validation of uncached | ||||
// inputs) is per-input atomic and validation in each thread stops very | // inputs) is per-input atomic and validation in each thread stops very | ||||
// quickly after the limit is exceeded, so an adversary cannot cause us to | // quickly after the limit is exceeded, so an adversary cannot cause us to | ||||
// exceed the limit by much at all. | // exceed the limit by much at all. | ||||
CheckInputsLimiter nSigChecksBlockLimiter( | CheckInputsLimiter nSigChecksBlockLimiter( | ||||
GetMaxBlockSigChecksCount(options.getExcessiveBlockSize())); | GetMaxBlockSigChecksCount(options.getExcessiveBlockSize())); | ||||
std::vector<TxSigCheckLimiter> nSigChecksTxLimiters; | |||||
nSigChecksTxLimiters.resize(block.vtx.size() - 1); | |||||
CBlockUndo blockundo; | CBlockUndo blockundo; | ||||
blockundo.vtxundo.resize(block.vtx.size() - 1); | blockundo.vtxundo.resize(block.vtx.size() - 1); | ||||
CCheckQueueControl<CScriptCheck> control(fScriptChecks ? &scriptcheckqueue | CCheckQueueControl<CScriptCheck> control(fScriptChecks ? &scriptcheckqueue | ||||
: nullptr); | : nullptr); | ||||
// Add all outputs | // Add all outputs | ||||
try { | try { | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | for (const auto &ptx : block.vtx) { | ||||
bool fCacheResults = fJustCheck; | bool fCacheResults = fJustCheck; | ||||
std::vector<CScriptCheck> vChecks; | std::vector<CScriptCheck> vChecks; | ||||
// nSigChecksRet may be accurate (found in cache) or 0 (checks were | // nSigChecksRet may be accurate (found in cache) or 0 (checks were | ||||
// deferred into vChecks). | // deferred into vChecks). | ||||
int nSigChecksRet; | int nSigChecksRet; | ||||
if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, | if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, | ||||
fCacheResults, PrecomputedTransactionData(tx), | fCacheResults, PrecomputedTransactionData(tx), | ||||
nSigChecksRet, &vChecks, &nSigChecksBlockLimiter)) { | nSigChecksRet, nSigChecksTxLimiters.at(txIndex), | ||||
&nSigChecksBlockLimiter, &vChecks)) { | |||||
// Parallel CheckInputs shouldn't fail except for this reason, which | // Parallel CheckInputs shouldn't fail except for this reason, which | ||||
// is banworthy. Use "blk-bad-inputs" to mimic the parallel script | // is banworthy. Use "blk-bad-inputs" to mimic the parallel script | ||||
// check error. | // check error. | ||||
if (!nSigChecksBlockLimiter.check()) { | if (!nSigChecksBlockLimiter.check()) { | ||||
return state.DoS(100, false, REJECT_INVALID, "blk-bad-inputs", | return state.DoS(100, false, REJECT_INVALID, "blk-bad-inputs", | ||||
false, "CheckInputs exceeded SigChecks limit"); | false, "CheckInputs exceeded SigChecks limit"); | ||||
} | } | ||||
return error("ConnectBlock(): CheckInputs on %s failed with %s", | return error("ConnectBlock(): CheckInputs on %s failed with %s", | ||||
▲ Show 20 Lines • Show All 3,888 Lines • Show Last 20 Lines |