From e617fe25785bfba30bcb0a8d8af6797b44ba07f5 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 13 May 2015 20:04:39 +0000 Subject: Fix various warnings Found while building on Debian 7 --- 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 1c16e2092..2292191be 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -166,7 +166,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in continue; const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); if (fSanityCheck) assert(coins); - if (!coins || (coins->IsCoinBase() && nMemPoolHeight - coins->nHeight < COINBASE_MATURITY)) { + if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { transactionsToRemove.push_back(tx); break; } -- cgit v1.2.3 From 5098c47b2430ded299c21620527ebd0544fe51e2 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 9 Jul 2015 13:56:31 -0400 Subject: Implement accurate memory accounting for mempool --- src/txmempool.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 2292191be..4caa5fc82 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -18,7 +18,7 @@ using namespace std; CTxMemPoolEntry::CTxMemPoolEntry(): - nFee(0), nTxSize(0), nModSize(0), nTime(0), dPriority(0.0), hadNoDependencies(false) + nFee(0), nTxSize(0), nModSize(0), nUsageSize(0), nTime(0), dPriority(0.0), hadNoDependencies(false) { nHeight = MEMPOOL_HEIGHT; } @@ -31,6 +31,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); + nUsageSize = tx.DynamicMemoryUsage(); } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -101,6 +102,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); + cachedInnerUsage += entry.DynamicMemoryUsage(); minerPolicyEstimator->processTransaction(entry, fCurrentEstimate); return true; @@ -146,6 +148,7 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem removed.push_back(tx); totalTxSize -= mapTx[hash].GetTxSize(); + cachedInnerUsage -= mapTx[hash].DynamicMemoryUsage(); mapTx.erase(hash); nTransactionsUpdated++; minerPolicyEstimator->removeTx(hash); @@ -226,6 +229,7 @@ void CTxMemPool::clear() mapTx.clear(); mapNextTx.clear(); totalTxSize = 0; + cachedInnerUsage = 0; ++nTransactionsUpdated; } @@ -237,6 +241,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); uint64_t checkTotal = 0; + uint64_t innerUsage = 0; CCoinsViewCache mempoolDuplicate(const_cast(pcoins)); @@ -245,6 +250,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { unsigned int i = 0; checkTotal += it->second.GetTxSize(); + innerUsage += it->second.DynamicMemoryUsage(); const CTransaction& tx = it->second.GetTx(); bool fDependsWait = false; BOOST_FOREACH(const CTxIn &txin, tx.vin) { @@ -299,6 +305,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const } assert(totalTxSize == checkTotal); + assert(innerUsage == cachedInnerUsage); } void CTxMemPool::queryHashes(vector& vtxid) @@ -419,3 +426,8 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const { bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { return mempool.exists(txid) || base->HaveCoins(txid); } + +size_t CTxMemPool::DynamicMemoryUsage() const { + LOCK(cs); + return memusage::DynamicUsage(mapTx) + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + cachedInnerUsage; +} -- cgit v1.2.3 From 9e38d0f7451092f6a16853a2b0a37b68a5b3c3fb Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 17 Jul 2015 13:46:18 -0400 Subject: Separate core memory usage computation in core_memusage.h --- 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 4caa5fc82..5bc06e505 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -31,7 +31,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); - nUsageSize = tx.DynamicMemoryUsage(); + nUsageSize = RecursiveDynamicUsage(tx); } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) -- cgit v1.2.3 From f18b8ec7cf6ebfff9eef839c6a5630ad2e6e7db6 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 31 Jul 2015 16:41:06 +0200 Subject: Make sure LogPrintf strings are line-terminated Fix the cases where LogPrint[f] was accidentally called without line terminator, which resulted in concatenated log lines. (see e.g. #6492) --- 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 5bc06e505..c921dae45 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -348,7 +348,7 @@ CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const minerPolicyEstimator->Write(fileout); } catch (const std::exception&) { - LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)"); + LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)\n"); return false; } return true; @@ -367,7 +367,7 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein) minerPolicyEstimator->Read(filein); } catch (const std::exception&) { - LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)"); + LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)\n"); return false; } return true; -- cgit v1.2.3 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 5bc06e505..0e65aa1c5 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 34628a18070064e75b35f28fd6a43d5c23832eb8 Mon Sep 17 00:00:00 2001 From: Ashley Holman Date: Wed, 24 Jun 2015 03:32:20 -0500 Subject: TxMemPool: Change mapTx to a boost::multi_index_container Indexes on: - Tx Hash - Fee Rate (fee-per-kb) --- src/txmempool.cpp | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index c921dae45..c410cd083 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -32,6 +32,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); nUsageSize = RecursiveDynamicUsage(tx); + feeRate = CFeeRate(nFee, nTxSize); } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -96,8 +97,8 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, // Used by main.cpp AcceptToMemoryPool(), which DOES do // all the appropriate checks. LOCK(cs); - mapTx[hash] = entry; - const CTransaction& tx = mapTx[hash].GetTx(); + mapTx.insert(entry); + const CTransaction& tx = mapTx.find(hash)->GetTx(); for (unsigned int i = 0; i < tx.vin.size(); i++) mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); nTransactionsUpdated++; @@ -134,7 +135,7 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem txToRemove.pop_front(); if (!mapTx.count(hash)) continue; - const CTransaction& tx = mapTx[hash].GetTx(); + const CTransaction& tx = mapTx.find(hash)->GetTx(); if (fRecursive) { for (unsigned int i = 0; i < tx.vout.size(); i++) { std::map::iterator it = mapNextTx.find(COutPoint(hash, i)); @@ -147,8 +148,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem mapNextTx.erase(txin.prevout); removed.push_back(tx); - totalTxSize -= mapTx[hash].GetTxSize(); - cachedInnerUsage -= mapTx[hash].DynamicMemoryUsage(); + totalTxSize -= mapTx.find(hash)->GetTxSize(); + cachedInnerUsage -= mapTx.find(hash)->DynamicMemoryUsage(); mapTx.erase(hash); nTransactionsUpdated++; minerPolicyEstimator->removeTx(hash); @@ -161,10 +162,10 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in // Remove transactions spending a coinbase which are now immature LOCK(cs); list transactionsToRemove; - for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { - const CTransaction& tx = it->second.GetTx(); + 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) { - std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); + indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) continue; const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); @@ -209,8 +210,10 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i BOOST_FOREACH(const CTransaction& tx, vtx) { uint256 hash = tx.GetHash(); - if (mapTx.count(hash)) - entries.push_back(mapTx[hash]); + + indexed_transaction_set::iterator i = mapTx.find(hash); + if (i != mapTx.end()) + entries.push_back(*i); } BOOST_FOREACH(const CTransaction& tx, vtx) { @@ -247,17 +250,17 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const LOCK(cs); list waitingOnDependants; - for (std::map::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; - checkTotal += it->second.GetTxSize(); - innerUsage += it->second.DynamicMemoryUsage(); - const CTransaction& tx = it->second.GetTx(); + checkTotal += it->GetTxSize(); + innerUsage += it->DynamicMemoryUsage(); + const CTransaction& tx = it->GetTx(); bool fDependsWait = false; BOOST_FOREACH(const CTxIn &txin, tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. - std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); + indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) { - const CTransaction& tx2 = it2->second.GetTx(); + const CTransaction& tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); fDependsWait = true; } else { @@ -272,7 +275,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const i++; } if (fDependsWait) - waitingOnDependants.push_back(&it->second); + waitingOnDependants.push_back(&(*it)); else { CValidationState state; assert(CheckInputs(tx, state, mempoolDuplicate, false, 0, false, NULL)); @@ -296,8 +299,8 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const } for (std::map::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) { uint256 hash = it->second.ptx->GetHash(); - map::const_iterator it2 = mapTx.find(hash); - const CTransaction& tx = it2->second.GetTx(); + indexed_transaction_set::const_iterator it2 = mapTx.find(hash); + const CTransaction& tx = it2->GetTx(); assert(it2 != mapTx.end()); assert(&tx == it->second.ptx); assert(tx.vin.size() > it->second.n); @@ -314,16 +317,16 @@ void CTxMemPool::queryHashes(vector& vtxid) LOCK(cs); vtxid.reserve(mapTx.size()); - for (map::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) - vtxid.push_back((*mi).first); + for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) + vtxid.push_back(mi->GetTx().GetHash()); } bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const { LOCK(cs); - map::const_iterator i = mapTx.find(hash); + indexed_transaction_set::const_iterator i = mapTx.find(hash); if (i == mapTx.end()) return false; - result = i->second.GetTx(); + result = i->GetTx(); return true; } @@ -429,5 +432,6 @@ bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { size_t CTxMemPool::DynamicMemoryUsage() const { LOCK(cs); - return memusage::DynamicUsage(mapTx) + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + cachedInnerUsage; + // Estimate the overhead of mapTx to be 6 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. + return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 6 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + cachedInnerUsage; } -- cgit v1.2.3 From 5add7a74a672cb12b0a2a630d318d9bc64dd0f77 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Wed, 15 Jul 2015 14:47:45 -0400 Subject: Track transaction packages in CTxMemPoolEntry Associate with each CTxMemPoolEntry all the size/fees of descendant mempool transactions. Sort mempool by max(feerate of entry, feerate of descendants). Update statistics on-the-fly as transactions enter or leave the mempool. Also add ancestor and descendant limiting, so that transactions can be rejected if the number or size of unconfirmed ancestors exceeds a target, or if adding a transaction would cause some other mempool entry to have too many (or too large) a set of unconfirmed in- mempool descendants. --- src/txmempool.cpp | 465 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 423 insertions(+), 42 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index c410cd083..2f603e3c9 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -17,12 +17,6 @@ using namespace std; -CTxMemPoolEntry::CTxMemPoolEntry(): - nFee(0), nTxSize(0), nModSize(0), nUsageSize(0), nTime(0), dPriority(0.0), hadNoDependencies(false) -{ - nHeight = MEMPOOL_HEIGHT; -} - CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _dPriority, unsigned int _nHeight, bool poolHasNoInputsOf): @@ -32,7 +26,10 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); nUsageSize = RecursiveDynamicUsage(tx); - feeRate = CFeeRate(nFee, nTxSize); + + nCountWithDescendants = 1; + nSizeWithDescendants = nTxSize; + nFeesWithDescendants = nFee; } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -49,6 +46,244 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const return dResult; } +// Update the given tx for any in-mempool descendants. +// Assumes that setMemPoolChildren is correct for the given tx and all +// descendants. +bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit, cacheMap &cachedDescendants, const std::set &setExclude) +{ + // Track the number of entries (outside setExclude) that we'd need to visit + // (will bail out if it exceeds maxDescendantsToVisit) + int nChildrenToVisit = 0; + + setEntries stageEntries, setAllDescendants; + stageEntries = GetMemPoolChildren(updateIt); + + while (!stageEntries.empty()) { + const txiter cit = *stageEntries.begin(); + if (cit->IsDirty()) { + // Don't consider any more children if any descendant is dirty + return false; + } + setAllDescendants.insert(cit); + stageEntries.erase(cit); + const setEntries &setChildren = GetMemPoolChildren(cit); + BOOST_FOREACH(const txiter childEntry, setChildren) { + cacheMap::iterator cacheIt = cachedDescendants.find(childEntry); + if (cacheIt != cachedDescendants.end()) { + // We've already calculated this one, just add the entries for this set + // but don't traverse again. + BOOST_FOREACH(const txiter cacheEntry, cacheIt->second) { + // update visit count only for new child transactions + // (outside of setExclude and stageEntries) + if (setAllDescendants.insert(cacheEntry).second && + !setExclude.count(cacheEntry->GetTx().GetHash()) && + !stageEntries.count(cacheEntry)) { + nChildrenToVisit++; + } + } + } else if (!setAllDescendants.count(childEntry)) { + // Schedule for later processing and update our visit count + if (stageEntries.insert(childEntry).second && !setExclude.count(childEntry->GetTx().GetHash())) { + nChildrenToVisit++; + } + } + if (nChildrenToVisit > maxDescendantsToVisit) { + return false; + } + } + } + // setAllDescendants now contains all in-mempool descendants of updateIt. + // Update and add to cached descendant map + int64_t modifySize = 0; + CAmount modifyFee = 0; + int64_t modifyCount = 0; + BOOST_FOREACH(txiter cit, setAllDescendants) { + if (!setExclude.count(cit->GetTx().GetHash())) { + modifySize += cit->GetTxSize(); + modifyFee += cit->GetFee(); + modifyCount++; + cachedDescendants[updateIt].insert(cit); + } + } + mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount)); + return true; +} + +// vHashesToUpdate is the set of transaction hashes from a disconnected block +// which has been re-added to the mempool. +// for each entry, look for descendants that are outside hashesToUpdate, and +// add fee/size information for such descendants to the parent. +void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashesToUpdate) +{ + LOCK(cs); + // For each entry in vHashesToUpdate, store the set of in-mempool, but not + // in-vHashesToUpdate transactions, so that we don't have to recalculate + // descendants when we come across a previously seen entry. + cacheMap mapMemPoolDescendantsToUpdate; + + // Use a set for lookups into vHashesToUpdate (these entries are already + // accounted for in the state of their ancestors) + std::set setAlreadyIncluded(vHashesToUpdate.begin(), vHashesToUpdate.end()); + + // Iterate in reverse, so that whenever we are looking at at a transaction + // we are sure that all in-mempool descendants have already been processed. + // This maximizes the benefit of the descendant cache and guarantees that + // setMemPoolChildren will be updated, an assumption made in + // UpdateForDescendants. + BOOST_REVERSE_FOREACH(const uint256 &hash, vHashesToUpdate) { + // we cache the in-mempool children to avoid duplicate updates + setEntries setChildren; + // calculate children from mapNextTx + txiter it = mapTx.find(hash); + if (it == mapTx.end()) { + continue; + } + std::map::iterator iter = mapNextTx.lower_bound(COutPoint(hash, 0)); + // First calculate the children, and update setMemPoolChildren to + // include them, and update their setMemPoolParents to include this tx. + for (; iter != mapNextTx.end() && iter->first.hash == hash; ++iter) { + const uint256 &childHash = iter->second.ptx->GetHash(); + txiter childIter = mapTx.find(childHash); + assert(childIter != mapTx.end()); + // We can skip updating entries we've encountered before or that + // are in the block (which are already accounted for). + if (setChildren.insert(childIter).second && !setAlreadyIncluded.count(childHash)) { + UpdateChild(it, childIter, true); + UpdateParent(childIter, it, true); + } + } + if (!UpdateForDescendants(it, 100, mapMemPoolDescendantsToUpdate, setAlreadyIncluded)) { + // Mark as dirty if we can't do the calculation. + mapTx.modify(it, set_dirty()); + } + } +} + +bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString) +{ + setEntries parentHashes; + const CTransaction &tx = entry.GetTx(); + + // Get parents of this transaction that are in the mempool + // Entry may or may not already be in the mempool, and GetMemPoolParents() + // is only valid for entries in the mempool, so we iterate mapTx to find + // parents. + // TODO: optimize this so that we only check limits and walk + // tx.vin when called on entries not already in the mempool. + for (unsigned int i = 0; i < tx.vin.size(); i++) { + txiter piter = mapTx.find(tx.vin[i].prevout.hash); + if (piter != mapTx.end()) { + parentHashes.insert(piter); + if (parentHashes.size() + 1 > limitAncestorCount) { + errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount); + return false; + } + } + } + + size_t totalSizeWithAncestors = entry.GetTxSize(); + + while (!parentHashes.empty()) { + txiter stageit = *parentHashes.begin(); + + setAncestors.insert(stageit); + parentHashes.erase(stageit); + totalSizeWithAncestors += stageit->GetTxSize(); + + if (stageit->GetSizeWithDescendants() + entry.GetTxSize() > limitDescendantSize) { + errString = strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limitDescendantSize); + return false; + } else if (stageit->GetCountWithDescendants() + 1 > limitDescendantCount) { + errString = strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limitDescendantCount); + return false; + } else if (totalSizeWithAncestors > limitAncestorSize) { + errString = strprintf("exceeds ancestor size limit [limit: %u]", limitAncestorSize); + return false; + } + + const setEntries & setMemPoolParents = GetMemPoolParents(stageit); + BOOST_FOREACH(const txiter &phash, setMemPoolParents) { + // If this is a new ancestor, add it. + if (setAncestors.count(phash) == 0) { + parentHashes.insert(phash); + } + if (parentHashes.size() + setAncestors.size() + 1 > limitAncestorCount) { + errString = strprintf("too many unconfirmed ancestors [limit: %u]", limitAncestorCount); + return false; + } + } + } + + return true; +} + +void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors) +{ + setEntries parentIters = GetMemPoolParents(it); + // add or remove this tx as a child of each parent + BOOST_FOREACH(txiter piter, parentIters) { + UpdateChild(piter, it, add); + } + const int64_t updateCount = (add ? 1 : -1); + const int64_t updateSize = updateCount * it->GetTxSize(); + const CAmount updateFee = updateCount * it->GetFee(); + BOOST_FOREACH(txiter ancestorIt, setAncestors) { + mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount)); + } +} + +void CTxMemPool::UpdateChildrenForRemoval(txiter it) +{ + const setEntries &setMemPoolChildren = GetMemPoolChildren(it); + BOOST_FOREACH(txiter updateIt, setMemPoolChildren) { + UpdateParent(updateIt, it, false); + } +} + +void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) +{ + // For each entry, walk back all ancestors and decrement size associated with this + // transaction + const uint64_t nNoLimit = std::numeric_limits::max(); + BOOST_FOREACH(txiter removeIt, entriesToRemove) { + setEntries setAncestors; + const CTxMemPoolEntry &entry = *removeIt; + std::string dummy; + CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); + // Note that UpdateAncestorsOf severs the child links that point to + // removeIt in the entries for the parents of removeIt. This is + // fine since we don't need to use the mempool children of any entries + // to walk back over our ancestors (but we do need the mempool + // parents!) + UpdateAncestorsOf(false, removeIt, setAncestors); + } + // After updating all the ancestor sizes, we can now sever the link between each + // transaction being removed and any mempool children (ie, update setMemPoolParents + // for each direct child of a transaction being removed). + BOOST_FOREACH(txiter removeIt, entriesToRemove) { + UpdateChildrenForRemoval(removeIt); + } +} + +void CTxMemPoolEntry::SetDirty() +{ + nCountWithDescendants = 0; + nSizeWithDescendants = nTxSize; + nFeesWithDescendants = nFee; +} + +void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) +{ + if (!IsDirty()) { + nSizeWithDescendants += modifySize; + assert(int64_t(nSizeWithDescendants) > 0); + nFeesWithDescendants += modifyFee; + assert(nFeesWithDescendants >= 0); + nCountWithDescendants += modifyCount; + assert(int64_t(nCountWithDescendants) > 0); + } +} + CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : nTransactionsUpdated(0) { @@ -90,34 +325,103 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n) nTransactionsUpdated += n; } - -bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate) +bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate) { // Add to memory pool without checking anything. // Used by main.cpp AcceptToMemoryPool(), which DOES do // all the appropriate checks. LOCK(cs); - mapTx.insert(entry); - const CTransaction& tx = mapTx.find(hash)->GetTx(); - for (unsigned int i = 0; i < tx.vin.size(); i++) + indexed_transaction_set::iterator newit = mapTx.insert(entry).first; + mapLinks.insert(make_pair(newit, TxLinks())); + + // Update cachedInnerUsage to include contained transaction's usage. + // (When we update the entry for in-mempool parents, memory usage will be + // further updated.) + cachedInnerUsage += entry.DynamicMemoryUsage(); + + const CTransaction& tx = newit->GetTx(); + std::set setParentTransactions; + for (unsigned int i = 0; i < tx.vin.size(); i++) { mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); + setParentTransactions.insert(tx.vin[i].prevout.hash); + } + // Don't bother worrying about child transactions of this one. + // Normal case of a new transaction arriving is that there can't be any + // children, because such children would be orphans. + // An exception to that is if a transaction enters that used to be in a block. + // In that case, our disconnect block logic will call UpdateTransactionsFromBlock + // to clean up the mess we're leaving here. + + // Update ancestors with information about this tx + BOOST_FOREACH (const uint256 &phash, setParentTransactions) { + txiter pit = mapTx.find(phash); + if (pit != mapTx.end()) { + UpdateParent(newit, pit, true); + } + } + UpdateAncestorsOf(true, newit, setAncestors); + nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); - cachedInnerUsage += entry.DynamicMemoryUsage(); minerPolicyEstimator->processTransaction(entry, fCurrentEstimate); return true; } +void CTxMemPool::removeUnchecked(txiter it) +{ + const uint256 hash = it->GetTx().GetHash(); + BOOST_FOREACH(const CTxIn& txin, it->GetTx().vin) + mapNextTx.erase(txin.prevout); + + totalTxSize -= it->GetTxSize(); + cachedInnerUsage -= it->DynamicMemoryUsage(); + cachedInnerUsage -= memusage::DynamicUsage(mapLinks[it].parents) + memusage::DynamicUsage(mapLinks[it].children); + mapLinks.erase(it); + mapTx.erase(it); + nTransactionsUpdated++; + minerPolicyEstimator->removeTx(hash); +} + +// Calculates descendants of entry that are not already in setDescendants, and adds to +// setDescendants. Assumes entryit is already a tx in the mempool and setMemPoolChildren +// is correct for tx and all descendants. +// Also assumes that if an entry is in setDescendants already, then all +// in-mempool descendants of it are already in setDescendants as well, so that we +// can save time by not iterating over those entries. +void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants) +{ + setEntries stage; + if (setDescendants.count(entryit) == 0) { + stage.insert(entryit); + } + // Traverse down the children of entry, only adding children that are not + // accounted for in setDescendants already (because those children have either + // already been walked, or will be walked in this iteration). + while (!stage.empty()) { + txiter it = *stage.begin(); + setDescendants.insert(it); + stage.erase(it); + + const setEntries &setChildren = GetMemPoolChildren(it); + BOOST_FOREACH(const txiter &childiter, setChildren) { + if (!setDescendants.count(childiter)) { + stage.insert(childiter); + } + } + } +} void CTxMemPool::remove(const CTransaction &origTx, std::list& removed, bool fRecursive) { // Remove transaction from memory pool { LOCK(cs); - std::deque txToRemove; - txToRemove.push_back(origTx.GetHash()); - if (fRecursive && !mapTx.count(origTx.GetHash())) { + setEntries txToRemove; + txiter origit = mapTx.find(origTx.GetHash()); + if (origit != mapTx.end()) { + txToRemove.insert(origit); + } else if (fRecursive) { // If recursively removing but origTx isn't in the mempool // be sure to remove any children that are in the pool. This can // happen during chain re-orgs if origTx isn't re-accepted into @@ -126,34 +430,23 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem std::map::iterator it = mapNextTx.find(COutPoint(origTx.GetHash(), i)); if (it == mapNextTx.end()) continue; - txToRemove.push_back(it->second.ptx->GetHash()); + txiter nextit = mapTx.find(it->second.ptx->GetHash()); + assert(nextit != mapTx.end()); + txToRemove.insert(nextit); } } - while (!txToRemove.empty()) - { - uint256 hash = txToRemove.front(); - txToRemove.pop_front(); - if (!mapTx.count(hash)) - continue; - const CTransaction& tx = mapTx.find(hash)->GetTx(); - if (fRecursive) { - for (unsigned int i = 0; i < tx.vout.size(); i++) { - std::map::iterator it = mapNextTx.find(COutPoint(hash, i)); - if (it == mapNextTx.end()) - continue; - txToRemove.push_back(it->second.ptx->GetHash()); - } + setEntries setAllRemoves; + if (fRecursive) { + BOOST_FOREACH(txiter it, txToRemove) { + CalculateDescendants(it, setAllRemoves); } - BOOST_FOREACH(const CTxIn& txin, tx.vin) - mapNextTx.erase(txin.prevout); - - removed.push_back(tx); - totalTxSize -= mapTx.find(hash)->GetTxSize(); - cachedInnerUsage -= mapTx.find(hash)->DynamicMemoryUsage(); - mapTx.erase(hash); - nTransactionsUpdated++; - minerPolicyEstimator->removeTx(hash); + } else { + setAllRemoves.swap(txToRemove); + } + BOOST_FOREACH(txiter it, setAllRemoves) { + removed.push_back(it->GetTx()); } + RemoveStaged(setAllRemoves); } } @@ -229,6 +522,7 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i void CTxMemPool::clear() { LOCK(cs); + mapLinks.clear(); mapTx.clear(); mapNextTx.clear(); totalTxSize = 0; @@ -255,7 +549,12 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const checkTotal += it->GetTxSize(); innerUsage += it->DynamicMemoryUsage(); const CTransaction& tx = it->GetTx(); + txlinksMap::const_iterator linksiter = mapLinks.find(it); + assert(linksiter != mapLinks.end()); + const TxLinks &links = linksiter->second; + innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children); bool fDependsWait = false; + setEntries setParentCheck; BOOST_FOREACH(const CTxIn &txin, tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); @@ -263,6 +562,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const const CTransaction& tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); fDependsWait = true; + setParentCheck.insert(it2); } else { const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash); assert(coins && coins->IsAvailable(txin.prevout.n)); @@ -274,6 +574,33 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const assert(it3->second.n == i); i++; } + assert(setParentCheck == GetMemPoolParents(it)); + // Check children against mapNextTx + CTxMemPool::setEntries setChildrenCheck; + std::map::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); + int64_t childSizes = 0; + CAmount childFees = 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(); + } + } + assert(setChildrenCheck == GetMemPoolChildren(it)); + // Also check to make sure size/fees 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->GetFeesWithDescendants() >= 0); + if (fDependsWait) waitingOnDependants.push_back(&(*it)); else { @@ -432,6 +759,60 @@ bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { size_t CTxMemPool::DynamicMemoryUsage() const { LOCK(cs); - // Estimate the overhead of mapTx to be 6 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. - return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 6 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + cachedInnerUsage; + // 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; +} + +void CTxMemPool::RemoveStaged(setEntries &stage) { + AssertLockHeld(cs); + UpdateForRemoveFromMempool(stage); + BOOST_FOREACH(const txiter& it, stage) { + removeUnchecked(it); + } +} + +bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate) +{ + LOCK(cs); + setEntries setAncestors; + uint64_t nNoLimit = std::numeric_limits::max(); + std::string dummy; + CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); + return addUnchecked(hash, entry, setAncestors, fCurrentEstimate); +} + +void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add) +{ + setEntries s; + if (add && mapLinks[entry].children.insert(child).second) { + cachedInnerUsage += memusage::IncrementalDynamicUsage(s); + } else if (!add && mapLinks[entry].children.erase(child)) { + cachedInnerUsage -= memusage::IncrementalDynamicUsage(s); + } +} + +void CTxMemPool::UpdateParent(txiter entry, txiter parent, bool add) +{ + setEntries s; + if (add && mapLinks[entry].parents.insert(parent).second) { + cachedInnerUsage += memusage::IncrementalDynamicUsage(s); + } else if (!add && mapLinks[entry].parents.erase(parent)) { + cachedInnerUsage -= memusage::IncrementalDynamicUsage(s); + } +} + +const CTxMemPool::setEntries & CTxMemPool::GetMemPoolParents(txiter entry) const +{ + assert (entry != mapTx.end()); + txlinksMap::const_iterator it = mapLinks.find(entry); + assert(it != mapLinks.end()); + return it->second.parents; +} + +const CTxMemPool::setEntries & CTxMemPool::GetMemPoolChildren(txiter entry) const +{ + assert (entry != mapTx.end()); + txlinksMap::const_iterator it = mapLinks.find(entry); + assert(it != mapLinks.end()); + return it->second.children; } -- cgit v1.2.3 From 60de0d5826f1b848a43ec989ff712f002eddc3dc Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Wed, 23 Sep 2015 13:37:32 -0400 Subject: Fix mempool package tracking edge case CalculateMemPoolAncestors was always looping over a transaction's inputs to find in-mempool parents. When adding a new transaction, this is the correct behavior, but when removing a transaction, we want to use the ancestor set that would be calculated by walking mapLinks (which should in general be the same set, except during a reorg when the mempool is in an inconsistent state, and the mapLinks-based calculation would be the correct one). --- src/txmempool.cpp | 51 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 15 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 2f603e3c9..1370cab0c 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -159,26 +159,30 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashes } } -bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString) +bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) { setEntries parentHashes; const CTransaction &tx = entry.GetTx(); - // Get parents of this transaction that are in the mempool - // Entry may or may not already be in the mempool, and GetMemPoolParents() - // is only valid for entries in the mempool, so we iterate mapTx to find - // parents. - // TODO: optimize this so that we only check limits and walk - // tx.vin when called on entries not already in the mempool. - for (unsigned int i = 0; i < tx.vin.size(); i++) { - txiter piter = mapTx.find(tx.vin[i].prevout.hash); - if (piter != mapTx.end()) { - parentHashes.insert(piter); - if (parentHashes.size() + 1 > limitAncestorCount) { - errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount); - return false; + if (fSearchForParents) { + // Get parents of this transaction that are in the mempool + // GetMemPoolParents() is only valid for entries in the mempool, so we + // iterate mapTx to find parents. + for (unsigned int i = 0; i < tx.vin.size(); i++) { + txiter piter = mapTx.find(tx.vin[i].prevout.hash); + if (piter != mapTx.end()) { + parentHashes.insert(piter); + if (parentHashes.size() + 1 > limitAncestorCount) { + errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount); + return false; + } } } + } else { + // If we're not searching for parents, we require this to be an + // entry in the mempool already. + txiter it = mapTx.iterator_to(entry); + parentHashes = GetMemPoolParents(it); } size_t totalSizeWithAncestors = entry.GetTxSize(); @@ -249,7 +253,24 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) setEntries setAncestors; const CTxMemPoolEntry &entry = *removeIt; std::string dummy; - CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); + // Since this is a tx that is already in the mempool, we can call CMPA + // with fSearchForParents = false. If the mempool is in a consistent + // state, then using true or false should both be correct, though false + // should be a bit faster. + // However, if we happen to be in the middle of processing a reorg, then + // the mempool can be in an inconsistent state. In this case, the set + // of ancestors reachable via mapLinks will be the same as the set of + // ancestors whose packages include this transaction, because when we + // add a new transaction to the mempool in addUnchecked(), we assume it + // has no children, and in the case of a reorg where that assumption is + // false, the in-mempool children aren't linked to the in-block tx's + // until UpdateTransactionsFromBlock() is called. + // So if we're being called during a reorg, ie before + // UpdateTransactionsFromBlock() has been called, then mapLinks[] will + // differ from the set of mempool parents we'd calculate by searching, + // and it's important that we use the mapLinks[] notion of ancestor + // transactions as the set of things to update for removal. + CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); // Note that UpdateAncestorsOf severs the child links that point to // removeIt in the entries for the parents of removeIt. This is // fine since we don't need to use the mempool children of any entries -- 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 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 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 1370cab0c..c379a45b4 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 bb148005c..efa5c8f7a 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 a772e7ade..503e73d45 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 503e73d45..58b8448bb 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 58b8448bb..ec7971c2f 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 ec7971c2f..ea3aad34a 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 ea3aad34a..6d1df0b3d 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 6d1df0b3d..1c38e3260 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 1c38e3260..a2a53b018 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 a2a53b018..5a3062291 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 5a3062291..9d2513948 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 9d2513948..fa62cbf16 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 fa62cbf16..35be21628 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 35be21628..fea5da802 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 fea5da802..c72a1e8c1 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 fea5da802..03a8e8eab 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 From c6c2f0fd782ccf607027414012f45c8f48561a30 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Mon, 7 Dec 2015 15:44:16 -0500 Subject: Implement SequenceLocks functions SequenceLocks functions are used to evaluate sequence lock times or heights per BIP 68. The majority of this code is copied from maaku in #6312 Further credit: btcdrak, sipa, NicolasDorier --- 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 fea5da802..67001cf7d 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -504,7 +504,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem list transactionsToRemove; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->GetTx(); - if (!CheckFinalTx(tx, flags)) { + if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags)) { transactionsToRemove.push_back(tx); } else if (it->GetSpendsCoinbase()) { BOOST_FOREACH(const CTxIn& txin, tx.vin) { -- cgit v1.2.3 From 086da92ea772b70d460993ada0e068d139beddd6 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Tue, 16 Feb 2016 12:10:12 -0500 Subject: Add tags to mempool's mapTx indices --- src/txmempool.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 0b0f32e40..eee6cbf85 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -859,9 +859,9 @@ 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(); + indexed_transaction_set::index::type::iterator it = mapTx.get().begin(); setEntries toremove; - while (it != mapTx.get<2>().end() && it->GetTime() < time) { + while (it != mapTx.get().end() && it->GetTime() < time) { toremove.insert(mapTx.project<0>(it)); it++; } @@ -957,7 +957,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe unsigned nTxnRemoved = 0; CFeeRate maxFeeRateRemoved(0); while (DynamicMemoryUsage() > sizelimit) { - indexed_transaction_set::nth_index<1>::type::iterator it = mapTx.get<1>().begin(); + indexed_transaction_set::index::type::iterator it = mapTx.get().begin(); // 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 -- cgit v1.2.3 From 7659438a63ef162b4a4f942f86683ae6785f8162 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 19 Oct 2015 12:42:42 -0400 Subject: CTxMemPool::removeForBlock now uses RemoveStaged --- src/txmempool.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index eee6cbf85..01f6c97ae 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -564,8 +564,12 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i } BOOST_FOREACH(const CTransaction& tx, vtx) { - std::list dummy; - remove(tx, dummy, false); + txiter it = mapTx.find(tx.GetHash()); + if (it != mapTx.end()) { + setEntries stage; + stage.insert(it); + RemoveStaged(stage); + } removeConflicts(tx, conflicts); ClearPrioritisation(tx.GetHash()); } -- cgit v1.2.3 From 5de2baa138cda501038a4558bc169b2cfe5b7d6b Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 19 Oct 2015 12:43:38 -0400 Subject: Rename CTxMemPool::remove -> removeRecursive remove is no longer called non-recursively, so simplify the logic and eliminate an unnecessary parameter --- src/txmempool.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 01f6c97ae..2d1b78bea 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -461,7 +461,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants } } -void CTxMemPool::remove(const CTransaction &origTx, std::list& removed, bool fRecursive) +void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list& removed) { // Remove transaction from memory pool { @@ -470,8 +470,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem txiter origit = mapTx.find(origTx.GetHash()); if (origit != mapTx.end()) { txToRemove.insert(origit); - } else if (fRecursive) { - // If recursively removing but origTx isn't in the mempool + } else { + // When recursively removing but origTx isn't in the mempool // be sure to remove any children that are in the pool. This can // happen during chain re-orgs if origTx isn't re-accepted into // the mempool for any reason. @@ -485,12 +485,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem } } setEntries setAllRemoves; - if (fRecursive) { - BOOST_FOREACH(txiter it, txToRemove) { - CalculateDescendants(it, setAllRemoves); - } - } else { - setAllRemoves.swap(txToRemove); + BOOST_FOREACH(txiter it, txToRemove) { + CalculateDescendants(it, setAllRemoves); } BOOST_FOREACH(txiter it, setAllRemoves) { removed.push_back(it->GetTx()); @@ -524,7 +520,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem } BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) { list removed; - remove(tx, removed, true); + removeRecursive(tx, removed); } } @@ -539,7 +535,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list const CTransaction &txConflict = *it->second.ptx; if (txConflict != tx) { - remove(txConflict, removed, true); + removeRecursive(txConflict, removed); ClearPrioritisation(txConflict.GetHash()); } } -- cgit v1.2.3 From 76a76321d2f36992178ddaaf4d023c5e33c14fbf Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Wed, 21 Oct 2015 10:18:24 -0400 Subject: Remove work limit in UpdateForDescendants() The work limit served to prevent the descendant walking algorithm from doing too much work by marking the parent transaction as dirty. However to implement ancestor tracking, it's not possible to similarly mark those descendant transactions as dirty without having to calculate them to begin with. This commit removes the work limit altogether. With appropriate chain limits (-limitdescendantcount) the concern about doing too much work inside this function should be mitigated. --- src/txmempool.cpp | 59 +++++++++++-------------------------------------------- 1 file changed, 11 insertions(+), 48 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 2d1b78bea..693d42667 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -64,21 +64,13 @@ void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta) // Update the given tx for any in-mempool descendants. // Assumes that setMemPoolChildren is correct for the given tx and all // descendants. -bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit, cacheMap &cachedDescendants, const std::set &setExclude) +void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set &setExclude) { - // Track the number of entries (outside setExclude) that we'd need to visit - // (will bail out if it exceeds maxDescendantsToVisit) - int nChildrenToVisit = 0; - setEntries stageEntries, setAllDescendants; stageEntries = GetMemPoolChildren(updateIt); while (!stageEntries.empty()) { const txiter cit = *stageEntries.begin(); - if (cit->IsDirty()) { - // Don't consider any more children if any descendant is dirty - return false; - } setAllDescendants.insert(cit); stageEntries.erase(cit); const setEntries &setChildren = GetMemPoolChildren(cit); @@ -88,22 +80,11 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit // We've already calculated this one, just add the entries for this set // but don't traverse again. BOOST_FOREACH(const txiter cacheEntry, cacheIt->second) { - // update visit count only for new child transactions - // (outside of setExclude and stageEntries) - if (setAllDescendants.insert(cacheEntry).second && - !setExclude.count(cacheEntry->GetTx().GetHash()) && - !stageEntries.count(cacheEntry)) { - nChildrenToVisit++; - } + setAllDescendants.insert(cacheEntry); } } else if (!setAllDescendants.count(childEntry)) { - // Schedule for later processing and update our visit count - if (stageEntries.insert(childEntry).second && !setExclude.count(childEntry->GetTx().GetHash())) { - nChildrenToVisit++; - } - } - if (nChildrenToVisit > maxDescendantsToVisit) { - return false; + // Schedule for later processing + stageEntries.insert(childEntry); } } } @@ -121,7 +102,6 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit } } mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount)); - return true; } // vHashesToUpdate is the set of transaction hashes from a disconnected block @@ -167,10 +147,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashes UpdateParent(childIter, it, true); } } - if (!UpdateForDescendants(it, 100, mapMemPoolDescendantsToUpdate, setAlreadyIncluded)) { - // Mark as dirty if we can't do the calculation. - mapTx.modify(it, set_dirty()); - } + UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded); } } @@ -301,22 +278,13 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) } } -void CTxMemPoolEntry::SetDirty() -{ - nCountWithDescendants = 0; - nSizeWithDescendants = nTxSize; - nModFeesWithDescendants = GetModifiedFee(); -} - void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) { - if (!IsDirty()) { - nSizeWithDescendants += modifySize; - assert(int64_t(nSizeWithDescendants) > 0); - nModFeesWithDescendants += modifyFee; - nCountWithDescendants += modifyCount; - assert(int64_t(nCountWithDescendants) > 0); - } + nSizeWithDescendants += modifySize; + assert(int64_t(nSizeWithDescendants) > 0); + nModFeesWithDescendants += modifyFee; + nCountWithDescendants += modifyCount; + assert(int64_t(nCountWithDescendants) > 0); } CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : @@ -658,12 +626,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const assert(setChildrenCheck == GetMemPoolChildren(it)); // Also check to make sure size is greater than sum with immediate children. // just a sanity check, not definitive that this calc is correct... - if (!it->IsDirty()) { - assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize()); - } else { - assert(it->GetSizeWithDescendants() == it->GetTxSize()); - assert(it->GetModFeesWithDescendants() == it->GetModifiedFee()); - } + assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize()); if (fDependsWait) waitingOnDependants.push_back(&(*it)); -- cgit v1.2.3 From 72abd2ce3c5ad8157d3a993693df1919a6ad79c3 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 19 Oct 2015 10:54:28 -0400 Subject: Add ancestor tracking to mempool This implements caching of ancestor state to each mempool entry, similar to descendant tracking, but also including caching sigops-with-ancestors (as that metric will be helpful to future code that implements better transaction selection in CreatenewBlock). --- src/txmempool.cpp | 88 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 15 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 693d42667..f7961a6b8 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -38,6 +38,11 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, assert(inChainInputValue <= nValueIn); feeDelta = 0; + + nCountWithAncestors = 1; + nSizeWithAncestors = nTxSize; + nModFeesWithAncestors = nFee; + nSigOpCountWithAncestors = sigOpCount; } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -58,6 +63,7 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta) { nModFeesWithDescendants += newFeeDelta - feeDelta; + nModFeesWithAncestors += newFeeDelta - feeDelta; feeDelta = newFeeDelta; } @@ -99,6 +105,8 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan modifyFee += cit->GetModifiedFee(); modifyCount++; cachedDescendants[updateIt].insert(cit); + // Update ancestor state for each descendant + mapTx.modify(cit, update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCount())); } } mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount)); @@ -108,6 +116,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan // which has been re-added to the mempool. // for each entry, look for descendants that are outside hashesToUpdate, and // add fee/size information for such descendants to the parent. +// for each such descendant, also update the ancestor state to include the parent. void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashesToUpdate) { LOCK(cs); @@ -228,6 +237,20 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors } } +void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncestors) +{ + int64_t updateCount = setAncestors.size(); + int64_t updateSize = 0; + CAmount updateFee = 0; + int updateSigOps = 0; + BOOST_FOREACH(txiter ancestorIt, setAncestors) { + updateSize += ancestorIt->GetTxSize(); + updateFee += ancestorIt->GetModifiedFee(); + updateSigOps += ancestorIt->GetSigOpCount(); + } + mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOps)); +} + void CTxMemPool::UpdateChildrenForRemoval(txiter it) { const setEntries &setMemPoolChildren = GetMemPoolChildren(it); @@ -236,11 +259,30 @@ void CTxMemPool::UpdateChildrenForRemoval(txiter it) } } -void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) +void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants) { // For each entry, walk back all ancestors and decrement size associated with this // transaction const uint64_t nNoLimit = std::numeric_limits::max(); + if (updateDescendants) { + // updateDescendants should be true whenever we're not recursively + // removing a tx and all its descendants, eg when a transaction is + // confirmed in a block. + // Here we only update statistics and not data in mapLinks (which + // we need to preserve until we're finished with all operations that + // need to traverse the mempool). + BOOST_FOREACH(txiter removeIt, entriesToRemove) { + setEntries setDescendants; + CalculateDescendants(removeIt, setDescendants); + setDescendants.erase(removeIt); // don't update state for self + int64_t modifySize = -((int64_t)removeIt->GetTxSize()); + CAmount modifyFee = -removeIt->GetModifiedFee(); + int modifySigOps = -removeIt->GetSigOpCount(); + BOOST_FOREACH(txiter dit, setDescendants) { + mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps)); + } + } + } BOOST_FOREACH(txiter removeIt, entriesToRemove) { setEntries setAncestors; const CTxMemPoolEntry &entry = *removeIt; @@ -264,10 +306,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) // transactions as the set of things to update for removal. CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); // Note that UpdateAncestorsOf severs the child links that point to - // removeIt in the entries for the parents of removeIt. This is - // fine since we don't need to use the mempool children of any entries - // to walk back over our ancestors (but we do need the mempool - // parents!) + // removeIt in the entries for the parents of removeIt. UpdateAncestorsOf(false, removeIt, setAncestors); } // After updating all the ancestor sizes, we can now sever the link between each @@ -278,7 +317,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) } } -void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) +void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) { nSizeWithDescendants += modifySize; assert(int64_t(nSizeWithDescendants) > 0); @@ -287,6 +326,17 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t assert(int64_t(nCountWithDescendants) > 0); } +void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps) +{ + nSizeWithAncestors += modifySize; + assert(int64_t(nSizeWithAncestors) > 0); + nModFeesWithAncestors += modifyFee; + nCountWithAncestors += modifyCount; + assert(int64_t(nCountWithAncestors) > 0); + nSigOpCountWithAncestors += modifySigOps; + assert(int(nSigOpCountWithAncestors) >= 0); +} + CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : nTransactionsUpdated(0) { @@ -377,6 +427,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, } } UpdateAncestorsOf(true, newit, setAncestors); + UpdateEntryForAncestors(newit, setAncestors); nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); @@ -459,7 +510,7 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, std::listGetTx()); } - RemoveStaged(setAllRemoves); + RemoveStaged(setAllRemoves, false); } } @@ -532,7 +583,7 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i if (it != mapTx.end()) { setEntries stage; stage.insert(it); - RemoveStaged(stage); + RemoveStaged(stage, true); } removeConflicts(tx, conflicts); ClearPrioritisation(tx.GetHash()); @@ -590,6 +641,8 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children); bool fDependsWait = false; setEntries setParentCheck; + int64_t parentSizes = 0; + unsigned int parentSigOpCount = 0; BOOST_FOREACH(const CTxIn &txin, tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); @@ -597,7 +650,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const const CTransaction& tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); fDependsWait = true; - setParentCheck.insert(it2); + if (setParentCheck.insert(it2).second) { + parentSizes += it2->GetTxSize(); + parentSigOpCount += it2->GetSigOpCount(); + } } else { const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash); assert(coins && coins->IsAvailable(txin.prevout.n)); @@ -610,17 +666,19 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const i++; } assert(setParentCheck == GetMemPoolParents(it)); + // Also check to make sure ancestor size/sigops are >= sum with immediate + // parents. + assert(it->GetSizeWithAncestors() >= parentSizes + it->GetTxSize()); + assert(it->GetSigOpCountWithAncestors() >= parentSigOpCount + it->GetSigOpCount()); // Check children against mapNextTx CTxMemPool::setEntries setChildrenCheck; std::map::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); int64_t childSizes = 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(); - childModFee += childit->GetModifiedFee(); } } assert(setChildrenCheck == GetMemPoolChildren(it)); @@ -812,9 +870,9 @@ size_t CTxMemPool::DynamicMemoryUsage() const { 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) { +void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants) { AssertLockHeld(cs); - UpdateForRemoveFromMempool(stage); + UpdateForRemoveFromMempool(stage, updateDescendants); BOOST_FOREACH(const txiter& it, stage) { removeUnchecked(it); } @@ -832,7 +890,7 @@ int CTxMemPool::Expire(int64_t time) { BOOST_FOREACH(txiter removeit, toremove) { CalculateDescendants(removeit, stage); } - RemoveStaged(stage); + RemoveStaged(stage, false); return stage.size(); } @@ -941,7 +999,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe BOOST_FOREACH(txiter it, stage) txn.push_back(it->GetTx()); } - RemoveStaged(stage); + RemoveStaged(stage, false); if (pvNoSpendsRemaining) { BOOST_FOREACH(const CTransaction& tx, txn) { BOOST_FOREACH(const CTxIn& txin, tx.vin) { -- cgit v1.2.3 From e2eeb5dda790cf301aa669704a25fb35f67400e7 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 19 Oct 2015 15:15:12 -0400 Subject: Add ancestor feerate index to mempool --- 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 f7961a6b8..48fbe5602 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -866,8 +866,8 @@ bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { size_t CTxMemPool::DynamicMemoryUsage() const { LOCK(cs); - // 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; + // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. + return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage; } void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants) { -- cgit v1.2.3 From ce019bf90fe89c1256a89c489795987ef0b8a18f Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Tue, 8 Mar 2016 15:49:26 -0500 Subject: Check all ancestor state in CTxMemPool::check() --- src/txmempool.cpp | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 48fbe5602..ae851621c 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -160,7 +160,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashes } } -bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) +bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) const { setEntries parentHashes; const CTransaction &tx = entry.GetTx(); @@ -666,10 +666,27 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const i++; } assert(setParentCheck == GetMemPoolParents(it)); - // Also check to make sure ancestor size/sigops are >= sum with immediate - // parents. - assert(it->GetSizeWithAncestors() >= parentSizes + it->GetTxSize()); - assert(it->GetSigOpCountWithAncestors() >= parentSigOpCount + it->GetSigOpCount()); + // Verify ancestor state is correct. + setEntries setAncestors; + uint64_t nNoLimit = std::numeric_limits::max(); + std::string dummy; + CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); + uint64_t nCountCheck = setAncestors.size() + 1; + uint64_t nSizeCheck = it->GetTxSize(); + CAmount nFeesCheck = it->GetModifiedFee(); + unsigned int nSigOpCheck = it->GetSigOpCount(); + + BOOST_FOREACH(txiter ancestorIt, setAncestors) { + nSizeCheck += ancestorIt->GetTxSize(); + nFeesCheck += ancestorIt->GetModifiedFee(); + nSigOpCheck += ancestorIt->GetSigOpCount(); + } + + assert(it->GetCountWithAncestors() == nCountCheck); + assert(it->GetSizeWithAncestors() == nSizeCheck); + assert(it->GetSigOpCountWithAncestors() == nSigOpCheck); + assert(it->GetModFeesWithAncestors() == nFeesCheck); + // Check children against mapNextTx CTxMemPool::setEntries setChildrenCheck; std::map::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); -- cgit v1.2.3 From 982670c333aff6d5660c18ed00931df764733529 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Fri, 4 Dec 2015 15:01:22 -0500 Subject: Add LockPoints Obtain LockPoints to store in CTxMemPoolEntry and during a reorg, evaluate whether they are still valid and if not, recalculate them. --- src/txmempool.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 0b0f32e40..5f814749b 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, unsigned int _sigOps): + bool _spendsCoinbase, unsigned int _sigOps, LockPoints lp): tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), - spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps) + spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp) { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); @@ -61,6 +61,11 @@ void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta) feeDelta = newFeeDelta; } +void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp) +{ + lockPoints = lp; +} + // Update the given tx for any in-mempool descendants. // Assumes that setMemPoolChildren is correct for the given tx and all // descendants. @@ -506,7 +511,11 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem list transactionsToRemove; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->GetTx(); - if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags)) { + LockPoints lp = it->GetLockPoints(); + bool validLP = TestLockPointValidity(&lp); + if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags, &lp, validLP)) { + // Note if CheckSequenceLocks fails the LockPoints may still be invalid + // So it's critical that we remove the tx and not depend on the LockPoints. transactionsToRemove.push_back(tx); } else if (it->GetSpendsCoinbase()) { BOOST_FOREACH(const CTxIn& txin, tx.vin) { @@ -521,6 +530,9 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem } } } + if (!validLP) { + mapTx.modify(it, update_lock_points(lp)); + } } BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) { list removed; -- cgit v1.2.3 From 9e072a6e66efbda7d39bf61eded21d2b324323be Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Fri, 12 Feb 2016 15:57:15 -0500 Subject: Implement "feefilter" P2P message. The "feefilter" p2p message is used to inform other nodes of your mempool min fee which is the feerate that any new transaction must meet to be accepted to your mempool. This will allow them to filter invs to you according to this feerate. --- 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 088e5edde..52c779311 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -771,6 +771,16 @@ bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const return true; } +bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const +{ + LOCK(cs); + indexed_transaction_set::const_iterator i = mapTx.find(hash); + if (i == mapTx.end()) + return false; + feeRate = CFeeRate(i->GetFee(), i->GetTxSize()); + return true; +} + CFeeRate CTxMemPool::estimateFee(int nBlocks) const { LOCK(cs); -- cgit v1.2.3 From f2d3ba73860e875972738d1da1507124d0971ae5 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Mon, 4 Apr 2016 02:36:47 +0000 Subject: Eliminate TX trickle bypass, sort TX invs for privacy and priority. Previously Bitcoin would send 1/4 of transactions out to all peers instantly. This causes high overhead because it makes >80% of INVs size 1. Doing so harms privacy, because it limits the amount of source obscurity a transaction can receive. These randomized broadcasts also disobeyed transaction dependencies and required use of the orphan pool. Because the orphan pool is so small this leads to poor propagation for dependent transactions. When the bypass wasn't in effect, transactions were sent in the order they were received. This avoided creating orphans but undermines privacy fairly significantly. This commit: Eliminates the bypass. The bypass is replaced by halving the average delay for outbound peers. Sorts candidate transactions for INV by their topological depth then by their feerate (then hash); removing the information leakage and providing priority service to higher fee transactions. Limits the amount of transactions sent in a single INV to 7tx/sec (and twice that for outbound); this limits the harm of low fee transaction floods, gives faster relay service to higher fee transactions. The 7 sounds lower than it really is because received advertisements need not be sent, and because the aggregate rate is multipled by the number of peers. --- src/txmempool.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 52c779311..3aba578fa 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -752,6 +752,21 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const assert(innerUsage == cachedInnerUsage); } +bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb) +{ + LOCK(cs); + indexed_transaction_set::const_iterator i = mapTx.find(hasha); + if (i == mapTx.end()) return false; + indexed_transaction_set::const_iterator j = mapTx.find(hashb); + if (j == mapTx.end()) return true; + uint64_t counta = i->GetCountWithAncestors(); + uint64_t countb = j->GetCountWithAncestors(); + if (counta == countb) { + return CompareTxMemPoolEntryByScore()(*i, *j); + } + return counta < countb; +} + void CTxMemPool::queryHashes(vector& vtxid) { vtxid.clear(); -- cgit v1.2.3 From 4578215e7f787968c1d6478e6df75499bd36dd8d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 10 Apr 2016 15:33:05 +0200 Subject: Return mempool queries in dependency order --- src/txmempool.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 3aba578fa..0d9fcc982 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -767,6 +767,16 @@ bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb return counta < countb; } +namespace { +class DepthAndScoreComparator +{ + CTxMemPool *mp; +public: + DepthAndScoreComparator(CTxMemPool *mempool) : mp(mempool) {} + bool operator()(const uint256& a, const uint256& b) { return mp->CompareDepthAndScore(a, b); } +}; +} + void CTxMemPool::queryHashes(vector& vtxid) { vtxid.clear(); @@ -775,6 +785,8 @@ void CTxMemPool::queryHashes(vector& vtxid) vtxid.reserve(mapTx.size()); for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) vtxid.push_back(mi->GetTx().GetHash()); + + std::sort(vtxid.begin(), vtxid.end(), DepthAndScoreComparator(this)); } bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const -- cgit v1.2.3 From f7c4f79f07c777801db7dc047cd45eaf2bba81c9 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Sat, 30 Apr 2016 19:25:00 +0200 Subject: [trivial] Add missing const qualifiers. Add some const qualifiers to references that are not modified and should be marked as const. --- 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 52c779311..420f6896b 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -885,7 +885,7 @@ bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const return true; } -CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } +CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const { // If an entry in the mempool exists, always return that one, as it's guaranteed to never -- cgit v1.2.3 From c8b92486c4eca1287546b0683b6af3551db1fe67 Mon Sep 17 00:00:00 2001 From: 21E14 <21xe14@gmail.com> Date: Fri, 29 Apr 2016 23:45:20 -0400 Subject: Remove obsolete reference to CValidationState from UpdateCoins. --- 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 52c779311..f9c33087f 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -720,7 +720,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const else { CValidationState state; assert(CheckInputs(tx, state, mempoolDuplicate, false, 0, false, NULL)); - UpdateCoins(tx, state, mempoolDuplicate, 1000000); + UpdateCoins(tx, mempoolDuplicate, 1000000); } } unsigned int stepsSinceLastRemove = 0; @@ -734,7 +734,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const assert(stepsSinceLastRemove < waitingOnDependants.size()); } else { assert(CheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, NULL)); - UpdateCoins(entry->GetTx(), state, mempoolDuplicate, 1000000); + UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000); stepsSinceLastRemove = 0; } } -- cgit v1.2.3 From 7e908c7b826cedbf29560ce7a668af809ee71524 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Fri, 20 May 2016 16:19:26 +0000 Subject: Do not use mempool for GETDATA for tx accepted after the last mempool req. The ability to GETDATA a transaction which has not (yet) been relayed is a privacy loss vector. The use of the mempool for this was added as part of the mempool p2p message and is only needed to fetch transactions returned by it. --- src/txmempool.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index aa5df6ca4..4f17e7f8c 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -789,15 +789,23 @@ void CTxMemPool::queryHashes(vector& vtxid) std::sort(vtxid.begin(), vtxid.end(), DepthAndScoreComparator(this)); } -bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const + +bool CTxMemPool::lookup(uint256 hash, CTransaction& result, int64_t& time) const { LOCK(cs); indexed_transaction_set::const_iterator i = mapTx.find(hash); if (i == mapTx.end()) return false; result = i->GetTx(); + time = i->GetTime(); return true; } +bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const +{ + int64_t time; + return CTxMemPool::lookup(hash, result, time); +} + bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const { LOCK(cs); -- cgit v1.2.3 From 9805f4af7ecb6becf8a146bd845fb131ffa625c9 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Sat, 30 Apr 2016 21:45:26 -0700 Subject: mapNextTx: use pointer as key, simplify value Saves about 10% of application memory usage once the mempool warms up. Since the mempool is DynamicUsage-regulated, this will translate to a larger mempool in the same amount of space. Map value type: eliminate the vin index; no users of the map need to know which input of the transaction is spending the prevout. Map key type: replace the COutPoint with a pointer to a COutPoint. A COutPoint is 36 bytes, but each COutPoint is accessible from the same map entry's value. A trivial DereferencingComparator functor allows indirect map keys, but the resulting syntax is misleading: `map.find(&outpoint)`. Implement an indirectmap that acts as a wrapper to a map that uses a DereferencingComparator, supporting a syntax that accurately reflect the container's semantics: inserts and iterators use pointers since they store pointers and need them to remain constant and dereferenceable, but lookup functions take const references. --- src/txmempool.cpp | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 52c779311..d7fb77661 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -147,11 +147,11 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashes if (it == mapTx.end()) { continue; } - std::map::iterator iter = mapNextTx.lower_bound(COutPoint(hash, 0)); + auto iter = mapNextTx.lower_bound(COutPoint(hash, 0)); // First calculate the children, and update setMemPoolChildren to // include them, and update their setMemPoolParents to include this tx. - for (; iter != mapNextTx.end() && iter->first.hash == hash; ++iter) { - const uint256 &childHash = iter->second.ptx->GetHash(); + for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) { + const uint256 &childHash = iter->second->GetHash(); txiter childIter = mapTx.find(childHash); assert(childIter != mapTx.end()); // We can skip updating entries we've encountered before or that @@ -365,11 +365,11 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins) { LOCK(cs); - std::map::iterator it = mapNextTx.lower_bound(COutPoint(hashTx, 0)); + auto it = mapNextTx.lower_bound(COutPoint(hashTx, 0)); // iterate over all COutPoints in mapNextTx whose hash equals the provided hashTx - while (it != mapNextTx.end() && it->first.hash == hashTx) { - coins.Spend(it->first.n); // and remove those outputs from coins + while (it != mapNextTx.end() && it->first->hash == hashTx) { + coins.Spend(it->first->n); // and remove those outputs from coins it++; } } @@ -414,7 +414,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, const CTransaction& tx = newit->GetTx(); std::set setParentTransactions; for (unsigned int i = 0; i < tx.vin.size(); i++) { - mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); + mapNextTx.insert(std::make_pair(&tx.vin[i].prevout, &tx)); setParentTransactions.insert(tx.vin[i].prevout.hash); } // Don't bother worrying about child transactions of this one. @@ -500,10 +500,10 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list::iterator it = mapNextTx.find(COutPoint(origTx.GetHash(), i)); + auto it = mapNextTx.find(COutPoint(origTx.GetHash(), i)); if (it == mapNextTx.end()) continue; - txiter nextit = mapTx.find(it->second.ptx->GetHash()); + txiter nextit = mapTx.find(it->second->GetHash()); assert(nextit != mapTx.end()); txToRemove.insert(nextit); } @@ -561,9 +561,9 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list list result; LOCK(cs); BOOST_FOREACH(const CTxIn &txin, tx.vin) { - std::map::iterator it = mapNextTx.find(txin.prevout); + auto it = mapNextTx.find(txin.prevout); if (it != mapNextTx.end()) { - const CTransaction &txConflict = *it->second.ptx; + const CTransaction &txConflict = *it->second; if (txConflict != tx) { removeRecursive(txConflict, removed); @@ -671,10 +671,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const assert(coins && coins->IsAvailable(txin.prevout.n)); } // Check whether its inputs are marked in mapNextTx. - std::map::const_iterator it3 = mapNextTx.find(txin.prevout); + auto it3 = mapNextTx.find(txin.prevout); assert(it3 != mapNextTx.end()); - assert(it3->second.ptx == &tx); - assert(it3->second.n == i); + assert(it3->first == &txin.prevout); + assert(it3->second == &tx); i++; } assert(setParentCheck == GetMemPoolParents(it)); @@ -701,10 +701,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const // Check children against mapNextTx CTxMemPool::setEntries setChildrenCheck; - std::map::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); + auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); int64_t childSizes = 0; - for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) { - txiter childit = mapTx.find(iter->second.ptx->GetHash()); + for (; iter != mapNextTx.end() && iter->first->hash == it->GetTx().GetHash(); ++iter) { + txiter childit = mapTx.find(iter->second->GetHash()); assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions if (setChildrenCheck.insert(childit).second) { childSizes += childit->GetTxSize(); @@ -738,14 +738,12 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const stepsSinceLastRemove = 0; } } - for (std::map::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) { - uint256 hash = it->second.ptx->GetHash(); + for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) { + uint256 hash = it->second->GetHash(); indexed_transaction_set::const_iterator it2 = mapTx.find(hash); const CTransaction& tx = it2->GetTx(); assert(it2 != mapTx.end()); - assert(&tx == it->second.ptx); - assert(tx.vin.size() > it->second.n); - assert(it->first == it->second.ptx->vin[it->second.n].prevout); + assert(&tx == it->second); } assert(totalTxSize == checkTotal); @@ -1044,8 +1042,8 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe 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) + auto 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); } } -- cgit v1.2.3 From 8d39d7a2cf1559e0ba40681b0ab90f13ea6c0618 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 30 May 2016 17:06:24 +0200 Subject: Switch CTransaction storage in mempool to std::shared_ptr --- src/txmempool.cpp | 84 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 24 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index f44e45036..d39c9577f 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -23,18 +23,18 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, bool poolHasNoInputsOf, CAmount _inChainInputValue, bool _spendsCoinbase, unsigned int _sigOps, LockPoints lp): - tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), + tx(std::make_shared(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp) { - nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - nModSize = tx.CalculateModifiedSize(nTxSize); - nUsageSize = RecursiveDynamicUsage(tx); + nTxSize = ::GetSerializeSize(_tx, SER_NETWORK, PROTOCOL_VERSION); + nModSize = _tx.CalculateModifiedSize(nTxSize); + nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx); nCountWithDescendants = 1; nSizeWithDescendants = nTxSize; nModFeesWithDescendants = nFee; - CAmount nValueIn = tx.GetValueOut()+nFee; + CAmount nValueIn = _tx.GetValueOut()+nFee; assert(inChainInputValue <= nValueIn); feeDelta = 0; @@ -768,50 +768,86 @@ bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb namespace { class DepthAndScoreComparator { - CTxMemPool *mp; public: - DepthAndScoreComparator(CTxMemPool *mempool) : mp(mempool) {} - bool operator()(const uint256& a, const uint256& b) { return mp->CompareDepthAndScore(a, b); } + bool operator()(const CTxMemPool::indexed_transaction_set::const_iterator& a, const CTxMemPool::indexed_transaction_set::const_iterator& b) + { + uint64_t counta = a->GetCountWithAncestors(); + uint64_t countb = b->GetCountWithAncestors(); + if (counta == countb) { + return CompareTxMemPoolEntryByScore()(*a, *b); + } + return counta < countb; + } }; } -void CTxMemPool::queryHashes(vector& vtxid) +std::vector CTxMemPool::GetSortedDepthAndScore() const { - vtxid.clear(); + std::vector iters; + AssertLockHeld(cs); + + iters.reserve(mapTx.size()); + for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) { + iters.push_back(mi); + } + std::sort(iters.begin(), iters.end(), DepthAndScoreComparator()); + return iters; +} + +void CTxMemPool::queryHashes(vector& vtxid) +{ LOCK(cs); + auto iters = GetSortedDepthAndScore(); + + vtxid.clear(); vtxid.reserve(mapTx.size()); - for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) - vtxid.push_back(mi->GetTx().GetHash()); - std::sort(vtxid.begin(), vtxid.end(), DepthAndScoreComparator(this)); + for (auto it : iters) { + vtxid.push_back(it->GetTx().GetHash()); + } } +std::vector CTxMemPool::infoAll() const +{ + LOCK(cs); + auto iters = GetSortedDepthAndScore(); + + std::vector ret; + ret.reserve(mapTx.size()); + for (auto it : iters) { + ret.push_back(TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize())}); + } + + return ret; +} -bool CTxMemPool::lookup(uint256 hash, CTransaction& result, int64_t& time) const +std::shared_ptr CTxMemPool::get(const uint256& hash) const { LOCK(cs); indexed_transaction_set::const_iterator i = mapTx.find(hash); - if (i == mapTx.end()) return false; - result = i->GetTx(); - time = i->GetTime(); - return true; + if (i == mapTx.end()) + return nullptr; + return i->GetSharedTx(); } bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const { - int64_t time; - return CTxMemPool::lookup(hash, result, time); + auto tx = get(hash); + if (tx) { + result = *tx; + return true; + } + return false; } -bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const +TxMempoolInfo CTxMemPool::info(const uint256& hash) const { LOCK(cs); indexed_transaction_set::const_iterator i = mapTx.find(hash); if (i == mapTx.end()) - return false; - feeRate = CFeeRate(i->GetFee(), i->GetTxSize()); - return true; + return TxMempoolInfo(); + return TxMempoolInfo{i->GetSharedTx(), i->GetTime(), CFeeRate(i->GetFee(), i->GetTxSize())}; } CFeeRate CTxMemPool::estimateFee(int nBlocks) const -- cgit v1.2.3 From 288d85ddf2e0a0c9d25a23db56052883170466d0 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 7 Jun 2016 13:44:56 +0200 Subject: Get rid of CTxMempool::lookup() entirely --- src/txmempool.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index d39c9577f..205ffd637 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -831,16 +831,6 @@ std::shared_ptr CTxMemPool::get(const uint256& hash) const return i->GetSharedTx(); } -bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const -{ - auto tx = get(hash); - if (tx) { - result = *tx; - return true; - } - return false; -} - TxMempoolInfo CTxMemPool::info(const uint256& hash) const { LOCK(cs); @@ -960,9 +950,9 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const { // If an entry in the mempool exists, always return that one, as it's guaranteed to never // conflict with the underlying cache, and it cannot have pruned entries (as it contains full) // transactions. First checking the underlying cache risks returning a pruned entry instead. - CTransaction tx; - if (mempool.lookup(txid, tx)) { - coins = CCoins(tx, MEMPOOL_HEIGHT); + shared_ptr ptx = mempool.get(txid); + if (ptx) { + coins = CCoins(*ptx, MEMPOOL_HEIGHT); return true; } return (base->GetCoins(txid, coins) && !coins.IsPruned()); -- cgit v1.2.3 From 96806c39f4ef395975c0cd7d654dcb71c4790be2 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 18 Jun 2016 18:16:36 +0200 Subject: Stop trimming when mapTx is empty --- 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 205ffd637..18c54b08b 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1075,7 +1075,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe unsigned nTxnRemoved = 0; CFeeRate maxFeeRateRemoved(0); - while (DynamicMemoryUsage() > sizelimit) { + while (!mapTx.empty() && DynamicMemoryUsage() > sizelimit) { indexed_transaction_set::index::type::iterator it = mapTx.get().begin(); // We set the new mempool min fee to the feerate of the removed set, plus the -- cgit v1.2.3 From 811902649d6aaddd886cb39b83aa69adf7b441bd Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 14 Jun 2016 23:59:03 -0700 Subject: Provide a flat list of txid/terators to txn in CTxMemPool --- src/txmempool.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 18c54b08b..ead28546d 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -438,6 +438,9 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, totalTxSize += entry.GetTxSize(); minerPolicyEstimator->processTransaction(entry, fCurrentEstimate); + vTxHashes.emplace_back(hash, newit); + newit->vTxHashesIdx = vTxHashes.size() - 1; + return true; } @@ -447,6 +450,15 @@ void CTxMemPool::removeUnchecked(txiter it) BOOST_FOREACH(const CTxIn& txin, it->GetTx().vin) mapNextTx.erase(txin.prevout); + if (vTxHashes.size() > 1) { + vTxHashes[it->vTxHashesIdx] = std::move(vTxHashes.back()); + vTxHashes[it->vTxHashesIdx].second->vTxHashesIdx = it->vTxHashesIdx; + vTxHashes.pop_back(); + if (vTxHashes.size() * 2 < vTxHashes.capacity()) + vTxHashes.shrink_to_fit(); + } else + vTxHashes.clear(); + totalTxSize -= it->GetTxSize(); cachedInnerUsage -= it->DynamicMemoryUsage(); cachedInnerUsage -= memusage::DynamicUsage(mapLinks[it].parents) + memusage::DynamicUsage(mapLinks[it].children); @@ -965,7 +977,7 @@ bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { size_t CTxMemPool::DynamicMemoryUsage() const { LOCK(cs); // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. - return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage; + return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + memusage::DynamicUsage(vTxHashes) + cachedInnerUsage; } void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants) { -- cgit v1.2.3 From 2b1f6f9ccf36f1e0a2c9d99154e1642f796d7c2b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 3 Jan 2016 18:54:50 +0100 Subject: BIP141: Other consensus critical limits, and BIP145 Includes changes by Suhas Daftuar, Luke-jr, and mruddy. --- src/txmempool.cpp | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index ead28546d..a48a6d946 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -9,6 +9,7 @@ #include "consensus/consensus.h" #include "consensus/validation.h" #include "main.h" +#include "policy/policy.h" #include "policy/fees.h" #include "streams.h" #include "timedata.h" @@ -22,17 +23,17 @@ 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, unsigned int _sigOps, LockPoints lp): + bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp): tx(std::make_shared(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), - spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp) + spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp) { - nTxSize = ::GetSerializeSize(_tx, SER_NETWORK, PROTOCOL_VERSION); - nModSize = _tx.CalculateModifiedSize(nTxSize); + nTxCost = GetTransactionCost(_tx); + nModSize = _tx.CalculateModifiedSize(GetTxSize()); nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx); nCountWithDescendants = 1; - nSizeWithDescendants = nTxSize; + nSizeWithDescendants = GetTxSize(); nModFeesWithDescendants = nFee; CAmount nValueIn = _tx.GetValueOut()+nFee; assert(inChainInputValue <= nValueIn); @@ -40,9 +41,9 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, feeDelta = 0; nCountWithAncestors = 1; - nSizeWithAncestors = nTxSize; + nSizeWithAncestors = GetTxSize(); nModFeesWithAncestors = nFee; - nSigOpCountWithAncestors = sigOpCount; + nSigOpCostWithAncestors = sigOpCost; } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -72,6 +73,11 @@ void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp) lockPoints = lp; } +size_t CTxMemPoolEntry::GetTxSize() const +{ + return GetVirtualTransactionSize(nTxCost); +} + // Update the given tx for any in-mempool descendants. // Assumes that setMemPoolChildren is correct for the given tx and all // descendants. @@ -111,7 +117,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan modifyCount++; cachedDescendants[updateIt].insert(cit); // Update ancestor state for each descendant - mapTx.modify(cit, update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCount())); + mapTx.modify(cit, update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCost())); } } mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount)); @@ -247,13 +253,13 @@ void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncesto int64_t updateCount = setAncestors.size(); int64_t updateSize = 0; CAmount updateFee = 0; - int updateSigOps = 0; + int64_t updateSigOpsCost = 0; BOOST_FOREACH(txiter ancestorIt, setAncestors) { updateSize += ancestorIt->GetTxSize(); updateFee += ancestorIt->GetModifiedFee(); - updateSigOps += ancestorIt->GetSigOpCount(); + updateSigOpsCost += ancestorIt->GetSigOpCost(); } - mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOps)); + mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOpsCost)); } void CTxMemPool::UpdateChildrenForRemoval(txiter it) @@ -282,7 +288,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b setDescendants.erase(removeIt); // don't update state for self int64_t modifySize = -((int64_t)removeIt->GetTxSize()); CAmount modifyFee = -removeIt->GetModifiedFee(); - int modifySigOps = -removeIt->GetSigOpCount(); + int modifySigOps = -removeIt->GetSigOpCost(); BOOST_FOREACH(txiter dit, setDescendants) { mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps)); } @@ -338,8 +344,8 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, nModFeesWithAncestors += modifyFee; nCountWithAncestors += modifyCount; assert(int64_t(nCountWithAncestors) > 0); - nSigOpCountWithAncestors += modifySigOps; - assert(int(nSigOpCountWithAncestors) >= 0); + nSigOpCostWithAncestors += modifySigOps; + assert(int(nSigOpCostWithAncestors) >= 0); } CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : @@ -666,7 +672,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const bool fDependsWait = false; setEntries setParentCheck; int64_t parentSizes = 0; - unsigned int parentSigOpCount = 0; + int64_t parentSigOpCost = 0; BOOST_FOREACH(const CTxIn &txin, tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); @@ -676,7 +682,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const fDependsWait = true; if (setParentCheck.insert(it2).second) { parentSizes += it2->GetTxSize(); - parentSigOpCount += it2->GetSigOpCount(); + parentSigOpCost += it2->GetSigOpCost(); } } else { const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash); @@ -698,17 +704,17 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const uint64_t nCountCheck = setAncestors.size() + 1; uint64_t nSizeCheck = it->GetTxSize(); CAmount nFeesCheck = it->GetModifiedFee(); - unsigned int nSigOpCheck = it->GetSigOpCount(); + int64_t nSigOpCheck = it->GetSigOpCost(); BOOST_FOREACH(txiter ancestorIt, setAncestors) { nSizeCheck += ancestorIt->GetTxSize(); nFeesCheck += ancestorIt->GetModifiedFee(); - nSigOpCheck += ancestorIt->GetSigOpCount(); + nSigOpCheck += ancestorIt->GetSigOpCost(); } assert(it->GetCountWithAncestors() == nCountCheck); assert(it->GetSizeWithAncestors() == nSizeCheck); - assert(it->GetSigOpCountWithAncestors() == nSigOpCheck); + assert(it->GetSigOpCostWithAncestors() == nSigOpCheck); assert(it->GetModFeesWithAncestors() == nFeesCheck); // Check children against mapNextTx -- cgit v1.2.3 From 2c06bae39edfaa9c0855d83377ad8fda09e4fa08 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 18 Jul 2016 13:28:26 -0400 Subject: Rename "block cost" to "block weight" --- 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 a48a6d946..691baa674 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -28,7 +28,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp) { - nTxCost = GetTransactionCost(_tx); + nTxWeight = GetTransactionWeight(_tx); nModSize = _tx.CalculateModifiedSize(GetTxSize()); nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx); @@ -75,7 +75,7 @@ void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp) size_t CTxMemPoolEntry::GetTxSize() const { - return GetVirtualTransactionSize(nTxCost); + return GetVirtualTransactionSize(nTxWeight); } // Update the given tx for any in-mempool descendants. -- cgit v1.2.3 From ab942c15bd3854650afa810d7c22d7fd30d346c1 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 18 Jul 2016 20:57:20 +0200 Subject: Treat high-sigop transactions as larger rather than rejecting them --- 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 691baa674..82827b8e4 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -75,7 +75,7 @@ void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp) size_t CTxMemPoolEntry::GetTxSize() const { - return GetVirtualTransactionSize(nTxWeight); + return GetVirtualTransactionSize(nTxWeight, sigOpCost); } // Update the given tx for any in-mempool descendants. -- cgit v1.2.3 From a6cc299541fc9df5af010ce63eb1dd34d8c4b6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Sat, 16 Jul 2016 20:57:42 +0200 Subject: Mempool: Use Consensus::CheckTxInputs direclty over main::CheckInputs --- src/txmempool.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index a48a6d946..b30022bd6 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -657,6 +657,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const uint64_t innerUsage = 0; CCoinsViewCache mempoolDuplicate(const_cast(pcoins)); + const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate); LOCK(cs); list waitingOnDependants; @@ -737,7 +738,9 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const waitingOnDependants.push_back(&(*it)); else { CValidationState state; - assert(CheckInputs(tx, state, mempoolDuplicate, false, 0, false, NULL)); + bool fCheckResult = tx.IsCoinBase() || + Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight); + assert(fCheckResult); UpdateCoins(tx, mempoolDuplicate, 1000000); } } @@ -751,7 +754,9 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const stepsSinceLastRemove++; assert(stepsSinceLastRemove < waitingOnDependants.size()); } else { - assert(CheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, NULL)); + bool fCheckResult = entry->GetTx().IsCoinBase() || + Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight); + assert(fCheckResult); UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000); stepsSinceLastRemove = 0; } -- cgit v1.2.3 From fa6dc9f0e5eac8ec473b63adfd43635005778f46 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 25 Aug 2016 12:48:23 +0200 Subject: Remove unused variables --- src/txmempool.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index b631c4848..0a00d757a 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -576,7 +576,6 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem void CTxMemPool::removeConflicts(const CTransaction &tx, std::list& removed) { // Remove transactions which depend on inputs of tx, recursively - list result; LOCK(cs); BOOST_FOREACH(const CTxIn &txin, tx.vin) { auto it = mapNextTx.find(txin.prevout); -- cgit v1.2.3 From 4731cab8fbff51a8178c85d572e2482040278616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Jan=C3=ADk?= Date: Fri, 2 Sep 2016 18:19:01 +0200 Subject: Do not shadow variables --- 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 0a00d757a..3586123d3 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1116,8 +1116,8 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe std::vector txn; if (pvNoSpendsRemaining) { txn.reserve(stage.size()); - BOOST_FOREACH(txiter it, stage) - txn.push_back(it->GetTx()); + BOOST_FOREACH(txiter iter, stage) + txn.push_back(iter->GetTx()); } RemoveStaged(stage, false); if (pvNoSpendsRemaining) { @@ -1125,8 +1125,8 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe BOOST_FOREACH(const CTxIn& txin, tx.vin) { if (exists(txin.prevout.hash)) continue; - auto it = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0)); - if (it == mapNextTx.end() || it->first->hash != txin.prevout.hash) + auto iter = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0)); + if (iter == mapNextTx.end() || iter->first->hash != txin.prevout.hash) pvNoSpendsRemaining->push_back(txin.prevout.hash); } } -- cgit v1.2.3 From 6aa28abf53ef4694692474b4a3b0a8fa7559b50b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 25 Jun 2016 19:17:45 +0200 Subject: Use cmpctblock type 2 for segwit-enabled transfer Contains version negotiation logic by Matt Corallo and bugfixes by Suhas Daftuar. --- 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 3586123d3..15fa6fbca 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -444,7 +444,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, totalTxSize += entry.GetTxSize(); minerPolicyEstimator->processTransaction(entry, fCurrentEstimate); - vTxHashes.emplace_back(hash, newit); + vTxHashes.emplace_back(tx.GetWitnessHash(), newit); newit->vTxHashesIdx = vTxHashes.size() - 1; return true; -- cgit v1.2.3 From 5eaaa83ac1f5eb525f93e2808fafd73f5ed97013 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 13 Oct 2016 16:19:20 +0200 Subject: Kill insecure_random and associated global state There are only a few uses of `insecure_random` outside the tests. This PR replaces uses of insecure_random (and its accompanying global state) in the core code with an FastRandomContext that is automatically seeded on creation. This is meant to be used for inner loops. The FastRandomContext can be in the outer scope, or the class itself, then rand32() is used inside the loop. Useful e.g. for pushing addresses in CNode or the fee rounding, or randomization for coin selection. As a context is created per purpose, thus it gets rid of cross-thread unprotected shared usage of a single set of globals, this should also get rid of the potential race conditions. - I'd say TxMempool::check is not called enough to warrant using a special fast random context, this is switched to GetRand() (open for discussion...) - The use of `insecure_rand` in ConnectThroughProxy has been replaced by an atomic integer counter. The only goal here is to have a different credentials pair for each connection to go on a different Tor circuit, it does not need to be random nor unpredictable. - To avoid having a FastRandomContext on every CNode, the context is passed into PushAddress as appropriate. There remains an insecure_random for test usage in `test_random.h`. --- 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 15fa6fbca..0f1c166ab 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -647,7 +647,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const if (nCheckFrequency == 0) return; - if (insecure_rand() >= nCheckFrequency) + if (GetRand(std::numeric_limits::max()) >= 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 f48211b700d171f7bcee7d3088269fdaaf1b5c13 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 15 Aug 2016 12:20:13 +0200 Subject: Bypass removeRecursive in removeForReorg --- src/txmempool.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 0f1c166ab..9816c9dcb 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -541,7 +541,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem { // Remove transactions spending a coinbase which are now immature and no-longer-final transactions LOCK(cs); - list transactionsToRemove; + setEntries txToRemove; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->GetTx(); LockPoints lp = it->GetLockPoints(); @@ -549,16 +549,16 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags, &lp, validLP)) { // Note if CheckSequenceLocks fails the LockPoints may still be invalid // So it's critical that we remove the tx and not depend on the LockPoints. - transactionsToRemove.push_back(tx); + txToRemove.insert(it); } 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()) continue; const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); - if (nCheckFrequency != 0) assert(coins); + if (nCheckFrequency != 0) assert(coins); if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { - transactionsToRemove.push_back(tx); + txToRemove.insert(it); break; } } @@ -567,10 +567,11 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem mapTx.modify(it, update_lock_points(lp)); } } - BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) { - list removed; - removeRecursive(tx, removed); + setEntries setAllRemoves; + for (txiter it : txToRemove) { + CalculateDescendants(it, setAllRemoves); } + RemoveStaged(setAllRemoves, false); } void CTxMemPool::removeConflicts(const CTransaction &tx, std::list& removed) -- cgit v1.2.3 From 51f278329d43398428d60f5986f8d29a2041d28d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 15 Aug 2016 13:10:57 +0200 Subject: Make removed and conflicted arguments optional to remove --- src/txmempool.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 9816c9dcb..193542ee5 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -503,7 +503,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants } } -void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list& removed) +void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list* removed) { // Remove transaction from memory pool { @@ -530,8 +530,10 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, std::listGetTx()); + if (removed) { + BOOST_FOREACH(txiter it, setAllRemoves) { + removed->push_back(it->GetTx()); + } } RemoveStaged(setAllRemoves, false); } @@ -574,7 +576,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem RemoveStaged(setAllRemoves, false); } -void CTxMemPool::removeConflicts(const CTransaction &tx, std::list& removed) +void CTxMemPool::removeConflicts(const CTransaction &tx, std::list* removed) { // Remove transactions which depend on inputs of tx, recursively LOCK(cs); @@ -595,7 +597,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list * Called when a block is connected. Removes from mempool and updates the miner fee estimator. */ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, - std::list& conflicts, bool fCurrentEstimate) + std::list* conflicts, bool fCurrentEstimate) { LOCK(cs); std::vector entries; -- cgit v1.2.3 From 4100499db4e886d7a9ad2dcf4007ce44fb2c1a62 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 15 Aug 2016 12:57:10 +0200 Subject: Return shared_ptr from mempool removes --- 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 193542ee5..e5d28ac2e 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -503,7 +503,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants } } -void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list* removed) +void CTxMemPool::removeRecursive(const CTransaction &origTx, std::vector>* removed) { // Remove transaction from memory pool { @@ -532,7 +532,7 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, std::listpush_back(it->GetTx()); + removed->emplace_back(it->GetSharedTx()); } } RemoveStaged(setAllRemoves, false); @@ -576,7 +576,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem RemoveStaged(setAllRemoves, false); } -void CTxMemPool::removeConflicts(const CTransaction &tx, std::list* removed) +void CTxMemPool::removeConflicts(const CTransaction &tx, std::vector>* removed) { // Remove transactions which depend on inputs of tx, recursively LOCK(cs); @@ -597,7 +597,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list * Called when a block is connected. Removes from mempool and updates the miner fee estimator. */ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, - std::list* conflicts, bool fCurrentEstimate) + std::vector>* conflicts, bool fCurrentEstimate) { LOCK(cs); std::vector entries; -- cgit v1.2.3 From c3efb586223c0459cdb47913375c2df805be925e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 31 Jul 2016 20:53:17 +0200 Subject: Add feedelta to TxMempoolInfo --- src/txmempool.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index e5d28ac2e..313d33507 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -833,6 +833,10 @@ void CTxMemPool::queryHashes(vector& vtxid) } } +static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) { + return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize()), it->GetModifiedFee() - it->GetFee()}; +} + std::vector CTxMemPool::infoAll() const { LOCK(cs); @@ -841,7 +845,7 @@ std::vector CTxMemPool::infoAll() const std::vector ret; ret.reserve(mapTx.size()); for (auto it : iters) { - ret.push_back(TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize())}); + ret.push_back(GetInfo(it)); } return ret; @@ -862,7 +866,7 @@ TxMempoolInfo CTxMemPool::info(const uint256& hash) const indexed_transaction_set::const_iterator i = mapTx.find(hash); if (i == mapTx.end()) return TxMempoolInfo(); - return TxMempoolInfo{i->GetSharedTx(), i->GetTime(), CFeeRate(i->GetFee(), i->GetTxSize())}; + return GetInfo(i); } CFeeRate CTxMemPool::estimateFee(int nBlocks) const -- cgit v1.2.3 From b2322e0fc6def0baf8581bbd2f4135e61c47d142 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Mon, 21 Mar 2016 13:04:40 -0400 Subject: Remove priority estimation --- src/txmempool.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 313d33507..45135a5f7 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -895,7 +895,7 @@ CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const { try { LOCK(cs); - fileout << 109900; // version required to read: 0.10.99 or later + fileout << 139900; // version required to read: 0.13.99 or later fileout << CLIENT_VERSION; // version that wrote the file minerPolicyEstimator->Write(fileout); } @@ -914,9 +914,8 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein) filein >> nVersionRequired >> nVersionThatWrote; if (nVersionRequired > CLIENT_VERSION) return error("CTxMemPool::ReadFeeEstimates(): up-version (%d) fee estimate file", nVersionRequired); - LOCK(cs); - minerPolicyEstimator->Read(filein); + minerPolicyEstimator->Read(filein, nVersionThatWrote); } catch (const std::exception&) { LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)\n"); -- cgit v1.2.3 From 1662b437b33b7ec5a1723f6ae6187d3bdd06f593 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 10 Nov 2016 17:26:00 -0800 Subject: Make CBlock::vtx a vector of shared_ptr --- src/txmempool.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 45135a5f7..fff20a609 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -596,29 +596,29 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::vector& vtx, unsigned int nBlockHeight, +void CTxMemPool::removeForBlock(const std::vector>& vtx, unsigned int nBlockHeight, std::vector>* conflicts, bool fCurrentEstimate) { LOCK(cs); std::vector entries; - BOOST_FOREACH(const CTransaction& tx, vtx) + for (const auto& tx : vtx) { - uint256 hash = tx.GetHash(); + uint256 hash = tx->GetHash(); indexed_transaction_set::iterator i = mapTx.find(hash); if (i != mapTx.end()) entries.push_back(*i); } - BOOST_FOREACH(const CTransaction& tx, vtx) + for (const auto& tx : vtx) { - txiter it = mapTx.find(tx.GetHash()); + txiter it = mapTx.find(tx->GetHash()); if (it != mapTx.end()) { setEntries stage; stage.insert(it); RemoveStaged(stage, true); } - removeConflicts(tx, conflicts); - ClearPrioritisation(tx.GetHash()); + removeConflicts(*tx, conflicts); + ClearPrioritisation(tx->GetHash()); } // After the txs in the new block have been removed from the mempool, update policy estimates minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate); -- cgit v1.2.3 From b4e4ba475a5679e09f279aaf2a83dcf93c632bdb Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 10 Nov 2016 17:34:17 -0800 Subject: Introduce convenience type CTransactionRef --- src/txmempool.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index fff20a609..417a88cbe 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -24,7 +24,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, bool poolHasNoInputsOf, CAmount _inChainInputValue, bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp): - tx(std::make_shared(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), + tx(MakeTransactionRef(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp) { @@ -503,7 +503,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants } } -void CTxMemPool::removeRecursive(const CTransaction &origTx, std::vector>* removed) +void CTxMemPool::removeRecursive(const CTransaction &origTx, std::vector* removed) { // Remove transaction from memory pool { @@ -576,7 +576,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem RemoveStaged(setAllRemoves, false); } -void CTxMemPool::removeConflicts(const CTransaction &tx, std::vector>* removed) +void CTxMemPool::removeConflicts(const CTransaction &tx, std::vector* removed) { // Remove transactions which depend on inputs of tx, recursively LOCK(cs); @@ -596,8 +596,8 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::vector>& vtx, unsigned int nBlockHeight, - std::vector>* conflicts, bool fCurrentEstimate) +void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, + std::vector* conflicts, bool fCurrentEstimate) { LOCK(cs); std::vector entries; @@ -851,7 +851,7 @@ std::vector CTxMemPool::infoAll() const return ret; } -std::shared_ptr CTxMemPool::get(const uint256& hash) const +CTransactionRef CTxMemPool::get(const uint256& hash) const { LOCK(cs); indexed_transaction_set::const_iterator i = mapTx.find(hash); @@ -978,7 +978,7 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const { // If an entry in the mempool exists, always return that one, as it's guaranteed to never // conflict with the underlying cache, and it cannot have pruned entries (as it contains full) // transactions. First checking the underlying cache risks returning a pruned entry instead. - shared_ptr ptx = mempool.get(txid); + CTransactionRef ptx = mempool.get(txid); if (ptx) { coins = CCoins(*ptx, MEMPOOL_HEIGHT); return true; -- cgit v1.2.3 From 76faa3cdfedbd3fc91be4ecfff77fc6dc18134fb Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 1 Dec 2016 16:06:41 -0800 Subject: Rename the remaining main.{h,cpp} to validation.{h,cpp} --- 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 417a88cbe..c035a84db 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -8,7 +8,7 @@ #include "clientversion.h" #include "consensus/consensus.h" #include "consensus/validation.h" -#include "main.h" +#include "validation.h" #include "policy/policy.h" #include "policy/fees.h" #include "streams.h" -- cgit v1.2.3 From bf663f8e93454fdc7c77e298586cefbb4488ee4c Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Tue, 29 Nov 2016 17:15:12 -0500 Subject: remove external usage of mempool conflict tracking --- 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 c035a84db..3bea0e4fb 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -597,7 +597,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::vector& vtx, unsigned int nBlockHeight, - std::vector* conflicts, bool fCurrentEstimate) + bool fCurrentEstimate) { LOCK(cs); std::vector entries; @@ -617,7 +617,7 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigne stage.insert(it); RemoveStaged(stage, true); } - removeConflicts(*tx, conflicts); + removeConflicts(*tx); ClearPrioritisation(tx->GetHash()); } // After the txs in the new block have been removed from the mempool, update policy estimates -- cgit v1.2.3 From a874ab5ccf7839edb445830f81591fa608d85fa6 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Tue, 29 Nov 2016 17:51:26 -0500 Subject: remove internal tracking of mempool conflicts for reporting to wallet --- src/txmempool.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 3bea0e4fb..4334ebde6 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -503,7 +503,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants } } -void CTxMemPool::removeRecursive(const CTransaction &origTx, std::vector* removed) +void CTxMemPool::removeRecursive(const CTransaction &origTx) { // Remove transaction from memory pool { @@ -530,11 +530,6 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, std::vectoremplace_back(it->GetSharedTx()); - } - } RemoveStaged(setAllRemoves, false); } } @@ -576,7 +571,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem RemoveStaged(setAllRemoves, false); } -void CTxMemPool::removeConflicts(const CTransaction &tx, std::vector* removed) +void CTxMemPool::removeConflicts(const CTransaction &tx) { // Remove transactions which depend on inputs of tx, recursively LOCK(cs); @@ -586,7 +581,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::vectorsecond; if (txConflict != tx) { - removeRecursive(txConflict, removed); + removeRecursive(txConflict); ClearPrioritisation(txConflict.GetHash()); } } -- cgit v1.2.3 From f8d43b8081eef080ebb4514d1493c0c8d81d27ab Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Thu, 8 Dec 2016 09:15:01 -0500 Subject: Avoid rollingMinimumFeeRate never being able to decay below half --- 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 c035a84db..981f31f48 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1082,7 +1082,7 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const { rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife); lastRollingFeeUpdate = time; - if (rollingMinimumFeeRate < minReasonableRelayFee.GetFeePerK() / 2) { + if (rollingMinimumFeeRate < (double)minReasonableRelayFee.GetFeePerK() / 2) { rollingMinimumFeeRate = 0; return CFeeRate(0); } -- cgit v1.2.3 From 0b2294a980319cbffa8612ce993e0ecaa26fa509 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Fri, 2 Dec 2016 15:29:20 -0500 Subject: SelectCoinsMinConf: Prefer coins with fewer ancestors --- src/txmempool.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 417a88cbe..f87713006 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1142,3 +1142,10 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe if (maxFeeRateRemoved > CFeeRate(0)) LogPrint("mempool", "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString()); } + +bool CTxMemPool::TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const { + LOCK(cs); + if (exists(txid) && std::max(mapTx.find(txid)->GetCountWithAncestors(), mapTx.find(txid)->GetCountWithDescendants()) >= chainLimit) + return false; + return true; +} -- cgit v1.2.3 From cee16123f550f6baad0205f776831f39d026758b Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Mon, 19 Dec 2016 09:35:23 -0500 Subject: reduce number of lookups in TransactionWithinChainLimit --- src/txmempool.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index f87713006..f11a36fd4 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1145,7 +1145,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe bool CTxMemPool::TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const { LOCK(cs); - if (exists(txid) && std::max(mapTx.find(txid)->GetCountWithAncestors(), mapTx.find(txid)->GetCountWithDescendants()) >= chainLimit) - return false; - return true; + auto it = mapTx.find(txid); + return it == mapTx.end() || (it->GetCountWithAncestors() < chainLimit && + it->GetCountWithDescendants() < chainLimit); } -- cgit v1.2.3 From c44e4c467c30fe7790372bdea8941ba29fd3327e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 10 Nov 2016 22:29:19 -0800 Subject: Make AcceptToMemoryPool take CTransactionRef --- 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 c3da69c3f..90a806611 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -20,22 +20,22 @@ using namespace std; -CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, +CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, bool poolHasNoInputsOf, CAmount _inChainInputValue, bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp): - tx(MakeTransactionRef(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), + tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp) { - nTxWeight = GetTransactionWeight(_tx); - nModSize = _tx.CalculateModifiedSize(GetTxSize()); + nTxWeight = GetTransactionWeight(*tx); + nModSize = tx->CalculateModifiedSize(GetTxSize()); nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx); nCountWithDescendants = 1; nSizeWithDescendants = GetTxSize(); nModFeesWithDescendants = nFee; - CAmount nValueIn = _tx.GetValueOut()+nFee; + CAmount nValueIn = tx->GetValueOut()+nFee; assert(inChainInputValue <= nValueIn); feeDelta = 0; -- cgit v1.2.3 From 27765b6403cece54320374b37afb01a0cfe571c3 Mon Sep 17 00:00:00 2001 From: isle2983 Date: Sat, 31 Dec 2016 11:01:21 -0700 Subject: Increment MIT Licence copyright header year on files modified in 2016 Edited via: $ contrib/devtools/copyright_header.py update . --- 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 c3da69c3f..fa9798a3e 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2015 The Bitcoin Core developers +// Copyright (c) 2009-2016 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 From 84f7ab08d2e8e83a584d72fdf44f68b34baf8165 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Fri, 11 Nov 2016 11:57:51 -0500 Subject: Remove member variable hadNoDependencies from CTxMemPoolEntry Fee estimation can just check its own mapMemPoolTxs to determine the same information. Note that now fee estimation for block processing must happen before those transactions are removed, but this shoudl be a speedup. --- 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 4ccbcadef..57300bb51 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -22,10 +22,10 @@ using namespace std; CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, - bool poolHasNoInputsOf, CAmount _inChainInputValue, + CAmount _inChainInputValue, bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp): tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), - hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), + inChainInputValue(_inChainInputValue), spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp) { nTxWeight = GetTransactionWeight(*tx); @@ -604,6 +604,8 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigne if (i != mapTx.end()) entries.push_back(*i); } + // Before the txs in the new block have been removed from the mempool, update policy estimates + minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate); for (const auto& tx : vtx) { txiter it = mapTx.find(tx->GetHash()); @@ -615,8 +617,6 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigne removeConflicts(*tx); ClearPrioritisation(tx->GetHash()); } - // 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; } -- cgit v1.2.3 From 6f06b268c1f383affb2cf397f325d48d25bc8880 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Fri, 11 Nov 2016 12:48:01 -0500 Subject: rename bool to validFeeEstimate --- 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 57300bb51..53f3e0e19 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -392,7 +392,7 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n) nTransactionsUpdated += n; } -bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate) +bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate) { // Add to memory pool without checking anything. // Used by main.cpp AcceptToMemoryPool(), which DOES do @@ -442,7 +442,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); - minerPolicyEstimator->processTransaction(entry, fCurrentEstimate); + minerPolicyEstimator->processTransaction(entry, validFeeEstimate); vTxHashes.emplace_back(tx.GetWitnessHash(), newit); newit->vTxHashesIdx = vTxHashes.size() - 1; @@ -1015,14 +1015,14 @@ int CTxMemPool::Expire(int64_t time) { return stage.size(); } -bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate) +bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool validFeeEstimate) { LOCK(cs); setEntries setAncestors; uint64_t nNoLimit = std::numeric_limits::max(); std::string dummy; CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); - return addUnchecked(hash, entry, setAncestors, fCurrentEstimate); + return addUnchecked(hash, entry, setAncestors, validFeeEstimate); } void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add) -- cgit v1.2.3 From d825838e6472f73c491f93506cb003472f071602 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Fri, 11 Nov 2016 13:14:45 -0500 Subject: Always update fee estimates on new blocks. All decisions about whether the transactions are valid data points are made at the time the transaction arrives. Updating on blocks all the time will now cause stale fee estimates to decay quickly when we restart a node. --- src/txmempool.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 53f3e0e19..e97099eb2 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -591,8 +591,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx) /** * Called when a block is connected. Removes from mempool and updates the miner fee estimator. */ -void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, - bool fCurrentEstimate) +void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned int nBlockHeight) { LOCK(cs); std::vector entries; @@ -605,7 +604,7 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigne entries.push_back(*i); } // Before the txs in the new block have been removed from the mempool, update policy estimates - minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate); + minerPolicyEstimator->processBlock(nBlockHeight, entries); for (const auto& tx : vtx) { txiter it = mapTx.find(tx->GetHash()); -- cgit v1.2.3 From ebafdcabb10a89b491cdb8430bc43b0220d436df Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Fri, 11 Nov 2016 14:16:42 -0500 Subject: Pass pointers to existing CTxMemPoolEntries to fee estimation --- 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 e97099eb2..4f4540a1f 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -594,14 +594,14 @@ void CTxMemPool::removeConflicts(const CTransaction &tx) void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned int nBlockHeight) { LOCK(cs); - std::vector entries; + std::vector entries; for (const auto& tx : vtx) { uint256 hash = tx->GetHash(); indexed_transaction_set::iterator i = mapTx.find(hash); if (i != mapTx.end()) - entries.push_back(*i); + entries.push_back(&*i); } // Before the txs in the new block have been removed from the mempool, update policy estimates minerPolicyEstimator->processBlock(nBlockHeight, entries); -- cgit v1.2.3 From fe7e593b24678082578e76d8f918d4544713b5f0 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Tue, 10 Jan 2017 15:21:21 -0500 Subject: Fix use-after-free in CTxMemPool::removeConflicts() --- 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 4f4540a1f..373687430 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -581,8 +581,8 @@ void CTxMemPool::removeConflicts(const CTransaction &tx) const CTransaction &txConflict = *it->second; if (txConflict != tx) { - removeRecursive(txConflict); ClearPrioritisation(txConflict.GetHash()); + removeRecursive(txConflict); } } } -- cgit v1.2.3 From 7b1add3c28aae8caf2e1517f15cd953eacbb4931 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Tue, 13 Dec 2016 13:43:35 -0500 Subject: Introduce -incrementalrelayfee --- src/txmempool.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 4ccbcadef..c6eaf661d 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -359,7 +359,6 @@ CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : nCheckFrequency = 0; minerPolicyEstimator = new CBlockPolicyEstimator(_minReasonableRelayFee); - minReasonableRelayFee = _minReasonableRelayFee; } CTxMemPool::~CTxMemPool() @@ -1077,12 +1076,12 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const { rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife); lastRollingFeeUpdate = time; - if (rollingMinimumFeeRate < (double)minReasonableRelayFee.GetFeePerK() / 2) { + if (rollingMinimumFeeRate < (double)incrementalRelayFee.GetFeePerK() / 2) { rollingMinimumFeeRate = 0; return CFeeRate(0); } } - return std::max(CFeeRate(rollingMinimumFeeRate), minReasonableRelayFee); + return std::max(CFeeRate(rollingMinimumFeeRate), incrementalRelayFee); } void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) { @@ -1106,7 +1105,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe // 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->GetModFeesWithDescendants(), it->GetSizeWithDescendants()); - removed += minReasonableRelayFee; + removed += incrementalRelayFee; trackPackageRemoved(removed); maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed); -- cgit v1.2.3 From 003cd60cc3697df25bb9dfa0bae0616a462af7ab Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 20 Jan 2017 18:10:48 -0500 Subject: Add missing mempool lock for CalculateMemPoolAncestors --- src/txmempool.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 5b085f492..34ca3baca 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -173,6 +173,8 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashes bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) const { + LOCK(cs); + setEntries parentHashes; const CTransaction &tx = entry.GetTx(); -- cgit v1.2.3 From ff25c32392596883c13623eed6018fabb7877ed7 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 26 Mar 2016 16:44:50 +0100 Subject: mempool: add notification for added/removed entries Add notification signals to make it possible to subscribe to mempool changes: - NotifyEntryAdded(CTransactionRef)> - NotifyEntryRemoved(CTransactionRef, MemPoolRemovalReason)> Also add a mempool removal reason enumeration, which is passed to the removed notification based on why the transaction was removed from the mempool. --- src/txmempool.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 5b085f492..54400cacc 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -393,6 +393,7 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n) bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate) { + NotifyEntryAdded(entry.GetSharedTx()); // Add to memory pool without checking anything. // Used by main.cpp AcceptToMemoryPool(), which DOES do // all the appropriate checks. @@ -449,8 +450,9 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, return true; } -void CTxMemPool::removeUnchecked(txiter it) +void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason) { + NotifyEntryRemoved(it->GetSharedTx(), reason); const uint256 hash = it->GetTx().GetHash(); BOOST_FOREACH(const CTxIn& txin, it->GetTx().vin) mapNextTx.erase(txin.prevout); @@ -502,7 +504,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants } } -void CTxMemPool::removeRecursive(const CTransaction &origTx) +void CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReason reason) { // Remove transaction from memory pool { @@ -529,7 +531,8 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx) BOOST_FOREACH(txiter it, txToRemove) { CalculateDescendants(it, setAllRemoves); } - RemoveStaged(setAllRemoves, false); + + RemoveStaged(setAllRemoves, false, reason); } } @@ -567,7 +570,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem for (txiter it : txToRemove) { CalculateDescendants(it, setAllRemoves); } - RemoveStaged(setAllRemoves, false); + RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG); } void CTxMemPool::removeConflicts(const CTransaction &tx) @@ -581,7 +584,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx) if (txConflict != tx) { ClearPrioritisation(txConflict.GetHash()); - removeRecursive(txConflict); + removeRecursive(txConflict, MemPoolRemovalReason::CONFLICT); } } } @@ -610,7 +613,7 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigne if (it != mapTx.end()) { setEntries stage; stage.insert(it); - RemoveStaged(stage, true); + RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK); } removeConflicts(*tx); ClearPrioritisation(tx->GetHash()); @@ -989,11 +992,11 @@ size_t CTxMemPool::DynamicMemoryUsage() const { return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + memusage::DynamicUsage(vTxHashes) + cachedInnerUsage; } -void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants) { +void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) { AssertLockHeld(cs); UpdateForRemoveFromMempool(stage, updateDescendants); BOOST_FOREACH(const txiter& it, stage) { - removeUnchecked(it); + removeUnchecked(it, reason); } } @@ -1009,7 +1012,7 @@ int CTxMemPool::Expire(int64_t time) { BOOST_FOREACH(txiter removeit, toremove) { CalculateDescendants(removeit, stage); } - RemoveStaged(stage, false); + RemoveStaged(stage, false, MemPoolRemovalReason::EXPIRY); return stage.size(); } @@ -1118,7 +1121,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe BOOST_FOREACH(txiter iter, stage) txn.push_back(iter->GetTx()); } - RemoveStaged(stage, false); + RemoveStaged(stage, false, MemPoolRemovalReason::SIZELIMIT); if (pvNoSpendsRemaining) { BOOST_FOREACH(const CTransaction& tx, txn) { BOOST_FOREACH(const CTxIn& txin, tx.vin) { -- cgit v1.2.3 From b7b48c8bbdf7a90861610b035d8b0a247ef78c45 Mon Sep 17 00:00:00 2001 From: Karl-Johan Alm Date: Fri, 27 Jan 2017 17:43:41 +0900 Subject: Refactor: Remove using namespace from src/*.cpp. --- src/txmempool.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 54400cacc..a1a37dac7 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -18,8 +18,6 @@ #include "utiltime.h" #include "version.h" -using namespace std; - CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, CAmount _inChainInputValue, @@ -658,7 +656,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate); LOCK(cs); - list waitingOnDependants; + std::list waitingOnDependants; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { unsigned int i = 0; checkTotal += it->GetTxSize(); @@ -816,7 +814,7 @@ std::vector CTxMemPool::Get return iters; } -void CTxMemPool::queryHashes(vector& vtxid) +void CTxMemPool::queryHashes(std::vector& vtxid) { LOCK(cs); auto iters = GetSortedDepthAndScore(); @@ -920,7 +918,7 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein) return true; } -void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, double dPriorityDelta, const CAmount& nFeeDelta) +void CTxMemPool::PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, const CAmount& nFeeDelta) { { LOCK(cs); -- cgit v1.2.3 From 00e623d0b8cd1c261a2671aa8ab221a0474bc7c8 Mon Sep 17 00:00:00 2001 From: CryptAxe Date: Tue, 14 Feb 2017 23:00:04 -0800 Subject: [Trivial] Update comments referencing main.cpp --- 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 236527a2b..5842dd88d 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -395,7 +395,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, { NotifyEntryAdded(entry.GetSharedTx()); // Add to memory pool without checking anything. - // Used by main.cpp AcceptToMemoryPool(), which DOES do + // Used by AcceptToMemoryPool(), which DOES do // all the appropriate checks. LOCK(cs); indexed_transaction_set::iterator newit = mapTx.insert(entry).first; -- cgit v1.2.3 From ea060c7495b10394ecf6909bc0327e93a2a34a7f Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 3 Apr 2017 15:50:15 -0400 Subject: Bugfix: ancestor modifed fees were incorrect for descendants If prioritisetransaction was called for a tx with in-mempool descendants, the modified ancestor fee values for those descendants was incorrect. Github-Pull: #10144 Rebased-From: 9bef02e36525d0eed4e2e31678b3ff04bbb0b8cb --- src/txmempool.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/txmempool.cpp') diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 5842dd88d..91040fb9b 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -938,6 +938,13 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const std::string str BOOST_FOREACH(txiter ancestorIt, setAncestors) { mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0)); } + // Now update all descendants' modified fees with ancestors + setEntries setDescendants; + CalculateDescendants(it, setDescendants); + setDescendants.erase(it); + BOOST_FOREACH(txiter descendantIt, setDescendants) { + mapTx.modify(descendantIt, update_ancestor_state(0, nFeeDelta, 0, 0)); + } } } LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta)); -- cgit v1.2.3 From d28d58382076c77dc7f8ec59997c5ce2fde99f70 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 3 Apr 2017 16:31:51 -0400 Subject: Bugfix: PrioritiseTransaction updates the mempool tx counter The mempool's nTransactionsUpdated is used by getblocktemplate to trigger new invocations of CreateNewBlock(). Github-Pull: #10196 Rebased-From: 909306cde3770ed7019e7b635e24cedbd9de66ce --- 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 91040fb9b..72547b582 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -945,6 +945,7 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const std::string str BOOST_FOREACH(txiter descendantIt, setDescendants) { mapTx.modify(descendantIt, update_ancestor_state(0, nFeeDelta, 0, 0)); } + ++nTransactionsUpdated; } } LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta)); -- cgit v1.2.3 From 7b81f4de0a006a6c01b88c79b6ab34a921eb86b5 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Mon, 8 Jan 2018 19:39:10 +0000 Subject: Move COINBASE_MATURITY to the consensus parameters (#1426) --- 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 72547b582..de0a1489e 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -5,6 +5,7 @@ #include "txmempool.h" +#include "chainparams.h" #include "clientversion.h" #include "consensus/consensus.h" #include "consensus/validation.h" @@ -556,7 +557,8 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem 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)) { + int nCoinbaseMaturity = Params().GetConsensus(coins->nHeight).nCoinbaseMaturity; + if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < nCoinbaseMaturity)) { txToRemove.insert(it); break; } -- cgit v1.2.3 From 9c3a11b2488f3e01e6763bc1217598a4d1c69bde Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Sun, 11 Feb 2018 21:00:50 +0000 Subject: Clean up RPC tests (#1465) * Enable full block tests * Fix invalidblocktest * Move watch only address funding to immediately before it's used, so node 0 doesn't spend the output before it checks it later. * Fix `fundrawtransaction` tests and sanitize fee calculation at the same time * Correct resolution of chain parameters when validating tx inputs, especially from previous coinbase transactions * Set block versions on full block tests so that the generated blocks are AuxPoW compatible --- 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 de0a1489e..c6b679aec 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -658,6 +658,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const CCoinsViewCache mempoolDuplicate(const_cast(pcoins)); const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate); + const CChainParams& params = Params(); LOCK(cs); std::list waitingOnDependants; @@ -739,7 +740,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const else { CValidationState state; bool fCheckResult = tx.IsCoinBase() || - Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight); + Consensus::CheckTxInputs(params, tx, state, mempoolDuplicate, nSpendHeight); assert(fCheckResult); UpdateCoins(tx, mempoolDuplicate, 1000000); } @@ -755,7 +756,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const assert(stepsSinceLastRemove < waitingOnDependants.size()); } else { bool fCheckResult = entry->GetTx().IsCoinBase() || - Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight); + Consensus::CheckTxInputs(params, entry->GetTx(), state, mempoolDuplicate, nSpendHeight); assert(fCheckResult); UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000); stepsSinceLastRemove = 0; -- cgit v1.2.3