diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py index be1aa189938..be0715df32c 100755 --- a/test/functional/feature_assumeutxo.py +++ b/test/functional/feature_assumeutxo.py @@ -142,7 +142,10 @@ def no_sync(): f"-stopatheight={PAUSE_HEIGHT}", *self.extra_args[1]]) # Finally connect the nodes and let them sync. - self.connect_nodes(0, 1) + # + # Set `wait_for_connect=False` to avoid a race between performing connection + # assertions and the -stopatheight tripping. + self.connect_nodes(0, 1, wait_for_connect=False) n1.wait_until_stopped(timeout=5) @@ -156,7 +159,15 @@ def no_sync(): self.connect_nodes(0, 1) self.log.info(f"Ensuring snapshot chain syncs to tip. ({FINAL_HEIGHT})") - wait_until_helper(lambda: n1.getchainstates()['snapshot']['blocks'] == FINAL_HEIGHT) + + def check_for_final_height(): + chainstates = n1.getchainstates() + # The background validation may have completed before we run our first + # check, so accept a final blockheight from either chainstate type. + cs = chainstates.get('snapshot') or chainstates.get('normal') + return cs['blocks'] == FINAL_HEIGHT + + wait_until_helper(check_for_final_height) self.sync_blocks(nodes=(n0, n1)) self.log.info("Ensuring background validation completes") diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index ab7fed335c6..a34c34713e9 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -586,7 +586,14 @@ def restart_node(self, i, extra_args=None): def wait_for_node_exit(self, i, timeout): self.nodes[i].process.wait(timeout) - def connect_nodes(self, a, b, *, peer_advertises_v2=None): + def connect_nodes(self, a, b, *, peer_advertises_v2=None, wait_for_connect: bool = True): + """ + Kwargs: + wait_for_connect: if True, block until the nodes are verified as connected. You might + want to disable this when using -stopatheight with one of the connected nodes, + since there will be a race between the actual connection and performing + the assertions before one node shuts down. + """ from_connection = self.nodes[a] to_connection = self.nodes[b] from_num_peers = 1 + len(from_connection.getpeerinfo()) @@ -603,6 +610,9 @@ def connect_nodes(self, a, b, *, peer_advertises_v2=None): # compatibility with older clients from_connection.addnode(ip_port, "onetry") + if not wait_for_connect: + return + # poll until version handshake complete to avoid race conditions # with transaction relaying # See comments in net_processing: