aboutsummaryrefslogtreecommitdiff
path: root/src/txmempool.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/txmempool.h')
-rw-r--r--src/txmempool.h53
1 files changed, 45 insertions, 8 deletions
diff --git a/src/txmempool.h b/src/txmempool.h
index fadb554723..a8a0f7fa45 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -184,7 +184,7 @@ private:
const LockPoints& lp;
};
-// extracts a transaction hash from CTxMempoolEntry or CTransactionRef
+// extracts a transaction hash from CTxMemPoolEntry or CTransactionRef
struct mempoolentry_txid
{
typedef uint256 result_type;
@@ -485,7 +485,43 @@ public:
>
> indexed_transaction_set;
- mutable CCriticalSection cs;
+ /**
+ * This mutex needs to be locked when accessing `mapTx` or other members
+ * that are guarded by it.
+ *
+ * @par Consistency guarantees
+ *
+ * By design, it is guaranteed that:
+ *
+ * 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool
+ * that is consistent with current chain tip (`chainActive` and
+ * `pcoinsTip`) and is fully populated. Fully populated means that if the
+ * current active chain is missing transactions that were present in a
+ * previously active chain, all the missing transactions will have been
+ * re-added to the mempool and should be present if they meet size and
+ * consistency constraints.
+ *
+ * 2. Locking `mempool.cs` without `cs_main` will give a view of a mempool
+ * consistent with some chain that was active since `cs_main` was last
+ * locked, and that is fully populated as described above. It is ok for
+ * code that only needs to query or remove transactions from the mempool
+ * to lock just `mempool.cs` without `cs_main`.
+ *
+ * To provide these guarantees, it is necessary to lock both `cs_main` and
+ * `mempool.cs` whenever adding transactions to the mempool and whenever
+ * changing the chain tip. It's necessary to keep both mutexes locked until
+ * the mempool is consistent with the new chain tip and fully populated.
+ *
+ * @par Consistency bug
+ *
+ * The second guarantee above is not currently enforced, but
+ * https://github.com/bitcoin/bitcoin/pull/14193 will fix it. No known code
+ * in bitcoin currently depends on second guarantee, but it is important to
+ * fix for third party code that needs be able to frequently poll the
+ * mempool without locking `cs_main` and without encountering missing
+ * transactions during reorgs.
+ */
+ mutable RecursiveMutex cs;
indexed_transaction_set mapTx GUARDED_BY(cs);
using txiter = indexed_transaction_set::nth_index<0>::type::const_iterator;
@@ -541,8 +577,8 @@ public:
// Note that addUnchecked is ONLY called from ATMP outside of tests
// and any other callers may break wallet's in-mempool tracking (due to
// lack of CValidationInterface::TransactionAddedToMempool callbacks).
- void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs);
- void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
+ void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -552,7 +588,7 @@ public:
void clear();
void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); //lock free
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
- void queryHashes(std::vector<uint256>& vtxid);
+ void queryHashes(std::vector<uint256>& vtxid) const;
bool isSpent(const COutPoint& outpoint) const;
unsigned int GetTransactionsUpdated() const;
void AddTransactionsUpdated(unsigned int n);
@@ -594,7 +630,7 @@ public:
* for). Note: vHashesToUpdate should be the set of transactions from the
* disconnected block that have been accepted back into the mempool.
*/
- void UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate);
+ void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Try to calculate all in-mempool ancestors of entry.
* (these are all calculated including the tx itself)
@@ -636,7 +672,7 @@ public:
*/
void GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const;
- unsigned long size()
+ unsigned long size() const
{
LOCK(cs);
return mapTx.size();
@@ -710,7 +746,8 @@ private:
* This allows transaction replacement to work as expected, as you want to
* have all inputs "available" to check signatures, and any cycles in the
* dependency graph are checked directly in AcceptToMemoryPool.
- * It also allows you to sign a double-spend directly in signrawtransaction,
+ * It also allows you to sign a double-spend directly in
+ * signrawtransactionwithkey and signrawtransactionwithwallet,
* as long as the conflicting transaction is not yet confirmed.
*/
class CCoinsViewMemPool : public CCoinsViewBacked