Merge #11689: mempool: Fix missing locking in CTxMemPool::check(…) and CTxMemPool::setSanityCheck(…)

47782b49e6 Add Clang thread safety analysis annotations (practicalswift)
0e2dfa8a65 Fix missing locking in CTxMemPool::setSanityCheck(double dFrequency) (practicalswift)
6bc5b7100b Fix missing locking in CTxMemPool::check(const CCoinsViewCache *pcoins) (practicalswift)

Pull request description:

  Fix missing locking in `CTxMemPool::check(const CCoinsViewCache *pcoins)`:
  * reading variable `mapTx` requires holding mutex `cs`
  * reading variable `mapNextTx` requires holding mutex `cs`
  * reading variable `nCheckFrequency` requires holding mutex `cs`

  Fix missing locking in `CTxMemPool::setSanityCheck(double dFrequency)`:
  * writing variable `nCheckFrequency` requires holding mutex `cs`

Tree-SHA512: ce7c365ac89225223fb06e6f469451b121acaa499f35b21ad8a6d2a266c91194639b3703c5428871be033d4f5f7be790cc297bd8c25b2e0c59345ef09c3693d0
This commit is contained in:
MarcoFalke 2018-05-14 10:29:17 -04:00 committed by pasta
parent 845fa89e58
commit 1d81e8dd52
5 changed files with 20 additions and 20 deletions

View File

@ -15,7 +15,6 @@
#include <consensus/merkle.h> #include <consensus/merkle.h>
#include <consensus/validation.h> #include <consensus/validation.h>
#include <hash.h> #include <hash.h>
#include <validation.h>
#include <net.h> #include <net.h>
#include <policy/feerate.h> #include <policy/feerate.h>
#include <policy/policy.h> #include <policy/policy.h>

View File

@ -8,6 +8,7 @@
#include <primitives/block.h> #include <primitives/block.h>
#include <txmempool.h> #include <txmempool.h>
#include <validation.h>
#include <stdint.h> #include <stdint.h>
#include <memory> #include <memory>
@ -171,7 +172,7 @@ private:
/** Add transactions based on feerate including unconfirmed ancestors /** Add transactions based on feerate including unconfirmed ancestors
* Increments nPackagesSelected / nDescendantsUpdated with corresponding * Increments nPackagesSelected / nDescendantsUpdated with corresponding
* statistics from the package selection (for logging statistics). */ * statistics from the package selection (for logging statistics). */
void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated); void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs);
// helper functions for addPackageTxs() // helper functions for addPackageTxs()
/** Remove confirmed (inBlock) entries from given set */ /** Remove confirmed (inBlock) entries from given set */
@ -185,13 +186,13 @@ private:
bool TestPackageTransactions(const CTxMemPool::setEntries& package); bool TestPackageTransactions(const CTxMemPool::setEntries& package);
/** Return true if given transaction from mapTx has already been evaluated, /** Return true if given transaction from mapTx has already been evaluated,
* or if the transaction's cached data in mapTx is incorrect. */ * or if the transaction's cached data in mapTx is incorrect. */
bool SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, CTxMemPool::setEntries &failedTx); bool SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, CTxMemPool::setEntries &failedTx) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs);
/** Sort the package in an order that is valid to appear in a block */ /** Sort the package in an order that is valid to appear in a block */
void SortForBlock(const CTxMemPool::setEntries& package, std::vector<CTxMemPool::txiter>& sortedEntries); void SortForBlock(const CTxMemPool::setEntries& package, std::vector<CTxMemPool::txiter>& sortedEntries);
/** Add descendants of given transactions to mapModifiedTx with ancestor /** Add descendants of given transactions to mapModifiedTx with ancestor
* state updated assuming given transactions are inBlock. Returns number * state updated assuming given transactions are inBlock. Returns number
* of updated descendants. */ * of updated descendants. */
int UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set &mapModifiedTx); int UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set &mapModifiedTx) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs);
}; };
/** Modify the extranonce in a block */ /** Modify the extranonce in a block */

View File

@ -105,7 +105,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
} }
template<typename name> template<typename name>
void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder) void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
{ {
BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size()); BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size());
typename CTxMemPool::indexed_transaction_set::index<name>::type::iterator it = pool.mapTx.get<name>().begin(); typename CTxMemPool::indexed_transaction_set::index<name>::type::iterator it = pool.mapTx.get<name>().begin();

View File

@ -1012,6 +1012,7 @@ static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& m
void CTxMemPool::check(const CCoinsViewCache *pcoins) const void CTxMemPool::check(const CCoinsViewCache *pcoins) const
{ {
LOCK(cs);
if (nCheckFrequency == 0) if (nCheckFrequency == 0)
return; return;
@ -1026,7 +1027,6 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins)); CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins));
const int64_t spendheight = GetSpendHeight(mempoolDuplicate); const int64_t spendheight = GetSpendHeight(mempoolDuplicate);
LOCK(cs);
std::list<const CTxMemPoolEntry*> waitingOnDependants; std::list<const CTxMemPoolEntry*> waitingOnDependants;
for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
unsigned int i = 0; unsigned int i = 0;

View File

