p2p: reject filtered block inv early when bloom is disabled
What changed, and why it matters
This change makes Bitcoin Core disconnect a peer earlier when it asks for a 'filtered block' from a node that does not advertise bloom-filter support. Previously, the node would read the block from disk first and only then ignore the request. Now it rejects the request before doing any disk read. This is mainly a small performance/hardening improvement rather than a serious security fix.
No urgent action needed; this is a minor hardening/performance improvement. Operators and downstream maintainers should include it in normal updates. Reviewers may want to confirm that the new disconnection behavior is consistent with other NODE_BLOOM violations.
Security signals we found
Adds early validation of peer request against advertised service bits
Disconnects peer on protocol violation instead of silently ignoring after disk I/O
Avoids unnecessary disk read for a request that will be rejected anyway
Adds regression test for the disconnection behavior
Evidence from the diff
In ProcessGetBlockData(), a guard is added at the top: if the inventory type is MSG_FILTERED_BLOCK and the local peer does not offer NODE_BLOOM, the node logs a debug message, sets fDisconnect=true, and returns immediately. Previously the filtered-block path was rejected only after the block was fetched from disk inside the bloom-filter check. A functional test is added to verify the peer is disconnected and the expected log message appears.
Changed components
src/net_processing.cpp - ProcessGetBlockData()test/functional/p2p_nobloomfilter_messages.pyInspect captured patch +13 / −1
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 00852a09..7387f78b 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2365,6 +2365,14 @@ void PeerManagerImpl::RelayAddress(NodeId originator,
void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv)
{
+ // First perform the stateless checks:
+ // A filtered-block can only ever be requested if we offer NODE_BLOOM
+ if (inv.IsMsgFilteredBlk() && !(peer.m_our_services & NODE_BLOOM)) {
+ LogDebug(BCLog::NET, "filtered block request received when NODE_BLOOM service disabled, %s", pfrom.DisconnectMsg());
+ pfrom.fDisconnect = true;
+ return;
+ }
+
std::shared_ptr<const CBlock> a_recent_block;
std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
{
diff --git a/test/functional/p2p_nobloomfilter_messages.py b/test/functional/p2p_nobloomfilter_messages.py
index 2d5d7add..77618742 100755
--- a/test/functional/p2p_nobloomfilter_messages.py
+++ b/test/functional/p2p_nobloomfilter_messages.py
@@ -11,7 +11,7 @@ Test that, when bloom filters are not enabled, peers are disconnected if:
4. They send a p2p filterclear message
"""
-from test_framework.messages import msg_mempool, msg_filteradd, msg_filterload, msg_filterclear
+from test_framework.messages import msg_mempool, msg_filteradd, msg_filterload, msg_filterclear, CInv, MSG_FILTERED_BLOCK, msg_getdata
from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -43,6 +43,10 @@ class P2PNoBloomFilterMessages(BitcoinTestFramework):
self.log.info("Test that peer is disconnected if it sends a filterclear message")
self.test_message_causes_disconnect(msg_filterclear())
+ self.log.info("Test that peer is disconnected if it requests a filtered block")
+ with self.nodes[0].assert_debug_log(['filtered block request received when NODE_BLOOM service disabled']):
+ self.test_message_causes_disconnect(msg_getdata([CInv(MSG_FILTERED_BLOCK, int(self.nodes[0].getbestblockhash(), 16))]))
+
if __name__ == '__main__':
P2PNoBloomFilterMessages(__file__).main()
Why this scored 28/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.