Merge 3f8dbcd655 into merged_master (Bitcoin PR #16658)

This commit is contained in:
Andrew Poelstra 2020-11-14 16:52:03 +00:00
commit c4e2622681
5 changed files with 41 additions and 39 deletions

View file

@ -185,7 +185,7 @@ std::unique_ptr<CBlockTreeDB> pblocktree;
// See definition for documentation
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs,
bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs,
unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore,
PrecomputedTransactionData& txdata,
std::vector<CCheck*> *pvChecks = nullptr);
@ -410,7 +410,7 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationS
// 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 when we actually call through to CheckInputs
// and when we actually call through to CheckInputScripts
LOCK(pool.cs);
assert(!tx.IsCoinBase());
@ -421,12 +421,12 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationS
const Coin& coin = view.AccessCoin(txin.prevout);
// At this point we haven't actually checked if the coins are all
// available (or shouldn't assume we have, since CheckInputs does).
// So we just return failure if the inputs are not available here,
// and then only have to check equivalence for available inputs.
// AcceptToMemoryPoolWorker has already checked that the coins are
// available, so this shouldn't fail. If the inputs are not available
// here then return false.
if (coin.IsSpent()) return false;
// Check equivalence for available inputs.
const CTransactionRef& txFrom = pool.get(txin.prevout.hash);
if (txFrom) {
assert(txFrom->GetHash() == txin.prevout.hash);
@ -439,8 +439,8 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationS
}
}
// Call CheckInputs() to cache signature and script validity against current tip consensus rules.
return CheckInputs(tx, state, view, flags, /* cacheSigStore = */ true, /* cacheFullSciptStore = */ true, txdata);
// Call CheckInputScripts() to cache signature and script validity against current tip consensus rules.
return CheckInputScripts(tx, state, view, flags, /* cacheSigStore = */ true, /* cacheFullSciptStore = */ true, txdata);
}
namespace {
@ -978,20 +978,20 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute
constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
// Check against previous transactions
// Check input scripts and signatures.
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if (!CheckInputs(tx, state, m_view, scriptVerifyFlags, true, false, txdata)) {
if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, txdata)) {
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// need to turn both off, and compare against just turning off CLEANSTACK
// to see if the failure is specifically due to witness validation.
TxValidationState state_dummy; // Want reported failures to be from first CheckInputs
if (!tx.HasWitness() && CheckInputs(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
!CheckInputs(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
TxValidationState state_dummy; // Want reported failures to be from first CheckInputScripts
if (!tx.HasWitness() && CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
!CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
// Only the witness is missing, so the transaction itself may be fine.
state.Invalid(TxValidationResult::TX_WITNESS_MUTATED,
state.GetRejectReason(), state.GetDebugMessage());
}
return false; // state filled in by CheckInputs
return false; // state filled in by CheckInputScripts
}
return true;
@ -1022,7 +1022,7 @@ bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, Precomp
// transactions into the mempool can be exploited as a DoS attack.
unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(::ChainActive().Tip(), chainparams.GetConsensus());
if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, txdata)) {
return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed against latest-block but not STANDARD flags %s, %s",
return error("%s: BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s",
__func__, hash.ToString(), FormatStateMessage(state));
}
@ -1550,8 +1550,10 @@ void InitScriptExecutionCache() {
}
/**
* Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
* This does not modify the UTXO set.
* Check whether all of this transaction's input scripts succeed.
*
* This involves ECDSA signature checks so can be computationally intensive. This function should
* only be called after the cheap sanity checks in CheckTxInputs passed.
*
* If pvChecks is not nullptr, script checks are pushed onto it instead of being performed inline. Any
* script checks which are not necessary (eg due to script execution cache hits) are, obviously,
@ -1566,7 +1568,7 @@ void InitScriptExecutionCache() {
*
* Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp
*/
bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CCheck*> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CCheck*> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
if (tx.IsCoinBase()) return true;
@ -2303,11 +2305,11 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
std::vector<CCheck*> vChecks;
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
TxValidationState tx_state;
if (fScriptChecks && !CheckInputs(tx, tx_state, view, flags, fCacheResults, fCacheResults, txdata[i], g_parallel_script_checks ? &vChecks : nullptr)) {
if (fScriptChecks && !CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txdata[i], g_parallel_script_checks ? &vChecks : nullptr)) {
// Any transaction validation failure in ConnectBlock is a block consensus failure
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
tx_state.GetRejectReason(), tx_state.GetDebugMessage());
return error("ConnectBlock(): CheckInputs on %s failed with %s",
return error("ConnectBlock(): CheckInputScripts on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state));
}
control.Add(vChecks);