test: p2p: Nodes ignore unsolicited CMPCTBLOCK's

This commit is contained in:
David Gumberg
2025-05-23 14:56:12 -07:00
parent 8313591715
commit e845e26344

View File

@@ -870,10 +870,10 @@ class CompactBlocksTest(BitcoinTestFramework):
assert_equal(node.getbestblockhash(), block.hash_hex)
# assert the RPC getpeerinfo boolean fields `bip152_hb_{to, from}`
# match the given parameters for the last peer of a given node
# match the given parameters for the peer at idx of a given node
@staticmethod
def assert_highbandwidth_states(node, hb_to, hb_from):
peerinfo = node.getpeerinfo()[-1]
def assert_highbandwidth_states(node, idx, hb_to, hb_from):
peerinfo = node.getpeerinfo()[idx]
assert_equal(peerinfo['bip152_hb_to'], hb_to)
assert_equal(peerinfo['bip152_hb_from'], hb_from)
@@ -881,22 +881,25 @@ class CompactBlocksTest(BitcoinTestFramework):
# create new p2p connection for a fresh state w/o any prior sendcmpct messages sent
hb_test_node = self.nodes[0].add_p2p_connection(TestP2PConn())
# Newly created hb_test_node is the last connection.
hb_test_node_idx = -1
# initially, neither node has selected the other peer as high-bandwidth yet
self.assert_highbandwidth_states(self.nodes[0], hb_to=False, hb_from=False)
self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=False, hb_from=False)
# peer requests high-bandwidth mode by sending sendcmpct(1)
hb_test_node.send_and_ping(msg_sendcmpct(announce=True, version=2))
self.assert_highbandwidth_states(self.nodes[0], hb_to=False, hb_from=True)
self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=False, hb_from=True)
# peer generates a block and sends it to node, which should
# select the peer as high-bandwidth (up to 3 peers according to BIP 152)
block = self.build_block_on_tip(self.nodes[0])
hb_test_node.send_and_ping(msg_block(block))
self.assert_highbandwidth_states(self.nodes[0], hb_to=True, hb_from=True)
self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=True, hb_from=True)
# peer requests low-bandwidth mode by sending sendcmpct(0)
hb_test_node.send_and_ping(msg_sendcmpct(announce=False, version=2))
self.assert_highbandwidth_states(self.nodes[0], hb_to=True, hb_from=False)
self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=True, hb_from=False)
def test_compactblock_reconstruction_parallel_reconstruction(self, stalling_peer, delivery_peer, inbound_peer, outbound_peer):
""" All p2p connections are inbound except outbound_peer. We test that ultimate parallel slot
@@ -952,6 +955,53 @@ class CompactBlocksTest(BitcoinTestFramework):
stalling_peer.send_and_ping(msg)
self.utxos.append([block.vtx[-1].txid_int, 0, block.vtx[-1].vout[0].nValue])
def test_compact_blocks_ignored(self):
node = self.nodes[0]
def build_compact_block():
# generate a compact block to send that will force a GETBLOCKTXN
utxo = self.utxos.pop(0)
block = self.build_block_with_transactions(node, utxo, 10)
cmpct_block = HeaderAndShortIDs()
cmpct_block.initialize_from_block(block)
msg = msg_cmpctblock(cmpct_block.to_p2p())
return block, msg
# Sends a compact block, uses presence of GETBLOCKTXN as a heuristic
# for whether or not the node processed the CMPCTBLOCK.
# Note: since we never fulfill the GETBLOCKTXN, this will never change
# the HB status of a connection.
def ignores_compact_block(conn, solicited=False):
block, msg = build_compact_block()
conn.clear_getblocktxn()
if solicited:
conn.send_without_ping(msg_headers([block]))
conn.wait_for_getdata([block.hash_int], timeout=30)
conn.send_and_ping(msg)
with p2p_lock:
return "getblocktxn" not in conn.last_message
# create new p2p connection for a fresh state w/o any prior sendcmpct messages sent
unsolicited_peer = self.nodes[0].add_p2p_connection(TestP2PConn())
self.assert_highbandwidth_states(node, idx=-1, hb_to=False, hb_from=False)
self.log.info("Test that a node ignores unsolicited CMPCTBLOCK messages from non-HB peers.")
assert ignores_compact_block(unsolicited_peer, solicited=False)
self.assert_highbandwidth_states(node, idx=-1, hb_to=False, hb_from=False)
self.log.info("Test that a node does not ignore solicited CMPCTBLOCK messages from non-HB peers.")
assert not ignores_compact_block(unsolicited_peer, solicited=True)
self.assert_highbandwidth_states(node, idx=-1, hb_to=False, hb_from=False)
# The node will ask for transactions from an unsolicited compact block
# it receives from a high bandwidth peer, we need to use one set up earlier,
# since all the slots are full.
self.log.info("Test that a node does not ignore unsolicited CMPCTBLOCK messages from HB peers.")
hb_peer_idx = -2
self.assert_highbandwidth_states(node, idx=hb_peer_idx, hb_to=True, hb_from=False)
hb_peer = self.nodes[0].p2ps[hb_peer_idx]
assert not ignores_compact_block(hb_peer, solicited=False)
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
@@ -1027,6 +1077,9 @@ class CompactBlocksTest(BitcoinTestFramework):
self.log.info("Testing high-bandwidth mode states via getpeerinfo...")
self.test_highbandwidth_mode_states_via_getpeerinfo()
self.log.info("Testing CMPCTBLOCK messages are ignored when expected...")
self.test_compact_blocks_ignored()
if __name__ == '__main__':
CompactBlocksTest(__file__).main()