@@ -399,6 +399,42 @@ void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool f
399399 LimitMempoolSize (mempool, GetArg (" -maxmempool" , DEFAULT_MAX_MEMPOOL_SIZE) * 1000000 , GetArg (" -mempoolexpiry" , DEFAULT_MEMPOOL_EXPIRY) * 60 * 60 );
400400}
401401
402+ // Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool
403+ // were somehow broken and returning the wrong scriptPubKeys
404+ static bool CheckInputsFromMempoolAndCache (const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, CTxMemPool& pool,
405+ unsigned int flags, bool cacheSigStore, PrecomputedTransactionData& txdata) {
406+ AssertLockHeld (cs_main);
407+
408+ // pool.cs should be locked already, but go ahead and re-take the lock here
409+ // to enforce that mempool doesn't change between when we check the view
410+ // and when we actually call through to CheckInputs
411+ LOCK (pool.cs );
412+
413+ assert (!tx.IsCoinBase ());
414+ for (const CTxIn& txin : tx.vin ) {
415+ const Coin& coin = view.AccessCoin (txin.prevout );
416+
417+ // At this point we haven't actually checked if the coins are all
418+ // available (or shouldn't assume we have, since CheckInputs does).
419+ // So we just return failure if the inputs are not available here,
420+ // and then only have to check equivalence for available inputs.
421+ if (coin.IsSpent ()) return false ;
422+
423+ const CTransactionRef& txFrom = pool.get (txin.prevout .hash );
424+ if (txFrom) {
425+ assert (txFrom->GetHash () == txin.prevout .hash );
426+ assert (txFrom->vout .size () > txin.prevout .n );
427+ assert (txFrom->vout [txin.prevout .n ] == coin.out );
428+ } else {
429+ const Coin& coinFromDisk = pcoinsTip->AccessCoin (txin.prevout );
430+ assert (!coinFromDisk.IsSpent ());
431+ assert (coinFromDisk.out == coin.out );
432+ }
433+ }
434+
435+ return CheckInputs (tx, state, view, true , flags, cacheSigStore, true , txdata);
436+ }
437+
402438static bool AcceptToMemoryPoolWorker (const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, bool fLimitFree ,
403439 bool * pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
404440 bool fOverrideMempoolLimit , const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache)
@@ -782,7 +818,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
782818 // invalid blocks (using TestBlockValidity), however allowing such
783819 // transactions into the mempool can be exploited as a DoS attack.
784820 unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags (chainActive.Tip (), Params ().GetConsensus ());
785- if (!CheckInputs (tx, state, view, true , currentBlockScriptVerifyFlags, true , true , txdata))
821+ if (!CheckInputsFromMempoolAndCache (tx, state, view, pool , currentBlockScriptVerifyFlags, true , txdata))
786822 {
787823 // If we're using promiscuousmempoolflags, we may hit this normally
788824 // Check if current block has some flags that scriptVerifyFlags
0 commit comments