Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 1,185 Lines • ▼ Show 20 Lines | void UpdateCoins(CCoinsViewCache &view, const CTransaction &tx, int nHeight) { | ||||
} | } | ||||
// Add outputs. | // Add outputs. | ||||
AddCoins(view, tx, nHeight); | AddCoins(view, tx, nHeight); | ||||
} | } | ||||
bool CScriptCheck::operator()() { | bool CScriptCheck::operator()() { | ||||
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; | const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; | ||||
return VerifyScript(scriptSig, scriptPubKey, nFlags, | bool ret = VerifyScript(scriptSig, scriptPubKey, nFlags, | ||||
deadalnix: if (!VerifyScript(...)) {
return false;
}
if (pLimitSigChecks && ! | |||||
CachingTransactionSignatureChecker(ptxTo, nIn, amount, | CachingTransactionSignatureChecker( | ||||
cacheStore, txdata), | ptxTo, nIn, amount, cacheStore, txdata), | ||||
metrics, &error); | metrics, &error); | ||||
if (ret && pLimitSigChecks && | |||||
!pLimitSigChecks->consume_and_check(metrics.nSigChecks)) { | |||||
// we can't assign a meaningful script error (since the script | |||||
// succeeded), but remove the ScriptError::OK which could be | |||||
// misinterpreted. | |||||
error = ScriptError::UNKNOWN; | |||||
deadalnixUnsubmitted Not Done Inline ActionsThere should probably be an error code for this regardless. I think it is fine to assign the sigops limit reached opcode that exist for standard scripts. deadalnix: There should probably be an error code for this regardless. I think it is fine to assign the… | |||||
ret = false; | |||||
} | |||||
return ret; | |||||
} | } | ||||
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, | ||||
deadalnixUnsubmitted Not Done Inline ActionsIs there any reason to have nSigChecksOut with that design? It seems redundant with the limiter. deadalnix: Is there any reason to have nSigChecksOut with that design? It seems redundant with the limiter. | |||||
markblundebergAuthorUnsubmitted Done Inline ActionsPerhaps we can get rid of it later on if it ends up being really redundant, but for now I want the limiting (optional, mutated variable with unspecified initial count; only signals good/bad) and per-tx accounting (required for cache & pure-output variable; any value) to be kept as totally distinct concepts. markblundeberg: Perhaps we can get rid of it later on if it ends up being really redundant, but for now I want… | |||||
std::vector<CScriptCheck> *pvChecks) { | std::vector<CScriptCheck> *pvChecks /*= nullptr*/, | ||||
CheckInputsLimiter *pLimitSigChecks /*= nullptr*/) { | |||||
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)) { | ||||
return true; | return !pLimitSigChecks || | ||||
pLimitSigChecks->consume_and_check(nSigChecksOut); | |||||
} | } | ||||
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); | txdata, pLimitSigChecks); | ||||
if (pvChecks) { | if (pvChecks) { | ||||
pvChecks->push_back(std::move(check)); | pvChecks->push_back(std::move(check)); | ||||
} else if (!check()) { | } else if (!check()) { | ||||
if (pLimitSigChecks && !pLimitSigChecks->check()) { | |||||
// It's not a script error to overrun the limit, and we just | |||||
// reject it as nonstandard. | |||||
return state.Invalid(false, REJECT_NONSTANDARD, | |||||
strprintf("too-many-sigchecks")); | |||||
} | |||||
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). | ||||
uint32_t mandatoryFlags = | uint32_t mandatoryFlags = | ||||
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS; | flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS; | ||||
if (flags != mandatoryFlags) { | if (flags != mandatoryFlags) { | ||||
▲ Show 20 Lines • Show All 623 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 | // 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)) { | 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)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 3,819 Lines • Show Last 20 Lines |
Don't try to carry state around when you don't need state.