aboutsummaryrefslogtreecommitdiff
path: root/src/txmempool.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/txmempool.h')
-rw-r--r--src/txmempool.h137
1 files changed, 113 insertions, 24 deletions
diff --git a/src/txmempool.h b/src/txmempool.h
index 386cb26d25..9dbb37dad0 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -19,6 +19,7 @@
#include "boost/multi_index/ordered_index.hpp"
class CAutoFile;
+class CBlockIndex;
inline double AllowFreeThreshold()
{
@@ -35,6 +36,21 @@ inline bool AllowFree(double dPriority)
/** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */
static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
+struct LockPoints
+{
+ // Will be set to the blockchain height and median time past
+ // values that would be necessary to satisfy all relative locktime
+ // constraints (BIP68) of this tx given our view of block chain history
+ int height;
+ int64_t time;
+ // As long as the current chain descends from the highest height block
+ // containing one of the inputs used in the calculation, then the cached
+ // values are still valid even after a reorg.
+ CBlockIndex* maxInputBlock;
+
+ LockPoints() : height(0), time(0), maxInputBlock(NULL) { }
+};
+
class CTxMemPool;
/** \class CTxMemPoolEntry
@@ -70,6 +86,7 @@ private:
bool spendsCoinbase; //! keep track of transactions that spend a coinbase
unsigned int sigOpCount; //! Legacy sig ops plus P2SH sig op count
int64_t feeDelta; //! Used for determining the priority of the transaction for mining in a block
+ LockPoints lockPoints; //! Track the height and time at which tx was final
// Information about descendants of this transaction that are in the
// mempool; if we remove this transaction we must remove all of these
@@ -80,11 +97,17 @@ private:
uint64_t nSizeWithDescendants; //! ... and size
CAmount nModFeesWithDescendants; //! ... and total fees (all including us)
+ // Analogous statistics for ancestor transactions
+ uint64_t nCountWithAncestors;
+ uint64_t nSizeWithAncestors;
+ CAmount nModFeesWithAncestors;
+ unsigned int nSigOpCountWithAncestors;
+
public:
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
bool poolHasNoInputsOf, CAmount _inChainInputValue, bool spendsCoinbase,
- unsigned int nSigOps);
+ unsigned int nSigOps, LockPoints lp);
CTxMemPoolEntry(const CTxMemPoolEntry& other);
const CTransaction& GetTx() const { return this->tx; }
@@ -101,25 +124,28 @@ public:
unsigned int GetSigOpCount() const { return sigOpCount; }
int64_t GetModifiedFee() const { return nFee + feeDelta; }
size_t DynamicMemoryUsage() const { return nUsageSize; }
+ const LockPoints& GetLockPoints() const { return lockPoints; }
// Adjusts the descendant state, if this entry is not dirty.
- void UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
+ void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
+ // Adjusts the ancestor state
+ void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps);
// Updates the fee delta used for mining priority score, and the
// modified fees with descendants.
void UpdateFeeDelta(int64_t feeDelta);
-
- /** We can set the entry to be dirty if doing the full calculation of in-
- * mempool descendants will be too expensive, which can potentially happen
- * when re-adding transactions from a block back to the mempool.
- */
- void SetDirty();
- bool IsDirty() const { return nCountWithDescendants == 0; }
+ // Update the LockPoints after a reorg
+ void UpdateLockPoints(const LockPoints& lp);
uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
bool GetSpendsCoinbase() const { return spendsCoinbase; }
+
+ uint64_t GetCountWithAncestors() const { return nCountWithAncestors; }
+ uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
+ CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
+ unsigned int GetSigOpCountWithAncestors() const { return nSigOpCountWithAncestors; }
};
// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.
@@ -130,7 +156,7 @@ struct update_descendant_state
{}
void operator() (CTxMemPoolEntry &e)
- { e.UpdateState(modifySize, modifyFee, modifyCount); }
+ { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); }
private:
int64_t modifySize;
@@ -138,10 +164,20 @@ struct update_descendant_state
int64_t modifyCount;
};
-struct set_dirty
+struct update_ancestor_state
{
+ update_ancestor_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount, int _modifySigOps) :
+ modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifySigOps(_modifySigOps)
+ {}
+
void operator() (CTxMemPoolEntry &e)
- { e.SetDirty(); }
+ { e.UpdateAncestorState(modifySize, modifyFee, modifyCount, modifySigOps); }
+
+ private:
+ int64_t modifySize;
+ CAmount modifyFee;
+ int64_t modifyCount;
+ int modifySigOps;
};
struct update_fee_delta
@@ -154,6 +190,16 @@ private:
int64_t feeDelta;
};
+struct update_lock_points
+{
+ update_lock_points(const LockPoints& _lp) : lp(_lp) { }
+
+ void operator() (CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); }
+
+private:
+ const LockPoints& lp;
+};
+
// extracts a TxMemPoolEntry's transaction hash
struct mempoolentry_txid
{
@@ -228,6 +274,35 @@ public:
}
};
+class CompareTxMemPoolEntryByAncestorFee
+{
+public:
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ {
+ double aFees = a.GetModFeesWithAncestors();
+ double aSize = a.GetSizeWithAncestors();
+
+ double bFees = b.GetModFeesWithAncestors();
+ double bSize = b.GetSizeWithAncestors();
+
+ // Avoid division by rewriting (a/b > c/d) as (a*d > c*b).
+ double f1 = aFees * bSize;
+ double f2 = aSize * bFees;
+
+ if (f1 == f2) {
+ return a.GetTx().GetHash() < b.GetTx().GetHash();
+ }
+
+ return f1 > f2;
+ }
+};
+
+// Multi_index tag names
+struct descendant_score {};
+struct entry_time {};
+struct mining_score {};
+struct ancestor_score {};
+
class CBlockPolicyEstimator;
/** An inpoint - a combination of a transaction and an index n into its vin */
@@ -350,18 +425,27 @@ public:
boost::multi_index::ordered_unique<mempoolentry_txid>,
// sorted by fee rate
boost::multi_index::ordered_non_unique<
+ boost::multi_index::tag<descendant_score>,
boost::multi_index::identity<CTxMemPoolEntry>,
CompareTxMemPoolEntryByDescendantScore
>,
// sorted by entry time
boost::multi_index::ordered_non_unique<
+ boost::multi_index::tag<entry_time>,
boost::multi_index::identity<CTxMemPoolEntry>,
CompareTxMemPoolEntryByEntryTime
- >,
+ >,
// sorted by score (for mining prioritization)
boost::multi_index::ordered_unique<
+ boost::multi_index::tag<mining_score>,
boost::multi_index::identity<CTxMemPoolEntry>,
CompareTxMemPoolEntryByScore
+ >,
+ // sorted by fee rate with ancestors
+ boost::multi_index::ordered_non_unique<
+ boost::multi_index::tag<ancestor_score>,
+ boost::multi_index::identity<CTxMemPoolEntry>,
+ CompareTxMemPoolEntryByAncestorFee
>
>
> indexed_transaction_set;
@@ -420,7 +504,7 @@ public:
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true);
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate = true);
- void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false);
+ void removeRecursive(const CTransaction &tx, std::list<CTransaction>& removed);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed);
void removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight,
@@ -445,8 +529,12 @@ public:
public:
/** Remove a set of transactions from the mempool.
* If a transaction is in this set, then all in-mempool descendants must
- * also be in the set.*/
- void RemoveStaged(setEntries &stage);
+ * also be in the set, unless this transaction is being removed for being
+ * in a block.
+ * Set updateDescendants to true when removing a tx that was in a block, so
+ * that any in-mempool descendants have their ancestor state updated.
+ */
+ void RemoveStaged(setEntries &stage, bool updateDescendants);
/** When adding transactions from a disconnected block back to the mempool,
* new mempool entries may have children in the mempool (which is generally
@@ -469,7 +557,7 @@ public:
* fSearchForParents = whether to search a tx's vin for in-mempool parents, or
* look up parents from mapLinks. Must be true for entries not in the mempool
*/
- bool 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 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;
/** Populate setDescendants with all in-mempool descendants of hash.
* Assumes that setDescendants includes all in-mempool descendants of anything
@@ -512,6 +600,7 @@ public:
}
bool lookup(uint256 hash, CTransaction& result) const;
+ bool lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const;
/** Estimate fee rate needed to get into the next nBlocks
* If no answer can be given at nBlocks, return an estimate
@@ -547,21 +636,21 @@ private:
* updated and hence their state is already reflected in the parent
* state).
*
- * If updating an entry requires looking at more than maxDescendantsToVisit
- * transactions, outside of the ones in setExclude, then give up.
- *
* cachedDescendants will be updated with the descendants of the transaction
* being updated, so that future invocations don't need to walk the
* same transaction again, if encountered in another transaction chain.
*/
- bool UpdateForDescendants(txiter updateIt,
- int maxDescendantsToVisit,
+ void UpdateForDescendants(txiter updateIt,
cacheMap &cachedDescendants,
const std::set<uint256> &setExclude);
/** Update ancestors of hash to add/remove it as a descendant transaction. */
void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors);
- /** For each transaction being removed, update ancestors and any direct children. */
- void UpdateForRemoveFromMempool(const setEntries &entriesToRemove);
+ /** Set ancestor state for an entry */
+ void UpdateEntryForAncestors(txiter it, const setEntries &setAncestors);
+ /** For each transaction being removed, update ancestors and any direct children.
+ * If updateDescendants is true, then also update in-mempool descendants'
+ * ancestor state. */
+ void UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants);
/** Sever link between specified transaction and direct children. */
void UpdateChildrenForRemoval(txiter entry);