Skip to content

Commit 32666d2

Browse files
instagibbspatricklodder
authored andcommitted
Add tests for parallel compact block downloads
1 parent 770e795 commit 32666d2

1 file changed

Lines changed: 84 additions & 3 deletions

File tree

test/functional/p2p_compactblocks.py

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ def clear_block_announcement(self):
109109
self.last_message.pop("headers", None)
110110
self.last_message.pop("cmpctblock", None)
111111

112+
def clear_getblocktxn(self):
113+
with p2p_lock:
114+
self.last_message.pop("getblocktxn", None)
115+
112116
def get_headers(self, locator, hashstop):
113117
msg = msg_getheaders()
114118
msg.locator.vHave = locator
@@ -764,7 +768,7 @@ def request_cb_announcements(self, peer):
764768
peer.get_headers(locator=[int(tip, 16)], hashstop=0)
765769
peer.send_and_ping(msg_sendcmpct(announce=True, version=peer.cmpct_version))
766770

767-
def test_compactblock_reconstruction_multiple_peers(self, stalling_peer, delivery_peer):
771+
def test_compactblock_reconstruction_stalling_peer(self, stalling_peer, delivery_peer):
768772
node = self.nodes[0]
769773
assert len(self.utxos)
770774

@@ -842,6 +846,77 @@ def assert_highbandwidth_states(node, hb_to, hb_from):
842846
hb_test_node.send_and_ping(msg_sendcmpct(announce=False, version=2))
843847
assert_highbandwidth_states(self.nodes[0], hb_to=True, hb_from=False)
844848

849+
def test_compactblock_reconstruction_parallel_reconstruction(self, stalling_peer, delivery_peer, inbound_peer, outbound_peer):
850+
""" All p2p connections are inbound except outbound_peer. We test that ultimate parallel slot
851+
can only be taken by an outbound node unless prior attempts were done by an outbound
852+
"""
853+
node = self.nodes[0]
854+
assert len(self.utxos)
855+
856+
def announce_cmpct_block(node, peer, txn_count):
857+
utxo = self.utxos.pop(0)
858+
block = self.build_block_with_transactions(node, utxo, txn_count)
859+
860+
cmpct_block = HeaderAndShortIDs()
861+
cmpct_block.initialize_from_block(block)
862+
msg = msg_cmpctblock(cmpct_block.to_p2p())
863+
peer.send_and_ping(msg)
864+
with p2p_lock:
865+
assert "getblocktxn" in peer.last_message
866+
return block, cmpct_block
867+
868+
for name, peer in [("delivery", delivery_peer), ("inbound", inbound_peer), ("outbound", outbound_peer)]:
869+
self.log.info(f"Setting {name} as high bandwidth peer")
870+
block, cmpct_block = announce_cmpct_block(node, peer, 1)
871+
msg = msg_blocktxn()
872+
msg.block_transactions.blockhash = block.sha256
873+
msg.block_transactions.transactions = block.vtx[1:]
874+
peer.send_and_ping(msg)
875+
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
876+
peer.clear_getblocktxn()
877+
878+
# Test the simple parallel download case...
879+
for num_missing in [1, 5, 20]:
880+
881+
# Remaining low-bandwidth peer is stalling_peer, who announces first
882+
assert_equal([peer['bip152_hb_to'] for peer in node.getpeerinfo()], [False, True, True, True])
883+
884+
block, cmpct_block = announce_cmpct_block(node, stalling_peer, num_missing)
885+
886+
delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
887+
with p2p_lock:
888+
# The second peer to announce should still get a getblocktxn
889+
assert "getblocktxn" in delivery_peer.last_message
890+
assert int(node.getbestblockhash(), 16) != block.sha256
891+
892+
inbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
893+
with p2p_lock:
894+
# The third inbound peer to announce should *not* get a getblocktxn
895+
assert "getblocktxn" not in inbound_peer.last_message
896+
assert int(node.getbestblockhash(), 16) != block.sha256
897+
898+
outbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
899+
with p2p_lock:
900+
# The third peer to announce should get a getblocktxn if outbound
901+
assert "getblocktxn" in outbound_peer.last_message
902+
assert int(node.getbestblockhash(), 16) != block.sha256
903+
904+
# Second peer completes the compact block first
905+
msg = msg_blocktxn()
906+
msg.block_transactions.blockhash = block.sha256
907+
msg.block_transactions.transactions = block.vtx[1:]
908+
delivery_peer.send_and_ping(msg)
909+
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
910+
911+
# Nothing bad should happen if we get a late fill from the first peer...
912+
stalling_peer.send_and_ping(msg)
913+
self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
914+
915+
delivery_peer.clear_getblocktxn()
916+
inbound_peer.clear_getblocktxn()
917+
outbound_peer.clear_getblocktxn()
918+
919+
845920
def run_test(self):
846921
# Get the nodes out of IBD
847922
self.nodes[0].generate(1)
@@ -850,6 +925,7 @@ def run_test(self):
850925
self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=2))
851926
self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=1), services=NODE_NETWORK)
852927
self.additional_segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=2))
928+
self.outbound_node = self.nodes[0].add_outbound_p2p_connection(TestP2PConn(), p2p_idx=3, connection_type="outbound-full-relay")
853929

854930
# We will need UTXOs to construct transactions in later tests.
855931
self.make_utxos()
@@ -859,6 +935,8 @@ def run_test(self):
859935
self.log.info("Testing SENDCMPCT p2p message... ")
860936
self.test_sendcmpct(self.segwit_node, old_node=self.old_node)
861937
self.test_sendcmpct(self.additional_segwit_node)
938+
self.test_sendcmpct(self.onemore_inbound_node)
939+
self.test_sendcmpct(self.outbound_node)
862940

863941
self.log.info("Testing compactblock construction...")
864942
self.test_compactblock_construction(self.old_node)
@@ -881,8 +959,11 @@ def run_test(self):
881959
self.log.info("Testing handling of incorrect blocktxn responses...")
882960
self.test_incorrect_blocktxn_response(self.segwit_node)
883961

884-
self.log.info("Testing reconstructing compact blocks from all peers...")
885-
self.test_compactblock_reconstruction_multiple_peers(self.segwit_node, self.additional_segwit_node)
962+
self.log.info("Testing reconstructing compact blocks with a stalling peer...")
963+
self.test_compactblock_reconstruction_stalling_peer(self.segwit_node, self.additional_segwit_node)
964+
965+
self.log.info("Testing reconstructing compact blocks from multiple peers...")
966+
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)
886967

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

0 commit comments

Comments
 (0)