@ -442,7 +442,7 @@ public:
class CTxMemPool class CTxMemPool
{ {
private: private:
uint32_t nCheckFrequency; //!< Value n means that n times in 2^32 we check. uint32_t nCheckFrequency GUARDED_BY(cs); //!< Value n means that n times in 2^32 we check.
unsigned int nTransactionsUpdated; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation unsigned int nTransactionsUpdated; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
CBlockPolicyEstimator* minerPolicyEstimator; CBlockPolicyEstimator* minerPolicyEstimator;
@ -486,7 +486,7 @@ public:
> indexed_transaction_set; > indexed_transaction_set;
mutable CCriticalSection cs; mutable CCriticalSection cs;
indexed_transaction_set mapTx; indexed_transaction_set mapTx GUARDED_BY(cs);
typedef indexed_transaction_set::nth_index<0>::type::iterator txiter; typedef indexed_transaction_set::nth_index<0>::type::iterator txiter;
std::vector<std::pair<uint256, txiter> > vTxHashes; //!< All tx hashes/entries in mapTx, in random order std::vector<std::pair<uint256, txiter> > vTxHashes; //!< All tx hashes/entries in mapTx, in random order
@ -498,8 +498,8 @@ public:
}; };
typedef std::set<txiter, CompareIteratorByHash> setEntries; typedef std::set<txiter, CompareIteratorByHash> setEntries;
const setEntries & GetMemPoolParents(txiter entry) const; const setEntries & GetMemPoolParents(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
const setEntries & GetMemPoolChildren(txiter entry) const; const setEntries & GetMemPoolChildren(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
private: private:
typedef std::map<txiter, setEntries, CompareIteratorByHash> cacheMap; typedef std::map<txiter, setEntries, CompareIteratorByHash> cacheMap;
@ -535,7 +535,7 @@ private:
std::vector<indexed_transaction_set::const_iterator> GetSortedDepthAndScore() const EXCLUSIVE_LOCKS_REQUIRED(cs); std::vector<indexed_transaction_set::const_iterator> GetSortedDepthAndScore() const EXCLUSIVE_LOCKS_REQUIRED(cs);
public: public:
indirectmap<COutPoint, const CTransaction*> mapNextTx; indirectmap<COutPoint, const CTransaction*> mapNextTx GUARDED_BY(cs);
std::map<uint256, CAmount> mapDeltas; std::map<uint256, CAmount> mapDeltas;
/** Create a new CTxMemPool. /** Create a new CTxMemPool.
@ -549,7 +549,7 @@ public:
* check does nothing. * check does nothing.
*/ */
void check(const CCoinsViewCache *pcoins) const; void check(const CCoinsViewCache *pcoins) const;
void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = static_cast<uint32_t>(dFrequency * 4294967295.0); } void setSanityCheck(double dFrequency = 1.0) { LOCK(cs); nCheckFrequency = static_cast<uint32_t>(dFrequency * 4294967295.0); }
// addUnchecked must updated state for all ancestors of a given transaction, // addUnchecked must updated state for all ancestors of a given transaction,
// to track size/count of descendant transactions. First version of // to track size/count of descendant transactions. First version of
@ -582,7 +582,7 @@ public:
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight); void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);
void clear(); void clear();
void _clear(); //lock free void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); //lock free
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb); bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
void queryHashes(std::vector<uint256>& vtxid); void queryHashes(std::vector<uint256>& vtxid);
bool isSpent(const COutPoint& outpoint); bool isSpent(const COutPoint& outpoint);
@ -635,7 +635,7 @@ public:
/** Populate setDescendants with all in-mempool descendants of hash. /** Populate setDescendants with all in-mempool descendants of hash.
* Assumes that setDescendants includes all in-mempool descendants of anything * Assumes that setDescendants includes all in-mempool descendants of anything
* already in it. */ * already in it. */
void CalculateDescendants(txiter it, setEntries &setDescendants); void CalculateDescendants(txiter it, setEntries &setDescendants) EXCLUSIVE_LOCKS_REQUIRED(cs);
/** The minimum fee to get into the mempool, which may itself not be enough /** The minimum fee to get into the mempool, which may itself not be enough
* for larger-sized transactions. * for larger-sized transactions.
@ -702,17 +702,17 @@ private:
*/ */
void UpdateForDescendants(txiter updateIt, void UpdateForDescendants(txiter updateIt,
cacheMap &cachedDescendants, cacheMap &cachedDescendants,
const std::set<uint256> &setExclude); const std::set<uint256> &setExclude) EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Update ancestors of hash to add/remove it as a descendant transaction. */ /** Update ancestors of hash to add/remove it as a descendant transaction. */
void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors); void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors) EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Set ancestor state for an entry */ /** Set ancestor state for an entry */
void UpdateEntryForAncestors(txiter it, const setEntries &setAncestors); void UpdateEntryForAncestors(txiter it, const setEntries &setAncestors) EXCLUSIVE_LOCKS_REQUIRED(cs);
/** For each transaction being removed, update ancestors and any direct children. /** For each transaction being removed, update ancestors and any direct children.
* If updateDescendants is true, then also update in-mempool descendants' * If updateDescendants is true, then also update in-mempool descendants'
* ancestor state. */ * ancestor state. */
void UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants); void UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants) EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Sever link between specified transaction and direct children. */ /** Sever link between specified transaction and direct children. */
void UpdateChildrenForRemoval(txiter entry); void UpdateChildrenForRemoval(txiter entry) EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Before calling removeUnchecked for a given transaction, /** Before calling removeUnchecked for a given transaction,
* UpdateForRemoveFromMempool must be called on the entire (dependent) set * UpdateForRemoveFromMempool must be called on the entire (dependent) set
@ -722,7 +722,7 @@ private:
* transactions in a chain before we've updated all the state for the * transactions in a chain before we've updated all the state for the
* removal. * removal.
*/ */
void removeUnchecked(txiter entry, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN); void removeUnchecked(txiter entry, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN) EXCLUSIVE_LOCKS_REQUIRED(cs);
}; };
/** /**