diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 956c251b8c3..6597019797c 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -51,9 +51,7 @@ #include #include -/** How long to cache transactions in mapRelay for normal relay */ -static constexpr auto RELAY_TX_CACHE_TIME = 15min; -/** How long a transaction has to be in the mempool before it can unconditionally be relayed (even when not in mapRelay). */ +/** How long a transaction has to be in the mempool before it can unconditionally be relayed. */ static constexpr auto UNCONDITIONAL_RELAY_DELAY = 2min; /** Headers download timeout. * Timeout = base + per_header * (expected number of headers) */ @@ -920,12 +918,6 @@ private: /** Process a new block. Perform any post-processing housekeeping */ void ProcessBlock(CNode& node, const std::shared_ptr& block, bool force_processing, bool min_pow_checked); - /** Relay map (txid or wtxid -> CTransactionRef) */ - typedef std::map MapRelay; - MapRelay mapRelay GUARDED_BY(NetEventsInterface::g_msgproc_mutex); - /** Expiration-time ordered list of (expire time, relay map entry) pairs. */ - std::deque> g_relay_expiration GUARDED_BY(NetEventsInterface::g_msgproc_mutex); - /** * When a peer sends us a valid block, instruct it to announce blocks to us * using CMPCTBLOCK if possible by adding its nodeid to the end of @@ -2322,12 +2314,6 @@ CTransactionRef PeerManagerImpl::FindTxForGetData(const Peer::TxRelay& tx_relay, } } - // Or it might be recent and in the relay pool. - if (recent) { - auto mi = mapRelay.find(gtxid.GetHash()); - if (mi != mapRelay.end()) return mi->second; - } - return {}; } @@ -5796,7 +5782,6 @@ bool PeerManagerImpl::SendMessages(CNode* pto) continue; } auto txid = txinfo.tx->GetHash(); - auto wtxid = txinfo.tx->GetWitnessHash(); // Peer told you to not send transactions at that feerate? Don't bother sending it. if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) { continue; @@ -5806,24 +5791,6 @@ bool PeerManagerImpl::SendMessages(CNode* pto) tx_relay->m_recently_announced_invs.insert(hash); vInv.push_back(inv); nRelayedTransactions++; - { - // Expire old relay messages - while (!g_relay_expiration.empty() && g_relay_expiration.front().first < current_time) - { - mapRelay.erase(g_relay_expiration.front().second); - g_relay_expiration.pop_front(); - } - - auto ret = mapRelay.emplace(txid, std::move(txinfo.tx)); - if (ret.second) { - g_relay_expiration.emplace_back(current_time + RELAY_TX_CACHE_TIME, ret.first); - } - // Add wtxid-based lookup into mapRelay as well, so that peers can request by wtxid - auto ret2 = mapRelay.emplace(wtxid, ret.first->second); - if (ret2.second) { - g_relay_expiration.emplace_back(current_time + RELAY_TX_CACHE_TIME, ret2.first); - } - } if (vInv.size() == MAX_INV_SZ) { m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py index ef327c7ce82..0a331eb96e6 100755 --- a/test/functional/p2p_leak_tx.py +++ b/test/functional/p2p_leak_tx.py @@ -4,8 +4,8 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test transaction upload""" -from test_framework.messages import msg_getdata, CInv, MSG_TX -from test_framework.p2p import p2p_lock, P2PDataStore +from test_framework.messages import msg_getdata, CInv, MSG_TX, MSG_WTX +from test_framework.p2p import p2p_lock, P2PDataStore, P2PTxInvStore from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -27,6 +27,7 @@ class P2PLeakTxTest(BitcoinTestFramework): self.miniwallet = MiniWallet(self.gen_node) self.test_tx_in_block() + self.test_notfound_on_replaced_tx() self.test_notfound_on_unannounced_tx() def test_tx_in_block(self): @@ -45,8 +46,36 @@ class P2PLeakTxTest(BitcoinTestFramework): inbound_peer.send_and_ping(want_tx) assert_equal(inbound_peer.last_message.get("tx").tx.getwtxid(), wtxid) + def test_notfound_on_replaced_tx(self): + self.gen_node.disconnect_p2ps() + inbound_peer = self.gen_node.add_p2p_connection(P2PTxInvStore()) + + self.log.info("Transaction tx_a is broadcast") + tx_a = self.miniwallet.send_self_transfer(from_node=self.gen_node) + inbound_peer.wait_for_broadcast(txns=[tx_a["wtxid"]]) + + tx_b = tx_a["tx"] + tx_b.vout[0].nValue -= 9000 + self.gen_node.sendrawtransaction(tx_b.serialize().hex()) + + self.log.info("Re-request of tx_a after replacement is answered with notfound") + req_vec = [ + CInv(t=MSG_TX, h=int(tx_a["txid"], 16)), + CInv(t=MSG_WTX, h=int(tx_a["wtxid"], 16)), + ] + want_tx = msg_getdata() + want_tx.inv = req_vec + with p2p_lock: + inbound_peer.last_message.pop("notfound", None) + inbound_peer.last_message.pop("tx", None) + inbound_peer.send_and_ping(want_tx) + + assert_equal(inbound_peer.last_message.get("notfound").vec, req_vec) + assert "tx" not in inbound_peer.last_message + def test_notfound_on_unannounced_tx(self): self.log.info("Check that we don't leak txs to inbound peers that we haven't yet announced to") + self.gen_node.disconnect_p2ps() inbound_peer = self.gen_node.add_p2p_connection(P2PNode()) # An "attacking" inbound peer MAX_REPEATS = 100