63
63
Expect: getdata request for 14 more blocks.
64
64
f. Announce 1 more header that builds on that fork.
65
65
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.
66
81
'''
67
82
68
83
class BaseNode (NodeConnCB ):
@@ -77,6 +92,8 @@ def __init__(self):
77
92
self .last_getdata = None
78
93
self .sleep_time = 0.05
79
94
self .block_announced = False
95
+ self .last_getheaders = None
96
+ self .disconnected = False
80
97
81
98
def clear_last_announcement (self ):
82
99
with mininode_lock :
@@ -127,6 +144,12 @@ def on_getdata(self, conn, message):
127
144
def on_pong (self , conn , message ):
128
145
self .last_pong = message
129
146
147
+ def on_getheaders (self , conn , message ):
148
+ self .last_getheaders = message
149
+
150
+ def on_close (self , conn ):
151
+ self .disconnected = True
152
+
130
153
# Test whether the last announcement we received had the
131
154
# right header or the right inv
132
155
# inv and headers should be lists of block hashes
@@ -178,6 +201,11 @@ def wait_for_block(self, blockhash, timeout=60):
178
201
self .sync (test_function , timeout )
179
202
return
180
203
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
+
181
209
def wait_for_getdata (self , hash_list , timeout = 60 ):
182
210
if hash_list == []:
183
211
return
@@ -186,6 +214,11 @@ def wait_for_getdata(self, hash_list, timeout=60):
186
214
self .sync (test_function , timeout )
187
215
return
188
216
217
+ def wait_for_disconnect (self , timeout = 60 ):
218
+ test_function = lambda : self .disconnected
219
+ self .sync (test_function , timeout )
220
+ return
221
+
189
222
def send_header_for_blocks (self , new_blocks ):
190
223
headers_message = msg_headers ()
191
224
headers_message .headers = [ CBlockHeader (b ) for b in new_blocks ]
@@ -510,6 +543,78 @@ def run_test(self):
510
543
511
544
print ("Part 4: success!" )
512
545
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
+
513
618
# Finally, check that the inv node never received a getdata request,
514
619
# throughout the test
515
620
assert_equal (inv_node .last_getdata , None )
0 commit comments