Skip to content

Commit 1c58250

Browse files
author
MarcoFalke
committed
Merge #13192: [tests] Fixed intermittent failure in p2p_sendheaders.py.
12d1b77 [tests] Fixed intermittent failure in p2p_sendheaders.py. (lmanners) Pull request description: Added handling for the case where headers are announced over more than one message. refs #12453 Tree-SHA512: 2c5b48ff019089b86e358181ba170d3aac09d4ae41ec79c2718e0ee83705860501bbcb8fd94d0f5c4f86c0d54a96781a967716621bb8c5ecc991b39af3cec506
2 parents f3e747e + 12d1b77 commit 1c58250

File tree

1 file changed

+51
-45
lines changed

1 file changed

+51
-45
lines changed

test/functional/p2p_sendheaders.py

Lines changed: 51 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ def __init__(self):
116116

117117
self.block_announced = False
118118
self.last_blockhash_announced = None
119+
self.recent_headers_announced = []
119120

120121
def send_get_data(self, block_hashes):
121122
"""Request data for a list of block hashes."""
@@ -163,40 +164,45 @@ def on_inv(self, message):
163164
def on_headers(self, message):
164165
if len(message.headers):
165166
self.block_announced = True
166-
message.headers[-1].calc_sha256()
167+
for x in message.headers:
168+
x.calc_sha256()
169+
# append because headers may be announced over multiple messages.
170+
self.recent_headers_announced.append(x.sha256)
167171
self.last_blockhash_announced = message.headers[-1].sha256
168172

169-
def clear_last_announcement(self):
173+
def clear_block_announcements(self):
170174
with mininode_lock:
171175
self.block_announced = False
172176
self.last_message.pop("inv", None)
173177
self.last_message.pop("headers", None)
178+
self.recent_headers_announced = []
174179

175-
def check_last_announcement(self, headers=None, inv=None):
176-
"""Test whether the last announcement received had the right header or the right inv.
177180

178-
inv and headers should be lists of block hashes."""
181+
def check_last_headers_announcement(self, headers):
182+
"""Test whether the last headers announcements received are right.
183+
Headers may be announced across more than one message."""
184+
test_function = lambda: (len(self.recent_headers_announced) >= len(headers))
185+
wait_until(test_function, timeout=60, lock=mininode_lock)
186+
with mininode_lock:
187+
assert_equal(self.recent_headers_announced, headers)
188+
self.block_announced = False
189+
self.last_message.pop("headers", None)
190+
self.recent_headers_announced = []
191+
192+
def check_last_inv_announcement(self, inv):
193+
"""Test whether the last announcement received had the right inv.
194+
inv should be a list of block hashes."""
179195

180196
test_function = lambda: self.block_announced
181197
wait_until(test_function, timeout=60, lock=mininode_lock)
182198

183199
with mininode_lock:
184-
self.block_announced = False
185-
186200
compare_inv = []
187201
if "inv" in self.last_message:
188202
compare_inv = [x.hash for x in self.last_message["inv"].inv]
189-
if inv is not None:
190-
assert_equal(compare_inv, inv)
191-
192-
compare_headers = []
193-
if "headers" in self.last_message:
194-
compare_headers = [x.sha256 for x in self.last_message["headers"].headers]
195-
if headers is not None:
196-
assert_equal(compare_headers, headers)
197-
203+
assert_equal(compare_inv, inv)
204+
self.block_announced = False
198205
self.last_message.pop("inv", None)
199-
self.last_message.pop("headers", None)
200206

201207
class SendHeadersTest(BitcoinTestFramework):
202208
def set_test_params(self):
@@ -206,8 +212,8 @@ def set_test_params(self):
206212
def mine_blocks(self, count):
207213
"""Mine count blocks and return the new tip."""
208214

209-
# Clear out last block announcement from each p2p listener
210-
[x.clear_last_announcement() for x in self.nodes[0].p2ps]
215+
# Clear out block announcements from each p2p listener
216+
[x.clear_block_announcements() for x in self.nodes[0].p2ps]
211217
self.nodes[0].generate(count)
212218
return int(self.nodes[0].getbestblockhash(), 16)
213219

