mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-12 05:32:22 +02:00
p2p: make blocksonly nodes ignore CMPCTBLOCK messages
blocksonly nodes don't benefit from compact blocks, since they don't have a mempool to aid in reconstruction, so they should not process CMPCTBLOCK messages. This is not just belt-and-suspenders, as a blocksonly node will trivially reveal exactly which transactions in a block are its own in the GETBLOCKTXN response to a CMPCTBLOCK. Since it will be missing every transaction in the block, except for its own. See discussion: https://github.com/bitcoin/bitcoin/issues/28272
This commit is contained in:
@@ -12,7 +12,9 @@ from test_framework.messages import (
|
||||
CBlockHeader,
|
||||
CInv,
|
||||
from_hex,
|
||||
HeaderAndShortIDs,
|
||||
msg_block,
|
||||
msg_cmpctblock,
|
||||
msg_getdata,
|
||||
msg_headers,
|
||||
msg_sendcmpct,
|
||||
@@ -38,6 +40,30 @@ class P2PCompactBlocksBlocksOnly(BitcoinTestFramework):
|
||||
block = from_hex(CBlock(), block_hex)
|
||||
return block
|
||||
|
||||
def ignores_cmpctblock(self, node_id, conn, solicited=False):
|
||||
# Briefly connect to mining node, sync, and disconnect, just to make
|
||||
# sure the node is on the same tip as the miner so that compact block
|
||||
# reconstruction works.
|
||||
self.connect_nodes(2, node_id)
|
||||
self.sync_blocks([self.nodes[2], self.nodes[node_id]], timeout=10)
|
||||
self.disconnect_nodes(2, node_id)
|
||||
|
||||
block = self.build_block_on_tip()
|
||||
if solicited:
|
||||
conn.send_without_ping(msg_headers([block]))
|
||||
conn.wait_for_getdata([block.hash_int], timeout=10)
|
||||
cmpct_block = HeaderAndShortIDs()
|
||||
cmpct_block.initialize_from_block(block, use_witness=True)
|
||||
msg = msg_cmpctblock(cmpct_block.to_p2p())
|
||||
conn.send_and_ping(msg)
|
||||
|
||||
cmpct_block_received = self.nodes[node_id].getbestblockhash() == cmpct_block.header.hash_hex
|
||||
if not cmpct_block_received:
|
||||
# Compact block was ignored, send the full block to keep in sync.
|
||||
conn.send_and_ping(msg_block(block))
|
||||
|
||||
return not cmpct_block_received
|
||||
|
||||
def run_test(self):
|
||||
# Nodes will only request hb compact blocks mode when they're out of IBD
|
||||
for node in self.nodes:
|
||||
@@ -98,11 +124,19 @@ class P2PCompactBlocksBlocksOnly(BitcoinTestFramework):
|
||||
p2p_conn_high_bw.send_and_ping(msg_headers(headers=[CBlockHeader(block1)]))
|
||||
assert_equal(p2p_conn_high_bw.last_message['getdata'].inv, [CInv(MSG_CMPCT_BLOCK, block1.hash_int)])
|
||||
|
||||
# Send the block to avoid stalling the peer later in the test.
|
||||
comp_block = HeaderAndShortIDs()
|
||||
comp_block.initialize_from_block(block1, use_witness=True)
|
||||
block1_cb_msg = msg_cmpctblock(comp_block.to_p2p())
|
||||
p2p_conn_high_bw.send_and_ping(block1_cb_msg)
|
||||
|
||||
self.log.info("Test that getdata(CMPCT) is still sent on BIP152 low bandwidth connections"
|
||||
" when no -blocksonly nodes are involved")
|
||||
|
||||
p2p_conn_low_bw.send_and_ping(msg_headers(headers=[CBlockHeader(block1)]))
|
||||
assert_equal(p2p_conn_low_bw.last_message['getdata'].inv, [CInv(MSG_CMPCT_BLOCK, block1.hash_int)])
|
||||
# Send the block to avoid stalling the peer later in the test.
|
||||
p2p_conn_low_bw.send_and_ping(block1_cb_msg)
|
||||
|
||||
self.log.info("Test that -blocksonly nodes still serve compact blocks")
|
||||
|
||||
@@ -122,5 +156,18 @@ class P2PCompactBlocksBlocksOnly(BitcoinTestFramework):
|
||||
self.nodes[0].submitblock(block2.serialize().hex())
|
||||
p2p_conn_blocksonly.wait_until(lambda: test_for_cmpctblock(block2))
|
||||
|
||||
# This is redundant with other tests, and is here as a test-of-the-test
|
||||
self.log.info("Test that normal nodes don't ignore CMPCTBLOCK messages from HB peers")
|
||||
assert not self.ignores_cmpctblock(1, p2p_conn_high_bw, solicited=False)
|
||||
|
||||
self.log.info("Test that -blocksonly nodes ignore CMPCTBLOCK messages")
|
||||
assert self.ignores_cmpctblock(0, p2p_conn_blocksonly, solicited=False)
|
||||
|
||||
self.log.info("Test that low bandwidth nodes listen to CMPCTBLOCK messages when the block is requested")
|
||||
assert not self.ignores_cmpctblock(3, p2p_conn_low_bw, solicited=True)
|
||||
|
||||
self.log.info("Test that -blocksonly nodes ignore CMPCTBLOCK messages even when the block is requested")
|
||||
assert self.ignores_cmpctblock(0, p2p_conn_blocksonly, solicited=True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
P2PCompactBlocksBlocksOnly(__file__).main()
|
||||
|
||||
Reference in New Issue
Block a user