merge bitcoin#28805: Make existing functional tests compatible with --v2transport

Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
Kittywhiskers Van Gogh 2024-10-09 12:01:58 +00:00
parent 9371e2e9a4
commit 4e96e261e0
No known key found for this signature in database
GPG Key ID: 30CD0C065E5C4AAD
6 changed files with 54 additions and 23 deletions

View File

@ -8,7 +8,15 @@ Tests that a node configured with -prune=550 signals NODE_NETWORK_LIMITED correc
and that it responds to getdata requests for blocks correctly: and that it responds to getdata requests for blocks correctly:
- send a block within 288 + 2 of the tip - send a block within 288 + 2 of the tip
- disconnect peers who request blocks older than that.""" - disconnect peers who request blocks older than that."""
from test_framework.messages import CInv, MSG_BLOCK, msg_getdata, NODE_BLOOM, NODE_NETWORK_LIMITED, NODE_HEADERS_COMPRESSED from test_framework.messages import (
CInv,
MSG_BLOCK,
NODE_BLOOM,
NODE_HEADERS_COMPRESSED,
NODE_NETWORK_LIMITED,
NODE_P2P_V2,
msg_getdata,
)
from test_framework.governance import EXPECTED_STDERR_NO_GOV_PRUNE from test_framework.governance import EXPECTED_STDERR_NO_GOV_PRUNE
from test_framework.p2p import P2PInterface from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
@ -48,6 +56,8 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
node = self.nodes[0].add_p2p_connection(P2PIgnoreInv()) node = self.nodes[0].add_p2p_connection(P2PIgnoreInv())
expected_services = NODE_BLOOM | NODE_NETWORK_LIMITED | NODE_HEADERS_COMPRESSED expected_services = NODE_BLOOM | NODE_NETWORK_LIMITED | NODE_HEADERS_COMPRESSED
if self.options.v2transport:
expected_services |= NODE_P2P_V2
self.log.info("Check that node has signalled expected services.") self.log.info("Check that node has signalled expected services.")
assert_equal(node.nServices, expected_services) assert_equal(node.nServices, expected_services)

View File

@ -68,11 +68,14 @@ class TimeoutsTest(BitcoinTestFramework):
with self.nodes[0].assert_debug_log(['Unsupported message "ping" prior to verack from peer=0']): with self.nodes[0].assert_debug_log(['Unsupported message "ping" prior to verack from peer=0']):
no_verack_node.send_message(msg_ping()) no_verack_node.send_message(msg_ping())
with self.nodes[0].assert_debug_log(['non-version message before version handshake. Message "ping" from peer=1']):
no_version_node.send_message(msg_ping()) # With v2, non-version messages before the handshake would be interpreted as part of the key exchange.
# Therefore, don't execute this part of the test if v2transport is chosen.
if not self.options.v2transport:
with self.nodes[0].assert_debug_log(['non-version message before version handshake. Message "ping" from peer=1']):
no_version_node.send_message(msg_ping())
self.mock_forward(1) self.mock_forward(1)
assert "version" in no_verack_node.last_message assert "version" in no_verack_node.last_message
assert no_verack_node.is_connected assert no_verack_node.is_connected
@ -80,11 +83,12 @@ class TimeoutsTest(BitcoinTestFramework):
assert no_send_node.is_connected assert no_send_node.is_connected
no_verack_node.send_message(msg_ping()) no_verack_node.send_message(msg_ping())
no_version_node.send_message(msg_ping()) if not self.options.v2transport:
no_version_node.send_message(msg_ping())
expected_timeout_logs = [ expected_timeout_logs = [
"version handshake timeout peer=0", "version handshake timeout peer=0",
"socket no message in first 3 seconds, 1 0 peer=1", f"socket no message in first 3 seconds, {'0' if self.options.v2transport else '1'} 0 peer=1",
"socket no message in first 3 seconds, 0 0 peer=2", "socket no message in first 3 seconds, 0 0 peer=2",
] ]
@ -95,5 +99,6 @@ class TimeoutsTest(BitcoinTestFramework):
no_send_node.wait_for_disconnect(timeout=1) no_send_node.wait_for_disconnect(timeout=1)
if __name__ == '__main__': if __name__ == '__main__':
TimeoutsTest().main() TimeoutsTest().main()

View File

