Merge #7594: Mempool: Add tracking of ancestor packages
ce019bfCheck all ancestor state in CTxMemPool::check() (Suhas Daftuar)e2eeb5dAdd ancestor feerate index to mempool (Suhas Daftuar)72abd2cAdd ancestor tracking to mempool (Suhas Daftuar)76a7632Remove work limit in UpdateForDescendants() (Suhas Daftuar)5de2baaRename CTxMemPool::remove -> removeRecursive (Suhas Daftuar)7659438CTxMemPool::removeForBlock now uses RemoveStaged (Suhas Daftuar)
This commit is contained in:
@@ -97,6 +97,12 @@ 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,
|
||||
@@ -121,25 +127,25 @@ public:
|
||||
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);
|
||||
// Update the LockPoints after a reorg
|
||||
void UpdateLockPoints(const LockPoints& lp);
|
||||
|
||||
/** 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; }
|
||||
|
||||
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.
|
||||
@@ -150,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;
|
||||
@@ -158,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
|
||||
@@ -258,10 +274,34 @@ 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;
|
||||
|
||||
@@ -394,12 +434,18 @@ public:
|
||||
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;
|
||||
@@ -458,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,
|
||||
@@ -483,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
|
||||
@@ -507,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
|
||||
@@ -585,21 +635,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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user