Line data Source code
1 : // Copyright (c) 2021 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 <txorphanage.h> 6 : 7 : #include <consensus/validation.h> 8 : #include <logging.h> 9 : #include <policy/policy.h> 10 : #include <stats/client.h> 11 : 12 : #include <cassert> 13 : 14 : /** Expiration time for orphan transactions in seconds */ 15 : static constexpr int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60; 16 : /** Minimum time between orphan transactions expire time checks in seconds */ 17 : static constexpr int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60; 18 : 19 : 20 1963 : bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer) 21 : { 22 1963 : LOCK(m_mutex); 23 : 24 1963 : const uint256& hash = tx->GetHash(); 25 1963 : if (m_orphans.count(hash)) 26 20 : return false; 27 : 28 : // Ignore big transactions, to avoid a 29 : // send-big-orphans memory exhaustion attack. If a peer has a legitimate 30 : // large transaction with a missing parent then we assume 31 : // it will rebroadcast it later, after the parent transaction(s) 32 : // have been mined or received. 33 : // 100 orphans, each of which is at most 99,999 bytes big is 34 : // at most 10 megabytes of orphans and somewhat more byprev index (in the worst case): 35 1943 : unsigned int sz = GetSerializeSize(*tx, CTransaction::CURRENT_VERSION); 36 1943 : if (sz > MAX_STANDARD_TX_SIZE) 37 : { 38 10 : LogPrint(BCLog::MEMPOOL, "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); 39 10 : return false; 40 : } 41 : 42 1933 : auto ret = m_orphans.emplace(hash, OrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME, m_orphan_list.size(), sz}); 43 1933 : assert(ret.second); 44 1933 : m_orphan_list.push_back(ret.first); 45 3870 : for (const CTxIn& txin : tx->vin) { 46 1937 : m_outpoint_to_orphan_it[txin.prevout].insert(ret.first); 47 : } 48 : 49 1933 : m_orphan_tx_size += sz; 50 : 51 1933 : LogPrint(BCLog::MEMPOOL, "stored orphan tx %s (mapsz %u outsz %u)\n", hash.ToString(), 52 : m_orphans.size(), m_outpoint_to_orphan_it.size()); 53 1933 : ::g_stats_client->inc("transactions.orphans.add", 1.0f); 54 1933 : ::g_stats_client->gauge("transactions.orphans", m_orphans.size()); 55 : 56 1933 : return true; 57 1963 : } 58 : 59 35 : int TxOrphanage::EraseTx(const uint256& txid) 60 : { 61 35 : LOCK(m_mutex); 62 35 : return _EraseTx(txid); 63 35 : } 64 : 65 1932 : int TxOrphanage::_EraseTx(const uint256& txid) 66 : { 67 1932 : AssertLockHeld(m_mutex); 68 1932 : std::map<uint256, OrphanTx>::iterator it = m_orphans.find(txid); 69 1932 : if (it == m_orphans.end()) 70 0 : return 0; 71 3868 : for (const CTxIn& txin : it->second.tx->vin) 72 : { 73 1936 : auto itPrev = m_outpoint_to_orphan_it.find(txin.prevout); 74 1936 : if (itPrev == m_outpoint_to_orphan_it.end()) 75 0 : continue; 76 1936 : itPrev->second.erase(it); 77 1936 : if (itPrev->second.empty()) 78 1936 : m_outpoint_to_orphan_it.erase(itPrev); 79 : } 80 : 81 1932 : size_t old_pos = it->second.list_pos; 82 1932 : assert(m_orphan_list[old_pos] == it); 83 1932 : if (old_pos + 1 != m_orphan_list.size()) { 84 : // Unless we're deleting the last entry in m_orphan_list, move the last 85 : // entry to the position we're deleting. 86 1839 : auto it_last = m_orphan_list.back(); 87 1839 : m_orphan_list[old_pos] = it_last; 88 1839 : it_last->second.list_pos = old_pos; 89 1839 : } 90 1932 : m_orphan_list.pop_back(); 91 : 92 1932 : assert(m_orphan_tx_size >= it->second.nTxSize); 93 1932 : m_orphan_tx_size -= it->second.nTxSize; 94 1932 : m_orphans.erase(it); 95 1932 : ::g_stats_client->inc("transactions.orphans.remove", 1.0f); 96 1932 : ::g_stats_client->gauge("transactions.orphans", m_orphans.size()); 97 1932 : return 1; 98 1932 : } 99 : 100 9975 : void TxOrphanage::EraseForPeer(NodeId peer) 101 : { 102 9975 : LOCK(m_mutex); 103 : 104 9975 : m_peer_work_set.erase(peer); 105 : 106 9975 : int nErased = 0; 107 9975 : std::map<uint256, OrphanTx>::iterator iter = m_orphans.begin(); 108 12018 : while (iter != m_orphans.end()) 109 : { 110 2043 : std::map<uint256, OrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid 111 2043 : if (maybeErase->second.fromPeer == peer) 112 : { 113 1812 : nErased += _EraseTx(maybeErase->second.tx->GetHash()); 114 1812 : } 115 : } 116 9975 : if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer); 117 9975 : } 118 : 119 1855 : void TxOrphanage::LimitOrphans(unsigned int max_orphans_size) 120 : { 121 1855 : LOCK(m_mutex); 122 : 123 1855 : unsigned int nEvicted = 0; 124 : static int64_t nNextSweep; 125 1855 : int64_t nNow = GetTime(); 126 1855 : if (nNextSweep <= nNow) { 127 : // Sweep out expired orphan pool entries: 128 14 : int nErased = 0; 129 14 : int64_t nMinExpTime = nNow + ORPHAN_TX_EXPIRE_TIME - ORPHAN_TX_EXPIRE_INTERVAL; 130 14 : std::map<uint256, OrphanTx>::iterator iter = m_orphans.begin(); 131 101 : while (iter != m_orphans.end()) 132 : { 133 87 : std::map<uint256, OrphanTx>::iterator maybeErase = iter++; 134 87 : if (maybeErase->second.nTimeExpire <= nNow) { 135 0 : nErased += _EraseTx(maybeErase->second.tx->GetHash()); 136 0 : } else { 137 87 : nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime); 138 : } 139 : } 140 : // Sweep again 5 minutes after the next entry that expires in order to batch the linear scan. 141 14 : nNextSweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL; 142 14 : if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx due to expiration\n", nErased); 143 14 : } 144 1855 : FastRandomContext rng; 145 1937 : while (!m_orphans.empty() && m_orphan_tx_size > max_orphans_size) 146 : { 147 : // Evict a random orphan: 148 82 : size_t randompos = rng.randrange(m_orphan_list.size()); 149 82 : _EraseTx(m_orphan_list[randompos]->first); 150 82 : ++nEvicted; 151 : } 152 1855 : if (nEvicted > 0) LogPrint(BCLog::MEMPOOL, "orphanage overflow, removed %u tx\n", nEvicted); 153 1855 : } 154 : 155 512054 : void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx, NodeId peer) 156 : { 157 512054 : LOCK(m_mutex); 158 : 159 : // Get this peer's work set, emplacing an empty set it didn't exist 160 512054 : std::set<uint256>& orphan_work_set = m_peer_work_set.try_emplace(peer).first->second; 161 : 162 1417492 : for (unsigned int i = 0; i < tx.vout.size(); i++) { 163 905438 : const auto it_by_prev = m_outpoint_to_orphan_it.find(COutPoint(tx.GetHash(), i)); 164 905438 : if (it_by_prev != m_outpoint_to_orphan_it.end()) { 165 72 : for (const auto& elem : it_by_prev->second) { 166 36 : orphan_work_set.insert(elem->first); 167 : } 168 36 : } 169 905438 : } 170 512054 : } 171 : 172 75010 : bool TxOrphanage::HaveTx(const uint256& txid) const 173 : { 174 75010 : LOCK(m_mutex); 175 75010 : return m_orphans.count(txid); 176 75010 : } 177 : 178 3919124 : CTransactionRef TxOrphanage::GetTxToReconsider(NodeId peer, NodeId& originator, bool& more) 179 : { 180 3919124 : LOCK(m_mutex); 181 : 182 3919124 : auto work_set_it = m_peer_work_set.find(peer); 183 3919124 : if (work_set_it != m_peer_work_set.end()) { 184 562494 : auto& work_set = work_set_it->second; 185 562494 : while (!work_set.empty()) { 186 36 : uint256 txid = *work_set.begin(); 187 36 : work_set.erase(work_set.begin()); 188 : 189 36 : const auto orphan_it = m_orphans.find(txid); 190 36 : if (orphan_it != m_orphans.end()) { 191 36 : more = !work_set.empty(); 192 36 : originator = orphan_it->second.fromPeer; 193 36 : return orphan_it->second.tx; 194 : } 195 : } 196 562458 : } 197 3919088 : more = false; 198 3919088 : return nullptr; 199 3919124 : } 200 : 201 228003 : void TxOrphanage::SetCandidatesByBlock(const CBlock& block) 202 : { 203 228003 : AssertLockNotHeld(m_mutex); 204 : // As these candidates are generated from a block, they have no peer to attribute it to. We use 205 : // NodeId -1 for this reason and need to flush the last set before processing this one. 206 456006 : WITH_LOCK(m_mutex, m_peer_work_set.try_emplace(NodeId{-1}).first->second.clear()); 207 721025 : for (const auto& ptx : block.vtx) { 208 493022 : AddChildrenToWorkSet(*ptx, /*peer=*/-1); 209 : } 210 228003 : } 211 : 212 228002 : void TxOrphanage::EraseForBlock(const CBlock& block) 213 : { 214 228002 : LOCK(m_mutex); 215 : 216 228002 : std::vector<uint256> vOrphanErase; 217 : 218 721023 : for (const CTransactionRef& ptx : block.vtx) { 219 493021 : const CTransaction& tx = *ptx; 220 : 221 : // Which orphan pool entries must we evict? 222 865656 : for (const auto& txin : tx.vin) { 223 372635 : auto itByPrev = m_outpoint_to_orphan_it.find(txin.prevout); 224 372635 : if (itByPrev == m_outpoint_to_orphan_it.end()) continue; 225 6 : for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) { 226 3 : const CTransaction& orphanTx = *(*mi)->second.tx; 227 3 : const uint256& orphanHash = orphanTx.GetHash(); 228 3 : vOrphanErase.push_back(orphanHash); 229 3 : } 230 : } 231 : } 232 : 233 : // Erase orphan transactions included or precluded by this block 234 228002 : if (vOrphanErase.size()) { 235 3 : int nErased = 0; 236 6 : for (const uint256& orphanHash : vOrphanErase) { 237 3 : nErased += _EraseTx(orphanHash); 238 : } 239 3 : LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased); 240 3 : } 241 228002 : } 242 : 243 3919107 : bool TxOrphanage::HaveMoreWork(NodeId peer) 244 : { 245 3919107 : LOCK(m_mutex); 246 3919107 : auto it = m_peer_work_set.find(peer); 247 3919107 : return it != m_peer_work_set.end() && !it->second.empty(); 248 3919107 : }