Inside Bitcoin
Opening the selected file…
Inside Bitcoin
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) 2024-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 <node/txdownloadman_impl.h>6#include <node/txdownloadman.h>8#include <chain.h>9#include <consensus/validation.h>10#include <txmempool.h>11#include <util/log.h>12#include <validation.h>13#include <validationinterface.h>15namespace node {16// TxDownloadManager wrappers17TxDownloadManager::TxDownloadManager(const TxDownloadOptions& options) :18m_impl{std::make_unique<TxDownloadManagerImpl>(options)}19{}20TxDownloadManager::~TxDownloadManager() = default;22void TxDownloadManager::ActiveTipChange()23{24m_impl->ActiveTipChange();25}26void TxDownloadManager::BlockConnected(const std::shared_ptr<const CBlock>& pblock)27{28m_impl->BlockConnected(pblock);29}30void TxDownloadManager::BlockDisconnected()31{32m_impl->BlockDisconnected();33}34void TxDownloadManager::ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo& info)35{36m_impl->ConnectedPeer(nodeid, info);37}38void TxDownloadManager::DisconnectedPeer(NodeId nodeid)39{40m_impl->DisconnectedPeer(nodeid);41}42bool TxDownloadManager::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now)43{44return m_impl->AddTxAnnouncement(peer, gtxid, now);45}46std::vector<GenTxid> TxDownloadManager::GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)47{48return m_impl->GetRequestsToSend(nodeid, current_time);49}50void TxDownloadManager::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& gtxids)51{52m_impl->ReceivedNotFound(nodeid, gtxids);53}54void TxDownloadManager::MempoolAcceptedTx(const CTransactionRef& tx)55{56m_impl->MempoolAcceptedTx(tx);57}58RejectedTxTodo TxDownloadManager::MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure)59{60return m_impl->MempoolRejectedTx(ptx, state, nodeid, first_time_failure);61}62void TxDownloadManager::MempoolRejectedPackage(const Package& package)63{64m_impl->MempoolRejectedPackage(package);65}66std::pair<bool, std::optional<PackageToValidate>> TxDownloadManager::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx)67{68return m_impl->ReceivedTx(nodeid, ptx);69}70bool TxDownloadManager::HaveMoreWork(NodeId nodeid) const71{72return m_impl->HaveMoreWork(nodeid);73}74CTransactionRef TxDownloadManager::GetTxToReconsider(NodeId nodeid)75{76return m_impl->GetTxToReconsider(nodeid);77}78void TxDownloadManager::CheckIsEmpty() const79{80m_impl->CheckIsEmpty();81}82void TxDownloadManager::CheckIsEmpty(NodeId nodeid) const83{84m_impl->CheckIsEmpty(nodeid);85}86std::vector<TxOrphanage::OrphanInfo> TxDownloadManager::GetOrphanTransactions() const87{88return m_impl->GetOrphanTransactions();89}91// TxDownloadManagerImpl92void TxDownloadManagerImpl::ActiveTipChange()93{94RecentRejectsFilter().reset();95RecentRejectsReconsiderableFilter().reset();96}98void TxDownloadManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock)99{100m_orphanage->EraseForBlock(*pblock);102for (const auto& ptx : pblock->vtx) {103// Reconsider potential child transactions.104m_orphanage->AddChildrenToWorkSet(*ptx, m_rng);106RecentConfirmedTransactionsFilter().insert(ptx->GetHash().ToUint256());107if (ptx->HasWitness()) {108RecentConfirmedTransactionsFilter().insert(ptx->GetWitnessHash().ToUint256());109}110m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256());111m_txrequest.ForgetTxHash(ptx->GetWitnessHash().ToUint256());112}113}115void TxDownloadManagerImpl::BlockDisconnected()116{117// To avoid relay problems with transactions that were previously118// confirmed, clear our filter of recently confirmed transactions whenever119// there's a reorg.120// This means that in a 1-block reorg (where 1 block is disconnected and121// then another block reconnected), our filter will drop to having only one122// block's worth of transactions in it, but that should be fine, since123// presumably the most common case of relaying a confirmed transaction124// should be just after a new block containing it is found.125RecentConfirmedTransactionsFilter().reset();126}128bool TxDownloadManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable)129{130const uint256& hash = gtxid.ToUint256();132// Never query by txid: it is possible that the transaction in the orphanage has the same133// txid but a different witness, which would give us a false positive result. If we decided134// not to request the transaction based on this result, an attacker could prevent us from135// downloading a transaction by intentionally creating a malleated version of it. While136// only one (or none!) of these transactions can ultimately be confirmed, we have no way of137// discerning which one that is, so the orphanage can store multiple transactions with the138// same txid.139//140// While we won't query by txid, we can try to "guess" what the wtxid is based on the txid.141// A non-segwit transaction's txid == wtxid. Query this txhash "casted" to a wtxid. This will142// help us find non-segwit transactions, saving bandwidth, and should have no false positives.143if (m_orphanage->HaveTx(Wtxid::FromUint256(hash))) return true;145if (include_reconsiderable && RecentRejectsReconsiderableFilter().contains(hash)) return true;147if (RecentConfirmedTransactionsFilter().contains(hash)) return true;149return RecentRejectsFilter().contains(hash) || std::visit([&](const auto& id) { return m_mempool.exists(id); }, gtxid);150}152void TxDownloadManagerImpl::ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo& info)153{154// If already connected (shouldn't happen in practice), exit early.155if (m_peer_info.contains(nodeid)) return;157m_peer_info.try_emplace(nodeid, info);158if (info.m_wtxid_relay) m_num_wtxid_peers += 1;159}161void TxDownloadManagerImpl::DisconnectedPeer(NodeId nodeid)162{163m_orphanage->EraseForPeer(nodeid);164m_txrequest.DisconnectedPeer(nodeid);166if (auto it = m_peer_info.find(nodeid); it != m_peer_info.end()) {167if (it->second.m_connection_info.m_wtxid_relay) m_num_wtxid_peers -= 1;168m_peer_info.erase(it);169}171}173bool TxDownloadManagerImpl::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now)174{175// If this is an orphan we are trying to resolve, consider this peer as a orphan resolution candidate instead.176// - is wtxid matching something in orphanage177// - exists in orphanage178// - peer can be an orphan resolution candidate179if (const auto* wtxid = std::get_if<Wtxid>(>xid)) {180if (auto orphan_tx{m_orphanage->GetTx(*wtxid)}) {181auto unique_parents{GetUniqueParents(*orphan_tx)};182std::erase_if(unique_parents, [&](const auto& txid) {183return AlreadyHaveTx(txid, /*include_reconsiderable=*/false);184});186// The missing parents may have all been rejected or accepted since the orphan was added to the orphanage.187// Do not delete from the orphanage, as it may be queued for processing.188if (unique_parents.empty()) {189return true;190}192if (MaybeAddOrphanResolutionCandidate(unique_parents, *wtxid, peer, now)) {193m_orphanage->AddAnnouncer(orphan_tx->GetWitnessHash(), peer);194}196// Return even if the peer isn't an orphan resolution candidate. This would be caught by AlreadyHaveTx.197return true;198}199}201// If this is an inv received from a peer and we already have it, we can drop it.202if (AlreadyHaveTx(gtxid, /*include_reconsiderable=*/true)) return true;204auto it = m_peer_info.find(peer);205if (it == m_peer_info.end()) return false;206const auto& info = it->second.m_connection_info;207if (!info.m_relay_permissions && m_txrequest.Count(peer) >= MAX_PEER_TX_ANNOUNCEMENTS) {208// Too many queued announcements for this peer209return false;210}211// Decide the TxRequestTracker parameters for this announcement:212// - "preferred": if fPreferredDownload is set (= outbound, or NetPermissionFlags::NoBan permission)213// - "reqtime": current time plus delays for:214// - NONPREF_PEER_TX_DELAY for announcements from non-preferred connections215// - TXID_RELAY_DELAY for txid announcements while wtxid peers are available216// - OVERLOADED_PEER_TX_DELAY for announcements from peers which have at least217// MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't have NetPermissionFlags::Relay).218auto delay{0us};219if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY;220if (!gtxid.IsWtxid() && m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY;221const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(peer) >= MAX_PEER_TX_REQUEST_IN_FLIGHT;222if (overloaded) delay += OVERLOADED_PEER_TX_DELAY;224m_txrequest.ReceivedInv(peer, gtxid, info.m_preferred, now + delay);226return false;227}229bool TxDownloadManagerImpl::MaybeAddOrphanResolutionCandidate(const std::vector<Txid>& unique_parents, const Wtxid& wtxid, NodeId nodeid, std::chrono::microseconds now)230{231auto it_peer = m_peer_info.find(nodeid);232if (it_peer == m_peer_info.end()) return false;233if (m_orphanage->HaveTxFromPeer(wtxid, nodeid)) return false;235const auto& peer_entry = m_peer_info.at(nodeid);236const auto& info = peer_entry.m_connection_info;238// TODO: add delays and limits based on the amount of orphan resolution we are already doing239// with this peer, how much they are using the orphanage, etc.240if (!info.m_relay_permissions) {241// This mirrors the delaying and dropping behavior in AddTxAnnouncement in order to preserve242// existing behavior: drop if we are tracking too many invs for this peer already. Each243// orphan resolution involves at least 1 transaction request which may or may not be244// currently tracked in m_txrequest, so we include that in the count.245if (m_txrequest.Count(nodeid) + unique_parents.size() > MAX_PEER_TX_ANNOUNCEMENTS) return false;246}248std::chrono::seconds delay{0s};249if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY;250// The orphan wtxid is used, but resolution entails requesting the parents by txid. Sometimes
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.