Skip to content

Commit 6629d1d

Browse files
committed
test: improve robustness of connect_nodes()
The 'connect_nodes' function in the test framework relies on a stable number of peer connections to verify the new connection between the nodes is successfully established. This approach is fragile, as any of the peers involved in the process can drop, lose, or create a connection at any step, causing subsequent 'wait_until' checks to stall indefinitely even when the peers in question are connected successfully. This commit improves the situation by using the nodes' subversion and the connection direction (inbound/outbound) to identify the exact peer connection and perform the checks exclusively on it.
1 parent 71f0f22 commit 6629d1d

File tree

2 files changed

+20
-9
lines changed

2 files changed

+20
-9
lines changed

test/functional/test_framework/test_framework.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -610,8 +610,6 @@ def connect_nodes(self, a, b, *, peer_advertises_v2=None, wait_for_connect: bool
610610
"""
611611
from_connection = self.nodes[a]
612612
to_connection = self.nodes[b]
613-
from_num_peers = 1 + len(from_connection.getpeerinfo())
614-
to_num_peers = 1 + len(to_connection.getpeerinfo())
615613
ip_port = "127.0.0.1:" + str(p2p_port(b))
616614

617615
if peer_advertises_v2 is None:
@@ -627,19 +625,32 @@ def connect_nodes(self, a, b, *, peer_advertises_v2=None, wait_for_connect: bool
627625
if not wait_for_connect:
628626
return
629627

628+
# Use subversion as peer id. Test nodes have their node number appended to the user agent string
629+
from_connection_subver = from_connection.getnetworkinfo()['subversion']
630+
to_connection_subver = to_connection.getnetworkinfo()['subversion']
631+
632+
def find_conn(node, peer_subversion, inbound):
633+
return next(filter(lambda peer: peer['subver'] == peer_subversion and peer['inbound'] == inbound, node.getpeerinfo()), None)
634+
630635
# poll until version handshake complete to avoid race conditions
631636
# with transaction relaying
632637
# See comments in net_processing:
633638
# * Must have a version message before anything else
634639
# * Must have a verack message before anything else
635-
self.wait_until(lambda: sum(peer['version'] != 0 for peer in from_connection.getpeerinfo()) == from_num_peers)
636-
self.wait_until(lambda: sum(peer['version'] != 0 for peer in to_connection.getpeerinfo()) == to_num_peers)
637-
self.wait_until(lambda: sum(peer['bytesrecv_per_msg'].pop('verack', 0) >= 21 for peer in from_connection.getpeerinfo()) == from_num_peers)
638-
self.wait_until(lambda: sum(peer['bytesrecv_per_msg'].pop('verack', 0) >= 21 for peer in to_connection.getpeerinfo()) == to_num_peers)
640+
self.wait_until(lambda: find_conn(from_connection, to_connection_subver, inbound=False) is not None)
641+
self.wait_until(lambda: find_conn(to_connection, from_connection_subver, inbound=True) is not None)
642+
643+
def check_bytesrecv(peer, msg_type, min_bytes_recv):
644+
assert peer is not None, "Error: peer disconnected"
645+
return peer['bytesrecv_per_msg'].pop(msg_type, 0) >= min_bytes_recv
646+
647+
self.wait_until(lambda: check_bytesrecv(find_conn(from_connection, to_connection_subver, inbound=False), 'verack', 21))
648+
self.wait_until(lambda: check_bytesrecv(find_conn(to_connection, from_connection_subver, inbound=True), 'verack', 21))
649+
639650
# The message bytes are counted before processing the message, so make
640651
# sure it was fully processed by waiting for a ping.
641-
self.wait_until(lambda: sum(peer["bytesrecv_per_msg"].pop("pong", 0) >= 29 for peer in from_connection.getpeerinfo()) == from_num_peers)
642-
self.wait_until(lambda: sum(peer["bytesrecv_per_msg"].pop("pong", 0) >= 29 for peer in to_connection.getpeerinfo()) == to_num_peers)
652+
self.wait_until(lambda: check_bytesrecv(find_conn(from_connection, to_connection_subver, inbound=False), 'pong', 29))
653+
self.wait_until(lambda: check_bytesrecv(find_conn(to_connection, from_connection_subver, inbound=True), 'pong', 29))
643654

644655
def disconnect_nodes(self, a, b):
645656
def disconnect_nodes_helper(node_a, node_b):

test/functional/test_framework/test_node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def __init__(self, i, datadir_path, *, chain, rpchost, timewait, timeout_factor,
106106
"-debugexclude=libevent",
107107
"-debugexclude=leveldb",
108108
"-debugexclude=rand",
109-
"-uacomment=testnode%d" % i,
109+
"-uacomment=testnode%d" % i, # required for subversion uniqueness across peers
110110
]
111111
if self.descriptors is None:
112112
self.args.append("-disablewallet")

0 commit comments

Comments
 (0)