6363 Expect: getdata request for 14 more blocks.
6464f. Announce 1 more header that builds on that fork.
6565 Expect: no response.
66+
67+ Part 5: Test handling of headers that don't connect.
68+ a. Repeat 10 times:
69+ 1. Announce a header that doesn't connect.
70+ Expect: getheaders message
71+ 2. Send headers chain.
72+ Expect: getdata for the missing blocks, tip update.
73+ b. Then send 9 more headers that don't connect.
74+ Expect: getheaders message each time.
75+ c. Announce a header that does connect.
76+ Expect: no response.
77+ d. Announce 49 headers that don't connect.
78+ Expect: getheaders message each time.
79+ e. Announce one more that doesn't connect.
80+ Expect: disconnect.
6681'''
6782
6883class BaseNode (NodeConnCB ):
@@ -77,6 +92,8 @@ def __init__(self):
7792 self .last_getdata = None
7893 self .sleep_time = 0.05
7994 self .block_announced = False
95+ self .last_getheaders = None
96+ self .disconnected = False
8097
8198 def clear_last_announcement (self ):
8299 with mininode_lock :
@@ -127,6 +144,12 @@ def on_getdata(self, conn, message):
127144 def on_pong (self , conn , message ):
128145 self .last_pong = message
129146
147+ def on_getheaders (self , conn , message ):
148+ self .last_getheaders = message
149+
150+ def on_close (self , conn ):
151+ self .disconnected = True
152+
130153 # Test whether the last announcement we received had the
131154 # right header or the right inv
132155 # inv and headers should be lists of block hashes
@@ -178,6 +201,11 @@ def wait_for_block(self, blockhash, timeout=60):
178201 self .sync (test_function , timeout )
179202 return
180203
204+ def wait_for_getheaders (self , timeout = 60 ):
205+ test_function = lambda : self .last_getheaders != None
206+ self .sync (test_function , timeout )
207+ return
208+
181209 def wait_for_getdata (self , hash_list , timeout = 60 ):
182210 if hash_list == []:
183211 return
@@ -186,6 +214,11 @@ def wait_for_getdata(self, hash_list, timeout=60):
186214 self .sync (test_function , timeout )
187215 return
188216
217+ def wait_for_disconnect (self , timeout = 60 ):
218+ test_function = lambda : self .disconnected
219+ self .sync (test_function , timeout )
220+ return
221+
189222 def send_header_for_blocks (self , new_blocks ):
190223 headers_message = msg_headers ()
191224 headers_message .headers = [ CBlockHeader (b ) for b in new_blocks ]
@@ -510,6 +543,78 @@ def run_test(self):
510543
511544 print ("Part 4: success!" )
512545
546+ # Now deliver all those blocks we announced.
547+ [ test_node .send_message (msg_block (x )) for x in blocks ]
548+
549+ print ("Part 5: Testing handling of unconnecting headers" )
550+ # First we test that receipt of an unconnecting header doesn't prevent
551+ # chain sync.
552+ for i in range (10 ):
553+ test_node .last_getdata = None
554+ blocks = []
555+ # Create two more blocks.
556+ for j in range (2 ):
557+ blocks .append (create_block (tip , create_coinbase (height ), block_time ))
558+ blocks [- 1 ].solve ()
559+ tip = blocks [- 1 ].sha256
560+ block_time += 1
561+ height += 1
562+ # Send the header of the second block -> this won't connect.
563+ with mininode_lock :
564+ test_node .last_getheaders = None
565+ test_node .send_header_for_blocks ([blocks [1 ]])
566+ test_node .wait_for_getheaders (timeout = 1 )
567+ test_node .send_header_for_blocks (blocks )
568+ test_node .wait_for_getdata ([x .sha256 for x in blocks ])
569+ [ test_node .send_message (msg_block (x )) for x in blocks ]
570+ test_node .sync_with_ping ()
571+ assert_equal (int (self .nodes [0 ].getbestblockhash (), 16 ), blocks [1 ].sha256 )
572+
573+ blocks = []
574+ # Now we test that if we repeatedly don't send connecting headers, we
575+ # don't go into an infinite loop trying to get them to connect.
576+ MAX_UNCONNECTING_HEADERS = 10
577+ for j in range (MAX_UNCONNECTING_HEADERS + 1 ):
578+ blocks .append (create_block (tip , create_coinbase (height ), block_time ))
579+ blocks [- 1 ].solve ()
580+ tip = blocks [- 1 ].sha256
581+ block_time += 1
582+ height += 1
583+
584+ for i in range (1 , MAX_UNCONNECTING_HEADERS ):
585+ # Send a header that doesn't connect, check that we get a getheaders.
586+ with mininode_lock :
587+ test_node .last_getheaders = None
588+ test_node .send_header_for_blocks ([blocks [i ]])
589+ test_node .wait_for_getheaders (timeout = 1 )
590+
591+ # Next header will connect, should re-set our count:
592+ test_node .send_header_for_blocks ([blocks [0 ]])
593+
594+ # Remove the first two entries (blocks[1] would connect):
595+ blocks = blocks [2 :]
596+
597+ # Now try to see how many unconnecting headers we can send
598+ # before we get disconnected. Should be 5*MAX_UNCONNECTING_HEADERS
599+ for i in range (5 * MAX_UNCONNECTING_HEADERS - 1 ):
600+ # Send a header that doesn't connect, check that we get a getheaders.
601+ with mininode_lock :
602+ test_node .last_getheaders = None
603+ test_node .send_header_for_blocks ([blocks [i % len (blocks )]])
604+ test_node .wait_for_getheaders (timeout = 1 )
605+
606+ # Eventually this stops working.
607+ with mininode_lock :
608+ self .last_getheaders = None
609+ test_node .send_header_for_blocks ([blocks [- 1 ]])
610+
611+ # Should get disconnected
612+ test_node .wait_for_disconnect ()
613+ with mininode_lock :
614+ self .last_getheaders = True
615+
616+ print ("Part 5: success!" )
617+
513618 # Finally, check that the inv node never received a getdata request,
514619 # throughout the test
515620 assert_equal (inv_node .last_getdata , None )
0 commit comments