test: send duplicate blocktxn message in p2p_compactblocks.py
What changed, and why it matters
This commit only adds a new test to Bitcoin Core's test suite. It verifies that a Bitcoin node correctly disconnects a peer that sends an unexpected duplicate 'blocktxn' message after a compact block reconstruction already failed. There is no change to production node code, so this commit does not introduce or fix a live security vulnerability by itself.
No action required; treat as a normal test addition. If reviewing for security, confirm the underlying disconnect logic already exists in the node implementation and is not being introduced by this commit.
Security signals we found
Test-only change: no production code modified
Covers existing peer-disconnect behavior for duplicate blocktxn after failed compact-block reconstruction
No memory safety, cryptographic, or consensus changes present in diff
Evidence from the diff
The diff adds test_multiple_blocktxn_response() in test/functional/p2p_compactblocks.py. The test builds a compact block, triggers a failed reconstruction by sending an incomplete/out-of-order blocktxn response, waits for the getdata fallback, then sends the same blocktxn again and asserts the peer is disconnected with the debug log message ‘previous compact block reconstruction attempt failed’. It is purely a regression/behavior test; no consensus, networking, or validation logic is modified.
Changed components
test/functional/p2p_compactblocks.pyInspect captured patch +42 / −0
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 56186bc1..a2a3ffe2 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -558,6 +558,42 @@ class CompactBlocksTest(BitcoinTestFramework):
test_node.send_and_ping(msg_block(block))
assert_equal(node.getbestblockhash(), block.hash_hex)
+ # Multiple blocktxn responses will cause a node to get disconnected.
+ def test_multiple_blocktxn_response(self, test_node):
+ node = self.nodes[0]
+ utxo = self.utxos[0]
+
+ block = self.build_block_with_transactions(node, utxo, 2)
+
+ # Send compact block
+ comp_block = HeaderAndShortIDs()
+ comp_block.initialize_from_block(block, prefill_list=[0], use_witness=True)
+ test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
+ absolute_indexes = []
+ with p2p_lock:
+ assert "getblocktxn" in test_node.last_message
+ absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute()
+ assert_equal(absolute_indexes, [1, 2])
+
+ # Send a blocktxn that does not succeed in reconstruction, triggering
+ # getdata fallback.
+ msg = msg_blocktxn()
+ msg.block_transactions = BlockTransactions(block.hash_int, [block.vtx[2]] + [block.vtx[1]])
+ test_node.send_and_ping(msg)
+
+ # Tip should not have updated
+ assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
+
+ # We should receive a getdata request
+ test_node.wait_for_getdata([block.hash_int], timeout=10)
+ assert test_node.last_message["getdata"].inv[0].type == MSG_BLOCK or \
+ test_node.last_message["getdata"].inv[0].type == MSG_BLOCK | MSG_WITNESS_FLAG
+
+ # Send the same blocktxn and assert the sender gets disconnected.
+ with node.assert_debug_log(['previous compact block reconstruction attempt failed']):
+ test_node.send_without_ping(msg)
+ test_node.wait_for_disconnect()
+
def test_getblocktxn_handler(self, test_node):
node = self.nodes[0]
# bitcoind will not send blocktxn responses for blocks whose height is
@@ -977,6 +1013,12 @@ class CompactBlocksTest(BitcoinTestFramework):
# The previous test will lead to a disconnection. Reconnect before continuing.
self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
+ self.log.info("Testing handling of multiple blocktxn responses...")
+ self.test_multiple_blocktxn_response(self.segwit_node)
+
+ # The previous test will lead to a disconnection. Reconnect before continuing.
+ self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
+
self.log.info("Testing invalid index in cmpctblock message...")
self.test_invalid_cmpctblock_message()
Why this scored 15/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.