p2p: trigger possible eviction if we support bloom filters and change a peer to tx relay
What changed, and why it matters
This Bitcoin Core patch fixes a small logic gap in peer-to-peer connection management. When a node supports bloom filters, a peer could switch itself into transaction-relaying mode at runtime without the node checking whether it already had too many transaction-relaying peers. The fix makes the node run its existing eviction check in those two cases, so an over-limit peer can be disconnected. The change is defensive and does not appear to enable remote crashes or theft of funds, but it could let a single peer occupy a limited tx-relay slot that the node otherwise tries to protect.
Treat as a low-to-moderate hardening improvement. Nodes that run with -peerbloomfilters and inbound connection limits should upgrade in due course. No emergency response is warranted; monitor release notes for any CVE or security advisory.
Security signals we found
Adds missing capacity-based eviction trigger after peer capability change
Functional test verifies connection drop after filterload message
Only affects nodes running with -peerbloomfilters enabled
No change to cryptographic, consensus, or wallet code
Relies on existing MaybeDisconnectForTxRelayCapacity routine
Evidence from the diff
In src/net_processing.cpp, processing of filterload and filterclear messages sets pfrom.m_relays_txs = true when the node supports bloom filters (-peerbloomfilters). Previously this state change did not invoke MaybeDisconnectForTxRelayCapacity, so a peer could become a tx-relay peer even when the node was already at its configured capacity for such peers. The patch adds that call after both state changes. A functional test demonstrates that sending filterload can now trigger the existing eviction logic and drop a connection. This is a hardening fix for a resource/slot-occupancy issue, not a memory-safety or consensus bug.
Changed components
src/net_processing.cpp (filterload and filterclear message handlers)test/functional/p2p_connection_limits.pyBitcoin Core P2P peer eviction / connection-slot logicInspect captured patch +15 / −0
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 8905b158..5dfed5ba 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -5017,6 +5017,7 @@ void PeerManagerImpl::ProcessMessage(Peer& peer, CNode& pfrom, const std::string
}
pfrom.m_bloom_filter_loaded = true;
pfrom.m_relays_txs = true;
+ MaybeDisconnectForTxRelayCapacity(pfrom, msg_type);
}
return;
}
@@ -5065,6 +5066,7 @@ void PeerManagerImpl::ProcessMessage(Peer& peer, CNode& pfrom, const std::string
}
pfrom.m_bloom_filter_loaded = false;
pfrom.m_relays_txs = true;
+ MaybeDisconnectForTxRelayCapacity(pfrom, msg_type);
return;
}
diff --git a/test/functional/p2p_connection_limits.py b/test/functional/p2p_connection_limits.py
index 338f8f74..44207e01 100755
--- a/test/functional/p2p_connection_limits.py
+++ b/test/functional/p2p_connection_limits.py
@@ -6,6 +6,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import (
msg_version,
+ msg_filterload
)
from test_framework.p2p import (
P2PInterface,
@@ -58,6 +59,18 @@ class P2PConnectionLimits(BitcoinTestFramework):
self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False, expect_success=False)
self.wait_until(lambda: len(node.getpeerinfo()) == 2)
+ self.log.info('Run with bloom filter support and check that a switch to tx relay during runtime can trigger eviction')
+ self.restart_node(0, ['-maxconnections=13', '-peerbloomfilters'])
+ peer1 = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False)
+ peer1.send_without_ping(self.create_blocks_only_version())
+ peer1.wait_for_verack()
+
+ node.add_p2p_connection(P2PInterface())
+ self.wait_until(lambda: len(node.getpeerinfo()) == 2)
+ with node.assert_debug_log(['connection dropped after filterload message'], timeout=2):
+ peer1.send_without_ping(msg_filterload(data=b'\xbb'*(100)))
+ self.wait_until(lambda: len(node.getpeerinfo()) == 1)
+
self.log.info('Test different values of inboundrelaypercent')
self.restart_node(0, ['-maxconnections=13', '-inboundrelaypercent=0'])
with node.assert_debug_log(['failed to find a tx-relaying eviction candidate - connection dropped'], timeout=2):
Why this scored 48/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.