Skip to content

Commit d513405

Browse files
sdaftuarlaanwj
authored andcommitted
[Tests] Eliminate intermittent failures in sendheaders.py
- Add race-condition debugging tool to mininode - Eliminate race condition in sendheaders.py test Clear the last block announcement before mining new blocks. Github-Pull: #7308 Rebased-From: 82a0ce0 168915e
1 parent 4707797 commit d513405

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

qa/rpc-tests/sendheaders.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -220,18 +220,20 @@ def setup_network(self):
220220

221221
# mine count blocks and return the new tip
222222
def mine_blocks(self, count):
223+
# Clear out last block announcement from each p2p listener
224+
[ x.clear_last_announcement() for x in self.p2p_connections ]
223225
self.nodes[0].generate(count)
224226
return int(self.nodes[0].getbestblockhash(), 16)
225227

226228
# mine a reorg that invalidates length blocks (replacing them with
227229
# length+1 blocks).
228-
# peers is the p2p nodes we're using; we clear their state after the
230+
# Note: we clear the state of our p2p connections after the
229231
# to-be-reorged-out blocks are mined, so that we don't break later tests.
230232
# return the list of block hashes newly mined
231-
def mine_reorg(self, length, peers):
233+
def mine_reorg(self, length):
232234
self.nodes[0].generate(length) # make sure all invalidated blocks are node0's
233235
sync_blocks(self.nodes, wait=0.1)
234-
[x.clear_last_announcement() for x in peers]
236+
[x.clear_last_announcement() for x in self.p2p_connections]
235237

236238
tip_height = self.nodes[1].getblockcount()
237239
hash_to_invalidate = self.nodes[1].getblockhash(tip_height-(length-1))
@@ -245,6 +247,8 @@ def run_test(self):
245247
inv_node = InvNode()
246248
test_node = TestNode()
247249

250+
self.p2p_connections = [inv_node, test_node]
251+
248252
connections = []
249253
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], inv_node))
250254
# Set nServices to 0 for test_node, so no block download will occur outside of
@@ -303,7 +307,6 @@ def run_test(self):
303307
prev_tip = int(self.nodes[0].getbestblockhash(), 16)
304308
test_node.get_headers(locator=[prev_tip], hashstop=0L)
305309
test_node.sync_with_ping()
306-
test_node.clear_last_announcement() # Clear out empty headers response
307310

308311
# Now that we've synced headers, headers announcements should work
309312
tip = self.mine_blocks(1)
@@ -352,8 +355,6 @@ def run_test(self):
352355
# broadcast it)
353356
assert_equal(inv_node.last_inv, None)
354357
assert_equal(inv_node.last_headers, None)
355-
inv_node.clear_last_announcement()
356-
test_node.clear_last_announcement()
357358
tip = self.mine_blocks(1)
358359
assert_equal(inv_node.check_last_announcement(inv=[tip]), True)
359360
assert_equal(test_node.check_last_announcement(headers=[tip]), True)
@@ -368,15 +369,15 @@ def run_test(self):
368369
# getheaders or inv from peer.
369370
for j in xrange(2):
370371
# First try mining a reorg that can propagate with header announcement
371-
new_block_hashes = self.mine_reorg(length=7, peers=[test_node, inv_node])
372+
new_block_hashes = self.mine_reorg(length=7)
372373
tip = new_block_hashes[-1]
373374
assert_equal(inv_node.check_last_announcement(inv=[tip]), True)
374375
assert_equal(test_node.check_last_announcement(headers=new_block_hashes), True)
375376

376377
block_time += 8
377378

378379
# Mine a too-large reorg, which should be announced with a single inv
379-
new_block_hashes = self.mine_reorg(length=8, peers=[test_node, inv_node])
380+
new_block_hashes = self.mine_reorg(length=8)
380381
tip = new_block_hashes[-1]
381382
assert_equal(inv_node.check_last_announcement(inv=[tip]), True)
382383
assert_equal(test_node.check_last_announcement(inv=[tip]), True)
@@ -407,7 +408,6 @@ def run_test(self):
407408
test_node.get_headers(locator=[fork_point], hashstop=new_block_hashes[1])
408409
test_node.get_data([tip])
409410
test_node.wait_for_block(tip)
410-
test_node.clear_last_announcement()
411411
elif i == 2:
412412
test_node.get_data([tip])
413413
test_node.wait_for_block(tip)

qa/rpc-tests/test_framework/mininode.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,18 @@ def __repr__(self):
10041004
class NodeConnCB(object):
10051005
def __init__(self):
10061006
self.verack_received = False
1007+
# deliver_sleep_time is helpful for debugging race conditions in p2p
1008+
# tests; it causes message delivery to sleep for the specified time
1009+
# before acquiring the global lock and delivering the next message.
1010+
self.deliver_sleep_time = None
1011+
1012+
def set_deliver_sleep_time(self, value):
1013+
with mininode_lock:
1014+
self.deliver_sleep_time = value
1015+
1016+
def get_deliver_sleep_time(self):
1017+
with mininode_lock:
1018+
return self.deliver_sleep_time
10071019

10081020
# Spin until verack message is received from the node.
10091021
# Tests may want to use this as a signal that the test can begin.
@@ -1017,6 +1029,9 @@ def wait_for_verack(self):
10171029
time.sleep(0.05)
10181030

10191031
def deliver(self, conn, message):
1032+
deliver_sleep = self.get_deliver_sleep_time()
1033+
if deliver_sleep is not None:
1034+
time.sleep(deliver_sleep)
10201035
with mininode_lock:
10211036
try:
10221037
getattr(self, 'on_' + message.command)(conn, message)

0 commit comments

Comments
 (0)