Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2023-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <kernel/disconnected_transactions.h>7#include <cassert>8#include <core_memusage.h>9#include <memusage.h>10#include <primitives/transaction.h>11#include <util/hasher.h>13#include <memory>14#include <utility>16// It's almost certainly a logic bug if we don't clear out queuedTx before17// destruction, as we add to it while disconnecting blocks, and then we18// need to re-process remaining transactions to ensure mempool consistency.19// For now, assert() that we've emptied out this object on destruction.20// This assert() can always be removed if the reorg-processing code were21// to be refactored such that this assumption is no longer true (for22// instance if there was some other way we cleaned up the mempool after a23// reorg, besides draining this object).24DisconnectedBlockTransactions::~DisconnectedBlockTransactions()25{26assert(queuedTx.empty());27assert(iters_by_txid.empty());28assert(cachedInnerUsage == 0);29}31std::vector<CTransactionRef> DisconnectedBlockTransactions::LimitMemoryUsage()32{33std::vector<CTransactionRef> evicted;35while (!queuedTx.empty() && DynamicMemoryUsage() > m_max_mem_usage) {36evicted.emplace_back(queuedTx.front());37cachedInnerUsage -= RecursiveDynamicUsage(queuedTx.front());38iters_by_txid.erase(queuedTx.front()->GetHash());39queuedTx.pop_front();40}41return evicted;42}44size_t DisconnectedBlockTransactions::DynamicMemoryUsage() const45{46return cachedInnerUsage + memusage::DynamicUsage(iters_by_txid) + memusage::DynamicUsage(queuedTx);47}49[[nodiscard]] std::vector<CTransactionRef> DisconnectedBlockTransactions::AddTransactionsFromBlock(const std::vector<CTransactionRef>& vtx)50{51iters_by_txid.reserve(iters_by_txid.size() + vtx.size());52for (auto block_it = vtx.rbegin(); block_it != vtx.rend(); ++block_it) {53auto it = queuedTx.insert(queuedTx.end(), *block_it);54auto [_, inserted] = iters_by_txid.emplace((*block_it)->GetHash(), it);55assert(inserted); // callers may never pass multiple transactions with the same txid56cachedInnerUsage += RecursiveDynamicUsage(*block_it);57}58return LimitMemoryUsage();59}61void DisconnectedBlockTransactions::removeForBlock(const std::vector<CTransactionRef>& vtx)62{63// Short-circuit in the common case of a block being added to the tip64if (queuedTx.empty()) {65return;66}67for (const auto& tx : vtx) {68auto iter = iters_by_txid.find(tx->GetHash());69if (iter != iters_by_txid.end()) {70auto list_iter = iter->second;71iters_by_txid.erase(iter);72cachedInnerUsage -= RecursiveDynamicUsage(*list_iter);73queuedTx.erase(list_iter);74}75}76}78void DisconnectedBlockTransactions::clear()79{80cachedInnerUsage = 0;81iters_by_txid.clear();82queuedTx.clear();83}85std::list<CTransactionRef> DisconnectedBlockTransactions::take()86{87std::list<CTransactionRef> ret = std::move(queuedTx);88clear();89return ret;90}