aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2019-04-26 13:09:25 -0400
committerMarcoFalke <falke.marco@gmail.com>2019-04-26 13:09:30 -0400
commitd76b72a454a1b89888f9bf787415323e011ce4dc (patch)
treeb76102cf25a00173d68d3d8309345df4b8872db2
parentb1e013e4fa21923d8b49aa6fccbbaf77721c7d90 (diff)
parent5d262052728acdaa2d108a35ba9921a23b3d761a (diff)
Merge #15267: doc: explain AcceptToMemoryPoolWorker's coins_to_uncache
5d26205272 doc: explain AcceptToMemoryPoolWorker's coins_to_uncache (James O'Beirne) Pull request description: I found ATMPW's `coins_to_uncache` a little hard to understand (see #15264). This adds some doc for posterity. ACKs for commit 5d2620: jnewbery: ACK 5d262052728acdaa2d108a35ba9921a23b3d761a Tree-SHA512: 088508fa78012fab8680663c4e30f5cee29768416c2ca8b8b2abc29b6ac7067c5a589674f0254474a7ccc95477889d41719760f5796792bf492f51b3dd499c6c
-rw-r--r--src/coins.h4
-rw-r--r--src/validation.cpp16
2 files changed, 20 insertions, 0 deletions
diff --git a/src/coins.h b/src/coins.h
index d39ebf9062..482e233e8c 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -294,6 +294,10 @@ public:
bool HaveInputs(const CTransaction& tx) const;
private:
+ /**
+ * @note this is marked const, but may actually append to `cacheCoins`, increasing
+ * memory usage.
+ */
CCoinsMap::iterator FetchCoin(const COutPoint &outpoint) const;
};
diff --git a/src/validation.cpp b/src/validation.cpp
index 599d6027c8..6bbce9d99a 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -562,6 +562,13 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt
return CheckInputs(tx, state, view, true, flags, cacheSigStore, true, txdata);
}
+/**
+ * @param[out] coins_to_uncache Return any outpoints which were not previously present in the
+ * coins cache, but were added as a result of validating the tx
+ * for mempool acceptance. This allows the caller to optionally
+ * remove the cache additions if the associated transaction ends
+ * up being rejected by the mempool.
+ */
static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx,
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
bool bypass_limits, const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -657,6 +664,10 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
if (!pcoinsTip->HaveCoinInCache(txin.prevout)) {
coins_to_uncache.push_back(txin.prevout);
}
+
+ // Note: this call may add txin.prevout to the coins cache
+ // (pcoinsTip.cacheCoins) by way of FetchCoin(). It should be removed
+ // later (via coins_to_uncache) if this tx turns out to be invalid.
if (!view.HaveCoin(txin.prevout)) {
// Are inputs missing because we already have the tx?
for (size_t out = 0; out < tx.vout.size(); out++) {
@@ -978,6 +989,11 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
std::vector<COutPoint> coins_to_uncache;
bool res = AcceptToMemoryPoolWorker(chainparams, pool, state, tx, pfMissingInputs, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept);
if (!res) {
+ // Remove coins that were not present in the coins cache before calling ATMPW;
+ // this is to prevent memory DoS in case we receive a large number of
+ // invalid transactions that attempt to overrun the in-memory coins cache
+ // (`CCoinsViewCache::cacheCoins`).
+
for (const COutPoint& hashTx : coins_to_uncache)
pcoinsTip->Uncache(hashTx);
}