diff --git a/src/coins.h b/src/coins.h --- a/src/coins.h +++ b/src/coins.h @@ -512,10 +512,10 @@ bool Flush(); /** - * Removes the transaction with the given hash from the cache, if it is - * not modified. + * Removes the UTXO with the given outpoint from the cache, if it is not + * modified. */ - void Uncache(const uint256 &txid); + void Uncache(const COutPoint &outpoint); //! Calculate the size of the cache (in number of transactions) unsigned int GetCacheSize() const; diff --git a/src/coins.cpp b/src/coins.cpp --- a/src/coins.cpp +++ b/src/coins.cpp @@ -289,8 +289,8 @@ return fOk; } -void CCoinsViewCache::Uncache(const uint256 &hash) { - CCoinsMap::iterator it = cacheCoins.find(hash); +void CCoinsViewCache::Uncache(const COutPoint &outpoint) { + CCoinsMap::iterator it = cacheCoins.find(outpoint.hash); if (it != cacheCoins.end() && it->second.flags == 0) { cachedCoinsUsage -= it->second.coins.DynamicMemoryUsage(); cacheCoins.erase(it); diff --git a/src/txmempool.h b/src/txmempool.h --- a/src/txmempool.h +++ b/src/txmempool.h @@ -656,11 +656,11 @@ /** * Remove transactions from the mempool until its dynamic size is <= * sizelimit. pvNoSpendsRemaining, if set, will be populated with the list - * of transactions which are not in mempool which no longer have any spends - * in this mempool. + * of outpoints which are not in mempool which no longer have any spends in + * this mempool. */ void TrimToSize(size_t sizelimit, - std::vector *pvNoSpendsRemaining = nullptr); + std::vector *pvNoSpendsRemaining = nullptr); /** Expire all transaction (and their dependencies) in the mempool older * than time. Return the number of removed transactions. */ diff --git a/src/txmempool.cpp b/src/txmempool.cpp --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1150,7 +1150,7 @@ } void CTxMemPool::TrimToSize(size_t sizelimit, - std::vector *pvNoSpendsRemaining) { + std::vector *pvNoSpendsRemaining) { LOCK(cs); unsigned nTxnRemoved = 0; @@ -1185,12 +1185,15 @@ if (pvNoSpendsRemaining) { for (const CTransaction &tx : txn) { for (const CTxIn &txin : tx.vin) { - if (exists(txin.prevout.hash)) continue; + if (exists(txin.prevout.hash)) { + continue; + } + auto iter = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0)); if (iter == mapNextTx.end() || iter->first->hash != txin.prevout.hash) - pvNoSpendsRemaining->push_back(txin.prevout.hash); + pvNoSpendsRemaining->push_back(txin.prevout); } } } diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -385,13 +385,6 @@ bool fOverrideMempoolLimit = false, const CAmount nAbsurdFee = 0); -/** (try to) add transaction to memory pool with a specified acceptance time **/ -bool AcceptToMemoryPoolWithTime( - const Config &config, CTxMemPool &pool, CValidationState &state, - const CTransactionRef &tx, bool fLimitFree, bool *pfMissingInputs, - int64_t nAcceptTime, std::list *plTxnReplaced = nullptr, - bool fOverrideMempoolLimit = false, const CAmount nAbsurdFee = 0); - /** Convert CValidationState to a human-readable message for logging */ std::string FormatStateMessage(const CValidationState &state); diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -564,13 +564,14 @@ void LimitMempoolSize(CTxMemPool &pool, size_t limit, unsigned long age) { int expired = pool.Expire(GetTime() - age); - if (expired != 0) + if (expired != 0) { LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired); + } - std::vector vNoSpendsRemaining; + std::vector vNoSpendsRemaining; pool.TrimToSize(limit, &vNoSpendsRemaining); - for (const uint256 &removed : vNoSpendsRemaining) { + for (const COutPoint &removed : vNoSpendsRemaining) { pcoinsTip->Uncache(removed); } } @@ -615,7 +616,7 @@ const CTransactionRef &ptx, bool fLimitFree, bool *pfMissingInputs, int64_t nAcceptTime, std::list *plTxnReplaced, bool fOverrideMempoolLimit, const CAmount &nAbsurdFee, - std::vector &vHashTxnToUncache) { + std::vector &coins_to_uncache) { AssertLockHeld(cs_main); const CTransaction &tx = *ptx; @@ -679,10 +680,10 @@ // Do we already have it? for (size_t out = 0; out < tx.vout.size(); out++) { COutPoint outpoint(txid, out); - bool fHadTxInCache = pcoinsTip->HaveCoinInCache(outpoint); + bool had_coin_in_cache = pcoinsTip->HaveCoinInCache(outpoint); if (view.HaveCoin(outpoint)) { - if (!fHadTxInCache) { - vHashTxnToUncache.push_back(txid); + if (!had_coin_in_cache) { + coins_to_uncache.push_back(outpoint); } return state.Invalid(false, REJECT_ALREADY_KNOWN, @@ -690,13 +691,10 @@ } } - // Do all inputs exist? Note that this does not check for the - // presence of actual outputs (see the next check for that), and - // only helps with filling in pfMissingInputs (to determine missing - // vs spent). + // Do all inputs exist? for (const CTxIn txin : tx.vin) { if (!pcoinsTip->HaveCoinInCache(txin.prevout)) { - vHashTxnToUncache.push_back(txin.prevout.hash); + coins_to_uncache.push_back(txin.prevout); } if (!view.HaveCoin(txin.prevout)) { @@ -918,22 +916,21 @@ return true; } -bool AcceptToMemoryPoolWithTime(const Config &config, CTxMemPool &pool, - CValidationState &state, - const CTransactionRef &tx, bool fLimitFree, - bool *pfMissingInputs, int64_t nAcceptTime, - std::list *plTxnReplaced, - bool fOverrideMempoolLimit, - const CAmount nAbsurdFee) { - std::vector vHashTxToUncache; +static bool AcceptToMemoryPoolWithTime( + const Config &config, CTxMemPool &pool, CValidationState &state, + const CTransactionRef &tx, bool fLimitFree, bool *pfMissingInputs, + int64_t nAcceptTime, std::list *plTxnReplaced = nullptr, + bool fOverrideMempoolLimit = false, const CAmount nAbsurdFee = 0) { + std::vector coins_to_uncache; bool res = AcceptToMemoryPoolWorker( config, pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, - plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache); + plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache); if (!res) { - for (const uint256 &txid : vHashTxToUncache) { - pcoinsTip->Uncache(txid); + for (const COutPoint &outpoint : coins_to_uncache) { + pcoinsTip->Uncache(outpoint); } } + // After we've (potentially) uncached entries, ensure our coins cache is // still within its size limits CValidationState stateDummy;