@@ -222,7 +228,7 @@ def mine_reorg(self, length):
222228
sync_blocks(self.nodes, wait=0.1)
223229
for x in self.nodes[0].p2ps:
224230
x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16))
225-
x.clear_last_announcement()
231+
x.clear_block_announcements()
226232

227233
tip_height = self.nodes[1].getblockcount()
228234
hash_to_invalidate = self.nodes[1].getblockhash(tip_height - (length - 1))
@@ -255,25 +261,25 @@ def test_null_locators(self, test_node, inv_node):
255261
tip = self.nodes[0].getblockheader(self.nodes[0].generate(1)[0])
256262
tip_hash = int(tip["hash"], 16)
257263

258-
inv_node.check_last_announcement(inv=[tip_hash], headers=[])
259-
test_node.check_last_announcement(inv=[tip_hash], headers=[])
264+
inv_node.check_last_inv_announcement(inv=[tip_hash])
265+
test_node.check_last_inv_announcement(inv=[tip_hash])
260266

261267
self.log.info("Verify getheaders with null locator and valid hashstop returns headers.")
262-
test_node.clear_last_announcement()
268+
test_node.clear_block_announcements()
263269
test_node.send_get_headers(locator=[], hashstop=tip_hash)
264-
test_node.check_last_announcement(headers=[tip_hash])
270+
test_node.check_last_headers_announcement(headers=[tip_hash])
265271

266272
self.log.info("Verify getheaders with null locator and invalid hashstop does not return headers.")
267273
block = create_block(int(tip["hash"], 16), create_coinbase(tip["height"] + 1), tip["mediantime"] + 1)
268274
block.solve()
269275
test_node.send_header_for_blocks([block])
270-
test_node.clear_last_announcement()
276+
test_node.clear_block_announcements()
271277
test_node.send_get_headers(locator=[], hashstop=int(block.hash, 16))
272278
test_node.sync_with_ping()
273279
assert_equal(test_node.block_announced, False)
274-
inv_node.clear_last_announcement()
280+
inv_node.clear_block_announcements()
275281
test_node.send_message(msg_block(block))
276-
inv_node.check_last_announcement(inv=[int(block.hash, 16)], headers=[])
282+
inv_node.check_last_inv_announcement(inv=[int(block.hash, 16)])
277283

278284
def test_nonnull_locators(self, test_node, inv_node):
279285
tip = int(self.nodes[0].getbestblockhash(), 16)
@@ -284,8 +290,8 @@ def test_nonnull_locators(self, test_node, inv_node):
284290
for i in range(4):
285291
old_tip = tip
286292
tip = self.mine_blocks(1)
287-
inv_node.check_last_announcement(inv=[tip], headers=[])
288-
test_node.check_last_announcement(inv=[tip], headers=[])
293+
inv_node.check_last_inv_announcement(inv=[tip])
294+
test_node.check_last_inv_announcement(inv=[tip])
289295
# Try a few different responses; none should affect next announcement
290296
if i == 0:
291297
# first request the block
@@ -296,7 +302,7 @@ def test_nonnull_locators(self, test_node, inv_node):
296302
test_node.send_get_headers(locator=[old_tip], hashstop=tip)
297303
test_node.send_get_data([tip])
298304
test_node.wait_for_block(tip)
299-
test_node.clear_last_announcement() # since we requested headers...
305+
test_node.clear_block_announcements() # since we requested headers...
300306
elif i == 2:
301307
# this time announce own block via headers
302308
height = self.nodes[0].getblockcount()
@@ -308,8 +314,8 @@ def test_nonnull_locators(self, test_node, inv_node):
308314
test_node.wait_for_getdata([new_block.sha256])
309315
test_node.send_message(msg_block(new_block))
310316
test_node.sync_with_ping() # make sure this block is processed
311-
inv_node.clear_last_announcement()
312-
test_node.clear_last_announcement()
317+
inv_node.clear_block_announcements()
318+
test_node.clear_block_announcements()
313319