@ -151,7 +151,7 @@ class NetTest(DashTestFramework):
"synced_blocks": -1, "synced_blocks": -1,
"synced_headers": -1, "synced_headers": -1,
"timeoffset": 0, "timeoffset": 0,
"transport_protocol_type": "v1", "transport_protocol_type": "v1" if not self.options.v2transport else "detecting",
"version": 0, "version": 0,
}, },
) )
@ -160,19 +160,23 @@ class NetTest(DashTestFramework):
def test_getnettotals(self): def test_getnettotals(self):
self.log.info("Test getnettotals") self.log.info("Test getnettotals")
# Test getnettotals and getpeerinfo by doing a ping. The bytes # Test getnettotals and getpeerinfo by doing a ping. The bytes
# sent/received should increase by at least the size of one ping (32 # sent/received should increase by at least the size of one ping
# bytes) and one pong (32 bytes). # and one pong. Both have a payload size of 8 bytes, but the total
# size depends on the used p2p version:
# - p2p v1: 24 bytes (header) + 8 bytes (payload) = 32 bytes
# - p2p v2: 21 bytes (header/tag with short-id) + 8 bytes (payload) = 29 bytes
ping_size = 32 if not self.options.v2transport else 29
net_totals_before = self.nodes[0].getnettotals() net_totals_before = self.nodes[0].getnettotals()
peer_info_before = self.nodes[0].getpeerinfo() peer_info_before = self.nodes[0].getpeerinfo()
self.nodes[0].ping() self.nodes[0].ping()
self.wait_until(lambda: (self.nodes[0].getnettotals()['totalbytessent'] >= net_totals_before['totalbytessent'] + 32 * 2), timeout=1) self.wait_until(lambda: (self.nodes[0].getnettotals()['totalbytessent'] >= net_totals_before['totalbytessent'] + ping_size * 2), timeout=1)
self.wait_until(lambda: (self.nodes[0].getnettotals()['totalbytesrecv'] >= net_totals_before['totalbytesrecv'] + 32 * 2), timeout=1) self.wait_until(lambda: (self.nodes[0].getnettotals()['totalbytesrecv'] >= net_totals_before['totalbytesrecv'] + ping_size * 2), timeout=1)
for peer_before in peer_info_before: for peer_before in peer_info_before:
peer_after = lambda: next(p for p in self.nodes[0].getpeerinfo() if p['id'] == peer_before['id']) peer_after = lambda: next(p for p in self.nodes[0].getpeerinfo() if p['id'] == peer_before['id'])
self.wait_until(lambda: peer_after()['bytesrecv_per_msg'].get('pong', 0) >= peer_before['bytesrecv_per_msg'].get('pong', 0) + 32, timeout=1) self.wait_until(lambda: peer_after()['bytesrecv_per_msg'].get('pong', 0) >= peer_before['bytesrecv_per_msg'].get('pong', 0) + ping_size, timeout=1)
self.wait_until(lambda: peer_after()['bytessent_per_msg'].get('ping', 0) >= peer_before['bytessent_per_msg'].get('ping', 0) + 32, timeout=1) self.wait_until(lambda: peer_after()['bytessent_per_msg'].get('ping', 0) >= peer_before['bytessent_per_msg'].get('ping', 0) + ping_size, timeout=1)
def test_getnetworkinfo(self): def test_getnetworkinfo(self):
self.log.info("Test getnetworkinfo") self.log.info("Test getnetworkinfo")
@ -348,7 +352,10 @@ class NetTest(DashTestFramework):
node = self.nodes[0] node = self.nodes[0]
self.restart_node(0) self.restart_node(0)
self.connect_nodes(0, 1) # we want to use a p2p v1 connection here in order to ensure
# a peer id of zero (a downgrade from v2 to v1 would lead
# to an increase of the peer id)
self.connect_nodes(0, 1, peer_advertises_v2=False)
self.log.info("Test sendmsgtopeer") self.log.info("Test sendmsgtopeer")
self.log.debug("Send a valid message") self.log.debug("Send a valid message")

View File

@ -527,9 +527,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
assert_equal(len(binary_cli), num_nodes) assert_equal(len(binary_cli), num_nodes)
old_num_nodes = len(self.nodes) old_num_nodes = len(self.nodes)
for i in range(num_nodes): for i in range(num_nodes):
args = extra_args[i]
if self.options.v2transport and ("-v2transport=0" not in args and "-v2transport=1" not in args):
args.append("-v2transport=1")
test_node_i = TestNode( test_node_i = TestNode(
old_num_nodes + i, old_num_nodes + i,
get_datadir_path(self.options.tmpdir, old_num_nodes + i), get_datadir_path(self.options.tmpdir, old_num_nodes + i),
@ -545,11 +542,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
coverage_dir=self.options.coveragedir, coverage_dir=self.options.coveragedir,
cwd=self.options.tmpdir, cwd=self.options.tmpdir,
extra_conf=extra_confs[i], extra_conf=extra_confs[i],
extra_args=args, extra_args=extra_args[i],
use_cli=self.options.usecli, use_cli=self.options.usecli,
start_perf=self.options.perf, start_perf=self.options.perf,
use_valgrind=self.options.valgrind, use_valgrind=self.options.valgrind,
descriptors=self.options.descriptors, descriptors=self.options.descriptors,
v2transport=self.options.v2transport,
) )
self.nodes.append(test_node_i) self.nodes.append(test_node_i)
if not test_node_i.version_is_at_least(160000): if not test_node_i.version_is_at_least(160000):
@ -707,7 +705,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
ip_port = "127.0.0.1:" + str(p2p_port(b)) ip_port = "127.0.0.1:" + str(p2p_port(b))
if peer_advertises_v2 is None: if peer_advertises_v2 is None:
peer_advertises_v2 = self.options.v2transport peer_advertises_v2 = from_connection.use_v2transport
if peer_advertises_v2: if peer_advertises_v2:
from_connection.addnode(node=ip_port, command="onetry", v2transport=True) from_connection.addnode(node=ip_port, command="onetry", v2transport=True)

