From 49b6fd5663dfe081d127cd1eb11407c4d3eaf93d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 2 Oct 2015 14:43:30 -0700 Subject: Add Mempool Expire function to remove old transactions (note the 9x multiplier on (void*)'s for CTxMemPool::DynamicMemoryUsage was accidentally introduced in 5add7a7 but should have waited for this commit which adds the extra index) --- src/txmempool.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 1370cab0c..57bb28460 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -792,6 +792,22 @@ void CTxMemPool::RemoveStaged(setEntries &stage) { } } +int CTxMemPool::Expire(int64_t time) { + LOCK(cs); + indexed_transaction_set::nth_index<2>::type::iterator it = mapTx.get<2>().begin(); + setEntries toremove; + while (it != mapTx.get<2>().end() && it->GetTime() < time) { + toremove.insert(mapTx.project<0>(it)); + it++; + } + setEntries stage; + BOOST_FOREACH(txiter removeit, toremove) { + CalculateDescendants(removeit, stage); + } + RemoveStaged(stage); + return stage.size(); +} + bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate) { LOCK(cs); -- cgit v1.2.3 From 9c9b66f771ad904cd665f7f5f68e3279ebb2fa7e Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 2 Oct 2015 14:17:27 -0700 Subject: Fix calling mempool directly, instead of pool, in ATMP --- src/txmempool.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 57bb28460..aa5aec055 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -735,10 +735,10 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta)); } -void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) +void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const { LOCK(cs); - std::map >::iterator pos = mapDeltas.find(hash); + std::map >::const_iterator pos = mapDeltas.find(hash); if (pos == mapDeltas.end()) return; const std::pair &deltas = pos->second; -- cgit v1.2.3 From e8bcdce8a245af235f8be9853c8f81c9bda56412 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 13 Oct 2015 00:57:41 -0700 Subject: Track (and define) ::minRelayTxFee in CTxMemPool --- src/txmempool.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index aa5aec055..e8d76dd2f 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -305,7 +305,7 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t } } -CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : +CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : nTransactionsUpdated(0) { // Sanity checks off by default for performance, because otherwise @@ -313,7 +313,8 @@ CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : // of transactions in the pool fSanityCheck = false; - minerPolicyEstimator = new CBlockPolicyEstimator(_minRelayFee); + minerPolicyEstimator = new CBlockPolicyEstimator(_minReasonableRelayFee); + minReasonableRelayFee = _minReasonableRelayFee; } CTxMemPool::~CTxMemPool() -- cgit v1.2.3 From 794a8cec5db84fde1cce82ada51740070ec188ac Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 2 Oct 2015 14:19:55 -0700 Subject: Implement on-the-fly mempool size limitation. After each transaction which is added to mempool, we first call Expire() to remove old transactions, then throwing away the lowest-feerate transactions. After throwing away transactions by feerate, we set the minimum relay fee to the maximum fee transaction-and-dependant-set we removed, plus the default minimum relay fee. After the next block is received, the minimum relay fee is allowed to decrease exponentially. Its halflife defaults to 12 hours, but is decreased to 6 hours if the mempool is smaller than half its maximum size, and 3 hours if the mempool is smaller than a quarter its maximum size. The minimum -maxmempool size is 40*-limitdescendantsize, as it is easy for an attacker to play games with the cheapest -limitdescendantsize transactions. -maxmempool defaults to 300MB. This disables high-priority transaction relay when the min relay fee adjustment is >0 (ie when the mempool is full). When the relay fee adjustment drops below the default minimum relay fee / 2 it is set to 0 (re-enabling priority-based free relay). --- src/txmempool.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index e8d76dd2f..7563c0788 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -13,6 +13,7 @@ #include "streams.h" #include "util.h" #include "utilmoneystr.h" +#include "utiltime.h" #include "version.h" using namespace std; @@ -308,6 +309,8 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : nTransactionsUpdated(0) { + clear(); + // Sanity checks off by default for performance, because otherwise // accepting transactions becomes O(N^2) where N is the number // of transactions in the pool @@ -539,6 +542,8 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i } // After the txs in the new block have been removed from the mempool, update policy estimates minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate); + lastRollingFeeUpdate = GetTime(); + blockSinceLastRollingFeeBump = true; } void CTxMemPool::clear() @@ -549,6 +554,9 @@ void CTxMemPool::clear() mapNextTx.clear(); totalTxSize = 0; cachedInnerUsage = 0; + lastRollingFeeUpdate = GetTime(); + blockSinceLastRollingFeeBump = false; + rollingMinimumFeeRate = 0; ++nTransactionsUpdated; } @@ -854,3 +862,60 @@ const CTxMemPool::setEntries & CTxMemPool::GetMemPoolChildren(txiter entry) cons assert(it != mapLinks.end()); return it->second.children; } + +CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const { + LOCK(cs); + if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0) + return CFeeRate(rollingMinimumFeeRate); + + int64_t time = GetTime(); + if (time > lastRollingFeeUpdate + 10) { + double halflife = ROLLING_FEE_HALFLIFE; + if (DynamicMemoryUsage() < sizelimit / 4) + halflife /= 4; + else if (DynamicMemoryUsage() < sizelimit / 2) + halflife /= 2; + + rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife); + lastRollingFeeUpdate = time; + + if (rollingMinimumFeeRate < minReasonableRelayFee.GetFeePerK() / 2) + rollingMinimumFeeRate = 0; + } + return std::max(CFeeRate(rollingMinimumFeeRate), minReasonableRelayFee); +} + +void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) { + AssertLockHeld(cs); + if (rate.GetFeePerK() > rollingMinimumFeeRate) { + rollingMinimumFeeRate = rate.GetFeePerK(); + blockSinceLastRollingFeeBump = false; + } +} + +void CTxMemPool::TrimToSize(size_t sizelimit) { + LOCK(cs); + + unsigned nTxnRemoved = 0; + CFeeRate maxFeeRateRemoved(0); + while (DynamicMemoryUsage() > sizelimit) { + indexed_transaction_set::nth_index<1>::type::iterator it = mapTx.get<1>().begin(); + + // We set the new mempool min fee to either the feerate of the removed set, + // or the "minimum reasonable fee rate" (ie some value under which we consider + // txn to have 0 fee). This way, if the mempool reaches its full size on free + // txn, we will simply disable free txn until there is a block, and some time. + CFeeRate removed(it->GetFeesWithDescendants(), it->GetSizeWithDescendants()); + removed += minReasonableRelayFee; + trackPackageRemoved(removed); + maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed); + + setEntries stage; + CalculateDescendants(mapTx.project<0>(it), stage); + RemoveStaged(stage); + nTxnRemoved += stage.size(); + } + + if (maxFeeRateRemoved > CFeeRate(0)) + LogPrint("mempool", "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString()); +} -- cgit v1.2.3 From 8abe0f56584ff49ad250115eb1f0a9ac8f9cf0ca Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 14 Oct 2015 12:44:18 -0700 Subject: Undo GetMinFee-requires-extra-call-to-hit-0 --- src/txmempool.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 7563c0788..9a651049d 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -879,8 +879,10 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const { rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife); lastRollingFeeUpdate = time; - if (rollingMinimumFeeRate < minReasonableRelayFee.GetFeePerK() / 2) + if (rollingMinimumFeeRate < minReasonableRelayFee.GetFeePerK() / 2) { rollingMinimumFeeRate = 0; + return CFeeRate(0); + } } return std::max(CFeeRate(rollingMinimumFeeRate), minReasonableRelayFee); } -- cgit v1.2.3 From 58254aa3bc2e92840679183cc884eb76670af525 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 19 Oct 2015 02:40:25 -0700 Subject: Fix stale comment in CTxMemPool::TrimToSize. --- src/txmempool.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 9a651049d..bb148005c 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -903,10 +903,10 @@ void CTxMemPool::TrimToSize(size_t sizelimit) { while (DynamicMemoryUsage() > sizelimit) { indexed_transaction_set::nth_index<1>::type::iterator it = mapTx.get<1>().begin(); - // We set the new mempool min fee to either the feerate of the removed set, - // or the "minimum reasonable fee rate" (ie some value under which we consider - // txn to have 0 fee). This way, if the mempool reaches its full size on free - // txn, we will simply disable free txn until there is a block, and some time. + // We set the new mempool min fee to the feerate of the removed set, plus the + // "minimum reasonable fee rate" (ie some value under which we consider txn + // to have 0 fee). This way, we don't allow txn to enter mempool with feerate + // equal to txn which were removed with no block in between. CFeeRate removed(it->GetFeesWithDescendants(), it->GetSizeWithDescendants()); removed += minReasonableRelayFee; trackPackageRemoved(removed); -- cgit v1.2.3