2013-08-27 07:51:57 +02:00
|
|
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
2014-12-17 02:47:57 +01:00
|
|
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
2014-11-17 03:29:09 +01:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
2013-08-27 07:51:57 +02:00
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
#include "txmempool.h"
|
2014-09-14 12:43:56 +02:00
|
|
|
|
2014-10-29 02:33:23 +01:00
|
|
|
#include "clientversion.h"
|
2015-01-24 15:29:29 +01:00
|
|
|
#include "consensus/consensus.h"
|
2015-01-24 15:57:12 +01:00
|
|
|
#include "consensus/validation.h"
|
2014-11-12 06:06:15 +01:00
|
|
|
#include "main.h"
|
2014-08-26 22:28:32 +02:00
|
|
|
#include "policy/fees.h"
|
2014-10-22 21:08:30 +02:00
|
|
|
#include "streams.h"
|
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
|
|
|
#include "util.h"
|
2014-04-23 00:46:19 +02:00
|
|
|
#include "utilmoneystr.h"
|
2015-10-02 23:19:55 +02:00
|
|
|
#include "utiltime.h"
|
2014-09-25 05:32:36 +02:00
|
|
|
#include "version.h"
|
2013-08-27 07:51:57 +02:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2014-04-23 00:46:19 +02:00
|
|
|
CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
2013-11-11 08:35:14 +01:00
|
|
|
int64_t _nTime, double _dPriority,
|
2014-08-26 22:28:32 +02:00
|
|
|
unsigned int _nHeight, bool poolHasNoInputsOf):
|
|
|
|
tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight),
|
|
|
|
hadNoDependencies(poolHasNoInputsOf)
|
2013-11-11 08:35:14 +01:00
|
|
|
{
|
|
|
|
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
2014-08-26 18:59:21 +02:00
|
|
|
nModSize = tx.CalculateModifiedSize(nTxSize);
|
2015-07-17 19:46:18 +02:00
|
|
|
nUsageSize = RecursiveDynamicUsage(tx);
|
2015-07-15 20:47:45 +02:00
|
|
|
|
|
|
|
nCountWithDescendants = 1;
|
|
|
|
nSizeWithDescendants = nTxSize;
|
|
|
|
nFeesWithDescendants = nFee;
|
2013-11-11 08:35:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
|
|
|
|
{
|
|
|
|
*this = other;
|
|
|
|
}
|
|
|
|
|
|
|
|
double
|
|
|
|
CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
|
|
|
|
{
|
2014-04-23 00:46:19 +02:00
|
|
|
CAmount nValueIn = tx.GetValueOut()+nFee;
|
2014-08-26 18:59:21 +02:00
|
|
|
double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nModSize;
|
2013-11-11 08:35:14 +01:00
|
|
|
double dResult = dPriority + deltaPriority;
|
|
|
|
return dResult;
|
|
|
|
}
|
|
|
|
|
2015-07-15 20:47:45 +02:00
|
|
|
// 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<uint256> &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<uint256> &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<uint256> 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<COutPoint, CInPoint>::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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-23 19:37:32 +02:00
|
|
|
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 */)
|
2015-07-15 20:47:45 +02:00
|
|
|
{
|
|
|
|
setEntries parentHashes;
|
|
|
|
const CTransaction &tx = entry.GetTx();
|
|
|
|
|
2015-09-23 19:37:32 +02:00
|
|
|
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;
|
|
|
|
}
|
2015-07-15 20:47:45 +02:00
|
|
|
}
|
|
|
|
}
|
2015-09-23 19:37:32 +02:00
|
|
|
} 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);
|
2015-07-15 20:47:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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<uint64_t>::max();
|
|
|
|
BOOST_FOREACH(txiter removeIt, entriesToRemove) {
|
|
|
|
setEntries setAncestors;
|
|
|
|
const CTxMemPoolEntry &entry = *removeIt;
|
|
|
|
std::string dummy;
|
2015-09-23 19:37:32 +02:00
|
|
|
// 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);
|
2015-07-15 20:47:45 +02:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-13 09:57:41 +02:00
|
|
|
CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) :
|
2014-08-26 22:28:32 +02:00
|
|
|
nTransactionsUpdated(0)
|
2013-08-27 07:51:57 +02:00
|
|
|
{
|
2015-10-26 14:55:17 +01:00
|
|
|
_clear(); //lock free clear
|
2015-10-02 23:19:55 +02:00
|
|
|
|
2013-08-27 07:51:57 +02:00
|
|
|
// 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
|
2015-10-07 23:34:55 +02:00
|
|
|
nCheckFrequency = 0;
|
2014-03-17 13:19:54 +01:00
|
|
|
|
2015-10-13 09:57:41 +02:00
|
|
|
minerPolicyEstimator = new CBlockPolicyEstimator(_minReasonableRelayFee);
|
|
|
|
minReasonableRelayFee = _minReasonableRelayFee;
|
2014-03-17 13:19:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CTxMemPool::~CTxMemPool()
|
|
|
|
{
|
|
|
|
delete minerPolicyEstimator;
|
2013-08-27 07:51:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
|
|
|
|
std::map<COutPoint, CInPoint>::iterator 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
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int CTxMemPool::GetTransactionsUpdated() const
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
return nTransactionsUpdated;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CTxMemPool::AddTransactionsUpdated(unsigned int n)
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
nTransactionsUpdated += n;
|
|
|
|
}
|
|
|
|
|
2015-07-15 20:47:45 +02:00
|
|
|
bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate)
|
2013-08-27 07:51:57 +02:00
|
|
|
{
|
|
|
|
// Add to memory pool without checking anything.
|
|
|
|
// Used by main.cpp AcceptToMemoryPool(), which DOES do
|
|
|
|
// all the appropriate checks.
|
|
|
|
LOCK(cs);
|
2015-07-15 20:47:45 +02:00
|
|
|
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<uint256> setParentTransactions;
|
|
|
|
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
2014-08-26 22:28:32 +02:00
|
|
|
mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i);
|
2015-07-15 20:47:45 +02:00
|
|
|
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);
|
|
|
|
|
2014-08-26 22:28:32 +02:00
|
|
|
nTransactionsUpdated++;
|
|
|
|
totalTxSize += entry.GetTxSize();
|
|
|
|
minerPolicyEstimator->processTransaction(entry, fCurrentEstimate);
|
|
|
|
|
2013-08-27 07:51:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-07-15 20:47:45 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-27 07:51:57 +02:00
|
|
|
|
2014-11-18 23:57:20 +01:00
|
|
|
void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& removed, bool fRecursive)
|
2013-08-27 07:51:57 +02:00
|
|
|
{
|
|
|
|
// Remove transaction from memory pool
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
2015-07-15 20:47:45 +02:00
|
|
|
setEntries txToRemove;
|
|
|
|
txiter origit = mapTx.find(origTx.GetHash());
|
|
|
|
if (origit != mapTx.end()) {
|
|
|
|
txToRemove.insert(origit);
|
|
|
|
} else if (fRecursive) {
|
2015-03-25 18:13:09 +01:00
|
|
|
// 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
|
|
|
|
// the mempool for any reason.
|
|
|
|
for (unsigned int i = 0; i < origTx.vout.size(); i++) {
|
|
|
|
std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(origTx.GetHash(), i));
|
|
|
|
if (it == mapNextTx.end())
|
|
|
|
continue;
|
2015-07-15 20:47:45 +02:00
|
|
|
txiter nextit = mapTx.find(it->second.ptx->GetHash());
|
|
|
|
assert(nextit != mapTx.end());
|
|
|
|
txToRemove.insert(nextit);
|
2015-03-25 18:13:09 +01:00
|
|
|
}
|
|
|
|
}
|
2015-07-15 20:47:45 +02:00
|
|
|
setEntries setAllRemoves;
|
|
|
|
if (fRecursive) {
|
|
|
|
BOOST_FOREACH(txiter it, txToRemove) {
|
|
|
|
CalculateDescendants(it, setAllRemoves);
|
2014-11-18 23:57:20 +01:00
|
|
|
}
|
2015-07-15 20:47:45 +02:00
|
|
|
} else {
|
|
|
|
setAllRemoves.swap(txToRemove);
|
|
|
|
}
|
|
|
|
BOOST_FOREACH(txiter it, setAllRemoves) {
|
|
|
|
removed.push_back(it->GetTx());
|
2013-08-27 07:51:57 +02:00
|
|
|
}
|
2015-07-15 20:47:45 +02:00
|
|
|
RemoveStaged(setAllRemoves);
|
2013-08-27 07:51:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-12 05:57:54 +01:00
|
|
|
void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight)
|
|
|
|
{
|
|
|
|
// Remove transactions spending a coinbase which are now immature
|
|
|
|
LOCK(cs);
|
|
|
|
list<CTransaction> transactionsToRemove;
|
2015-06-24 10:32:20 +02:00
|
|
|
for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
|
|
|
|
const CTransaction& tx = it->GetTx();
|
2014-11-12 05:57:54 +01:00
|
|
|
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
2015-06-24 10:32:20 +02:00
|
|
|
indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
|
2014-11-12 05:57:54 +01:00
|
|
|
if (it2 != mapTx.end())
|
|
|
|
continue;
|
|
|
|
const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash);
|
2015-10-07 23:34:55 +02:00
|
|
|
if (nCheckFrequency != 0) assert(coins);
|
2015-05-13 22:04:39 +02:00
|
|
|
if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) {
|
2014-11-12 05:57:54 +01:00
|
|
|
transactionsToRemove.push_back(tx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) {
|
|
|
|
list<CTransaction> removed;
|
|
|
|
remove(tx, removed, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-15 22:38:28 +01:00
|
|
|
void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed)
|
2013-08-27 07:51:57 +02:00
|
|
|
{
|
|
|
|
// Remove transactions which depend on inputs of tx, recursively
|
2014-07-17 14:09:55 +02:00
|
|
|
list<CTransaction> result;
|
2013-08-27 07:51:57 +02:00
|
|
|
LOCK(cs);
|
|
|
|
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
|
|
|
|
std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(txin.prevout);
|
|
|
|
if (it != mapNextTx.end()) {
|
|
|
|
const CTransaction &txConflict = *it->second.ptx;
|
|
|
|
if (txConflict != tx)
|
2014-02-15 22:38:28 +01:00
|
|
|
{
|
|
|
|
remove(txConflict, removed, true);
|
2015-08-03 21:49:01 +02:00
|
|
|
ClearPrioritisation(txConflict.GetHash());
|
2014-02-15 22:38:28 +01:00
|
|
|
}
|
2013-08-27 07:51:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-17 03:29:09 +01:00
|
|
|
/**
|
|
|
|
* Called when a block is connected. Removes from mempool and updates the miner fee estimator.
|
|
|
|
*/
|
2014-03-17 13:19:54 +01:00
|
|
|
void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight,
|
2014-08-26 22:28:32 +02:00
|
|
|
std::list<CTransaction>& conflicts, bool fCurrentEstimate)
|
2014-03-17 13:19:54 +01:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
std::vector<CTxMemPoolEntry> entries;
|
|
|
|
BOOST_FOREACH(const CTransaction& tx, vtx)
|
|
|
|
{
|
|
|
|
uint256 hash = tx.GetHash();
|
2015-06-24 10:32:20 +02:00
|
|
|
|
|
|
|
indexed_transaction_set::iterator i = mapTx.find(hash);
|
|
|
|
if (i != mapTx.end())
|
|
|
|
entries.push_back(*i);
|
2014-03-17 13:19:54 +01:00
|
|
|
}
|
|
|
|
BOOST_FOREACH(const CTransaction& tx, vtx)
|
|
|
|
{
|
|
|
|
std::list<CTransaction> dummy;
|
|
|
|
remove(tx, dummy, false);
|
|
|
|
removeConflicts(tx, conflicts);
|
2012-07-11 20:52:41 +02:00
|
|
|
ClearPrioritisation(tx.GetHash());
|
2014-03-17 13:19:54 +01:00
|
|
|
}
|
2014-08-26 22:28:32 +02:00
|
|
|
// After the txs in the new block have been removed from the mempool, update policy estimates
|
|
|
|
minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate);
|
2015-10-02 23:19:55 +02:00
|
|
|
lastRollingFeeUpdate = GetTime();
|
|
|
|
blockSinceLastRollingFeeBump = true;
|
2014-03-17 13:19:54 +01:00
|
|
|
}
|
|
|
|
|
2015-10-26 14:55:17 +01:00
|
|
|
void CTxMemPool::_clear()
|
2013-08-27 07:51:57 +02:00
|
|
|
{
|
2015-07-15 20:47:45 +02:00
|
|
|
mapLinks.clear();
|
2013-08-27 07:51:57 +02:00
|
|
|
mapTx.clear();
|
|
|
|
mapNextTx.clear();
|
2014-08-07 05:58:19 +02:00
|
|
|
totalTxSize = 0;
|
2015-07-09 19:56:31 +02:00
|
|
|
cachedInnerUsage = 0;
|
2015-10-02 23:19:55 +02:00
|
|
|
lastRollingFeeUpdate = GetTime();
|
|
|
|
blockSinceLastRollingFeeBump = false;
|
|
|
|
rollingMinimumFeeRate = 0;
|
2013-08-27 07:51:57 +02:00
|
|
|
++nTransactionsUpdated;
|
|
|
|
}
|
|
|
|
|
2015-10-26 14:55:17 +01:00
|
|
|
void CTxMemPool::clear()
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
_clear();
|
|
|
|
}
|
|
|
|
|
2014-07-19 17:14:23 +02:00
|
|
|
void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
2013-08-27 07:51:57 +02:00
|
|
|
{
|
2015-10-07 23:34:55 +02:00
|
|
|
if (nCheckFrequency == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (insecure_rand() >= nCheckFrequency)
|
2013-08-27 07:51:57 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
|
|
|
|
|
2014-08-07 05:58:19 +02:00
|
|
|
uint64_t checkTotal = 0;
|
2015-07-09 19:56:31 +02:00
|
|
|
uint64_t innerUsage = 0;
|
2014-08-07 05:58:19 +02:00
|
|
|
|
2014-11-12 06:06:15 +01:00
|
|
|
CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins));
|
|
|
|
|
2013-08-27 07:51:57 +02:00
|
|
|
LOCK(cs);
|
2014-11-12 06:06:15 +01:00
|
|
|
list<const CTxMemPoolEntry*> waitingOnDependants;
|
2015-06-24 10:32:20 +02:00
|
|
|
for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
|
2013-08-27 07:51:57 +02:00
|
|
|
unsigned int i = 0;
|
2015-06-24 10:32:20 +02:00
|
|
|
checkTotal += it->GetTxSize();
|
|
|
|
innerUsage += it->DynamicMemoryUsage();
|
|
|
|
const CTransaction& tx = it->GetTx();
|
2015-07-15 20:47:45 +02:00
|
|
|
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);
|
2014-11-12 06:06:15 +01:00
|
|
|
bool fDependsWait = false;
|
2015-07-15 20:47:45 +02:00
|
|
|
setEntries setParentCheck;
|
2013-11-11 08:35:14 +01:00
|
|
|
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
|
2013-08-27 07:51:57 +02:00
|
|
|
// Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
|
2015-06-24 10:32:20 +02:00
|
|
|
indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
|
2013-08-27 07:51:57 +02:00
|
|
|
if (it2 != mapTx.end()) {
|
2015-06-24 10:32:20 +02:00
|
|
|
const CTransaction& tx2 = it2->GetTx();
|
2013-11-11 08:35:14 +01:00
|
|
|
assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull());
|
2014-11-12 06:06:15 +01:00
|
|
|
fDependsWait = true;
|
2015-07-15 20:47:45 +02:00
|
|
|
setParentCheck.insert(it2);
|
2013-08-27 07:51:57 +02:00
|
|
|
} else {
|
2014-09-02 21:21:15 +02:00
|
|
|
const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash);
|
|
|
|
assert(coins && coins->IsAvailable(txin.prevout.n));
|
2013-08-27 07:51:57 +02:00
|
|
|
}
|
|
|
|
// Check whether its inputs are marked in mapNextTx.
|
|
|
|
std::map<COutPoint, CInPoint>::const_iterator it3 = mapNextTx.find(txin.prevout);
|
|
|
|
assert(it3 != mapNextTx.end());
|
2013-11-11 08:35:14 +01:00
|
|
|
assert(it3->second.ptx == &tx);
|
2013-08-27 07:51:57 +02:00
|
|
|
assert(it3->second.n == i);
|
|
|
|
i++;
|
|
|
|
}
|
2015-07-15 20:47:45 +02:00
|
|
|
assert(setParentCheck == GetMemPoolParents(it));
|
|
|
|
// Check children against mapNextTx
|
|
|
|
CTxMemPool::setEntries setChildrenCheck;
|
|
|
|
std::map<COutPoint, CInPoint>::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);
|
|
|
|
|
2014-11-12 06:06:15 +01:00
|
|
|
if (fDependsWait)
|
2015-06-24 10:32:20 +02:00
|
|
|
waitingOnDependants.push_back(&(*it));
|
2014-11-12 06:06:15 +01:00
|
|
|
else {
|
2014-10-27 16:07:50 +01:00
|
|
|
CValidationState state;
|
2014-11-12 06:06:15 +01:00
|
|
|
assert(CheckInputs(tx, state, mempoolDuplicate, false, 0, false, NULL));
|
2014-10-27 16:07:50 +01:00
|
|
|
UpdateCoins(tx, state, mempoolDuplicate, 1000000);
|
2014-11-12 06:06:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
unsigned int stepsSinceLastRemove = 0;
|
|
|
|
while (!waitingOnDependants.empty()) {
|
|
|
|
const CTxMemPoolEntry* entry = waitingOnDependants.front();
|
|
|
|
waitingOnDependants.pop_front();
|
|
|
|
CValidationState state;
|
|
|
|
if (!mempoolDuplicate.HaveInputs(entry->GetTx())) {
|
|
|
|
waitingOnDependants.push_back(entry);
|
|
|
|
stepsSinceLastRemove++;
|
|
|
|
assert(stepsSinceLastRemove < waitingOnDependants.size());
|
|
|
|
} else {
|
|
|
|
assert(CheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, NULL));
|
2014-10-27 16:07:50 +01:00
|
|
|
UpdateCoins(entry->GetTx(), state, mempoolDuplicate, 1000000);
|
2014-11-12 06:06:15 +01:00
|
|
|
stepsSinceLastRemove = 0;
|
|
|
|
}
|
2013-08-27 07:51:57 +02:00
|
|
|
}
|
|
|
|
for (std::map<COutPoint, CInPoint>::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) {
|
|
|
|
uint256 hash = it->second.ptx->GetHash();
|
2015-06-24 10:32:20 +02:00
|
|
|
indexed_transaction_set::const_iterator it2 = mapTx.find(hash);
|
|
|
|
const CTransaction& tx = it2->GetTx();
|
2013-08-27 07:51:57 +02:00
|
|
|
assert(it2 != mapTx.end());
|
2013-11-11 08:35:14 +01:00
|
|
|
assert(&tx == it->second.ptx);
|
|
|
|
assert(tx.vin.size() > it->second.n);
|
2013-08-27 07:51:57 +02:00
|
|
|
assert(it->first == it->second.ptx->vin[it->second.n].prevout);
|
|
|
|
}
|
2014-08-07 05:58:19 +02:00
|
|
|
|
|
|
|
assert(totalTxSize == checkTotal);
|
2015-07-09 19:56:31 +02:00
|
|
|
assert(innerUsage == cachedInnerUsage);
|
2013-08-27 07:51:57 +02:00
|
|
|
}
|
|
|
|
|
2013-11-11 08:35:14 +01:00
|
|
|
void CTxMemPool::queryHashes(vector<uint256>& vtxid)
|
2013-08-27 07:51:57 +02:00
|
|
|
{
|
|
|
|
vtxid.clear();
|
|
|
|
|
|
|
|
LOCK(cs);
|
|
|
|
vtxid.reserve(mapTx.size());
|
2015-06-24 10:32:20 +02:00
|
|
|
for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
|
|
|
|
vtxid.push_back(mi->GetTx().GetHash());
|
2013-08-27 07:51:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
2015-06-24 10:32:20 +02:00
|
|
|
indexed_transaction_set::const_iterator i = mapTx.find(hash);
|
2013-08-27 07:51:57 +02:00
|
|
|
if (i == mapTx.end()) return false;
|
2015-06-24 10:32:20 +02:00
|
|
|
result = i->GetTx();
|
2013-08-27 07:51:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
2013-11-05 02:47:07 +01:00
|
|
|
|
2014-03-17 13:19:54 +01:00
|
|
|
CFeeRate CTxMemPool::estimateFee(int nBlocks) const
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
return minerPolicyEstimator->estimateFee(nBlocks);
|
|
|
|
}
|
|
|
|
double CTxMemPool::estimatePriority(int nBlocks) const
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
return minerPolicyEstimator->estimatePriority(nBlocks);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
LOCK(cs);
|
2014-08-26 22:28:32 +02:00
|
|
|
fileout << 109900; // version required to read: 0.10.99 or later
|
2014-03-17 13:19:54 +01:00
|
|
|
fileout << CLIENT_VERSION; // version that wrote the file
|
|
|
|
minerPolicyEstimator->Write(fileout);
|
|
|
|
}
|
2014-12-07 13:29:06 +01:00
|
|
|
catch (const std::exception&) {
|
2015-07-31 16:41:06 +02:00
|
|
|
LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)\n");
|
2014-03-17 13:19:54 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
int nVersionRequired, nVersionThatWrote;
|
|
|
|
filein >> nVersionRequired >> nVersionThatWrote;
|
|
|
|
if (nVersionRequired > CLIENT_VERSION)
|
2015-01-08 11:44:25 +01:00
|
|
|
return error("CTxMemPool::ReadFeeEstimates(): up-version (%d) fee estimate file", nVersionRequired);
|
2014-03-17 13:19:54 +01:00
|
|
|
|
|
|
|
LOCK(cs);
|
2014-08-26 22:28:32 +02:00
|
|
|
minerPolicyEstimator->Read(filein);
|
2014-03-17 13:19:54 +01:00
|
|
|
}
|
2014-12-07 13:29:06 +01:00
|
|
|
catch (const std::exception&) {
|
2015-07-31 16:41:06 +02:00
|
|
|
LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)\n");
|
2014-03-17 13:19:54 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-04-23 00:46:19 +02:00
|
|
|
void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, double dPriorityDelta, const CAmount& nFeeDelta)
|
2012-07-11 20:52:41 +02:00
|
|
|
{
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
2014-04-23 00:46:19 +02:00
|
|
|
std::pair<double, CAmount> &deltas = mapDeltas[hash];
|
2012-07-11 20:52:41 +02:00
|
|
|
deltas.first += dPriorityDelta;
|
|
|
|
deltas.second += nFeeDelta;
|
|
|
|
}
|
2014-04-23 00:46:19 +02:00
|
|
|
LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta));
|
2012-07-11 20:52:41 +02:00
|
|
|
}
|
|
|
|
|
2015-10-02 23:17:27 +02:00
|
|
|
void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const
|
2012-07-11 20:52:41 +02:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
2015-10-02 23:17:27 +02:00
|
|
|
std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
|
2012-07-11 20:52:41 +02:00
|
|
|
if (pos == mapDeltas.end())
|
|
|
|
return;
|
2014-04-23 00:46:19 +02:00
|
|
|
const std::pair<double, CAmount> &deltas = pos->second;
|
2012-07-11 20:52:41 +02:00
|
|
|
dPriorityDelta += deltas.first;
|
|
|
|
nFeeDelta += deltas.second;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CTxMemPool::ClearPrioritisation(const uint256 hash)
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
mapDeltas.erase(hash);
|
|
|
|
}
|
|
|
|
|
2014-08-26 22:28:32 +02:00
|
|
|
bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
|
|
|
|
{
|
|
|
|
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
|
|
|
if (exists(tx.vin[i].prevout.hash))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
2014-03-17 13:19:54 +01:00
|
|
|
|
2014-09-24 03:19:04 +02:00
|
|
|
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
|
2013-11-05 02:47:07 +01:00
|
|
|
|
2014-07-19 16:42:48 +02:00
|
|
|
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
|
2014-07-23 15:28:45 +02:00
|
|
|
// 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.
|
2013-11-05 02:47:07 +01:00
|
|
|
CTransaction tx;
|
|
|
|
if (mempool.lookup(txid, tx)) {
|
|
|
|
coins = CCoins(tx, MEMPOOL_HEIGHT);
|
|
|
|
return true;
|
|
|
|
}
|
2014-07-23 15:28:45 +02:00
|
|
|
return (base->GetCoins(txid, coins) && !coins.IsPruned());
|
2013-11-05 02:47:07 +01:00
|
|
|
}
|
|
|
|
|
2014-07-19 16:42:48 +02:00
|
|
|
bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const {
|
2013-11-05 02:47:07 +01:00
|
|
|
return mempool.exists(txid) || base->HaveCoins(txid);
|
|
|
|
}
|
2015-07-09 19:56:31 +02:00
|
|
|
|
|
|
|
size_t CTxMemPool::DynamicMemoryUsage() const {
|
|
|
|
LOCK(cs);
|
2015-07-15 20:47:45 +02:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 23:43:30 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2015-07-15 20:47:45 +02:00
|
|
|
bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate)
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
setEntries setAncestors;
|
|
|
|
uint64_t nNoLimit = std::numeric_limits<uint64_t>::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;
|
2015-07-09 19:56:31 +02:00
|
|
|
}
|
2015-10-02 23:19:55 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2015-10-14 21:44:18 +02:00
|
|
|
if (rollingMinimumFeeRate < minReasonableRelayFee.GetFeePerK() / 2) {
|
2015-10-02 23:19:55 +02:00
|
|
|
rollingMinimumFeeRate = 0;
|
2015-10-14 21:44:18 +02:00
|
|
|
return CFeeRate(0);
|
|
|
|
}
|
2015-10-02 23:19:55 +02:00
|
|
|
}
|
|
|
|
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();
|
|
|
|
|
2015-10-19 11:40:25 +02:00
|
|
|
// 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.
|
2015-10-02 23:19:55 +02:00
|
|
|
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());
|
|
|
|
}
|