/root/bitcoin/src/node/txdownloadman_impl.cpp
| Line | Count | Source | 
| 1 |  | // Copyright (c) 2024-present The Bitcoin Core developers | 
| 2 |  | // Distributed under the MIT software license, see the accompanying | 
| 3 |  | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | 
| 4 |  |  | 
| 5 |  | #include <node/txdownloadman_impl.h> | 
| 6 |  | #include <node/txdownloadman.h> | 
| 7 |  |  | 
| 8 |  | #include <chain.h> | 
| 9 |  | #include <consensus/validation.h> | 
| 10 |  | #include <logging.h> | 
| 11 |  | #include <txmempool.h> | 
| 12 |  | #include <validation.h> | 
| 13 |  | #include <validationinterface.h> | 
| 14 |  |  | 
| 15 |  | namespace node { | 
| 16 |  | // TxDownloadManager wrappers | 
| 17 |  | TxDownloadManager::TxDownloadManager(const TxDownloadOptions& options) : | 
| 18 | 0 |     m_impl{std::make_unique<TxDownloadManagerImpl>(options)} | 
| 19 | 0 | {} | 
| 20 | 1 | TxDownloadManager::~TxDownloadManager() = default; | 
| 21 |  |  | 
| 22 |  | void TxDownloadManager::ActiveTipChange() | 
| 23 | 0 | { | 
| 24 | 0 |     m_impl->ActiveTipChange(); | 
| 25 | 0 | } | 
| 26 |  | void TxDownloadManager::BlockConnected(const std::shared_ptr<const CBlock>& pblock) | 
| 27 | 0 | { | 
| 28 | 0 |     m_impl->BlockConnected(pblock); | 
| 29 | 0 | } | 
| 30 |  | void TxDownloadManager::BlockDisconnected() | 
| 31 | 0 | { | 
| 32 | 0 |     m_impl->BlockDisconnected(); | 
| 33 | 0 | } | 
| 34 |  | void TxDownloadManager::ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo& info) | 
| 35 | 0 | { | 
| 36 | 0 |     m_impl->ConnectedPeer(nodeid, info); | 
| 37 | 0 | } | 
| 38 |  | void TxDownloadManager::DisconnectedPeer(NodeId nodeid) | 
| 39 | 0 | { | 
| 40 | 0 |     m_impl->DisconnectedPeer(nodeid); | 
| 41 | 0 | } | 
| 42 |  | bool TxDownloadManager::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now) | 
| 43 | 0 | { | 
| 44 | 0 |     return m_impl->AddTxAnnouncement(peer, gtxid, now); | 
| 45 | 0 | } | 
| 46 |  | std::vector<GenTxid> TxDownloadManager::GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time) | 
| 47 | 0 | { | 
| 48 | 0 |     return m_impl->GetRequestsToSend(nodeid, current_time); | 
| 49 | 0 | } | 
| 50 |  | void TxDownloadManager::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& gtxids) | 
| 51 | 0 | { | 
| 52 | 0 |     m_impl->ReceivedNotFound(nodeid, gtxids); | 
| 53 | 0 | } | 
| 54 |  | void TxDownloadManager::MempoolAcceptedTx(const CTransactionRef& tx) | 
| 55 | 0 | { | 
| 56 | 0 |     m_impl->MempoolAcceptedTx(tx); | 
| 57 | 0 | } | 
| 58 |  | RejectedTxTodo TxDownloadManager::MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure) | 
| 59 | 0 | { | 
| 60 | 0 |     return m_impl->MempoolRejectedTx(ptx, state, nodeid, first_time_failure); | 
| 61 | 0 | } | 
| 62 |  | void TxDownloadManager::MempoolRejectedPackage(const Package& package) | 
| 63 | 0 | { | 
| 64 | 0 |     m_impl->MempoolRejectedPackage(package); | 
| 65 | 0 | } | 
| 66 |  | std::pair<bool, std::optional<PackageToValidate>> TxDownloadManager::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx) | 
| 67 | 0 | { | 
| 68 | 0 |     return m_impl->ReceivedTx(nodeid, ptx); | 
| 69 | 0 | } | 
| 70 |  | bool TxDownloadManager::HaveMoreWork(NodeId nodeid) const | 
| 71 | 0 | { | 
| 72 | 0 |     return m_impl->HaveMoreWork(nodeid); | 
| 73 | 0 | } | 
| 74 |  | CTransactionRef TxDownloadManager::GetTxToReconsider(NodeId nodeid) | 
| 75 | 0 | { | 
| 76 | 0 |     return m_impl->GetTxToReconsider(nodeid); | 
| 77 | 0 | } | 
| 78 |  | void TxDownloadManager::CheckIsEmpty() const | 
| 79 | 0 | { | 
| 80 | 0 |     m_impl->CheckIsEmpty(); | 
| 81 | 0 | } | 
| 82 |  | void TxDownloadManager::CheckIsEmpty(NodeId nodeid) const | 
| 83 | 0 | { | 
| 84 | 0 |     m_impl->CheckIsEmpty(nodeid); | 
| 85 | 0 | } | 
| 86 |  | std::vector<TxOrphanage::OrphanInfo> TxDownloadManager::GetOrphanTransactions() const | 
| 87 | 0 | { | 
| 88 | 0 |     return m_impl->GetOrphanTransactions(); | 
| 89 | 0 | } | 
| 90 |  |  | 
| 91 |  | // TxDownloadManagerImpl | 
| 92 |  | void TxDownloadManagerImpl::ActiveTipChange() | 
| 93 | 48.8k | { | 
| 94 | 48.8k |     RecentRejectsFilter().reset(); | 
| 95 | 48.8k |     RecentRejectsReconsiderableFilter().reset(); | 
| 96 | 48.8k | } | 
| 97 |  |  | 
| 98 |  | void TxDownloadManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock) | 
| 99 | 128k | { | 
| 100 | 128k |     m_orphanage->EraseForBlock(*pblock); | 
| 101 |  |  | 
| 102 | 128k |     for (const auto& ptx : pblock->vtx) { | 
| 103 | 128k |         RecentConfirmedTransactionsFilter().insert(ptx->GetHash().ToUint256()); | 
| 104 | 128k |         if (ptx->HasWitness()) { | 
| 105 | 98.7k |             RecentConfirmedTransactionsFilter().insert(ptx->GetWitnessHash().ToUint256()); | 
| 106 | 98.7k |         } | 
| 107 | 128k |         m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256()); | 
| 108 | 128k |         m_txrequest.ForgetTxHash(ptx->GetWitnessHash().ToUint256()); | 
| 109 | 128k |     } | 
| 110 | 128k | } | 
| 111 |  |  | 
| 112 |  | void TxDownloadManagerImpl::BlockDisconnected() | 
| 113 | 25.5k | { | 
| 114 |  |     // To avoid relay problems with transactions that were previously | 
| 115 |  |     // confirmed, clear our filter of recently confirmed transactions whenever | 
| 116 |  |     // there's a reorg. | 
| 117 |  |     // This means that in a 1-block reorg (where 1 block is disconnected and | 
| 118 |  |     // then another block reconnected), our filter will drop to having only one | 
| 119 |  |     // block's worth of transactions in it, but that should be fine, since | 
| 120 |  |     // presumably the most common case of relaying a confirmed transaction | 
| 121 |  |     // should be just after a new block containing it is found. | 
| 122 | 25.5k |     RecentConfirmedTransactionsFilter().reset(); | 
| 123 | 25.5k | } | 
| 124 |  |  | 
| 125 |  | bool TxDownloadManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable) | 
| 126 | 1.49M | { | 
| 127 | 1.49M |     const uint256& hash = gtxid.ToUint256(); | 
| 128 |  |  | 
| 129 |  |     // Never query by txid: it is possible that the transaction in the orphanage has the same | 
| 130 |  |     // txid but a different witness, which would give us a false positive result. If we decided | 
| 131 |  |     // not to request the transaction based on this result, an attacker could prevent us from | 
| 132 |  |     // downloading a transaction by intentionally creating a malleated version of it.  While | 
| 133 |  |     // only one (or none!) of these transactions can ultimately be confirmed, we have no way of | 
| 134 |  |     // discerning which one that is, so the orphanage can store multiple transactions with the | 
| 135 |  |     // same txid. | 
| 136 |  |     // | 
| 137 |  |     // While we won't query by txid, we can try to "guess" what the wtxid is based on the txid. | 
| 138 |  |     // A non-segwit transaction's txid == wtxid. Query this txhash "casted" to a wtxid. This will | 
| 139 |  |     // help us find non-segwit transactions, saving bandwidth, and should have no false positives. | 
| 140 | 1.49M |     if (m_orphanage->HaveTx(Wtxid::FromUint256(hash))) return true; | 
| 141 |  |  | 
| 142 | 1.44M |     if (include_reconsiderable && RecentRejectsReconsiderableFilter().contains(hash)) return true; | 
| 143 |  |  | 
| 144 | 1.44M |     if (RecentConfirmedTransactionsFilter().contains(hash)) return true; | 
| 145 |  |  | 
| 146 | 1.41M |     return RecentRejectsFilter().contains(hash) || std::visit([&](const auto& id) { return m_opts.m_mempool.exists(id); }, gtxid);txdownloadman_impl.cpp:_ZZN4node21TxDownloadManagerImpl13AlreadyHaveTxERK7GenTxidbENK3$_0clI22transaction_identifierILb0EEEEDaRKT_| Line | Count | Source |  | 146 | 1.17M |     return RecentRejectsFilter().contains(hash) || std::visit([&](const auto& id) { return m_opts.m_mempool.exists(id); }, gtxid); | 
txdownloadman_impl.cpp:_ZZN4node21TxDownloadManagerImpl13AlreadyHaveTxERK7GenTxidbENK3$_0clI22transaction_identifierILb1EEEEDaRKT_| Line | Count | Source |  | 146 | 243k |     return RecentRejectsFilter().contains(hash) || std::visit([&](const auto& id) { return m_opts.m_mempool.exists(id); }, gtxid); | 
 | 
| 147 | 1.44M | } | 
| 148 |  |  | 
| 149 |  | void TxDownloadManagerImpl::ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo& info) | 
| 150 | 160k | { | 
| 151 |  |     // If already connected (shouldn't happen in practice), exit early. | 
| 152 | 160k |     if (m_peer_info.contains(nodeid)) return; | 
| 153 |  |  | 
| 154 | 26.0k |     m_peer_info.try_emplace(nodeid, info); | 
| 155 | 26.0k |     if (info.m_wtxid_relay) m_num_wtxid_peers += 1; | 
| 156 | 26.0k | } | 
| 157 |  |  | 
| 158 |  | void TxDownloadManagerImpl::DisconnectedPeer(NodeId nodeid) | 
| 159 | 93.8k | { | 
| 160 | 93.8k |     m_orphanage->EraseForPeer(nodeid); | 
| 161 | 93.8k |     m_txrequest.DisconnectedPeer(nodeid); | 
| 162 |  |  | 
| 163 | 93.8k |     if (auto it = m_peer_info.find(nodeid); it != m_peer_info.end()) { | 
| 164 | 26.0k |         if (it->second.m_connection_info.m_wtxid_relay) m_num_wtxid_peers -= 1; | 
| 165 | 26.0k |         m_peer_info.erase(it); | 
| 166 | 26.0k |     } | 
| 167 |  |  | 
| 168 | 93.8k | } | 
| 169 |  |  | 
| 170 |  | bool TxDownloadManagerImpl::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now) | 
| 171 | 291k | { | 
| 172 |  |     // If this is an orphan we are trying to resolve, consider this peer as a orphan resolution candidate instead. | 
| 173 |  |     // - is wtxid matching something in orphanage | 
| 174 |  |     // - exists in orphanage | 
| 175 |  |     // - peer can be an orphan resolution candidate | 
| 176 | 291k |     if (const auto* wtxid = std::get_if<Wtxid>(>xid)) { | 
| 177 | 37.9k |         if (auto orphan_tx{m_orphanage->GetTx(*wtxid)}) { | 
| 178 | 3.55k |             auto unique_parents{GetUniqueParents(*orphan_tx)}; | 
| 179 | 13.0k |             std::erase_if(unique_parents, [&](const auto& txid) { | 
| 180 | 13.0k |                 return AlreadyHaveTx(txid, /*include_reconsiderable=*/false); | 
| 181 | 13.0k |             }); | 
| 182 |  |  | 
| 183 |  |             // The missing parents may have all been rejected or accepted since the orphan was added to the orphanage. | 
| 184 |  |             // Do not delete from the orphanage, as it may be queued for processing. | 
| 185 | 3.55k |             if (unique_parents.empty()) { | 
| 186 | 232 |                 return true; | 
| 187 | 232 |             } | 
| 188 |  |  | 
| 189 | 3.32k |             if (MaybeAddOrphanResolutionCandidate(unique_parents, *wtxid, peer, now)) { | 
| 190 | 1.31k |                 m_orphanage->AddAnnouncer(orphan_tx->GetWitnessHash(), peer); | 
| 191 | 1.31k |             } | 
| 192 |  |  | 
| 193 |  |             // Return even if the peer isn't an orphan resolution candidate. This would be caught by AlreadyHaveTx. | 
| 194 | 3.32k |             return true; | 
| 195 | 3.55k |         } | 
| 196 | 37.9k |     } | 
| 197 |  |  | 
| 198 |  |     // If this is an inv received from a peer and we already have it, we can drop it. | 
| 199 | 287k |     if (AlreadyHaveTx(gtxid, /*include_reconsiderable=*/true)) return true; | 
| 200 |  |  | 
| 201 | 279k |     auto it = m_peer_info.find(peer); | 
| 202 | 279k |     if (it == m_peer_info.end()) return false; | 
| 203 | 205k |     const auto& info = it->second.m_connection_info; | 
| 204 | 205k |     if (!info.m_relay_permissions && m_txrequest.Count(peer) >= MAX_PEER_TX_ANNOUNCEMENTS) { | 
| 205 |  |         // Too many queued announcements for this peer | 
| 206 | 0 |         return false; | 
| 207 | 0 |     } | 
| 208 |  |     // Decide the TxRequestTracker parameters for this announcement: | 
| 209 |  |     // - "preferred": if fPreferredDownload is set (= outbound, or NetPermissionFlags::NoBan permission) | 
| 210 |  |     // - "reqtime": current time plus delays for: | 
| 211 |  |     //   - NONPREF_PEER_TX_DELAY for announcements from non-preferred connections | 
| 212 |  |     //   - TXID_RELAY_DELAY for txid announcements while wtxid peers are available | 
| 213 |  |     //   - OVERLOADED_PEER_TX_DELAY for announcements from peers which have at least | 
| 214 |  |     //     MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't have NetPermissionFlags::Relay). | 
| 215 | 205k |     auto delay{0us}; | 
| 216 | 205k |     if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY; | 
| 217 | 205k |     if (!gtxid.IsWtxid() && m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY; | 
| 218 | 205k |     const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(peer) >= MAX_PEER_TX_REQUEST_IN_FLIGHT; | 
| 219 | 205k |     if (overloaded) delay += OVERLOADED_PEER_TX_DELAY; | 
| 220 |  |  | 
| 221 | 205k |     m_txrequest.ReceivedInv(peer, gtxid, info.m_preferred, now + delay); | 
| 222 |  |  | 
| 223 | 205k |     return false; | 
| 224 | 205k | } | 
| 225 |  |  | 
| 226 |  | bool TxDownloadManagerImpl::MaybeAddOrphanResolutionCandidate(const std::vector<Txid>& unique_parents, const Wtxid& wtxid, NodeId nodeid, std::chrono::microseconds now) | 
| 227 | 253k | { | 
| 228 | 253k |     auto it_peer = m_peer_info.find(nodeid); | 
| 229 | 253k |     if (it_peer == m_peer_info.end()) return false; | 
| 230 | 177k |     if (m_orphanage->HaveTxFromPeer(wtxid, nodeid)) return false; | 
| 231 |  |  | 
| 232 | 119k |     const auto& peer_entry = m_peer_info.at(nodeid); | 
| 233 | 119k |     const auto& info = peer_entry.m_connection_info; | 
| 234 |  |  | 
| 235 |  |     // TODO: add delays and limits based on the amount of orphan resolution we are already doing | 
| 236 |  |     // with this peer, how much they are using the orphanage, etc. | 
| 237 | 119k |     if (!info.m_relay_permissions) { | 
| 238 |  |         // This mirrors the delaying and dropping behavior in AddTxAnnouncement in order to preserve | 
| 239 |  |         // existing behavior: drop if we are tracking too many invs for this peer already. Each | 
| 240 |  |         // orphan resolution involves at least 1 transaction request which may or may not be | 
| 241 |  |         // currently tracked in m_txrequest, so we include that in the count. | 
| 242 | 115k |         if (m_txrequest.Count(nodeid) + unique_parents.size() > MAX_PEER_TX_ANNOUNCEMENTS) return false; | 
| 243 | 115k |     } | 
| 244 |  |  | 
| 245 | 119k |     std::chrono::seconds delay{0s}; | 
| 246 | 119k |     if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY; | 
| 247 |  |     // The orphan wtxid is used, but resolution entails requesting the parents by txid. Sometimes | 
| 248 |  |     // parent and child are announced and thus requested around the same time, and we happen to | 
| 249 |  |     // receive child sooner. Waiting a few seconds may allow us to cancel the orphan resolution | 
| 250 |  |     // request if the parent arrives in that time. | 
| 251 | 119k |     if (m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY; | 
| 252 | 119k |     const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(nodeid) >= MAX_PEER_TX_REQUEST_IN_FLIGHT; | 
| 253 | 119k |     if (overloaded) delay += OVERLOADED_PEER_TX_DELAY; | 
| 254 |  |  | 
| 255 |  |     // Treat finding orphan resolution candidate as equivalent to the peer announcing all missing parents. | 
| 256 |  |     // In the future, orphan resolution may include more explicit steps | 
| 257 | 413k |     for (const auto& parent_txid : unique_parents) { | 
| 258 | 413k |         m_txrequest.ReceivedInv(nodeid, parent_txid, info.m_preferred, now + delay); | 
| 259 | 413k |     } | 
| 260 | 119k |     LogDebug(BCLog::TXPACKAGES, "added peer=%d as a candidate for resolving orphan %s\n", nodeid, wtxid.ToString()); | 
| 261 | 119k |     return true; | 
| 262 | 119k | } | 
| 263 |  |  | 
| 264 |  | std::vector<GenTxid> TxDownloadManagerImpl::GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time) | 
| 265 | 68.5k | { | 
| 266 | 68.5k |     std::vector<GenTxid> requests; | 
| 267 | 68.5k |     std::vector<std::pair<NodeId, GenTxid>> expired; | 
| 268 | 68.5k |     auto requestable = m_txrequest.GetRequestable(nodeid, current_time, &expired); | 
| 269 | 68.5k |     for (const auto& [expired_nodeid, gtxid] : expired) { | 
| 270 | 45.2k |         LogDebug(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx", | 
| 271 | 45.2k |                  gtxid.ToUint256().ToString(), expired_nodeid); | 
| 272 | 45.2k |     } | 
| 273 | 68.5k |     for (const GenTxid& gtxid : requestable) { | 
| 274 | 49.8k |         if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) { | 
| 275 | 49.8k |             LogDebug(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx", | 
| 276 | 49.8k |                      gtxid.ToUint256().ToString(), nodeid); | 
| 277 | 49.8k |             requests.emplace_back(gtxid); | 
| 278 | 49.8k |             m_txrequest.RequestedTx(nodeid, gtxid.ToUint256(), current_time + GETDATA_TX_INTERVAL); | 
| 279 | 49.8k |         } else { | 
| 280 |  |             // We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as | 
| 281 |  |             // this should already be called whenever a transaction becomes AlreadyHaveTx(). | 
| 282 | 0 |             m_txrequest.ForgetTxHash(gtxid.ToUint256()); | 
| 283 | 0 |         } | 
| 284 | 49.8k |     } | 
| 285 | 68.5k |     return requests; | 
| 286 | 68.5k | } | 
| 287 |  |  | 
| 288 |  | void TxDownloadManagerImpl::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& gtxids) | 
| 289 | 27.1k | { | 
| 290 | 27.1k |     for (const auto& gtxid : gtxids) { | 
| 291 |  |         // If we receive a NOTFOUND message for a tx we requested, mark the announcement for it as | 
| 292 |  |         // completed in TxRequestTracker. | 
| 293 | 27.1k |         m_txrequest.ReceivedResponse(nodeid, gtxid.ToUint256()); | 
| 294 | 27.1k |     } | 
| 295 | 27.1k | } | 
| 296 |  |  | 
| 297 |  | std::optional<PackageToValidate> TxDownloadManagerImpl::Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid) | 
| 298 | 58.9k | { | 
| 299 | 58.9k |     const auto& parent_wtxid{ptx->GetWitnessHash()}; | 
| 300 |  |  | 
| 301 | 58.9k |     Assume(RecentRejectsReconsiderableFilter().contains(parent_wtxid.ToUint256())); | 
| 302 |  |  | 
| 303 |  |     // Only consider children from this peer. This helps prevent censorship attempts in which an attacker | 
| 304 |  |     // sends lots of fake children for the parent, and we (unluckily) keep selecting the fake | 
| 305 |  |     // children instead of the real one provided by the honest peer. Since we track all announcers | 
| 306 |  |     // of an orphan, this does not exclude parent + orphan pairs that we happened to request from | 
| 307 |  |     // different peers. | 
| 308 | 58.9k |     const auto cpfp_candidates_same_peer{m_orphanage->GetChildrenFromSamePeer(ptx, nodeid)}; | 
| 309 |  |  | 
| 310 |  |     // These children should be sorted from newest to oldest. In the (probably uncommon) case | 
| 311 |  |     // of children that replace each other, this helps us accept the highest feerate (probably the | 
| 312 |  |     // most recent) one efficiently. | 
| 313 | 58.9k |     for (const auto& child : cpfp_candidates_same_peer) { | 
| 314 | 35.7k |         Package maybe_cpfp_package{ptx, child}; | 
| 315 | 35.7k |         if (!RecentRejectsReconsiderableFilter().contains(GetPackageHash(maybe_cpfp_package)) && | 
| 316 | 35.7k |             !RecentRejectsFilter().contains(child->GetHash().ToUint256())) { | 
| 317 | 34.6k |             return PackageToValidate{ptx, child, nodeid, nodeid}; | 
| 318 | 34.6k |         } | 
| 319 | 35.7k |     } | 
| 320 | 24.2k |     return std::nullopt; | 
| 321 | 58.9k | } | 
| 322 |  |  | 
| 323 |  | void TxDownloadManagerImpl::MempoolAcceptedTx(const CTransactionRef& tx) | 
| 324 | 57.3k | { | 
| 325 |  |     // As this version of the transaction was acceptable, we can forget about any requests for it. | 
| 326 |  |     // No-op if the tx is not in txrequest. | 
| 327 | 57.3k |     m_txrequest.ForgetTxHash(tx->GetHash().ToUint256()); | 
| 328 | 57.3k |     m_txrequest.ForgetTxHash(tx->GetWitnessHash().ToUint256()); | 
| 329 |  |  | 
| 330 | 57.3k |     m_orphanage->AddChildrenToWorkSet(*tx, m_opts.m_rng); | 
| 331 |  |     // If it came from the orphanage, remove it. No-op if the tx is not in txorphanage. | 
| 332 | 57.3k |     m_orphanage->EraseTx(tx->GetWitnessHash()); | 
| 333 | 57.3k | } | 
| 334 |  |  | 
| 335 |  | std::vector<Txid> TxDownloadManagerImpl::GetUniqueParents(const CTransaction& tx) | 
| 336 | 251k | { | 
| 337 | 251k |     std::vector<Txid> unique_parents; | 
| 338 | 251k |     unique_parents.reserve(tx.vin.size()); | 
| 339 | 1.30M |     for (const CTxIn& txin : tx.vin) { | 
| 340 |  |         // We start with all parents, and then remove duplicates below. | 
| 341 | 1.30M |         unique_parents.push_back(txin.prevout.hash); | 
| 342 | 1.30M |     } | 
| 343 |  |  | 
| 344 | 251k |     std::sort(unique_parents.begin(), unique_parents.end()); | 
| 345 | 251k |     unique_parents.erase(std::unique(unique_parents.begin(), unique_parents.end()), unique_parents.end()); | 
| 346 |  |  | 
| 347 | 251k |     return unique_parents; | 
| 348 | 251k | } | 
| 349 |  |  | 
| 350 |  | node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure) | 
| 351 | 314k | { | 
| 352 | 314k |     const CTransaction& tx{*ptx}; | 
| 353 |  |     // Results returned to caller | 
| 354 |  |     // Whether we should call AddToCompactExtraTransactions at the end | 
| 355 | 314k |     bool add_extra_compact_tx{first_time_failure}; | 
| 356 |  |     // Hashes to pass to AddKnownTx later | 
| 357 | 314k |     std::vector<Txid> unique_parents; | 
| 358 |  |     // Populated if failure is reconsiderable and eligible package is found. | 
| 359 | 314k |     std::optional<node::PackageToValidate> package_to_validate; | 
| 360 |  |  | 
| 361 | 314k |     if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { | 
| 362 |  |         // Only process a new orphan if this is a first time failure, as otherwise it must be either | 
| 363 |  |         // already in orphanage or from 1p1c processing. | 
| 364 | 260k |         if (first_time_failure && !RecentRejectsFilter().contains(ptx->GetWitnessHash().ToUint256())) { | 
| 365 | 248k |             bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected | 
| 366 |  |  | 
| 367 |  |             // Deduplicate parent txids, so that we don't have to loop over | 
| 368 |  |             // the same parent txid more than once down below. | 
| 369 | 248k |             unique_parents = GetUniqueParents(tx); | 
| 370 |  |  | 
| 371 |  |             // Distinguish between parents in m_lazy_recent_rejects and m_lazy_recent_rejects_reconsiderable. | 
| 372 |  |             // We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we | 
| 373 |  |             // submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects. | 
| 374 | 248k |             std::optional<Txid> rejected_parent_reconsiderable; | 
| 375 | 872k |             for (const Txid& parent_txid : unique_parents) { | 
| 376 | 872k |                 if (RecentRejectsFilter().contains(parent_txid.ToUint256())) { | 
| 377 | 1.33k |                     fRejectedParents = true; | 
| 378 | 1.33k |                     break; | 
| 379 | 870k |                 } else if (RecentRejectsReconsiderableFilter().contains(parent_txid.ToUint256()) && | 
| 380 | 870k |                            !m_opts.m_mempool.exists(parent_txid)) { | 
| 381 |  |                     // More than 1 parent in m_lazy_recent_rejects_reconsiderable: 1p1c will not be | 
| 382 |  |                     // sufficient to accept this package, so just give up here. | 
| 383 | 120k |                     if (rejected_parent_reconsiderable.has_value()) { | 
| 384 | 0 |                         fRejectedParents = true; | 
| 385 | 0 |                         break; | 
| 386 | 0 |                     } | 
| 387 | 120k |                     rejected_parent_reconsiderable = parent_txid; | 
| 388 | 120k |                 } | 
| 389 | 872k |             } | 
| 390 | 248k |             if (!fRejectedParents) { | 
| 391 |  |                 // Filter parents that we already have. | 
| 392 |  |                 // Exclude m_lazy_recent_rejects_reconsiderable: the missing parent may have been | 
| 393 |  |                 // previously rejected for being too low feerate. This orphan might CPFP it. | 
| 394 | 867k |                 std::erase_if(unique_parents, [&](const auto& txid) { | 
| 395 | 867k |                     return AlreadyHaveTx(txid, /*include_reconsiderable=*/false); | 
| 396 | 867k |                 }); | 
| 397 | 246k |                 const auto now{GetTime<std::chrono::microseconds>()}; | 
| 398 | 246k |                 const auto& wtxid = ptx->GetWitnessHash(); | 
| 399 |  |                 // Potentially flip add_extra_compact_tx to false if tx is already in orphanage, which | 
| 400 |  |                 // means it was already added to vExtraTxnForCompact. | 
| 401 | 246k |                 add_extra_compact_tx &= !m_orphanage->HaveTx(wtxid); | 
| 402 |  |  | 
| 403 |  |                 // If there is no candidate for orphan resolution, AddTx will not be called. This means | 
| 404 |  |                 // that if a peer is overloading us with invs and orphans, they will eventually not be | 
| 405 |  |                 // able to add any more transactions to the orphanage. | 
| 406 |  |                 // | 
| 407 |  |                 // Search by txid and, if the tx has a witness, wtxid | 
| 408 | 246k |                 std::vector<NodeId> orphan_resolution_candidates{nodeid}; | 
| 409 | 246k |                 m_txrequest.GetCandidatePeers(ptx->GetHash().ToUint256(), orphan_resolution_candidates); | 
| 410 | 246k |                 if (ptx->HasWitness()) m_txrequest.GetCandidatePeers(ptx->GetWitnessHash().ToUint256(), orphan_resolution_candidates); | 
| 411 |  |  | 
| 412 | 250k |                 for (const auto& nodeid : orphan_resolution_candidates) { | 
| 413 | 250k |                     if (MaybeAddOrphanResolutionCandidate(unique_parents, ptx->GetWitnessHash(), nodeid, now)) { | 
| 414 | 117k |                         m_orphanage->AddTx(ptx, nodeid); | 
| 415 | 117k |                     } | 
| 416 | 250k |                 } | 
| 417 |  |  | 
| 418 |  |                 // Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore. | 
| 419 | 246k |                 m_txrequest.ForgetTxHash(tx.GetHash().ToUint256()); | 
| 420 | 246k |                 m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256()); | 
| 421 | 246k |             } else { | 
| 422 | 1.33k |                 unique_parents.clear(); | 
| 423 | 1.33k |                 LogDebug(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n", | 
| 424 | 1.33k |                          tx.GetHash().ToString(), | 
| 425 | 1.33k |                          tx.GetWitnessHash().ToString()); | 
| 426 |  |                 // We will continue to reject this tx since it has rejected | 
| 427 |  |                 // parents so avoid re-requesting it from other peers. | 
| 428 |  |                 // Here we add both the txid and the wtxid, as we know that | 
| 429 |  |                 // regardless of what witness is provided, we will not accept | 
| 430 |  |                 // this, so we don't need to allow for redownload of this txid | 
| 431 |  |                 // from any of our non-wtxidrelay peers. | 
| 432 | 1.33k |                 RecentRejectsFilter().insert(tx.GetHash().ToUint256()); | 
| 433 | 1.33k |                 RecentRejectsFilter().insert(tx.GetWitnessHash().ToUint256()); | 
| 434 | 1.33k |                 m_txrequest.ForgetTxHash(tx.GetHash().ToUint256()); | 
| 435 | 1.33k |                 m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256()); | 
| 436 | 1.33k |             } | 
| 437 | 248k |         } | 
| 438 | 260k |     } else if (state.GetResult() == TxValidationResult::TX_WITNESS_STRIPPED) { | 
| 439 | 391 |         add_extra_compact_tx = false; | 
| 440 | 54.4k |     } else { | 
| 441 |  |         // We can add the wtxid of this transaction to our reject filter. | 
| 442 |  |         // Do not add txids of witness transactions or witness-stripped | 
| 443 |  |         // transactions to the filter, as they can have been malleated; | 
| 444 |  |         // adding such txids to the reject filter would potentially | 
| 445 |  |         // interfere with relay of valid transactions from peers that | 
| 446 |  |         // do not support wtxid-based relay. See | 
| 447 |  |         // https://github.com/bitcoin/bitcoin/issues/8279 for details. | 
| 448 |  |         // We can remove this restriction (and always add wtxids to | 
| 449 |  |         // the filter even for witness stripped transactions) once | 
| 450 |  |         // wtxid-based relay is broadly deployed. | 
| 451 |  |         // See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034 | 
| 452 |  |         // for concerns around weakening security of unupgraded nodes | 
| 453 |  |         // if we start doing this too early. | 
| 454 | 54.4k |         if (state.GetResult() == TxValidationResult::TX_RECONSIDERABLE) { | 
| 455 |  |             // If the result is TX_RECONSIDERABLE, add it to m_lazy_recent_rejects_reconsiderable | 
| 456 |  |             // because we should not download or submit this transaction by itself again, but may | 
| 457 |  |             // submit it as part of a package later. | 
| 458 | 26.2k |             RecentRejectsReconsiderableFilter().insert(ptx->GetWitnessHash().ToUint256()); | 
| 459 |  |  | 
| 460 | 26.2k |             if (first_time_failure) { | 
| 461 |  |                 // When a transaction fails for TX_RECONSIDERABLE, look for a matching child in the | 
| 462 |  |                 // orphanage, as it is possible that they succeed as a package. | 
| 463 | 23.4k |                 LogDebug(BCLog::TXPACKAGES, "tx %s (wtxid=%s) failed but reconsiderable, looking for child in orphanage\n", | 
| 464 | 23.4k |                          ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString()); | 
| 465 | 23.4k |                 package_to_validate = Find1P1CPackage(ptx, nodeid); | 
| 466 | 23.4k |             } | 
| 467 | 28.1k |         } else { | 
| 468 | 28.1k |             RecentRejectsFilter().insert(ptx->GetWitnessHash().ToUint256()); | 
| 469 | 28.1k |         } | 
| 470 | 54.4k |         m_txrequest.ForgetTxHash(ptx->GetWitnessHash().ToUint256()); | 
| 471 |  |         // If the transaction failed for TX_INPUTS_NOT_STANDARD, | 
| 472 |  |         // then we know that the witness was irrelevant to the policy | 
| 473 |  |         // failure, since this check depends only on the txid | 
| 474 |  |         // (the scriptPubKey being spent is covered by the txid). | 
| 475 |  |         // Add the txid to the reject filter to prevent repeated | 
| 476 |  |         // processing of this transaction in the event that child | 
| 477 |  |         // transactions are later received (resulting in | 
| 478 |  |         // parent-fetching by txid via the orphan-handling logic). | 
| 479 |  |         // We only add the txid if it differs from the wtxid, to avoid wasting entries in the | 
| 480 |  |         // rolling bloom filter. | 
| 481 | 54.4k |         if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && ptx->HasWitness()) { | 
| 482 | 2.62k |             RecentRejectsFilter().insert(ptx->GetHash().ToUint256()); | 
| 483 | 2.62k |             m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256()); | 
| 484 | 2.62k |         } | 
| 485 | 54.4k |     } | 
| 486 |  |  | 
| 487 |  |     // If the tx failed in ProcessOrphanTx, it should be removed from the orphanage unless the | 
| 488 |  |     // tx was still missing inputs. If the tx was not in the orphanage, EraseTx does nothing and returns 0. | 
| 489 | 314k |     if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS && m_orphanage->EraseTx(ptx->GetWitnessHash())) { | 
| 490 | 2.80k |         LogDebug(BCLog::TXPACKAGES, "   removed orphan tx %s (wtxid=%s)\n", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString()); | 
| 491 | 2.80k |     } | 
| 492 |  |  | 
| 493 | 314k |     return RejectedTxTodo{ | 
| 494 | 314k |         .m_should_add_extra_compact_tx = add_extra_compact_tx, | 
| 495 | 314k |         .m_unique_parents = std::move(unique_parents), | 
| 496 | 314k |         .m_package_to_validate = std::move(package_to_validate) | 
| 497 | 314k |     }; | 
| 498 | 314k | } | 
| 499 |  |  | 
| 500 |  | void TxDownloadManagerImpl::MempoolRejectedPackage(const Package& package) | 
| 501 | 0 | { | 
| 502 | 0 |     RecentRejectsReconsiderableFilter().insert(GetPackageHash(package)); | 
| 503 | 0 | } | 
| 504 |  |  | 
| 505 |  | std::pair<bool, std::optional<PackageToValidate>> TxDownloadManagerImpl::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx) | 
| 506 | 137k | { | 
| 507 | 137k |     const Txid& txid = ptx->GetHash(); | 
| 508 | 137k |     const Wtxid& wtxid = ptx->GetWitnessHash(); | 
| 509 |  |  | 
| 510 |  |     // Mark that we have received a response | 
| 511 | 137k |     m_txrequest.ReceivedResponse(nodeid, txid.ToUint256()); | 
| 512 | 137k |     if (ptx->HasWitness()) m_txrequest.ReceivedResponse(nodeid, wtxid.ToUint256()); | 
| 513 |  |  | 
| 514 |  |     // First check if we should drop this tx. | 
| 515 |  |     // We do the AlreadyHaveTx() check using wtxid, rather than txid - in the | 
| 516 |  |     // absence of witness malleation, this is strictly better, because the | 
| 517 |  |     // recent rejects filter may contain the wtxid but rarely contains | 
| 518 |  |     // the txid of a segwit transaction that has been rejected. | 
| 519 |  |     // In the presence of witness malleation, it's possible that by only | 
| 520 |  |     // doing the check with wtxid, we could overlook a transaction which | 
| 521 |  |     // was confirmed with a different witness, or exists in our mempool | 
| 522 |  |     // with a different witness, but this has limited downside: | 
| 523 |  |     // mempool validation does its own lookup of whether we have the txid | 
| 524 |  |     // already; and an adversary can already relay us old transactions | 
| 525 |  |     // (older than our recency filter) if trying to DoS us, without any need | 
| 526 |  |     // for witness malleation. | 
| 527 | 137k |     if (AlreadyHaveTx(wtxid, /*include_reconsiderable=*/false)) { | 
| 528 |  |         // If a tx is detected by m_lazy_recent_rejects it is ignored. Because we haven't | 
| 529 |  |         // submitted the tx to our mempool, we won't have computed a DoS | 
| 530 |  |         // score for it or determined exactly why we consider it invalid. | 
| 531 |  |         // | 
| 532 |  |         // This means we won't penalize any peer subsequently relaying a DoSy | 
| 533 |  |         // tx (even if we penalized the first peer who gave it to us) because | 
| 534 |  |         // we have to account for m_lazy_recent_rejects showing false positives. In | 
| 535 |  |         // other words, we shouldn't penalize a peer if we aren't *sure* they | 
| 536 |  |         // submitted a DoSy tx. | 
| 537 |  |         // | 
| 538 |  |         // Note that m_lazy_recent_rejects doesn't just record DoSy or invalid | 
| 539 |  |         // transactions, but any tx not accepted by the mempool, which may be | 
| 540 |  |         // due to node policy (vs. consensus). So we can't blanket penalize a | 
| 541 |  |         // peer simply for relaying a tx that our m_lazy_recent_rejects has caught, | 
| 542 |  |         // regardless of false positives. | 
| 543 | 21.1k |         return {false, std::nullopt}; | 
| 544 | 116k |     } else if (RecentRejectsReconsiderableFilter().contains(wtxid.ToUint256())) { | 
| 545 |  |         // When a transaction is already in m_lazy_recent_rejects_reconsiderable, we shouldn't submit | 
| 546 |  |         // it by itself again. However, look for a matching child in the orphanage, as it is | 
| 547 |  |         // possible that they succeed as a package. | 
| 548 | 35.4k |         LogDebug(BCLog::TXPACKAGES, "found tx %s (wtxid=%s) in reconsiderable rejects, looking for child in orphanage\n", | 
| 549 | 35.4k |                  txid.ToString(), wtxid.ToString()); | 
| 550 | 35.4k |         return {false, Find1P1CPackage(ptx, nodeid)}; | 
| 551 | 35.4k |     } | 
| 552 |  |  | 
| 553 |  |  | 
| 554 | 80.7k |     return {true, std::nullopt}; | 
| 555 | 137k | } | 
| 556 |  |  | 
| 557 |  | bool TxDownloadManagerImpl::HaveMoreWork(NodeId nodeid) | 
| 558 | 69.1k | { | 
| 559 | 69.1k |     return m_orphanage->HaveTxToReconsider(nodeid); | 
| 560 | 69.1k | } | 
| 561 |  |  | 
| 562 |  | CTransactionRef TxDownloadManagerImpl::GetTxToReconsider(NodeId nodeid) | 
| 563 | 69.1k | { | 
| 564 | 69.1k |     return m_orphanage->GetTxToReconsider(nodeid); | 
| 565 | 69.1k | } | 
| 566 |  |  | 
| 567 |  | void TxDownloadManagerImpl::CheckIsEmpty(NodeId nodeid) | 
| 568 | 93.8k | { | 
| 569 | 93.8k |     assert(m_txrequest.Count(nodeid) == 0); | 
| 570 | 93.8k |     assert(m_orphanage->UsageByPeer(nodeid) == 0); | 
| 571 | 93.8k | } | 
| 572 |  | void TxDownloadManagerImpl::CheckIsEmpty() | 
| 573 | 618 | { | 
| 574 | 618 |     assert(m_orphanage->TotalOrphanUsage() == 0); | 
| 575 | 618 |     assert(m_orphanage->CountUniqueOrphans() == 0); | 
| 576 | 618 |     assert(m_txrequest.Size() == 0); | 
| 577 | 618 |     assert(m_num_wtxid_peers == 0); | 
| 578 | 618 | } | 
| 579 |  | std::vector<TxOrphanage::OrphanInfo> TxDownloadManagerImpl::GetOrphanTransactions() const | 
| 580 | 0 | { | 
| 581 | 0 |     return m_orphanage->GetOrphanTransactions(); | 
| 582 | 0 | } | 
| 583 |  | } // namespace node |