@@ -105,6 +105,10 @@ def clear_block_announcement(self):
105
105
self .last_message .pop ("headers" , None )
106
106
self .last_message .pop ("cmpctblock" , None )
107
107
108
+ def clear_getblocktxn (self ):
109
+ with p2p_lock :
110
+ self .last_message .pop ("getblocktxn" , None )
111
+
108
112
def get_headers (self , locator , hashstop ):
109
113
msg = msg_getheaders ()
110
114
msg .locator .vHave = locator
@@ -745,7 +749,7 @@ def request_cb_announcements(self, peer):
745
749
peer .get_headers (locator = [int (tip , 16 )], hashstop = 0 )
746
750
peer .send_and_ping (msg_sendcmpct (announce = True , version = 2 ))
747
751
748
- def test_compactblock_reconstruction_multiple_peers (self , stalling_peer , delivery_peer ):
752
+ def test_compactblock_reconstruction_stalling_peer (self , stalling_peer , delivery_peer ):
749
753
node = self .nodes [0 ]
750
754
assert len (self .utxos )
751
755
@@ -823,12 +827,85 @@ def assert_highbandwidth_states(node, hb_to, hb_from):
823
827
hb_test_node .send_and_ping (msg_sendcmpct (announce = False , version = 2 ))
824
828
assert_highbandwidth_states (self .nodes [0 ], hb_to = True , hb_from = False )
825
829
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
+
826
901
def run_test (self ):
827
902
self .wallet = MiniWallet (self .nodes [0 ])
828
903
829
904
# Setup the p2p connections
830
905
self .segwit_node = self .nodes [0 ].add_p2p_connection (TestP2PConn ())
831
906
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" )
832
909
833
910
# We will need UTXOs to construct transactions in later tests.
834
911
self .make_utxos ()
@@ -838,6 +915,8 @@ def run_test(self):
838
915
self .log .info ("Testing SENDCMPCT p2p message... " )
839
916
self .test_sendcmpct (self .segwit_node )
840
917
self .test_sendcmpct (self .additional_segwit_node )
918
+ self .test_sendcmpct (self .onemore_inbound_node )
919
+ self .test_sendcmpct (self .outbound_node )
841
920
842
921
self .log .info ("Testing compactblock construction..." )
843
922
self .test_compactblock_construction (self .segwit_node )
@@ -860,8 +939,11 @@ def run_test(self):
860
939
self .log .info ("Testing handling of incorrect blocktxn responses..." )
861
940
self .test_incorrect_blocktxn_response (self .segwit_node )
862
941
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 )
865
947
866
948
# Test that if we submitblock to node1, we'll get a compact block
867
949
# announcement to all peers.
0 commit comments