mempool: Avoid expensive loop in removeForBlock during IBD

During Initial Block Download, the mempool is usually empty, but `CTxMemPool::removeForBlock` is still called for every connected block where we:
* iterate over every transaction in the block even though none will be found in the empty `mapTx`, always leaving `txs_removed_for_block` empty...
* which is pre-allocated regardless with 40 bytes * vtx.size(), even though it will always remain empty.

This change introduces a minor performance optimization by only executing the loop if any of the core mempool maps have any contents.

The call to `MempoolTransactionsRemovedForBlock` and the updates to the rolling fee logic remain unchanged.

The `removeForBlock` was also updated stylistically to match the surrounding methods and a clarification was added to clarify that it affects fee estimation as well.
This commit is contained in:
Lőrinc
2025-06-29 20:20:17 +02:00
parent e9edd43a95
commit 41ad2be434

View File

@@ -661,26 +661,25 @@ void CTxMemPool::removeConflicts(const CTransaction &tx)
}
}
/**
* Called when a block is connected. Removes from mempool.
*/
void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight)
{
// Remove confirmed txs and conflicts when a new block is connected, updating the fee logic
AssertLockHeld(cs);
Assume(!m_have_changeset);
std::vector<RemovedMempoolTransactionInfo> txs_removed_for_block;
txs_removed_for_block.reserve(vtx.size());
for (const auto& tx : vtx)
{
txiter it = mapTx.find(tx->GetHash());
if (it != mapTx.end()) {
setEntries stage;
stage.insert(it);
txs_removed_for_block.emplace_back(*it);
RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK);
if (mapTx.size() || mapNextTx.size() || mapDeltas.size()) {
txs_removed_for_block.reserve(vtx.size());
for (const auto& tx : vtx) {
txiter it = mapTx.find(tx->GetHash());
if (it != mapTx.end()) {
setEntries stage;
stage.insert(it);
txs_removed_for_block.emplace_back(*it);
RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK);
}
removeConflicts(*tx);
ClearPrioritisation(tx->GetHash());
}
removeConflicts(*tx);
ClearPrioritisation(tx->GetHash());
}
if (m_opts.signals) {
m_opts.signals->MempoolTransactionsRemovedForBlock(txs_removed_for_block, nBlockHeight);