From 2d8c49d126bf2551ef0268f314ab75932fa96510 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Mon, 3 Aug 2015 15:49:01 -0400 Subject: Clean up tx prioritization when conflict mined --- src/txmempool.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 5bc06e5056..0e65aa1c59 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -193,6 +193,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list if (txConflict != tx) { remove(txConflict, removed, true); + ClearPrioritisation(txConflict.GetHash()); } } } -- cgit v1.2.3 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 1370cab0c0..57bb284602 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 57bb284602..aa5aec0556 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 aa5aec0556..e8d76dd2f1 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 e8d76dd2f1..7563c07880 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 7563c07880..9a651049d5 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 9a651049d5..bb148005cd 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 From ab1f56072a796b0ff039d6690c6ac929dbcbf243 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 7 Oct 2015 23:34:55 +0200 Subject: Support -checkmempool=N, which runs checks on average once every N transactions --- src/txmempool.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 1370cab0c0..c379a45b48 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -311,7 +311,7 @@ CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : // 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 - fSanityCheck = false; + nCheckFrequency = 0; minerPolicyEstimator = new CBlockPolicyEstimator(_minRelayFee); } @@ -483,7 +483,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in if (it2 != mapTx.end()) continue; const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); - if (fSanityCheck) assert(coins); + if (nCheckFrequency != 0) assert(coins); if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { transactionsToRemove.push_back(tx); break; @@ -553,7 +553,10 @@ void CTxMemPool::clear() void CTxMemPool::check(const CCoinsViewCache *pcoins) const { - if (!fSanityCheck) + if (nCheckFrequency == 0) + return; + + if (insecure_rand() >= nCheckFrequency) return; LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); -- cgit v1.2.3 From 0d699fc821048ab9316b0004e6552c8f1dc5e5f4 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 26 Oct 2015 14:55:17 +0100 Subject: fix locking issue with new mempool limiting Current master crashes on OSX with an exception: "boost: mutex lock failed in pthread_mutex_lock: Invalid argument" --- src/txmempool.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index bb148005cd..efa5c8f7a3 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -309,7 +309,7 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : nTransactionsUpdated(0) { - clear(); + _clear(); //lock free clear // Sanity checks off by default for performance, because otherwise // accepting transactions becomes O(N^2) where N is the number @@ -546,9 +546,8 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i blockSinceLastRollingFeeBump = true; } -void CTxMemPool::clear() +void CTxMemPool::_clear() { - LOCK(cs); mapLinks.clear(); mapTx.clear(); mapNextTx.clear(); @@ -560,6 +559,12 @@ void CTxMemPool::clear() ++nTransactionsUpdated; } +void CTxMemPool::clear() +{ + LOCK(cs); + _clear(); +} + void CTxMemPool::check(const CCoinsViewCache *pcoins) const { if (!fSanityCheck) -- cgit v1.2.3 From 22eca7da22b67409d757d6859b1cf212e445dd39 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Mon, 16 Nov 2015 15:10:22 -0500 Subject: Add smart fee estimation functions These are more useful fee and priority estimation functions. If there is no fee/pri high enough for the target you are aiming for, it will give you the estimate for the lowest target that you can reliably obtain. This is better than defaulting to the minimum. It will also pass back the target for which it returned an answer. --- src/txmempool.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index a772e7adea..503e73d454 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -701,11 +701,21 @@ CFeeRate CTxMemPool::estimateFee(int nBlocks) const LOCK(cs); return minerPolicyEstimator->estimateFee(nBlocks); } +CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, int *answerFoundAtBlocks) const +{ + LOCK(cs); + return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks); +} double CTxMemPool::estimatePriority(int nBlocks) const { LOCK(cs); return minerPolicyEstimator->estimatePriority(nBlocks); } +double CTxMemPool::estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks) const +{ + LOCK(cs); + return minerPolicyEstimator->estimateSmartPriority(nBlocks, answerFoundAtBlocks); +} bool CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const -- cgit v1.2.3 From 63030514701828a06040413837f5eced9deeee03 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Mon, 16 Nov 2015 15:21:51 -0500 Subject: EstimateSmart functions consider mempool min fee --- 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 503e73d454..58b8448bb6 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -704,7 +704,7 @@ CFeeRate CTxMemPool::estimateFee(int nBlocks) const CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, int *answerFoundAtBlocks) const { LOCK(cs); - return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks); + return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, this); } double CTxMemPool::estimatePriority(int nBlocks) const { @@ -714,7 +714,7 @@ double CTxMemPool::estimatePriority(int nBlocks) const double CTxMemPool::estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks) const { LOCK(cs); - return minerPolicyEstimator->estimateSmartPriority(nBlocks, answerFoundAtBlocks); + return minerPolicyEstimator->estimateSmartPriority(nBlocks, answerFoundAtBlocks, this); } bool -- cgit v1.2.3 From e30443244a7a50f2db70e593ec8a57e5086db3d9 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Tue, 24 Nov 2015 08:53:14 -0500 Subject: Pass reference to estimateSmartFee and cleanup whitespace --- 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 58b8448bb6..ec7971c2f1 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -704,7 +704,7 @@ CFeeRate CTxMemPool::estimateFee(int nBlocks) const CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, int *answerFoundAtBlocks) const { LOCK(cs); - return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, this); + return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, *this); } double CTxMemPool::estimatePriority(int nBlocks) const { @@ -714,7 +714,7 @@ double CTxMemPool::estimatePriority(int nBlocks) const double CTxMemPool::estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks) const { LOCK(cs); - return minerPolicyEstimator->estimateSmartPriority(nBlocks, answerFoundAtBlocks, this); + return minerPolicyEstimator->estimateSmartPriority(nBlocks, answerFoundAtBlocks, *this); } bool -- cgit v1.2.3 From 71f1d9fd4ae2c2fc90d5487bdf2096f9eb5898d9 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Tue, 30 Jun 2015 11:14:24 -0400 Subject: Modify variable names for entry height and priority --- src/txmempool.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index ec7971c2f1..ea3aad34a3 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -19,9 +19,9 @@ using namespace std; CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, - int64_t _nTime, double _dPriority, - unsigned int _nHeight, bool poolHasNoInputsOf): - tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight), + int64_t _nTime, double _entryPriority, + unsigned int _entryHeight, bool poolHasNoInputsOf): + tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), hadNoDependencies(poolHasNoInputsOf) { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); @@ -42,8 +42,8 @@ double CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const { CAmount nValueIn = tx.GetValueOut()+nFee; - double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nModSize; - double dResult = dPriority + deltaPriority; + double deltaPriority = ((double)(currentHeight-entryHeight)*nValueIn)/nModSize; + double dResult = entryPriority + deltaPriority; return dResult; } -- cgit v1.2.3 From c0353064ddf71ad103bd19f6e7c10ff8e240ac46 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Fri, 13 Nov 2015 10:05:21 -0500 Subject: Change GetPriority calculation. Compute the value of inputs that already are in the chain at time of mempool entry and only increase priority due to aging for those inputs. This effectively changes the CTxMemPoolEntry's GetPriority calculation from an upper bound to a lower bound. --- src/txmempool.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index ea3aad34a3..6d1df0b3d1 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -19,10 +19,10 @@ using namespace std; CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, - int64_t _nTime, double _entryPriority, - unsigned int _entryHeight, bool poolHasNoInputsOf): + int64_t _nTime, double _entryPriority, unsigned int _entryHeight, + bool poolHasNoInputsOf, CAmount _inChainInputValue): tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), - hadNoDependencies(poolHasNoInputsOf) + hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue) { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); @@ -31,6 +31,8 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, nCountWithDescendants = 1; nSizeWithDescendants = nTxSize; nFeesWithDescendants = nFee; + CAmount nValueIn = tx.GetValueOut()+nFee; + assert(inChainInputValue <= nValueIn); } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -41,9 +43,10 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) double CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const { - CAmount nValueIn = tx.GetValueOut()+nFee; - double deltaPriority = ((double)(currentHeight-entryHeight)*nValueIn)/nModSize; + double deltaPriority = ((double)(currentHeight-entryHeight)*inChainInputValue)/nModSize; double dResult = entryPriority + deltaPriority; + if (dResult < 0) // This should only happen if it was called with a height below entry height + dResult = 0; return dResult; } -- cgit v1.2.3 From 9b060e5cfb0d185b553b21ae19d390f81e83bd4d Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 26 Aug 2015 18:58:17 -0700 Subject: Fix removal of time-locked transactions during reorg --- src/txmempool.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 6d1df0b3d1..1c38e32601 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -11,6 +11,7 @@ #include "main.h" #include "policy/fees.h" #include "streams.h" +#include "timedata.h" #include "util.h" #include "utilmoneystr.h" #include "utiltime.h" @@ -478,22 +479,26 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem } } -void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight) +void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight) { // Remove transactions spending a coinbase which are now immature LOCK(cs); list transactionsToRemove; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->GetTx(); - BOOST_FOREACH(const CTxIn& txin, tx.vin) { - indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); - if (it2 != mapTx.end()) - continue; - const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); - if (nCheckFrequency != 0) assert(coins); - if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { - transactionsToRemove.push_back(tx); - break; + if (!IsFinalTx(tx, nMemPoolHeight, GetAdjustedTime())) { + transactionsToRemove.push_back(tx); + } else { + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); + if (it2 != mapTx.end()) + continue; + const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); + if (nCheckFrequency != 0) assert(coins); + if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { + transactionsToRemove.push_back(tx); + break; + } } } } -- cgit v1.2.3 From b0a064c4b825c15dee87739348bab23f13541bdd Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sat, 5 Sep 2015 21:40:21 -0700 Subject: Fix comment in removeForReorg --- src/txmempool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 1c38e32601..a2a53b0180 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -481,7 +481,7 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight) { - // Remove transactions spending a coinbase which are now immature + // Remove transactions spending a coinbase which are now immature and no-longer-final transactions LOCK(cs); list transactionsToRemove; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { -- cgit v1.2.3 From 7e49f5f8b4e237d7212d027a7bea4bbd52c9e7b6 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 29 Oct 2015 14:06:13 -0400 Subject: Track coinbase spends in CTxMemPoolEntry This allows us to optimize CTxMemPool::removeForReorg. --- src/txmempool.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index a2a53b0180..5a3062291f 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -21,9 +21,11 @@ using namespace std; CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, - bool poolHasNoInputsOf, CAmount _inChainInputValue): + bool poolHasNoInputsOf, CAmount _inChainInputValue, + bool _spendsCoinbase): tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), - hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue) + hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), + spendsCoinbase(_spendsCoinbase) { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); @@ -488,7 +490,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem const CTransaction& tx = it->GetTx(); if (!IsFinalTx(tx, nMemPoolHeight, GetAdjustedTime())) { transactionsToRemove.push_back(tx); - } else { + } else if (it->GetSpendsCoinbase()) { BOOST_FOREACH(const CTxIn& txin, tx.vin) { indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) -- cgit v1.2.3 From 2d8860e820e2ca73000f558eb9686206bec2652a Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 23 Nov 2015 16:06:12 -0500 Subject: Fix removeForReorg to use MedianTimePast --- 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 5a3062291f..9d25139481 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -481,14 +481,14 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem } } -void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight) +void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) { // Remove transactions spending a coinbase which are now immature and no-longer-final transactions LOCK(cs); list transactionsToRemove; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->GetTx(); - if (!IsFinalTx(tx, nMemPoolHeight, GetAdjustedTime())) { + if (!CheckFinalTx(tx, flags)) { transactionsToRemove.push_back(tx); } else if (it->GetSpendsCoinbase()) { BOOST_FOREACH(const CTxIn& txin, tx.vin) { -- cgit v1.2.3 From c49d5bc9e6c97c47c0bd78604b2c393a7e4af097 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Mon, 26 Oct 2015 11:08:46 -0400 Subject: Store the total sig op count of a tx. Store sum of legacy and P2SH sig op counts. This is calculated in AcceptToMemory pool and storing it saves redoing the expensive calculation in block template creation. --- 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 9d25139481..fa62cbf166 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -22,10 +22,10 @@ using namespace std; CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, bool poolHasNoInputsOf, CAmount _inChainInputValue, - bool _spendsCoinbase): + bool _spendsCoinbase, unsigned int _sigOps): tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), - spendsCoinbase(_spendsCoinbase) + spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps) { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); -- cgit v1.2.3 From f3fe83673e84ef4d20b3026faa397cad17212ff8 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Mon, 26 Oct 2015 14:06:06 -0400 Subject: Add a score index to the mempool. The score index is meant to represent the order of priority for being included in a block for miners. Initially this is set to the transactions modified (by any feeDelta) fee rate. Index improvements and unit tests by sdaftuar. --- src/txmempool.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index fa62cbf166..35be216287 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -36,6 +36,8 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, nFeesWithDescendants = nFee; CAmount nValueIn = tx.GetValueOut()+nFee; assert(inChainInputValue <= nValueIn); + + feeDelta = 0; } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -53,6 +55,11 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const return dResult; } +void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta) +{ + feeDelta = newFeeDelta; +} + // Update the given tx for any in-mempool descendants. // Assumes that setMemPoolChildren is correct for the given tx and all // descendants. @@ -392,6 +399,15 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, } UpdateAncestorsOf(true, newit, setAncestors); + // Update transaction's score for any feeDelta created by PrioritiseTransaction + std::map >::const_iterator pos = mapDeltas.find(hash); + if (pos != mapDeltas.end()) { + const std::pair &deltas = pos->second; + if (deltas.second) { + mapTx.modify(newit, update_fee_delta(deltas.second)); + } + } + nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); minerPolicyEstimator->processTransaction(entry, fCurrentEstimate); @@ -769,6 +785,10 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, std::pair &deltas = mapDeltas[hash]; deltas.first += dPriorityDelta; deltas.second += nFeeDelta; + txiter it = mapTx.find(hash); + if (it != mapTx.end()) { + mapTx.modify(it, update_fee_delta(deltas.second)); + } } LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta)); } @@ -818,8 +838,8 @@ bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { size_t CTxMemPool::DynamicMemoryUsage() const { LOCK(cs); - // Estimate the overhead of mapTx to be 9 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. - return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 9 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage; + // Estimate the overhead of mapTx to be 12 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. + return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 12 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage; } void CTxMemPool::RemoveStaged(setEntries &stage) { -- cgit v1.2.3 From b2e74bd292460ca00fefc6356594318307365397 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 21 Oct 2015 17:44:00 -0700 Subject: Get the set of now-uncacheable-txn from CTxMemPool::TrimToSize --- src/txmempool.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 35be216287..fea5da8029 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -944,7 +944,7 @@ void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) { } } -void CTxMemPool::TrimToSize(size_t sizelimit) { +void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRemaining) { LOCK(cs); unsigned nTxnRemoved = 0; @@ -963,8 +963,26 @@ void CTxMemPool::TrimToSize(size_t sizelimit) { setEntries stage; CalculateDescendants(mapTx.project<0>(it), stage); - RemoveStaged(stage); nTxnRemoved += stage.size(); + + std::vector txn; + if (pvNoSpendsRemaining) { + txn.reserve(stage.size()); + BOOST_FOREACH(txiter it, stage) + txn.push_back(it->GetTx()); + } + RemoveStaged(stage); + if (pvNoSpendsRemaining) { + BOOST_FOREACH(const CTransaction& tx, txn) { + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + if (exists(txin.prevout.hash)) + continue; + std::map::iterator it = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0)); + if (it == mapNextTx.end() || it->first.hash != txin.prevout.hash) + pvNoSpendsRemaining->push_back(txin.prevout.hash); + } + } + } } if (maxFeeRateRemoved > CFeeRate(0)) -- cgit v1.2.3 From eb306664e786ae43d539fde66f0fbe2a3e89d910 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 19 Nov 2015 11:18:28 -0500 Subject: Fix mempool limiting for PrioritiseTransaction Redo the feerate index to be based on mining score, rather than fee. Update mempool_packages.py to test prioritisetransaction's effect on package scores. --- src/txmempool.cpp | 53 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 23 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index fea5da8029..c72a1e8c19 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -33,7 +33,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, nCountWithDescendants = 1; nSizeWithDescendants = nTxSize; - nFeesWithDescendants = nFee; + nModFeesWithDescendants = nFee; CAmount nValueIn = tx.GetValueOut()+nFee; assert(inChainInputValue <= nValueIn); @@ -57,6 +57,7 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta) { + nModFeesWithDescendants += newFeeDelta - feeDelta; feeDelta = newFeeDelta; } @@ -114,7 +115,7 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit BOOST_FOREACH(txiter cit, setAllDescendants) { if (!setExclude.count(cit->GetTx().GetHash())) { modifySize += cit->GetTxSize(); - modifyFee += cit->GetFee(); + modifyFee += cit->GetModifiedFee(); modifyCount++; cachedDescendants[updateIt].insert(cit); } @@ -244,7 +245,7 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors } const int64_t updateCount = (add ? 1 : -1); const int64_t updateSize = updateCount * it->GetTxSize(); - const CAmount updateFee = updateCount * it->GetFee(); + const CAmount updateFee = updateCount * it->GetModifiedFee(); BOOST_FOREACH(txiter ancestorIt, setAncestors) { mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount)); } @@ -304,7 +305,7 @@ void CTxMemPoolEntry::SetDirty() { nCountWithDescendants = 0; nSizeWithDescendants = nTxSize; - nFeesWithDescendants = nFee; + nModFeesWithDescendants = GetModifiedFee(); } void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) @@ -312,8 +313,7 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t if (!IsDirty()) { nSizeWithDescendants += modifySize; assert(int64_t(nSizeWithDescendants) > 0); - nFeesWithDescendants += modifyFee; - assert(nFeesWithDescendants >= 0); + nModFeesWithDescendants += modifyFee; nCountWithDescendants += modifyCount; assert(int64_t(nCountWithDescendants) > 0); } @@ -372,6 +372,17 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, indexed_transaction_set::iterator newit = mapTx.insert(entry).first; mapLinks.insert(make_pair(newit, TxLinks())); + // Update transaction for any feeDelta created by PrioritiseTransaction + // TODO: refactor so that the fee delta is calculated before inserting + // into mapTx. + std::map >::const_iterator pos = mapDeltas.find(hash); + if (pos != mapDeltas.end()) { + const std::pair &deltas = pos->second; + if (deltas.second) { + mapTx.modify(newit, update_fee_delta(deltas.second)); + } + } + // Update cachedInnerUsage to include contained transaction's usage. // (When we update the entry for in-mempool parents, memory usage will be // further updated.) @@ -399,15 +410,6 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, } UpdateAncestorsOf(true, newit, setAncestors); - // Update transaction's score for any feeDelta created by PrioritiseTransaction - std::map >::const_iterator pos = mapDeltas.find(hash); - if (pos != mapDeltas.end()) { - const std::pair &deltas = pos->second; - if (deltas.second) { - mapTx.modify(newit, update_fee_delta(deltas.second)); - } - } - nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); minerPolicyEstimator->processTransaction(entry, fCurrentEstimate); @@ -644,27 +646,24 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const CTxMemPool::setEntries setChildrenCheck; std::map::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); int64_t childSizes = 0; - CAmount childFees = 0; + CAmount childModFee = 0; for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) { txiter childit = mapTx.find(iter->second.ptx->GetHash()); assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions if (setChildrenCheck.insert(childit).second) { childSizes += childit->GetTxSize(); - childFees += childit->GetFee(); + childModFee += childit->GetModifiedFee(); } } assert(setChildrenCheck == GetMemPoolChildren(it)); - // Also check to make sure size/fees is greater than sum with immediate children. + // Also check to make sure size is greater than sum with immediate children. // just a sanity check, not definitive that this calc is correct... - // also check that the size is less than the size of the entire mempool. if (!it->IsDirty()) { assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize()); - assert(it->GetFeesWithDescendants() >= childFees + it->GetFee()); } else { assert(it->GetSizeWithDescendants() == it->GetTxSize()); - assert(it->GetFeesWithDescendants() == it->GetFee()); + assert(it->GetModFeesWithDescendants() == it->GetModifiedFee()); } - assert(it->GetFeesWithDescendants() >= 0); if (fDependsWait) waitingOnDependants.push_back(&(*it)); @@ -788,6 +787,14 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, txiter it = mapTx.find(hash); if (it != mapTx.end()) { mapTx.modify(it, update_fee_delta(deltas.second)); + // Now update all ancestors' modified fees with descendants + setEntries setAncestors; + uint64_t nNoLimit = std::numeric_limits::max(); + std::string dummy; + CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); + BOOST_FOREACH(txiter ancestorIt, setAncestors) { + mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0)); + } } } LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta)); @@ -956,7 +963,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe // "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()); + CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants()); removed += minReasonableRelayFee; trackPackageRemoved(removed); maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed); -- cgit v1.2.3 From fa24439ff3d8ab5b9efaf66ef4dae6713b88cb35 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 13 Dec 2015 17:58:29 +0100 Subject: Bump copyright headers to 2015 --- src/txmempool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index fea5da8029..03a8e8eab0 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -- cgit v1.2.3