@@ -399,6 +399,42 @@ void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool f
399
399
LimitMempoolSize (mempool, GetArg (" -maxmempool" , DEFAULT_MAX_MEMPOOL_SIZE) * 1000000 , GetArg (" -mempoolexpiry" , DEFAULT_MEMPOOL_EXPIRY) * 60 * 60 );
400
400
}
401
401
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
+
402
438
static bool AcceptToMemoryPoolWorker (const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, bool fLimitFree ,
403
439
bool * pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
404
440
bool fOverrideMempoolLimit , const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache)
@@ -782,7 +818,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
782
818
// invalid blocks (using TestBlockValidity), however allowing such
783
819
// transactions into the mempool can be exploited as a DoS attack.
784
820
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))
786
822
{
787
823
// If we're using promiscuousmempoolflags, we may hit this normally
788
824
// Check if current block has some flags that scriptVerifyFlags
0 commit comments