314320
self.log.info("Part 1: success!")
315321
self.log.info("Part 2: announce blocks with headers after sendheaders message...")
@@ -323,8 +329,8 @@ def test_nonnull_locators(self, test_node, inv_node):
323329

324330
# Now that we've synced headers, headers announcements should work
325331
tip = self.mine_blocks(1)
326-
inv_node.check_last_announcement(inv=[tip], headers=[])
327-
test_node.check_last_announcement(headers=[tip])
332+
inv_node.check_last_inv_announcement(inv=[tip])
333+
test_node.check_last_headers_announcement(headers=[tip])
328334

329335
height = self.nodes[0].getblockcount() + 1
330336
block_time += 10 # Advance far enough ahead
@@ -368,8 +374,8 @@ def test_nonnull_locators(self, test_node, inv_node):
368374
assert "inv" not in inv_node.last_message
369375
assert "headers" not in inv_node.last_message
370376
tip = self.mine_blocks(1)
371-
inv_node.check_last_announcement(inv=[tip], headers=[])
372-
test_node.check_last_announcement(headers=[tip])
377+
inv_node.check_last_inv_announcement(inv=[tip])
378+
test_node.check_last_headers_announcement(headers=[tip])
373379
height += 1
374380
block_time += 1
375381

@@ -383,16 +389,16 @@ def test_nonnull_locators(self, test_node, inv_node):
383389
# First try mining a reorg that can propagate with header announcement
384390
new_block_hashes = self.mine_reorg(length=7)
385391
tip = new_block_hashes[-1]
386-
inv_node.check_last_announcement(inv=[tip], headers=[])
387-
test_node.check_last_announcement(headers=new_block_hashes)
392+
inv_node.check_last_inv_announcement(inv=[tip])
393+
test_node.check_last_headers_announcement(headers=new_block_hashes)
388394

389395
block_time += 8
390396

391397
# Mine a too-large reorg, which should be announced with a single inv
392398
new_block_hashes = self.mine_reorg(length=8)
393399
tip = new_block_hashes[-1]
394-
inv_node.check_last_announcement(inv=[tip], headers=[])
395-
test_node.check_last_announcement(inv=[tip], headers=[])
400+
inv_node.check_last_inv_announcement(inv=[tip])
401+
test_node.check_last_inv_announcement(inv=[tip])
396402

397403
block_time += 9
398404

@@ -401,15 +407,15 @@ def test_nonnull_locators(self, test_node, inv_node):
401407

402408
# Use getblocks/getdata
403409
test_node.send_getblocks(locator=[fork_point])
404-
test_node.check_last_announcement(inv=new_block_hashes, headers=[])
410+
test_node.check_last_inv_announcement(inv=new_block_hashes)
405411
test_node.send_get_data(new_block_hashes)
406412
test_node.wait_for_block(new_block_hashes[-1])
407413

408414
for i in range(3):
409415
# Mine another block, still should get only an inv
410416
tip = self.mine_blocks(1)
411-
inv_node.check_last_announcement(inv=[tip], headers=[])
412-
test_node.check_last_announcement(inv=[tip], headers=[])
417+
inv_node.check_last_inv_announcement(inv=[tip])
418+
test_node.check_last_inv_announcement(inv=[tip])
413419
if i == 0:
414420
self.log.debug("Just get the data -- shouldn't cause headers announcements to resume")
415421
test_node.send_get_data([tip])
@@ -431,8 +437,8 @@ def test_nonnull_locators(self, test_node, inv_node):
431437
test_node.sync_with_ping()
432438
# New blocks should now be announced with header
433439
tip = self.mine_blocks(1)
434-
inv_node.check_last_announcement(inv=[tip], headers=[])
435-
test_node.check_last_announcement(headers=[tip])
440+
inv_node.check_last_inv_announcement(inv=[tip])
441+
test_node.check_last_headers_announcement(headers=[tip])
436442

437443
self.log.info("Part 3: success!")
438444

0 commit comments

Comments
 (0)