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.
251// parent and child are announced and thus requested around the same time, and we happen to252// receive child sooner. Waiting a few seconds may allow us to cancel the orphan resolution253// request if the parent arrives in that time.254if (m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY;255const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(nodeid) >= MAX_PEER_TX_REQUEST_IN_FLIGHT;256if (overloaded) delay += OVERLOADED_PEER_TX_DELAY;258// Treat finding orphan resolution candidate as equivalent to the peer announcing all missing parents.259// In the future, orphan resolution may include more explicit steps260for (const auto& parent_txid : unique_parents) {261m_txrequest.ReceivedInv(nodeid, parent_txid, info.m_preferred, now + delay);262}263LogDebug(BCLog::TXPACKAGES, "added peer=%d as a candidate for resolving orphan %s\n", nodeid, wtxid.ToString());264return true;265}267std::vector<GenTxid> TxDownloadManagerImpl::GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)268{269std::vector<GenTxid> requests;270std::vector<std::pair<NodeId, GenTxid>> expired;271auto requestable = m_txrequest.GetRequestable(nodeid, current_time, &expired);272for (const auto& [expired_nodeid, gtxid] : expired) {273LogDebug(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx",274gtxid.ToUint256().ToString(), expired_nodeid);275}276for (const GenTxid& gtxid : requestable) {277if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) {278LogDebug(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx",279gtxid.ToUint256().ToString(), nodeid);280requests.emplace_back(gtxid);281m_txrequest.RequestedTx(nodeid, gtxid.ToUint256(), current_time + GETDATA_TX_INTERVAL);282} else {283// We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as284// this should already be called whenever a transaction becomes AlreadyHaveTx().285m_txrequest.ForgetTxHash(gtxid.ToUint256());286}287}288return requests;289}291void TxDownloadManagerImpl::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& gtxids)292{293for (const auto& gtxid : gtxids) {294// If we receive a NOTFOUND message for a tx we requested, mark the announcement for it as295// completed in TxRequestTracker.296m_txrequest.ReceivedResponse(nodeid, gtxid.ToUint256());297}298}300std::optional<PackageToValidate> TxDownloadManagerImpl::Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid)301{302const auto& parent_wtxid{ptx->GetWitnessHash()};304Assume(RecentRejectsReconsiderableFilter().contains(parent_wtxid.ToUint256()));306// Only consider children from this peer. This helps prevent censorship attempts in which an attacker307// sends lots of fake children for the parent, and we (unluckily) keep selecting the fake308// children instead of the real one provided by the honest peer. Since we track all announcers309// of an orphan, this does not exclude parent + orphan pairs that we happened to request from310// different peers.311const auto cpfp_candidates_same_peer{m_orphanage->GetChildrenFromSamePeer(ptx, nodeid)};313// These children should be sorted from newest to oldest. In the (probably uncommon) case314// of children that replace each other, this helps us accept the highest feerate (probably the315// most recent) one efficiently.316for (const auto& child : cpfp_candidates_same_peer) {317Package maybe_cpfp_package{ptx, child};318if (!RecentRejectsReconsiderableFilter().contains(GetPackageHash(maybe_cpfp_package)) &&319!RecentRejectsFilter().contains(child->GetHash().ToUint256())) {320return PackageToValidate{ptx, child, nodeid, nodeid};321}322}323return std::nullopt;324}326void TxDownloadManagerImpl::MempoolAcceptedTx(const CTransactionRef& tx)327{328// As this version of the transaction was acceptable, we can forget about any requests for it.329// No-op if the tx is not in txrequest.330m_txrequest.ForgetTxHash(tx->GetHash().ToUint256());331m_txrequest.ForgetTxHash(tx->GetWitnessHash().ToUint256());333m_orphanage->AddChildrenToWorkSet(*tx, m_rng);334// If it came from the orphanage, remove it. No-op if the tx is not in txorphanage.335m_orphanage->EraseTx(tx->GetWitnessHash());336}338std::vector<Txid> TxDownloadManagerImpl::GetUniqueParents(const CTransaction& tx)339{340std::vector<Txid> unique_parents;341unique_parents.reserve(tx.vin.size());342for (const CTxIn& txin : tx.vin) {343// We start with all parents, and then remove duplicates below.344unique_parents.push_back(txin.prevout.hash);345}347std::sort(unique_parents.begin(), unique_parents.end());348unique_parents.erase(std::unique(unique_parents.begin(), unique_parents.end()), unique_parents.end());350return unique_parents;351}353node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure)354{355const CTransaction& tx{*ptx};356// Results returned to caller357// Whether we should call AddToCompactExtraTransactions at the end358bool add_extra_compact_tx{first_time_failure};359// Hashes to pass to AddKnownTx later360std::vector<Txid> unique_parents;361// Populated if failure is reconsiderable and eligible package is found.362std::optional<node::PackageToValidate> package_to_validate;364if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {365// Only process a new orphan if this is a first time failure, as otherwise it must be either366// already in orphanage or from 1p1c processing.367if (first_time_failure && !RecentRejectsFilter().contains(ptx->GetWitnessHash().ToUint256())) {368bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected370// Deduplicate parent txids, so that we don't have to loop over371// the same parent txid more than once down below.372unique_parents = GetUniqueParents(tx);374// Distinguish between parents in m_lazy_recent_rejects and m_lazy_recent_rejects_reconsiderable.375// We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we376// submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects.377std::optional<Txid> rejected_parent_reconsiderable;378for (const Txid& parent_txid : unique_parents) {379if (RecentRejectsFilter().contains(parent_txid.ToUint256())) {380fRejectedParents = true;381break;382} else if (RecentRejectsReconsiderableFilter().contains(parent_txid.ToUint256()) &&383!m_mempool.exists(parent_txid)) {384// More than 1 parent in m_lazy_recent_rejects_reconsiderable: 1p1c will not be385// sufficient to accept this package, so just give up here.386if (rejected_parent_reconsiderable.has_value()) {387fRejectedParents = true;388break;389}390rejected_parent_reconsiderable = parent_txid;391}392}393if (!fRejectedParents) {394// Filter parents that we already have.395// Exclude m_lazy_recent_rejects_reconsiderable: the missing parent may have been396// previously rejected for being too low feerate. This orphan might CPFP it.397std::erase_if(unique_parents, [&](const auto& txid) {398return AlreadyHaveTx(txid, /*include_reconsiderable=*/false);399});400const auto now{GetTime<std::chrono::microseconds>()};401const auto& wtxid = ptx->GetWitnessHash();402// Potentially flip add_extra_compact_tx to false if tx is already in orphanage, which403// means it was already added to vExtraTxnForCompact.404add_extra_compact_tx &= !m_orphanage->HaveTx(wtxid);406// If there is no candidate for orphan resolution, AddTx will not be called. This means407// that if a peer is overloading us with invs and orphans, they will eventually not be408// able to add any more transactions to the orphanage.409//410// Search by txid and, if the tx has a witness, wtxid411std::vector<NodeId> orphan_resolution_candidates{nodeid};412m_txrequest.GetCandidatePeers(ptx->GetHash().ToUint256(), orphan_resolution_candidates);413if (ptx->HasWitness()) m_txrequest.GetCandidatePeers(ptx->GetWitnessHash().ToUint256(), orphan_resolution_candidates);415for (const auto& nodeid : orphan_resolution_candidates) {416if (MaybeAddOrphanResolutionCandidate(unique_parents, ptx->GetWitnessHash(), nodeid, now)) {417m_orphanage->AddTx(ptx, nodeid);418}419}421// Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore.422m_txrequest.ForgetTxHash(tx.GetHash().ToUint256());423m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256());424} else {425unique_parents.clear();426LogDebug(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n",427tx.GetHash().ToString(),428tx.GetWitnessHash().ToString());429// We will continue to reject this tx since it has rejected430// parents so avoid re-requesting it from other peers.431// Here we add both the txid and the wtxid, as we know that432// regardless of what witness is provided, we will not accept433// this, so we don't need to allow for redownload of this txid434// from any of our non-wtxidrelay peers.435RecentRejectsFilter().insert(tx.GetHash().ToUint256());436RecentRejectsFilter().insert(tx.GetWitnessHash().ToUint256());437m_txrequest.ForgetTxHash(tx.GetHash().ToUint256());438m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256());439}440}441} else if (state.GetResult() == TxValidationResult::TX_WITNESS_STRIPPED) {442add_extra_compact_tx = false;443} else {444// We can add the wtxid of this transaction to our reject filter.445// Do not add txids of witness transactions or witness-stripped446// transactions to the filter, as they can have been malleated;447// adding such txids to the reject filter would potentially448// interfere with relay of valid transactions from peers that449// do not support wtxid-based relay. See450// https://github.com/bitcoin/bitcoin/issues/8279 for details.451// We can remove this restriction (and always add wtxids to452// the filter even for witness stripped transactions) once453// wtxid-based relay is broadly deployed.454// See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034455// for concerns around weakening security of unupgraded nodes456// if we start doing this too early.457if (state.GetResult() == TxValidationResult::TX_RECONSIDERABLE) {458// If the result is TX_RECONSIDERABLE, add it to m_lazy_recent_rejects_reconsiderable459// because we should not download or submit this transaction by itself again, but may460// submit it as part of a package later.461RecentRejectsReconsiderableFilter().insert(ptx->GetWitnessHash().ToUint256());463if (first_time_failure) {464// When a transaction fails for TX_RECONSIDERABLE, look for a matching child in the465// orphanage, as it is possible that they succeed as a package.466LogDebug(BCLog::TXPACKAGES, "tx %s (wtxid=%s) failed but reconsiderable, looking for child in orphanage\n",467ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());468package_to_validate = Find1P1CPackage(ptx, nodeid);469}470} else {471RecentRejectsFilter().insert(ptx->GetWitnessHash().ToUint256());472}473m_txrequest.ForgetTxHash(ptx->GetWitnessHash().ToUint256());474// If the transaction failed for TX_INPUTS_NOT_STANDARD,475// then we know that the witness was irrelevant to the policy476// failure, since this check depends only on the txid477// (the scriptPubKey being spent is covered by the txid).478// Add the txid to the reject filter to prevent repeated479// processing of this transaction in the event that child480// transactions are later received (resulting in481// parent-fetching by txid via the orphan-handling logic).482// We only add the txid if it differs from the wtxid, to avoid wasting entries in the483// rolling bloom filter.484if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && ptx->HasWitness()) {485RecentRejectsFilter().insert(ptx->GetHash().ToUint256());486m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256());487}488}490// If the tx failed in ProcessOrphanTx, it should be removed from the orphanage unless the491// tx was still missing inputs. If the tx was not in the orphanage, EraseTx does nothing and returns 0.492if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS && m_orphanage->EraseTx(ptx->GetWitnessHash())) {493LogDebug(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s)\n", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());494}496return RejectedTxTodo{497.m_should_add_extra_compact_tx = add_extra_compact_tx,498.m_unique_parents = std::move(unique_parents),499.m_package_to_validate = std::move(package_to_validate)500};
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.