@@ -1492,12 +1492,13 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
14921492
14931493 // Check against previous transactions
14941494 // This is done last to help prevent CPU exhaustion denial-of-service attacks.
1495- if (!CheckInputs (tx, state, view, true , scriptVerifyFlags, true )) {
1495+ CachedHashes cachedHashes (tx);
1496+ if (!CheckInputs (tx, state, view, true , scriptVerifyFlags, true , cachedHashes)) {
14961497 // SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
14971498 // need to turn both off, and compare against just turning off CLEANSTACK
14981499 // to see if the failure is specifically due to witness validation.
1499- if (CheckInputs (tx, state, view, true , scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true ) &&
1500- !CheckInputs (tx, state, view, true , scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true )) {
1500+ if (CheckInputs (tx, state, view, true , scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true , cachedHashes ) &&
1501+ !CheckInputs (tx, state, view, true , scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true , cachedHashes )) {
15011502 // Only the witness is wrong, so the transaction itself may be fine.
15021503 state.SetCorruptionPossible ();
15031504 }
@@ -1513,7 +1514,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
15131514 // There is a similar check in CreateNewBlock() to prevent creating
15141515 // invalid blocks, however allowing such transactions into the mempool
15151516 // can be exploited as a DoS attack.
1516- if (!CheckInputs (tx, state, view, true , MANDATORY_SCRIPT_VERIFY_FLAGS, true ))
1517+ if (!CheckInputs (tx, state, view, true , MANDATORY_SCRIPT_VERIFY_FLAGS, true , cachedHashes ))
15171518 {
15181519 return error (" %s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s" ,
15191520 __func__, hash.ToString (), FormatStateMessage (state));
@@ -1910,7 +1911,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
19101911bool CScriptCheck::operator ()() {
19111912 const CScript &scriptSig = ptxTo->vin [nIn].scriptSig ;
19121913 const CScriptWitness *witness = (nIn < ptxTo->wit .vtxinwit .size ()) ? &ptxTo->wit .vtxinwit [nIn].scriptWitness : NULL ;
1913- if (!VerifyScript (scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker (ptxTo, nIn, amount, cacheStore), &error)) {
1914+ if (!VerifyScript (scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker (ptxTo, nIn, amount, cacheStore, *cachedHashes ), &error)) {
19141915 return false ;
19151916 }
19161917 return true ;
@@ -1969,7 +1970,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
19691970}
19701971}// namespace Consensus
19711972
1972- bool CheckInputs (const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks , unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
1973+ bool CheckInputs (const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks , unsigned int flags, bool cacheStore, CachedHashes& cachedHashes, std::vector<CScriptCheck> *pvChecks)
19731974{
19741975 if (!tx.IsCoinBase ())
19751976 {
@@ -1996,7 +1997,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
19961997 assert (coins);
19971998
19981999 // Verify signature
1999- CScriptCheck check (*coins, tx, i, flags, cacheStore);
2000+ CScriptCheck check (*coins, tx, i, flags, cacheStore, &cachedHashes );
20002001 if (pvChecks) {
20012002 pvChecks->push_back (CScriptCheck ());
20022003 check.swap (pvChecks->back ());
@@ -2009,7 +2010,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
20092010 // avoid splitting the network between upgraded and
20102011 // non-upgraded nodes.
20112012 CScriptCheck check2 (*coins, tx, i,
2012- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
2013+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &cachedHashes );
20132014 if (check2 ())
20142015 return state.Invalid (false , REJECT_NONSTANDARD, strprintf (" non-mandatory-script-verify-flag (%s)" , ScriptErrorString (check.GetScriptError ())));
20152016 }
@@ -2405,6 +2406,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
24052406 std::vector<std::pair<uint256, CDiskTxPos> > vPos;
24062407 vPos.reserve (block.vtx .size ());
24072408 blockundo.vtxundo .reserve (block.vtx .size () - 1 );
2409+ std::vector<CachedHashes> cachedHashes;
2410+ cachedHashes.reserve (block.vtx .size ()); // Required so that pointers to individual CachedHashes don't get invalidated
24082411 for (unsigned int i = 0 ; i < block.vtx .size (); i++)
24092412 {
24102413 const CTransaction &tx = block.vtx [i];
@@ -2451,13 +2454,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
24512454 return state.DoS (100 , error (" ConnectBlock(): too many sigops" ),
24522455 REJECT_INVALID, " bad-blk-sigops" );
24532456
2457+ cachedHashes.emplace_back (tx);
24542458 if (!tx.IsCoinBase ())
24552459 {
24562460 nFees += view.GetValueIn (tx)-tx.GetValueOut ();
24572461
24582462 std::vector<CScriptCheck> vChecks;
24592463 bool fCacheResults = fJustCheck ; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
2460- if (!CheckInputs (tx, state, view, fScriptChecks , flags, fCacheResults , nScriptCheckThreads ? &vChecks : NULL ))
2464+ if (!CheckInputs (tx, state, view, fScriptChecks , flags, fCacheResults , cachedHashes[i], nScriptCheckThreads ? &vChecks : NULL ))
24612465 return error (" ConnectBlock(): CheckInputs on %s failed with %s" ,
24622466 tx.GetHash ().ToString (), FormatStateMessage (state));
24632467 control.Add (vChecks);
0 commit comments