View File

@ -65,7 +65,7 @@ class TestNode():
To make things easier for the test writer, any unrecognised messages will To make things easier for the test writer, any unrecognised messages will
be dispatched to the RPC connection.""" be dispatched to the RPC connection."""
def __init__(self, i, datadir, extra_args_from_options, *, chain, rpchost, timewait, timeout_factor, bitcoind, bitcoin_cli, mocktime, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False): def __init__(self, i, datadir, extra_args_from_options, *, chain, rpchost, timewait, timeout_factor, bitcoind, bitcoin_cli, mocktime, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False, v2transport=False):
""" """
Kwargs: Kwargs:
start_perf (bool): If True, begin profiling the node with `perf` as soon as start_perf (bool): If True, begin profiling the node with `perf` as soon as
@ -124,6 +124,12 @@ class TestNode():
if self.version_is_at_least(21000000): if self.version_is_at_least(21000000):
self.args.append("-logsourcelocations") self.args.append("-logsourcelocations")
# Default behavior from global -v2transport flag is added to args to persist it over restarts.
# May be overwritten in individual tests, using extra_args.
self.default_to_v2 = v2transport
if self.default_to_v2:
self.args.append("-v2transport=1")
self.cli = TestNodeCLI(bitcoin_cli, self.datadir) self.cli = TestNodeCLI(bitcoin_cli, self.datadir)
self.use_cli = use_cli self.use_cli = use_cli
self.start_perf = start_perf self.start_perf = start_perf
@ -205,6 +211,8 @@ class TestNode():
if extra_args is None: if extra_args is None:
extra_args = self.extra_args extra_args = self.extra_args
self.use_v2transport = "-v2transport=1" in extra_args or (self.default_to_v2 and "-v2transport=0" not in extra_args)
# Add a new stdout and stderr file each time dashd is started # Add a new stdout and stderr file each time dashd is started
if stderr is None: if stderr is None:
stderr = tempfile.NamedTemporaryFile(dir=self.stderr_dir, delete=False) stderr = tempfile.NamedTemporaryFile(dir=self.stderr_dir, delete=False)
@ -732,15 +740,15 @@ class TestNodeCLI():
results.append(dict(error=e)) results.append(dict(error=e))
return results return results
def send_cli(self, command=None, *args, **kwargs): def send_cli(self, clicommand=None, *args, **kwargs):
"""Run dash-cli command. Deserializes returned string as python object.""" """Run dash-cli command. Deserializes returned string as python object."""
pos_args = [arg_to_cli(arg) for arg in args] pos_args = [arg_to_cli(arg) for arg in args]
named_args = [str(key) + "=" + arg_to_cli(value) for (key, value) in kwargs.items()] named_args = [str(key) + "=" + arg_to_cli(value) for (key, value) in kwargs.items()]
p_args = [self.binary, "-datadir=" + self.datadir] + self.options p_args = [self.binary, "-datadir=" + self.datadir] + self.options
if named_args: if named_args:
p_args += ["-named"] p_args += ["-named"]
if command is not None: if clicommand is not None:
p_args += [command] p_args += [clicommand]
p_args += pos_args + named_args p_args += pos_args + named_args
self.log.debug("Running dash-cli {}".format(p_args[2:])) self.log.debug("Running dash-cli {}".format(p_args[2:]))
process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

View File

@ -114,6 +114,7 @@ BASE_SCRIPTS = [
'wallet_labels.py --legacy-wallet', 'wallet_labels.py --legacy-wallet',
'wallet_labels.py --descriptors', 'wallet_labels.py --descriptors',
'p2p_timeouts.py', 'p2p_timeouts.py',
'p2p_timeouts.py --v2transport',
'feature_bip68_sequence.py', 'feature_bip68_sequence.py',
'mempool_updatefromblock.py', 'mempool_updatefromblock.py',
'p2p_tx_download.py', 'p2p_tx_download.py',
@ -224,6 +225,7 @@ BASE_SCRIPTS = [
'p2p_getdata.py', 'p2p_getdata.py',
'p2p_addrfetch.py', 'p2p_addrfetch.py',
'rpc_net.py', 'rpc_net.py',
'rpc_net.py --v2transport',
'wallet_keypool.py --legacy-wallet', 'wallet_keypool.py --legacy-wallet',
'wallet_keypool_hd.py --legacy-wallet', 'wallet_keypool_hd.py --legacy-wallet',
'wallet_keypool_hd.py --descriptors', 'wallet_keypool_hd.py --descriptors',
@ -360,6 +362,7 @@ BASE_SCRIPTS = [
'feature_coinstatsindex.py', 'feature_coinstatsindex.py',
'wallet_orphanedreward.py', 'wallet_orphanedreward.py',
'p2p_node_network_limited.py', 'p2p_node_network_limited.py',
'p2p_node_network_limited.py --v2transport',
'p2p_permissions.py', 'p2p_permissions.py',
'feature_blocksdir.py', 'feature_blocksdir.py',
'wallet_startup.py', 'wallet_startup.py',