mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-02 09:15:04 +02:00
Apply mempool changeset transactions directly into the mempool
Rather than individually calling addUnchecked for each transaction added in a changeset (after removing all the to-be-removed transactions), instead we can take advantage of boost::multi_index's splicing features to extract and insert entries directly from the staging multi_index into mapTx. This has the immediate advantage of saving allocation overhead for mempool entries which have already been allocated once. This also means that the memory locations of mempool entries will not change when transactions go from staging to the main mempool. Additionally, eliminate addUnchecked and require all new transactions to enter the mempool via a CTxMemPoolChangeSet.
This commit is contained in:
@@ -260,13 +260,13 @@ struct TxMempoolInfo
|
||||
*
|
||||
* Usually when a new transaction is added to the mempool, it has no in-mempool
|
||||
* children (because any such children would be an orphan). So in
|
||||
* addUnchecked(), we:
|
||||
* - update a new entry's setMemPoolParents to include all in-mempool parents
|
||||
* - update the new entry's direct parents to include the new tx as a child
|
||||
* addNewTransaction(), we:
|
||||
* - update a new entry's m_parents to include all in-mempool parents
|
||||
* - update each of those parent entries to include the new tx as a child
|
||||
* - update all ancestors of the transaction to include the new tx's size/fee
|
||||
*
|
||||
* When a transaction is removed from the mempool, we must:
|
||||
* - update all in-mempool parents to not track the tx in setMemPoolChildren
|
||||
* - update all in-mempool parents to not track the tx in their m_children
|
||||
* - update all ancestors to not include the tx's size/fees in descendant state
|
||||
* - update all in-mempool children to not include it as a parent
|
||||
*
|
||||
@@ -283,7 +283,7 @@ struct TxMempoolInfo
|
||||
* unreachable from just looking at transactions in the mempool (the linking
|
||||
* transactions may also be in the disconnected block, waiting to be added).
|
||||
* Because of this, there's not much benefit in trying to search for in-mempool
|
||||
* children in addUnchecked(). Instead, in the special case of transactions
|
||||
* children in addNewTransaction(). Instead, in the special case of transactions
|
||||
* being added from a disconnected block, we require the caller to clean up the
|
||||
* state, to account for in-mempool, out-of-block descendants for all the
|
||||
* in-block transactions by calling UpdateTransactionsFromBlock(). Note that
|
||||
@@ -453,15 +453,6 @@ public:
|
||||
*/
|
||||
void check(const CCoinsViewCache& active_coins_tip, int64_t spendheight) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||
|
||||
// addUnchecked must updated state for all ancestors of a given transaction,
|
||||
// to track size/count of descendant transactions. First version of
|
||||
// addUnchecked can be used to have it call CalculateMemPoolAncestors(), and
|
||||
// then invoke the second version.
|
||||
// Note that addUnchecked is ONLY called from ATMP outside of tests
|
||||
// and any other callers may break wallet's in-mempool tracking (due to
|
||||
// lack of CValidationInterface::TransactionAddedToMempool callbacks).
|
||||
void addUnchecked(const CTxMemPoolEntry& entry) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
|
||||
void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
|
||||
|
||||
void removeRecursive(const CTransaction& tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
/** After reorg, filter the entries that would no longer be valid in the next block, and update
|
||||
@@ -791,7 +782,7 @@ private:
|
||||
/** Before calling removeUnchecked for a given transaction,
|
||||
* UpdateForRemoveFromMempool must be called on the entire (dependent) set
|
||||
* of transactions being removed at the same time. We use each
|
||||
* CTxMemPoolEntry's setMemPoolParents in order to walk ancestors of a
|
||||
* CTxMemPoolEntry's m_parents in order to walk ancestors of a
|
||||
* given transaction that is removed, so we can't remove intermediate
|
||||
* transactions in a chain before we've updated all the state for the
|
||||
* removal.
|
||||
@@ -865,9 +856,29 @@ public:
|
||||
// map from the m_to_add index to the ancestors for the transaction
|
||||
std::map<CTxMemPool::txiter, CTxMemPool::setEntries, CompareIteratorByHash> m_ancestors;
|
||||
CTxMemPool::setEntries m_to_remove;
|
||||
|
||||
friend class CTxMemPool;
|
||||
};
|
||||
|
||||
std::unique_ptr<ChangeSet> GetChangeSet() EXCLUSIVE_LOCKS_REQUIRED(cs) { return std::make_unique<ChangeSet>(this); }
|
||||
|
||||
friend class CTxMemPool::ChangeSet;
|
||||
|
||||
private:
|
||||
// Apply the given changeset to the mempool, by removing transactions in
|
||||
// the to_remove set and adding transactions in the to_add set.
|
||||
void Apply(CTxMemPool::ChangeSet* changeset) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
// addNewTransaction must update state for all ancestors of a given transaction,
|
||||
// to track size/count of descendant transactions. First version of
|
||||
// addNewTransaction can be used to have it call CalculateMemPoolAncestors(), and
|
||||
// then invoke the second version.
|
||||
// Note that addNewTransaction is ONLY called (via Apply()) from ATMP
|
||||
// outside of tests and any other callers may break wallet's in-mempool
|
||||
// tracking (due to lack of CValidationInterface::TransactionAddedToMempool
|
||||
// callbacks).
|
||||
void addNewTransaction(CTxMemPool::txiter it) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void addNewTransaction(CTxMemPool::txiter it, CTxMemPool::setEntries& setAncestors) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user