diff options
Diffstat (limited to 'test')
-rwxr-xr-x | test/functional/feature_backwards_compatibility.py | 60 | ||||
-rwxr-xr-x | test/functional/p2p_leak.py | 7 | ||||
-rwxr-xr-x | test/functional/p2p_segwit.py | 4 | ||||
-rwxr-xr-x | test/functional/test_framework/mininode.py | 30 | ||||
-rwxr-xr-x | test/functional/test_framework/test_framework.py | 54 | ||||
-rwxr-xr-x | test/functional/test_framework/test_node.py | 9 | ||||
-rw-r--r-- | test/functional/test_framework/util.py | 5 | ||||
-rwxr-xr-x | test/functional/wallet_upgradewallet.py | 25 |
8 files changed, 116 insertions, 78 deletions
diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/feature_backwards_compatibility.py index 166c28d376..9cff79a42c 100755 --- a/test/functional/feature_backwards_compatibility.py +++ b/test/functional/feature_backwards_compatibility.py @@ -18,15 +18,16 @@ needs an older patch version. import os import shutil -from test_framework.test_framework import BitcoinTestFramework, SkipTest +from test_framework.test_framework import BitcoinTestFramework from test_framework.descriptors import descsum_create from test_framework.util import ( assert_equal, sync_blocks, - sync_mempools + sync_mempools, ) + class BackwardsCompatibilityTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True @@ -42,35 +43,15 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() + self.skip_if_no_previous_releases() def setup_nodes(self): - if os.getenv("TEST_PREVIOUS_RELEASES") == "false": - raise SkipTest("backwards compatibility tests") - - releases_path = os.getenv("PREVIOUS_RELEASES_DIR") or os.getcwd() + "/releases" - if not os.path.isdir(releases_path): - if os.getenv("TEST_PREVIOUS_RELEASES") == "true": - raise AssertionError("TEST_PREVIOUS_RELEASES=1 but releases missing: " + releases_path) - raise SkipTest("This test requires binaries for previous releases") - self.add_nodes(self.num_nodes, extra_args=self.extra_args, versions=[ None, None, - 190000, + 190001, 180100, - 170100 - ], binary=[ - self.options.bitcoind, - self.options.bitcoind, - releases_path + "/v0.19.0.1/bin/bitcoind", - releases_path + "/v0.18.1/bin/bitcoind", - releases_path + "/v0.17.1/bin/bitcoind" - ], binary_cli=[ - self.options.bitcoincli, - self.options.bitcoincli, - releases_path + "/v0.19.0.1/bin/bitcoin-cli", - releases_path + "/v0.18.1/bin/bitcoin-cli", - releases_path + "/v0.17.1/bin/bitcoin-cli" + 170100, ]) self.start_nodes() @@ -321,9 +302,9 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): node_v17.rpc.createwallet(wallet_name="u1_v17") wallet = node_v17.get_wallet_rpc("u1_v17") address = wallet.getnewaddress("bech32") - info = wallet.getaddressinfo(address) - hdkeypath = info["hdkeypath"] - pubkey = info["pubkey"] + v17_info = wallet.getaddressinfo(address) + hdkeypath = v17_info["hdkeypath"] + pubkey = v17_info["pubkey"] # Copy the 0.17 wallet to the last Bitcoin Core version and open it: node_v17.unloadwallet("u1_v17") @@ -337,6 +318,18 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): descriptor = "wpkh([" + info["hdmasterfingerprint"] + hdkeypath[1:] + "]" + pubkey + ")" assert_equal(info["desc"], descsum_create(descriptor)) + # Now copy that same wallet back to 0.17 to make sure no automatic upgrade breaks it + node_master.unloadwallet("u1_v17") + shutil.rmtree(os.path.join(node_v17_wallets_dir, "u1_v17")) + shutil.copytree( + os.path.join(node_master_wallets_dir, "u1_v17"), + os.path.join(node_v17_wallets_dir, "u1_v17") + ) + node_v17.loadwallet("u1_v17") + wallet = node_v17.get_wallet_rpc("u1_v17") + info = wallet.getaddressinfo(address) + assert_equal(info, v17_info) + # Copy the 0.19 wallet to the last Bitcoin Core version and open it: shutil.copytree( os.path.join(node_v19_wallets_dir, "w1_v19"), @@ -346,5 +339,16 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): wallet = node_master.get_wallet_rpc("w1_v19") assert wallet.getaddressinfo(address_18075)["solvable"] + # Now copy that same wallet back to 0.19 to make sure no automatic upgrade breaks it + node_master.unloadwallet("w1_v19") + shutil.rmtree(os.path.join(node_v19_wallets_dir, "w1_v19")) + shutil.copytree( + os.path.join(node_master_wallets_dir, "w1_v19"), + os.path.join(node_v19_wallets_dir, "w1_v19") + ) + node_v19.loadwallet("w1_v19") + wallet = node_v19.get_wallet_rpc("w1_v19") + assert wallet.getaddressinfo(address_18075)["solvable"] + if __name__ == '__main__': BackwardsCompatibilityTest().main() diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py index 7f7430d04e..157af68203 100755 --- a/test/functional/p2p_leak.py +++ b/test/functional/p2p_leak.py @@ -141,12 +141,11 @@ class P2PLeakTest(BitcoinTestFramework): assert no_verack_idlenode.unexpected_msg == False self.log.info('Check that the version message does not leak the local address of the node') - time_begin = int(time.time()) p2p_version_store = self.nodes[0].add_p2p_connection(P2PVersionStore()) - time_end = time.time() ver = p2p_version_store.version_received - assert_greater_than_or_equal(ver.nTime, time_begin) - assert_greater_than_or_equal(time_end, ver.nTime) + # Check that received time is within one hour of now + assert_greater_than_or_equal(ver.nTime, time.time() - 3600) + assert_greater_than_or_equal(time.time() + 3600, ver.nTime) assert_equal(ver.addrFrom.port, 0) assert_equal(ver.addrFrom.ip, '0.0.0.0') assert_equal(ver.nStartingHeight, 201) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index dbdce6552a..6fb0fec32b 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -1896,12 +1896,12 @@ class SegWitTest(BitcoinTestFramework): def test_upgrade_after_activation(self): """Test the behavior of starting up a segwit-aware node after the softfork has activated.""" - # Restart with the new binary self.stop_node(2) self.start_node(2, extra_args=["-segwitheight={}".format(SEGWIT_HEIGHT)]) connect_nodes(self.nodes[0], 2) - self.sync_blocks() + # We reconnect more than 100 blocks, give it plenty of time + self.sync_blocks(timeout=240) # Make sure that this peer thinks segwit has activated. assert softfork_active(self.nodes[2], 'segwit') diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index 257499fcb9..31cec66ee7 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -120,8 +120,9 @@ class P2PConnection(asyncio.Protocol): def is_connected(self): return self._transport is not None - def peer_connect(self, dstaddr, dstport, *, net): + def peer_connect(self, dstaddr, dstport, *, net, factor): assert not self.is_connected + self.factor = factor self.dstaddr = dstaddr self.dstport = dstport # The initial message to send after the connection was made: @@ -367,9 +368,12 @@ class P2PInterface(P2PConnection): # Connection helper methods + def wait_until(self, test_function, timeout): + wait_until(test_function, timeout=timeout, lock=mininode_lock, factor=self.factor) + def wait_for_disconnect(self, timeout=60): test_function = lambda: not self.is_connected - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) # Message receiving helper methods @@ -380,14 +384,14 @@ class P2PInterface(P2PConnection): return False return self.last_message['tx'].tx.rehash() == txid - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_block(self, blockhash, timeout=60): def test_function(): assert self.is_connected return self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_header(self, blockhash, timeout=60): def test_function(): @@ -397,7 +401,7 @@ class P2PInterface(P2PConnection): return False return last_headers.headers[0].rehash() == int(blockhash, 16) - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_merkleblock(self, blockhash, timeout=60): def test_function(): @@ -407,7 +411,7 @@ class P2PInterface(P2PConnection): return False return last_filtered_block.merkleblock.header.rehash() == int(blockhash, 16) - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_getdata(self, hash_list, timeout=60): """Waits for a getdata message. @@ -421,7 +425,7 @@ class P2PInterface(P2PConnection): return False return [x.hash for x in last_data.inv] == hash_list - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_getheaders(self, timeout=60): """Waits for a getheaders message. @@ -435,7 +439,7 @@ class P2PInterface(P2PConnection): assert self.is_connected return self.last_message.get("getheaders") - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_inv(self, expected_inv, timeout=60): """Waits for an INV message and checks that the first inv object in the message was as expected.""" @@ -448,13 +452,13 @@ class P2PInterface(P2PConnection): self.last_message["inv"].inv[0].type == expected_inv[0].type and \ self.last_message["inv"].inv[0].hash == expected_inv[0].hash - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_verack(self, timeout=60): def test_function(): return self.message_count["verack"] - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) # Message sending helper functions @@ -470,7 +474,7 @@ class P2PInterface(P2PConnection): assert self.is_connected return self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) self.ping_counter += 1 @@ -586,7 +590,7 @@ class P2PDataStore(P2PInterface): self.send_message(msg_block(block=b)) else: self.send_message(msg_headers([CBlockHeader(block) for block in blocks])) - wait_until(lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout, lock=mininode_lock) + self.wait_until(lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout) if expect_disconnect: self.wait_for_disconnect(timeout=timeout) @@ -594,7 +598,7 @@ class P2PDataStore(P2PInterface): self.sync_with_ping(timeout=timeout) if success: - wait_until(lambda: node.getbestblockhash() == blocks[-1].hash, timeout=timeout) + self.wait_until(lambda: node.getbestblockhash() == blocks[-1].hash, timeout=timeout) else: assert node.getbestblockhash() != blocks[-1].hash diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 8719bd0d39..11c96deefb 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -6,11 +6,12 @@ import configparser from enum import Enum -import logging import argparse +import logging import os import pdb import random +import re import shutil import subprocess import sys @@ -101,6 +102,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.bind_to_localhost_only = True self.set_test_params() self.parse_args() + self.rpc_timeout = int(self.rpc_timeout * self.options.factor) # optionally, increase timeout by a factor def main(self): """Main function. This should not be overridden by the subclass test scripts.""" @@ -167,6 +169,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): help="set a random seed for deterministically reproducing a previous test run") parser.add_argument("--descriptors", default=False, action="store_true", help="Run test using a descriptor wallet") + parser.add_argument('--factor', type=float, default=1.0, help='adjust test timeouts by a factor') self.add_options(parser) self.options = parser.parse_args() @@ -185,10 +188,11 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.options.bitcoind = os.getenv("BITCOIND", default=config["environment"]["BUILDDIR"] + '/src/bitcoind' + config["environment"]["EXEEXT"]) self.options.bitcoincli = os.getenv("BITCOINCLI", default=config["environment"]["BUILDDIR"] + '/src/bitcoin-cli' + config["environment"]["EXEEXT"]) + self.options.previous_releases_path = os.getenv("PREVIOUS_RELEASES_DIR") or os.getcwd() + "/releases" + os.environ['PATH'] = os.pathsep.join([ os.path.join(config['environment']['BUILDDIR'], 'src'), - os.path.join(config['environment']['BUILDDIR'], 'src', 'qt'), - os.environ['PATH'] + os.path.join(config['environment']['BUILDDIR'], 'src', 'qt'), os.environ['PATH'] ]) # Set up temp directory and start logging @@ -388,6 +392,25 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): Should only be called once after the nodes have been specified in set_test_params().""" + def get_bin_from_version(version, bin_name, bin_default): + if not version: + return bin_default + return os.path.join( + self.options.previous_releases_path, + re.sub( + r'\.0$', + '', # remove trailing .0 for point releases + 'v{}.{}.{}.{}'.format( + (version % 100000000) // 1000000, + (version % 1000000) // 10000, + (version % 10000) // 100, + (version % 100) // 1, + ), + ), + 'bin', + bin_name, + ) + if self.bind_to_localhost_only: extra_confs = [["bind=127.0.0.1"]] * num_nodes else: @@ -397,9 +420,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): if versions is None: versions = [None] * num_nodes if binary is None: - binary = [self.options.bitcoind] * num_nodes + binary = [get_bin_from_version(v, 'bitcoind', self.options.bitcoind) for v in versions] if binary_cli is None: - binary_cli = [self.options.bitcoincli] * num_nodes + binary_cli = [get_bin_from_version(v, 'bitcoin-cli', self.options.bitcoincli) for v in versions] assert_equal(len(extra_confs), num_nodes) assert_equal(len(extra_args), num_nodes) assert_equal(len(versions), num_nodes) @@ -412,6 +435,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): chain=self.chain, rpchost=rpchost, timewait=self.rpc_timeout, + factor=self.options.factor, bitcoind=binary[i], bitcoin_cli=binary_cli[i], version=versions[i], @@ -558,6 +582,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): extra_args=['-disablewallet'], rpchost=None, timewait=self.rpc_timeout, + factor=self.options.factor, bitcoind=self.options.bitcoind, bitcoin_cli=self.options.bitcoincli, coverage_dir=None, @@ -640,6 +665,25 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): if not self.is_cli_compiled(): raise SkipTest("bitcoin-cli has not been compiled.") + def skip_if_no_previous_releases(self): + """Skip the running test if previous releases are not available.""" + if not self.has_previous_releases(): + raise SkipTest("previous releases not available or disabled") + + def has_previous_releases(self): + """Checks whether previous releases are present and enabled.""" + if os.getenv("TEST_PREVIOUS_RELEASES") == "false": + # disabled + return False + + if not os.path.isdir(self.options.previous_releases_path): + if os.getenv("TEST_PREVIOUS_RELEASES") == "true": + raise AssertionError("TEST_PREVIOUS_RELEASES=true but releases missing: {}".format( + self.options.previous_releases_path)) + # missing + return False + return True + def is_cli_compiled(self): """Checks whether bitcoin-cli was compiled.""" return self.config["components"].getboolean("ENABLE_CLI") diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index c0075fd8ec..e6ec3c1b2d 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -62,7 +62,7 @@ class TestNode(): To make things easier for the test writer, any unrecognised messages will be dispatched to the RPC connection.""" - def __init__(self, i, datadir, *, chain, rpchost, timewait, bitcoind, bitcoin_cli, 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, *, chain, rpchost, timewait, factor, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False): """ Kwargs: start_perf (bool): If True, begin profiling the node with `perf` as soon as @@ -128,6 +128,7 @@ class TestNode(): self.perf_subprocesses = {} self.p2ps = [] + self.factor = factor AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key']) PRIV_KEYS = [ @@ -324,13 +325,13 @@ class TestNode(): return True def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT): - wait_until(self.is_node_stopped, timeout=timeout) + wait_until(self.is_node_stopped, timeout=timeout, factor=self.factor) @contextlib.contextmanager def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2): if unexpected_msgs is None: unexpected_msgs = [] - time_end = time.time() + timeout + time_end = time.time() + timeout * self.factor debug_log = os.path.join(self.datadir, self.chain, 'debug.log') with open(debug_log, encoding='utf-8') as dl: dl.seek(0, 2) @@ -487,7 +488,7 @@ class TestNode(): if 'dstaddr' not in kwargs: kwargs['dstaddr'] = '127.0.0.1' - p2p_conn.peer_connect(**kwargs, net=self.chain)() + p2p_conn.peer_connect(**kwargs, net=self.chain, factor=self.factor)() self.p2ps.append(p2p_conn) if wait_for_verack: # Wait for the node to send us the version and verack diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index eb9f6528b3..20ab9ee464 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -208,9 +208,10 @@ def str_to_b64str(string): def satoshi_round(amount): return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) -def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None): +def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None, factor=1.0): if attempts == float('inf') and timeout == float('inf'): timeout = 60 + timeout = timeout * factor attempt = 0 time_end = time.time() + timeout @@ -265,7 +266,7 @@ def get_rpc_proxy(url, node_number, *, timeout=None, coveragedir=None): """ proxy_kwargs = {} if timeout is not None: - proxy_kwargs['timeout'] = timeout + proxy_kwargs['timeout'] = int(timeout) proxy = AuthServiceProxy(url, **proxy_kwargs) proxy.url = url # store URL on proxy for info diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py index d04bc4ce44..e7e71bf3f6 100755 --- a/test/functional/wallet_upgradewallet.py +++ b/test/functional/wallet_upgradewallet.py @@ -12,14 +12,15 @@ contrib/devtools/previous_release.sh -b v0.15.2 v0.16.3 import os import shutil -from test_framework.test_framework import BitcoinTestFramework, SkipTest +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( adjust_bitcoin_conf_for_pre_17, assert_equal, assert_greater_than, - assert_is_hex_string + assert_is_hex_string, ) + class UpgradeWalletTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True @@ -32,32 +33,16 @@ class UpgradeWalletTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() + self.skip_if_no_previous_releases() def setup_network(self): self.setup_nodes() def setup_nodes(self): - if os.getenv("TEST_PREVIOUS_RELEASES") == "false": - raise SkipTest("upgradewallet RPC tests") - - releases_path = os.getenv("PREVIOUS_RELEASES_DIR") or os.getcwd() + "/releases" - if not os.path.isdir(releases_path): - if os.getenv("TEST_PREVIOUS_RELEASES") == "true": - raise AssertionError("TEST_PREVIOUS_RELEASES=1 but releases missing: " + releases_path) - raise SkipTest("This test requires binaries for previous releases") - self.add_nodes(self.num_nodes, extra_args=self.extra_args, versions=[ None, 160300, - 150200 - ], binary=[ - self.options.bitcoind, - releases_path + "/v0.16.3/bin/bitcoind", - releases_path + "/v0.15.2/bin/bitcoind", - ], binary_cli=[ - self.options.bitcoincli, - releases_path + "/v0.16.3/bin/bitcoin-cli", - releases_path + "/v0.15.2/bin/bitcoin-cli", + 150200, ]) # adapt bitcoin.conf, because older bitcoind's don't recognize config sections adjust_bitcoin_conf_for_pre_17(self.nodes[1].bitcoinconf) |