diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index d32ebf1523..860aedf5a1 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -17,6 +17,7 @@ def set_test_params(self): self.num_nodes = 1 self.supports_cli = False self.wallet_names = [] + self.disable_autoconnect = False def test_config_file_parser(self): self.stop_node(0) @@ -157,14 +158,19 @@ def test_seed_peers(self): self.stop_node(0) # No peers.dat exists and -dnsseed=1 - # We expect the node will use DNS Seeds, but Regtest mode has 0 DNS seeds - # So after 60 seconds, the node should fallback to fixed seeds (this is a slow test) + # We expect the node will use DNS Seeds, but Regtest mode does not have + # any valid DNS seeds. So after 60 seconds, the node should fallback to + # fixed seeds assert not os.path.exists(os.path.join(default_data_dir, "peers.dat")) start = int(time.time()) - with self.nodes[0].assert_debug_log(expected_msgs=[ - "Loaded 0 addresses from peers.dat", - "0 addresses found from DNS seeds", - ]): + with self.nodes[0].assert_debug_log( + expected_msgs=[ + "Loaded 0 addresses from peers.dat", + "0 addresses found from DNS seeds", + "opencon thread start", # Ensure ThreadOpenConnections::start time is properly set + ], + timeout=10, + ): self.start_node(0, extra_args=['-dnsseed=1', '-fixedseeds=1', f'-mocktime={start}']) with self.nodes[0].assert_debug_log(expected_msgs=[ "Adding fixed seeds as 60 seconds have passed and addrman is empty", @@ -202,10 +208,14 @@ def test_seed_peers(self): # We expect the node will allow 60 seconds prior to using fixed seeds assert not os.path.exists(os.path.join(default_data_dir, "peers.dat")) start = int(time.time()) - with self.nodes[0].assert_debug_log(expected_msgs=[ - "Loaded 0 addresses from peers.dat", - "DNS seeding disabled", - ]): + with self.nodes[0].assert_debug_log( + expected_msgs=[ + "Loaded 0 addresses from peers.dat", + "DNS seeding disabled", + "opencon thread start", # Ensure ThreadOpenConnections::start time is properly set + ], + timeout=10, + ): self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=1', '-addnode=fakenodeaddr', f'-mocktime={start}']) with self.nodes[0].assert_debug_log(expected_msgs=[ "Adding fixed seeds as 60 seconds have passed and addrman is empty", diff --git a/test/functional/feature_loadblock.py b/test/functional/feature_loadblock.py index 6a12cdc567..3cde60ca56 100755 --- a/test/functional/feature_loadblock.py +++ b/test/functional/feature_loadblock.py @@ -16,6 +16,7 @@ import tempfile import urllib +from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import ( BGLTestFramework, ) @@ -30,15 +31,14 @@ def set_test_params(self): def run_test(self): self.nodes[1].setnetworkactive(state=False) - self.nodes[0].generate(100) - + self.nodes[0].generate(1, COINBASE_MATURITY)[0] # Parsing the url of our node to get settings for config file data_dir = self.nodes[0].datadir node_url = urllib.parse.urlparse(self.nodes[0].url) cfg_file = os.path.join(data_dir, "linearize.cfg") bootstrap_file = os.path.join(self.options.tmpdir, "bootstrap.dat") genesis_block = self.nodes[0].getblockhash(0) - blocks_dir = os.path.join(data_dir, "regtest", "blocks") + blocks_dir = os.path.join(data_dir, self.chain, "blocks") hash_list = tempfile.NamedTemporaryFile(dir=data_dir, mode='w', delete=False, @@ -46,17 +46,17 @@ def run_test(self): self.log.info("Create linearization config file") with open(cfg_file, "a", encoding="utf-8") as cfg: - cfg.write("datadir={}\n".format(data_dir)) - cfg.write("rpcuser={}\n".format(node_url.username)) - cfg.write("rpcpassword={}\n".format(node_url.password)) - cfg.write("port={}\n".format(node_url.port)) - cfg.write("host={}\n".format(node_url.hostname)) - cfg.write("output_file={}\n".format(bootstrap_file)) - cfg.write("max_height=100\n") - cfg.write("netmagic=fabfb5da\n") - cfg.write("input={}\n".format(blocks_dir)) - cfg.write("genesis={}\n".format(genesis_block)) - cfg.write("hashlist={}\n".format(hash_list.name)) + cfg.write(f"datadir={data_dir}\n") + cfg.write(f"rpcuser={node_url.username}\n") + cfg.write(f"rpcpassword={node_url.password}\n") + cfg.write(f"port={node_url.port}\n") + cfg.write(f"host={node_url.hostname}\n") + cfg.write(f"output_file={bootstrap_file}\n") + cfg.write(f"max_height=100\n") + cfg.write(f"netmagic=fabfb5da\n") + cfg.write(f"input={blocks_dir}\n") + cfg.write(f"genesis={genesis_block}\n") + cfg.write(f"hashlist={hash_list.name}\n") base_dir = self.config["environment"]["SRCDIR"] linearize_dir = os.path.join(base_dir, "contrib", "linearize") @@ -73,7 +73,7 @@ def run_test(self): check=True) self.log.info("Restart second, unsynced node with bootstrap file") - self.restart_node(1, extra_args=["-loadblock=" + bootstrap_file]) + self.restart_node(1, extra_args=[f"-loadblock={bootstrap_file}"]) assert_equal(self.nodes[1].getblockcount(), 100) # start_node is blocking on all block files being imported assert_equal(self.nodes[1].getblockchaininfo()['blocks'], 100) diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index aebbd90044..70c51509c6 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -17,7 +17,7 @@ from test_framework.blocktools import witness_script, send_to_witness from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, sha256, ToHex from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG, OP_TRUE, OP_DROP -from test_framework.test_framework import BGLTestFramework +from test_framework.test_framework import BGLTestFramework, SkipTest from test_framework.util import ( assert_equal, assert_is_hex_string, @@ -26,6 +26,7 @@ try_rpc, ) + NODE_0 = 0 NODE_2 = 2 P2WPKH = 0 @@ -95,7 +96,12 @@ def skip_mine(self, node, txid, sign, redeem_script=""): def fail_accept(self, node, error_msg, txid, sign, redeem_script=""): assert_raises_rpc_error(-26, error_msg, send_to_witness, use_p2wsh=1, node=node, utxo=getutxo(txid), pubkey=self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=sign, insert_redeem_script=redeem_script) + def skip_test_bgl_fork(self): + raise SkipTest("Forked after segwit.") + def run_test(self): + self.skip_test_bgl_fork() + self.nodes[0].generate(161) # block 161 self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork") diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py index 142b0097b7..6a3f8ec2a2 100755 --- a/test/functional/interface_zmq.py +++ b/test/functional/interface_zmq.py @@ -90,6 +90,7 @@ def caused_notification(self, notification): class ZMQTest (BGLTestFramework): def set_test_params(self): + self.setup() self.num_nodes = 2 if self.is_wallet_compiled(): self.requires_wallet = True diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 77e8d6eced..d8e921d38c 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -276,11 +276,7 @@ def run_test(self): self.test_non_witness_transaction() self.test_v0_outputs_arent_spendable() self.test_block_relay() - self.test_getblocktemplate_before_lockin() - self.test_unnecessary_witness_before_segwit_activation() - self.test_witness_tx_relay_before_segwit_activation() - self.test_standardness_v0() - + self.log.info("Advancing to segwit activation") self.advance_to_segwit_active() diff --git a/test/functional/rpc_addresses_deprecation.py b/test/functional/rpc_addresses_deprecation.py index 1e1d81dab9..f360050862 100644 --- a/test/functional/rpc_addresses_deprecation.py +++ b/test/functional/rpc_addresses_deprecation.py @@ -50,7 +50,7 @@ def test_addresses_deprecation(self): self.log.info("Test RPCResult scriptPubKey returns the addresses field with -deprecatedrpc=addresses") script_pub_key = self.nodes[1].getblock(blockhash=hash, verbose=2)['tx'][-1]['vout'][0]['scriptPubKey'] - assert_equal(script_pub_key['addresses'], ['mvKDK6D54HU8wQumJBLHY95eq5iHFqXSBz', 'mv3rHCQSwKp2BLSuMHD8uCS32LW5xiNAA5', 'mirrsyhAQYzo5CwVhcaYJKwUJu1WJRCRJe']) + assert_equal(script_pub_key['addresses'], ['EwHmVjFtPPnfy3B6QsgkCV85NEseUTVLvx', 'Ew2QTqTGGS8ZCxiETyZbZYUTZVfTG44d9U', 'EjqR4cjyjfKL6qCppJvzxfytr4AsU4WonJ']) assert_equal(script_pub_key['reqSigs'], 2) diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py index 53fa5fbf5a..0ae1ba89e0 100755 --- a/test/functional/test_framework/p2p.py +++ b/test/functional/test_framework/p2p.py @@ -437,6 +437,7 @@ def on_version(self, message): self.send_message(msg_sendaddrv2()) self.send_message(msg_verack()) self.nServices = message.nServices + self.send_message(msg_getaddr()) # Connection helper methods @@ -575,6 +576,8 @@ def __init__(self): NetworkThread.listeners = {} NetworkThread.protos = {} + if sys.platform == 'win32': + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) NetworkThread.network_event_loop = asyncio.new_event_loop() def run(self): diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 083b816270..dc296567ca 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -113,6 +113,9 @@ def __init__(self): # By default the wallet is not required. Set to true by skip_if_no_wallet(). # When False, we ignore wallet_names regardless of what it is. self.requires_wallet = False + # Disable ThreadOpenConnections by default, so that adding entries to + # addrman will not result in automatic connections to them. + self.disable_autoconnect = True self.set_test_params() assert self.wallet_names is None or len(self.wallet_names) <= self.num_nodes if self.options.timeout_factor == 0 : @@ -554,18 +557,19 @@ def wait_for_node_exit(self, i, timeout): self.nodes[i].process.wait(timeout) def connect_nodes(self, a, b): - def connect_nodes_helper(from_connection, node_num): - ip_port = "127.0.0.1:" + str(p2p_port(node_num)) - from_connection.addnode(ip_port, "onetry") - # poll until version handshake complete to avoid race conditions - # with transaction relaying - # See comments in net_processing: - # * Must have a version message before anything else - # * Must have a verack message before anything else - wait_until_helper(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo())) - wait_until_helper(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo())) - - connect_nodes_helper(self.nodes[a], b) + from_connection = self.nodes[a] + to_connection = self.nodes[b] + ip_port = "127.0.0.1:" + str(p2p_port(b)) + from_connection.addnode(ip_port, "onetry") + # poll until version handshake complete to avoid race conditions + # with transaction relaying + # See comments in net_processing: + # * Must have a version message before anything else + # * Must have a verack message before anything else + wait_until_helper(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo())) + wait_until_helper(lambda: all(peer['version'] != 0 for peer in to_connection.getpeerinfo())) + wait_until_helper(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo())) + wait_until_helper(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in to_connection.getpeerinfo())) def disconnect_nodes(self, a, b): def disconnect_nodes_helper(from_connection, node_num): @@ -613,6 +617,29 @@ def join_network(self): self.connect_nodes(1, 2) self.sync_all() + def no_op(self): + pass + + def generate(self, generator, *args, sync_fun=None, **kwargs): + blocks = generator.generate(*args, invalid_call=False, **kwargs) + sync_fun() if sync_fun else self.sync_all() + return blocks + + def generateblock(self, generator, *args, sync_fun=None, **kwargs): + blocks = generator.generateblock(*args, invalid_call=False, **kwargs) + sync_fun() if sync_fun else self.sync_all() + return blocks + + def generatetoaddress(self, generator, *args, sync_fun=None, **kwargs): + blocks = generator.generatetoaddress(*args, invalid_call=False, **kwargs) + sync_fun() if sync_fun else self.sync_all() + return blocks + + def generatetodescriptor(self, generator, *args, sync_fun=None, **kwargs): + blocks = generator.generatetodescriptor(*args, invalid_call=False, **kwargs) + sync_fun() if sync_fun else self.sync_all() + return blocks + def sync_blocks(self, nodes=None, wait=1, timeout=60): """ Wait until everybody has the same tip. @@ -708,7 +735,7 @@ def _initialize_chain(self): if not os.path.isdir(cache_node_dir): self.log.debug("Creating cache directory {}".format(cache_node_dir)) - initialize_datadir(self.options.cachedir, CACHE_NODE_ID, self.chain) + initialize_datadir(self.options.cachedir, CACHE_NODE_ID, self.chain, self.disable_autoconnect) self.nodes.append( TestNode( CACHE_NODE_ID, @@ -765,7 +792,7 @@ def cache_path(*paths): self.log.debug("Copy cache directory {} to node {}".format(cache_node_dir, i)) to_dir = get_datadir_path(self.options.tmpdir, i) shutil.copytree(cache_node_dir, to_dir) - initialize_datadir(self.options.tmpdir, i, self.chain) # Overwrite port/rpcport in BGL.conf + initialize_datadir(self.options.tmpdir, i, self.chain, self.disable_autoconnect) # Overwrite port/rpcport in bitcoin.conf def _initialize_chain_clean(self): """Initialize empty blockchain for use by the test. @@ -773,7 +800,7 @@ def _initialize_chain_clean(self): Create an empty blockchain and num_nodes wallets. Useful if a test case wants complete control over initialization.""" for i in range(self.num_nodes): - initialize_datadir(self.options.tmpdir, i, self.chain) + initialize_datadir(self.options.tmpdir, i, self.chain, self.disable_autoconnect) def skip_if_no_py3_zmq(self): """Attempt to import the zmq package and skip the test if the import fails.""" diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 3a26a2971e..4dcc9381d0 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -339,17 +339,17 @@ def rpc_url(datadir, i, chain, rpchost): ################ -def initialize_datadir(dirname, n, chain): +def initialize_datadir(dirname, n, chain, disable_autoconnect=True): datadir = get_datadir_path(dirname, n) if not os.path.isdir(datadir): os.makedirs(datadir) - write_config(os.path.join(datadir, "BGL.conf"), n=n, chain=chain) + write_config(os.path.join(datadir, "BGL.conf"), n=n, chain=chain, disable_autoconnect=disable_autoconnect) os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True) os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True) return datadir -def write_config(config_path, *, n, chain, extra_config=""): +def write_config(config_path, *, n, chain, extra_config="", disable_autoconnect=True): # Translate chain subdirectory name to config name if chain == 'testnet3': chain_name_conf_arg = 'testnet' @@ -371,12 +371,19 @@ def write_config(config_path, *, n, chain, extra_config=""): f.write("dnsseed=0\n") f.write("fixedseeds=0\n") f.write("listenonion=0\n") + # Increase peertimeout to avoid disconnects while using mocktime. + # peertimeout is measured in wall clock time, so setting it to the + # duration of the longest test is sufficient. It can be overridden in + # tests. + f.write("peertimeout=999999\n") f.write("printtoconsole=0\n") f.write("upnp=0\n") f.write("natpmp=0\n") f.write("shrinkdebugfile=0\n") # To improve SQLite wallet performance so that the tests don't timeout, use -unsafesqlitesync f.write("unsafesqlitesync=1\n") + if disable_autoconnect: + f.write("connect=0\n") f.write(extra_config) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index a904fcd787..2c8479f676 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -142,7 +142,6 @@ 'wallet_txn_doublespend.py --mineblock', 'tool_wallet.py --legacy-wallet', 'tool_wallet.py --descriptors', - 'wallet_txn_clone.py', 'wallet_txn_clone.py --segwit', 'rpc_getchaintips.py', 'rpc_misc.py', @@ -247,7 +246,6 @@ 'p2p_leak.py', 'wallet_encryption.py --legacy-wallet', 'wallet_encryption.py --descriptors', - 'feature_dersig.py', 'feature_cltv.py', 'rpc_uptime.py', 'wallet_resendwallettransactions.py --legacy-wallet', diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index e2b039608c..045195e80d 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -593,9 +593,9 @@ def run_test(self): # Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") - address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") - assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") - assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac") + address_info = self.nodes[0].getaddressinfo("rbgl1qmevj8zfx0wdvp05cqwkmr6mxkfx60yezhdmczp") + assert_equal(address_info['address'], "rbgl1qmevj8zfx0wdvp05cqwkmr6mxkfx60yezhdmczp") + assert_equal(address_info["scriptPubKey"], "0014de592389267b9ac0be9803adb1eb66b24da79322") assert not address_info["ismine"] assert not address_info["iswatchonly"] assert not address_info["isscript"] diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py index 34b562f702..a98eb46b17 100755 --- a/test/functional/wallet_txn_clone.py +++ b/test/functional/wallet_txn_clone.py @@ -36,8 +36,8 @@ def run_test(self): else: output_type = "legacy" - # All nodes should start with 1,250 BTC: - starting_balance = 1250 + # All nodes should start with 5000 BGL: + starting_balance = 5000 for i in range(3): assert_equal(self.nodes[i].getbalance(), starting_balance) diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py index e43e95ce19..6f4cf53586 100755 --- a/test/functional/wallet_txn_doublespend.py +++ b/test/functional/wallet_txn_doublespend.py @@ -29,8 +29,8 @@ def setup_network(self): self.disconnect_nodes(1, 2) def run_test(self): - # All nodes should start with 1,250 BTC: - starting_balance = 1250 + # All nodes should start with 5000 BGL: + starting_balance = 5000 # All nodes should be out of IBD. # If the nodes are not all out of IBD, that can interfere with @@ -132,8 +132,8 @@ def run_test(self): expected = starting_balance + 100 - 1240 + fund_foo_tx["fee"] + fund_bar_tx["fee"] + doublespend_fee assert_equal(self.nodes[0].getbalance(), expected) - # Node1's balance should be its initial balance (1250 for 25 block rewards) plus the doublespend: - assert_equal(self.nodes[1].getbalance(), 1250 + 1240) + # Node1's balance should be its initial balance (5000 for 25 block rewards) plus the doublespend: + assert_equal(self.nodes[1].getbalance(), 5000 + 1240) if __name__ == '__main__': diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py index 7f35c2fe2a..bccbf0543d 100755 --- a/test/functional/wallet_upgradewallet.py +++ b/test/functional/wallet_upgradewallet.py @@ -94,10 +94,11 @@ def dumb_sync_blocks(self): def test_upgradewallet(self, wallet, previous_version, requested_version=None, expected_version=None): unchanged = expected_version == previous_version new_version = previous_version if unchanged else expected_version if expected_version else requested_version - assert_equal(wallet.getwalletinfo()["walletversion"], previous_version) + old_wallet_info = wallet.getwalletinfo() + assert_equal(old_wallet_info["walletversion"], previous_version) assert_equal(wallet.upgradewallet(requested_version), { - "wallet_name": "", + "wallet_name": old_wallet_info["walletname"], "previous_version": previous_version, "current_version": new_version, "result": "Already at latest version. Wallet version unchanged." if unchanged else "Wallet upgraded successfully from version {} to version {}.".format(previous_version, new_version),