Skip to content

Commit d7f359b

Browse files
committed
Add tests for parallel compact block downloads
1 parent 03423f8 commit d7f359b

File tree

1 file changed

+85
-3
lines changed

1 file changed

+85
-3
lines changed

test/functional/p2p_compactblocks.py

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ def clear_block_announcement(self):
105105
self.last_message.pop("headers", None)
106106
self.last_message.pop("cmpctblock", None)
107107

108+
def clear_getblocktxn(self):
109+
with p2p_lock:
110+
self.last_message.pop("getblocktxn", None)
111+
108112
def get_headers(self, locator, hashstop):
109113
msg = msg_getheaders()
110114
msg.locator.vHave = locator
@@ -745,7 +749,7 @@ def request_cb_announcements(self, peer):
745749
peer.get_headers(locator=[int(tip, 16)], hashstop=0)
746750
peer.send_and_ping(msg_sendcmpct(announce=True, version=2))
747751

748-
def test_compactblock_reconstruction_multiple_peers(self, stalling_peer, delivery_peer):
752+
def test_compactblock_reconstruction_stalling_peer(self, stalling_peer, delivery_peer):
749753
node = self.nodes[0]
750754
assert len(self.utxos)
751755

@@ -823,12 +827,85 @@ def assert_highbandwidth_states(node, hb_to, hb_from):
823827
hb_test_node.send_and_ping(msg_sendcmpct(announce=False, version=2))
824828
assert_highbandwidth_states(self.nodes[0], hb_to=True, hb_from=False)
825829

830+
def test_compactblock_reconstruction_parallel_reconstruction(self, stalling_peer, delivery_peer, inbound_peer, outbound_peer):
831+
""" All p2p connections are inbound except outbound_peer. We test that ultimate parallel slot
832+
can only be taken by an outbound node unless prior attempts were done by an outbound
833+
"""
834+
node = self.nodes[0]
835+
assert len(self.utxos)
836+
837+
def announce_cmpct_block(node, peer, txn_count):
838+
utxo = self.utxos.pop(0)
839+
block = self.build_block_with_transactions(node, utxo, txn_count)
840+
841+
cmpct_block = HeaderAndShortIDs()
842+
cmpct_block.initialize_from_block(block)
843+
msg = msg_cmpctblock(cmpct_block.to_p2p())
844+
peer.send_and_ping(msg)
845+
with p2p_lock:
846+
assert "getblocktxn" in peer.last_message
847+
return block, cmpct_block
848+
849+
for name, peer in [("delivery", delivery_peer), ("inbound", inbound_peer), ("outbound", outbound_peer)]:
850+
self.log.info(f"Setting {name} as high bandwidth peer")
851+
block, cmpct_block = announce_cmpct_block(node, peer, 1)
852+
msg = msg_blocktxn()
853+
msg.block_transactions.blockhash = block.sha256
854+
msg.block_transactions.transactions = block.vtx[1:]
855+
peer.send_and_ping(msg)
856+
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
857+
peer.clear_getblocktxn()
858+
859+
# Test the simple parallel download case...
860+
for num_missing in [1, 5, 20]:
861+
862+
# Remaining low-bandwidth peer is stalling_peer, who announces first
863+
assert_equal([peer['bip152_hb_to'] for peer in node.getpeerinfo()], [False, True, True, True])
864+
865+
block, cmpct_block = announce_cmpct_block(node, stalling_peer, num_missing)
866+
867+
delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
868+
with p2p_lock:
869+
# The second peer to announce should still get a getblocktxn
870+
assert "getblocktxn" in delivery_peer.last_message
871+
assert int(node.getbestblockhash(), 16) != block.sha256
872+
873+
inbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
874+
with p2p_lock:
875+
# The third inbound peer to announce should *not* get a getblocktxn
876+
assert "getblocktxn" not in inbound_peer.last_message
877+
assert int(node.getbestblockhash(), 16) != block.sha256
878+
879+
outbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
880+
with p2p_lock:
881+
# The third peer to announce should get a getblocktxn if outbound
882+
assert "getblocktxn" in outbound_peer.last_message
883+
assert int(node.getbestblockhash(), 16) != block.sha256
884+
885+
# Second peer completes the compact block first
886+
msg = msg_blocktxn()
887+
msg.block_transactions.blockhash = block.sha256
888+
msg.block_transactions.transactions = block.vtx[1:]
889+
delivery_peer.send_and_ping(msg)
890+
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
891+
892+
# Nothing bad should happen if we get a late fill from the first peer...
893+
stalling_peer.send_and_ping(msg)
894+
self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
895+
896+
delivery_peer.clear_getblocktxn()
897+
inbound_peer.clear_getblocktxn()
898+
outbound_peer.clear_getblocktxn()
899+
900+
826901
def run_test(self):
827902
self.wallet = MiniWallet(self.nodes[0])
828903

829904
# Setup the p2p connections
830905
self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
831906
self.additional_segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
907+
self.onemore_inbound_node = self.nodes[0].add_p2p_connection(TestP2PConn())
908+
self.outbound_node = self.nodes[0].add_outbound_p2p_connection(TestP2PConn(), p2p_idx=3, connection_type="outbound-full-relay")
832909

833910
# We will need UTXOs to construct transactions in later tests.
834911
self.make_utxos()
@@ -838,6 +915,8 @@ def run_test(self):
838915
self.log.info("Testing SENDCMPCT p2p message... ")
839916
self.test_sendcmpct(self.segwit_node)
840917
self.test_sendcmpct(self.additional_segwit_node)
918+
self.test_sendcmpct(self.onemore_inbound_node)
919+
self.test_sendcmpct(self.outbound_node)
841920

842921
self.log.info("Testing compactblock construction...")
843922
self.test_compactblock_construction(self.segwit_node)
@@ -860,8 +939,11 @@ def run_test(self):
860939
self.log.info("Testing handling of incorrect blocktxn responses...")
861940
self.test_incorrect_blocktxn_response(self.segwit_node)
862941

863-
self.log.info("Testing reconstructing compact blocks from all peers...")
864-
self.test_compactblock_reconstruction_multiple_peers(self.segwit_node, self.additional_segwit_node)
942+
self.log.info("Testing reconstructing compact blocks with a stalling peer...")
943+
self.test_compactblock_reconstruction_stalling_peer(self.segwit_node, self.additional_segwit_node)
944+
945+
self.log.info("Testing reconstructing compact blocks from multiple peers...")
946+
self.test_compactblock_reconstruction_parallel_reconstruction(stalling_peer=self.segwit_node, inbound_peer=self.onemore_inbound_node, delivery_peer=self.additional_segwit_node, outbound_peer=self.outbound_node)
865947

866948
# Test that if we submitblock to node1, we'll get a compact block
867949
# announcement to all peers.

0 commit comments

Comments
 (0)