aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional')
-rwxr-xr-xtest/functional/feature_addrman.py17
-rwxr-xr-xtest/functional/feature_backwards_compatibility.py283
-rwxr-xr-xtest/functional/feature_dirsymlinks.py24
-rwxr-xr-xtest/functional/feature_proxy.py2
-rwxr-xr-xtest/functional/feature_txindex_compatibility.py2
-rwxr-xr-xtest/functional/rpc_blockchain.py9
-rwxr-xr-xtest/functional/rpc_decodescript.py2
-rwxr-xr-xtest/functional/rpc_help.py2
-rwxr-xr-xtest/functional/rpc_uptime.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py11
-rwxr-xr-xtest/functional/test_framework/test_node.py3
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/wallet_encryption.py6
-rwxr-xr-xtest/functional/wallet_inactive_hdchains.py147
-rwxr-xr-xtest/functional/wallet_timelock.py2
-rwxr-xr-xtest/functional/wallet_upgradewallet.py11
16 files changed, 301 insertions, 223 deletions
diff --git a/test/functional/feature_addrman.py b/test/functional/feature_addrman.py
index 14a4f8abb7..0fdefaa9c3 100755
--- a/test/functional/feature_addrman.py
+++ b/test/functional/feature_addrman.py
@@ -68,17 +68,16 @@ class AddrmanTest(BitcoinTestFramework):
self.start_node(0, extra_args=["-checkaddrman=1"])
assert_equal(self.nodes[0].getnodeaddresses(), [])
- self.log.info("Check that addrman from future cannot be read")
+ self.log.info("Check that addrman from future is overwritten with new addrman")
self.stop_node(0)
write_addrman(peers_dat, lowest_compatible=111)
- self.nodes[0].assert_start_raises_init_error(
- expected_msg=init_error(
- "Unsupported format of addrman database: 1. It is compatible with "
- "formats >=111, but the maximum supported by this version of "
- f"{self.config['environment']['PACKAGE_NAME']} is 4.: (.+)"
- ),
- match=ErrorMatch.FULL_REGEX,
- )
+ assert_equal(os.path.exists(peers_dat + ".bak"), False)
+ with self.nodes[0].assert_debug_log([
+ f'Creating new peers.dat because the file version was not compatible ("{peers_dat}"). Original backed up to peers.dat.bak',
+ ]):
+ self.start_node(0)
+ assert_equal(self.nodes[0].getnodeaddresses(), [])
+ assert_equal(os.path.exists(peers_dat + ".bak"), True)
self.log.info("Check that corrupt addrman cannot be read (EOF)")
self.stop_node(0)
diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/feature_backwards_compatibility.py
index 476a6a0c14..a7fb3184a6 100755
--- a/test/functional/feature_backwards_compatibility.py
+++ b/test/functional/feature_backwards_compatibility.py
@@ -34,15 +34,18 @@ from test_framework.util import (
class BackwardsCompatibilityTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
- self.num_nodes = 6
+ self.num_nodes = 9
# Add new version after each release:
self.extra_args = [
- ["-addresstype=bech32"], # Pre-release: use to mine blocks
- ["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # Pre-release: use to receive coins, swap wallets, etc
- ["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.19.1
- ["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.18.1
- ["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.17.2
- ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-wallet=wallet.dat"], # v0.16.3
+ ["-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # Pre-release: use to mine blocks. noban for immediate tx relay
+ ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # Pre-release: use to receive coins, swap wallets, etc
+ ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # v22.0
+ ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # v0.21.0
+ ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # v0.20.1
+ ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=noban@127.0.0.1"], # v0.19.1
+ ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=127.0.0.1"], # v0.18.1
+ ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=127.0.0.1"], # v0.17.2
+ ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-whitelist=127.0.0.1", "-wallet=wallet.dat"], # v0.16.3
]
self.wallet_names = [self.default_wallet_name]
@@ -54,6 +57,9 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
self.add_nodes(self.num_nodes, extra_args=self.extra_args, versions=[
None,
None,
+ 220000,
+ 210000,
+ 200100,
190100,
180100,
170200,
@@ -63,19 +69,27 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
self.start_nodes()
self.import_deterministic_coinbase_privkeys()
- def run_test(self):
- self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 1, self.nodes[0].getnewaddress())
-
- # Sanity check the test framework:
- res = self.nodes[self.num_nodes - 1].getblockchaininfo()
- assert_equal(res['blocks'], COINBASE_MATURITY + 1)
+ def nodes_wallet_dir(self, node):
+ if node.version < 170000:
+ return os.path.join(node.datadir, "regtest")
+ return os.path.join(node.datadir, "regtest/wallets")
- node_master = self.nodes[self.num_nodes - 5]
+ def run_test(self):
+ node_miner = self.nodes[0]
+ node_master = self.nodes[1]
node_v19 = self.nodes[self.num_nodes - 4]
node_v18 = self.nodes[self.num_nodes - 3]
node_v17 = self.nodes[self.num_nodes - 2]
node_v16 = self.nodes[self.num_nodes - 1]
+ legacy_nodes = self.nodes[2:]
+
+ self.generatetoaddress(node_miner, COINBASE_MATURITY + 1, node_miner.getnewaddress())
+
+ # Sanity check the test framework:
+ res = node_v16.getblockchaininfo()
+ assert_equal(res['blocks'], COINBASE_MATURITY + 1)
+
self.log.info("Test wallet backwards compatibility...")
# Create a number of wallets and open them in older versions:
@@ -88,21 +102,21 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
assert info['keypoolsize'] > 0
# Create a confirmed transaction, receiving coins
address = wallet.getnewaddress()
- self.nodes[0].sendtoaddress(address, 10)
+ node_miner.sendtoaddress(address, 10)
self.sync_mempools()
- self.generate(self.nodes[0], 1)
+ self.generate(node_miner, 1)
# Create a conflicting transaction using RBF
- return_address = self.nodes[0].getnewaddress()
- tx1_id = self.nodes[1].sendtoaddress(return_address, 1)
- tx2_id = self.nodes[1].bumpfee(tx1_id)["txid"]
+ return_address = node_miner.getnewaddress()
+ tx1_id = node_master.sendtoaddress(return_address, 1)
+ tx2_id = node_master.bumpfee(tx1_id)["txid"]
# Confirm the transaction
self.sync_mempools()
- self.generate(self.nodes[0], 1)
+ self.generate(node_miner, 1)
# Create another conflicting transaction using RBF
- tx3_id = self.nodes[1].sendtoaddress(return_address, 1)
- tx4_id = self.nodes[1].bumpfee(tx3_id)["txid"]
+ tx3_id = node_master.sendtoaddress(return_address, 1)
+ tx4_id = node_master.bumpfee(tx3_id)["txid"]
# Abandon transaction, but don't confirm
- self.nodes[1].abandontransaction(tx3_id)
+ node_master.abandontransaction(tx3_id)
# w1_v19: regular wallet, created with v0.19
node_v19.rpc.createwallet(wallet_name="w1_v19")
@@ -113,6 +127,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
# Use addmultisigaddress (see #18075)
address_18075 = wallet.rpc.addmultisigaddress(1, ["0296b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52", "037211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073"], "", "legacy")["address"]
assert wallet.getaddressinfo(address_18075)["solvable"]
+ node_v19.unloadwallet("w1_v19")
# w1_v18: regular wallet, created with v0.18
node_v18.rpc.createwallet(wallet_name="w1_v18")
@@ -130,20 +145,6 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
assert info['private_keys_enabled'] == False
assert info['keypoolsize'] == 0
- # w2_v19: wallet with private keys disabled, created with v0.19
- node_v19.rpc.createwallet(wallet_name="w2_v19", disable_private_keys=True)
- wallet = node_v19.get_wallet_rpc("w2_v19")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled'] == False
- assert info['keypoolsize'] == 0
-
- # w2_v18: wallet with private keys disabled, created with v0.18
- node_v18.rpc.createwallet(wallet_name="w2_v18", disable_private_keys=True)
- wallet = node_v18.get_wallet_rpc("w2_v18")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled'] == False
- assert info['keypoolsize'] == 0
-
# w3: blank wallet, created on master: update this
# test when default blank wallets can no longer be opened by older versions.
node_master.createwallet(wallet_name="w3", blank=True)
@@ -152,170 +153,72 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
assert info['private_keys_enabled']
assert info['keypoolsize'] == 0
- # w3_v19: blank wallet, created with v0.19
- node_v19.rpc.createwallet(wallet_name="w3_v19", blank=True)
- wallet = node_v19.get_wallet_rpc("w3_v19")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled']
- assert info['keypoolsize'] == 0
-
- # w3_v18: blank wallet, created with v0.18
- node_v18.rpc.createwallet(wallet_name="w3_v18", blank=True)
- wallet = node_v18.get_wallet_rpc("w3_v18")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled']
- assert info['keypoolsize'] == 0
-
- # Copy the wallets to older nodes:
+ # Unload wallets and copy to older nodes:
node_master_wallets_dir = os.path.join(node_master.datadir, "regtest/wallets")
node_v19_wallets_dir = os.path.join(node_v19.datadir, "regtest/wallets")
- node_v18_wallets_dir = os.path.join(node_v18.datadir, "regtest/wallets")
node_v17_wallets_dir = os.path.join(node_v17.datadir, "regtest/wallets")
node_v16_wallets_dir = os.path.join(node_v16.datadir, "regtest")
node_master.unloadwallet("w1")
node_master.unloadwallet("w2")
- node_v19.unloadwallet("w1_v19")
- node_v19.unloadwallet("w2_v19")
- node_v18.unloadwallet("w1_v18")
- node_v18.unloadwallet("w2_v18")
-
- # Copy wallets to v0.16
- for wallet in os.listdir(node_master_wallets_dir):
- shutil.copytree(
- os.path.join(node_master_wallets_dir, wallet),
- os.path.join(node_v16_wallets_dir, wallet)
- )
+ node_master.unloadwallet("w3")
- # Copy wallets to v0.17
- for wallet in os.listdir(node_master_wallets_dir):
- shutil.copytree(
- os.path.join(node_master_wallets_dir, wallet),
- os.path.join(node_v17_wallets_dir, wallet)
- )
- for wallet in os.listdir(node_v18_wallets_dir):
- shutil.copytree(
- os.path.join(node_v18_wallets_dir, wallet),
- os.path.join(node_v17_wallets_dir, wallet)
- )
-
- # Copy wallets to v0.18
- for wallet in os.listdir(node_master_wallets_dir):
- shutil.copytree(
- os.path.join(node_master_wallets_dir, wallet),
- os.path.join(node_v18_wallets_dir, wallet)
- )
-
- # Copy wallets to v0.19
- for wallet in os.listdir(node_master_wallets_dir):
- shutil.copytree(
- os.path.join(node_master_wallets_dir, wallet),
- os.path.join(node_v19_wallets_dir, wallet)
- )
+ for node in legacy_nodes:
+ # Copy wallets to previous version
+ for wallet in os.listdir(node_master_wallets_dir):
+ shutil.copytree(
+ os.path.join(node_master_wallets_dir, wallet),
+ os.path.join(self.nodes_wallet_dir(node), wallet)
+ )
if not self.options.descriptors:
# Descriptor wallets break compatibility, only run this test for legacy wallet
- # Open the wallets in v0.19
- node_v19.loadwallet("w1")
- wallet = node_v19.get_wallet_rpc("w1")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled']
- assert info['keypoolsize'] > 0
- txs = wallet.listtransactions()
- assert_equal(len(txs), 5)
- assert_equal(txs[1]["txid"], tx1_id)
- assert_equal(txs[2]["walletconflicts"], [tx1_id])
- assert_equal(txs[1]["replaced_by_txid"], tx2_id)
- assert not(txs[1]["abandoned"])
- assert_equal(txs[1]["confirmations"], -1)
- assert_equal(txs[2]["blockindex"], 1)
- assert txs[3]["abandoned"]
- assert_equal(txs[4]["walletconflicts"], [tx3_id])
- assert_equal(txs[3]["replaced_by_txid"], tx4_id)
- assert not(hasattr(txs[3], "blockindex"))
-
- node_v19.loadwallet("w2")
- wallet = node_v19.get_wallet_rpc("w2")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled'] == False
- assert info['keypoolsize'] == 0
-
- node_v19.loadwallet("w3")
- wallet = node_v19.get_wallet_rpc("w3")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled']
- assert info['keypoolsize'] == 0
-
- # Open the wallets in v0.18
- node_v18.loadwallet("w1")
- wallet = node_v18.get_wallet_rpc("w1")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled']
- assert info['keypoolsize'] > 0
- txs = wallet.listtransactions()
- assert_equal(len(txs), 5)
- assert_equal(txs[1]["txid"], tx1_id)
- assert_equal(txs[2]["walletconflicts"], [tx1_id])
- assert_equal(txs[1]["replaced_by_txid"], tx2_id)
- assert not(txs[1]["abandoned"])
- assert_equal(txs[1]["confirmations"], -1)
- assert_equal(txs[2]["blockindex"], 1)
- assert txs[3]["abandoned"]
- assert_equal(txs[4]["walletconflicts"], [tx3_id])
- assert_equal(txs[3]["replaced_by_txid"], tx4_id)
- assert not(hasattr(txs[3], "blockindex"))
-
- node_v18.loadwallet("w2")
- wallet = node_v18.get_wallet_rpc("w2")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled'] == False
- assert info['keypoolsize'] == 0
-
- node_v18.loadwallet("w3")
- wallet = node_v18.get_wallet_rpc("w3")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled']
- assert info['keypoolsize'] == 0
-
- node_v17.loadwallet("w1")
- wallet = node_v17.get_wallet_rpc("w1")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled']
- assert info['keypoolsize'] > 0
-
- node_v17.loadwallet("w2")
- wallet = node_v17.get_wallet_rpc("w2")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled'] == False
- assert info['keypoolsize'] == 0
+ # Load modern wallet with older nodes
+ for node in legacy_nodes:
+ for wallet_name in ["w1", "w2", "w3"]:
+ if node.version < 170000:
+ # loadwallet was introduced in v0.17.0
+ continue
+ if node.version < 180000 and wallet_name == "w3":
+ # Blank wallets were introduced in v0.18.0. We test the loading error below.
+ continue
+ node.loadwallet(wallet_name)
+ wallet = node.get_wallet_rpc(wallet_name)
+ info = wallet.getwalletinfo()
+ if wallet_name == "w1":
+ assert info['private_keys_enabled'] == True
+ assert info['keypoolsize'] > 0
+ txs = wallet.listtransactions()
+ assert_equal(len(txs), 5)
+ assert_equal(txs[1]["txid"], tx1_id)
+ assert_equal(txs[2]["walletconflicts"], [tx1_id])
+ assert_equal(txs[1]["replaced_by_txid"], tx2_id)
+ assert not(txs[1]["abandoned"])
+ assert_equal(txs[1]["confirmations"], -1)
+ assert_equal(txs[2]["blockindex"], 1)
+ assert txs[3]["abandoned"]
+ assert_equal(txs[4]["walletconflicts"], [tx3_id])
+ assert_equal(txs[3]["replaced_by_txid"], tx4_id)
+ assert not(hasattr(txs[3], "blockindex"))
+ elif wallet_name == "w2":
+ assert(info['private_keys_enabled'] == False)
+ assert info['keypoolsize'] == 0
+ else:
+ assert(info['private_keys_enabled'] == True)
+ assert info['keypoolsize'] == 0
else:
- # Descriptor wallets appear to be corrupted wallets to old software
- assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v19.loadwallet, "w1")
- assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v19.loadwallet, "w2")
- assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v19.loadwallet, "w3")
- assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v18.loadwallet, "w1")
- assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v18.loadwallet, "w2")
- assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v18.loadwallet, "w3")
-
- # Open the wallets in v0.17
- node_v17.loadwallet("w1_v18")
- wallet = node_v17.get_wallet_rpc("w1_v18")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled']
- assert info['keypoolsize'] > 0
-
- node_v17.loadwallet("w2_v18")
- wallet = node_v17.get_wallet_rpc("w2_v18")
- info = wallet.getwalletinfo()
- assert info['private_keys_enabled'] == False
- assert info['keypoolsize'] == 0
+ for node in legacy_nodes:
+ # Descriptor wallets appear to be corrupted wallets to old software
+ # and loadwallet is introduced in v0.17.0
+ if node.version >= 170000 and node.version < 210000:
+ for wallet_name in ["w1", "w2", "w3"]:
+ assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node.loadwallet, wallet_name)
# RPC loadwallet failure causes bitcoind to exit, in addition to the RPC
# call failure, so the following test won't work:
- # assert_raises_rpc_error(-4, "Wallet loading failed.", node_v17.loadwallet, 'w3_v18')
+ # assert_raises_rpc_error(-4, "Wallet loading failed.", node_v17.loadwallet, 'w3')
# Instead, we stop node and try to launch it with the wallet:
- self.stop_node(4)
- node_v17.assert_start_raises_init_error(["-wallet=w3_v18"], "Error: Error loading w3_v18: Wallet requires newer version of Bitcoin Core")
+ self.stop_node(node_v17.index)
if self.options.descriptors:
# Descriptor wallets appear to be corrupted wallets to old software
node_v17.assert_start_raises_init_error(["-wallet=w1"], "Error: wallet.dat corrupt, salvage failed")
@@ -323,23 +226,23 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
node_v17.assert_start_raises_init_error(["-wallet=w3"], "Error: wallet.dat corrupt, salvage failed")
else:
node_v17.assert_start_raises_init_error(["-wallet=w3"], "Error: Error loading w3: Wallet requires newer version of Bitcoin Core")
- self.start_node(4)
+ self.start_node(node_v17.index)
if not self.options.descriptors:
# Descriptor wallets break compatibility, only run this test for legacy wallets
# Open most recent wallet in v0.16 (no loadwallet RPC)
- self.restart_node(5, extra_args=["-wallet=w2"])
+ self.restart_node(node_v16.index, extra_args=["-wallet=w2"])
wallet = node_v16.get_wallet_rpc("w2")
info = wallet.getwalletinfo()
assert info['keypoolsize'] == 1
# Create upgrade wallet in v0.16
- self.restart_node(-1, extra_args=["-wallet=u1_v16"])
+ self.restart_node(node_v16.index, extra_args=["-wallet=u1_v16"])
wallet = node_v16.get_wallet_rpc("u1_v16")
v16_addr = wallet.getnewaddress('', "bech32")
v16_info = wallet.validateaddress(v16_addr)
v16_pubkey = v16_info['pubkey']
- self.stop_node(-1)
+ self.stop_node(node_v16.index)
self.log.info("Test wallet upgrade path...")
# u1: regular wallet, created with v0.17
@@ -371,7 +274,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
os.path.join(node_master_wallets_dir, "u1_v16"),
os.path.join(node_v16_wallets_dir, "wallets/u1_v16")
)
- self.start_node(-1, extra_args=["-wallet=u1_v16"])
+ self.start_node(node_v16.index, extra_args=["-wallet=u1_v16"])
wallet = node_v16.get_wallet_rpc("u1_v16")
info = wallet.validateaddress(v16_addr)
assert_equal(info, v16_info)
diff --git a/test/functional/feature_dirsymlinks.py b/test/functional/feature_dirsymlinks.py
index 85c8e27600..288754c04c 100755
--- a/test/functional/feature_dirsymlinks.py
+++ b/test/functional/feature_dirsymlinks.py
@@ -6,9 +6,8 @@
"""
import os
-import sys
-from test_framework.test_framework import BitcoinTestFramework, SkipTest
+from test_framework.test_framework import BitcoinTestFramework
def rename_and_link(*, from_name, to_name):
@@ -16,24 +15,27 @@ def rename_and_link(*, from_name, to_name):
os.symlink(to_name, from_name)
assert os.path.islink(from_name) and os.path.isdir(from_name)
-class SymlinkTest(BitcoinTestFramework):
- def skip_test_if_missing_module(self):
- if sys.platform == 'win32':
- raise SkipTest("Symlinks test skipped on Windows")
+class SymlinkTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
def run_test(self):
+ dir_new_blocks = self.nodes[0].chain_path / "new_blocks"
+ dir_new_chainstate = self.nodes[0].chain_path / "new_chainstate"
self.stop_node(0)
- rename_and_link(from_name=os.path.join(self.nodes[0].datadir, self.chain, "blocks"),
- to_name=os.path.join(self.nodes[0].datadir, self.chain, "newblocks"))
- rename_and_link(from_name=os.path.join(self.nodes[0].datadir, self.chain, "chainstate"),
- to_name=os.path.join(self.nodes[0].datadir, self.chain, "newchainstate"))
+ rename_and_link(
+ from_name=self.nodes[0].chain_path / "blocks",
+ to_name=dir_new_blocks,
+ )
+ rename_and_link(
+ from_name=self.nodes[0].chain_path / "chainstate",
+ to_name=dir_new_chainstate,
+ )
self.start_node(0)
-if __name__ == '__main__':
+if __name__ == "__main__":
SymlinkTest().main()
diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py
index 7d9e5b70fc..fb0f6d7cb7 100755
--- a/test/functional/feature_proxy.py
+++ b/test/functional/feature_proxy.py
@@ -280,7 +280,7 @@ class ProxyTest(BitcoinTestFramework):
n3 = networks_dict(self.nodes[3].getnetworkinfo())
assert_equal(NETWORKS, n3.keys())
for net in NETWORKS:
- if net == NET_I2P:
+ if net == NET_I2P or net == NET_ONION:
expected_proxy = ''
else:
expected_proxy = f'[{self.conf3.addr[0]}]:{self.conf3.addr[1]}'
diff --git a/test/functional/feature_txindex_compatibility.py b/test/functional/feature_txindex_compatibility.py
index bbe1d1b537..20b023d82c 100755
--- a/test/functional/feature_txindex_compatibility.py
+++ b/test/functional/feature_txindex_compatibility.py
@@ -78,7 +78,7 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
self.stop_nodes()
- self.log.info("Check migrated txindex can not be read by legacy node")
+ self.log.info("Check migrated txindex cannot be read by legacy node")
err_msg = f": You need to rebuild the database using -reindex to change -txindex.{os.linesep}Please restart with -reindex or -reindex-chainstate to recover."
shutil.rmtree(legacy_chain_dir)
shutil.copytree(migrate_chain_dir, legacy_chain_dir)
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index 2d96ba74b5..b264f23fb5 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -69,7 +69,14 @@ class BlockchainTest(BitcoinTestFramework):
self.wallet = MiniWallet(self.nodes[0])
self.mine_chain()
self._test_max_future_block_time()
- self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1']) # Set extra args with pruning after rescan is complete
+ self.restart_node(
+ 0,
+ extra_args=[
+ "-stopatheight=207",
+ "-checkblocks=-1", # Check all blocks
+ "-prune=1", # Set pruning after rescan is complete
+ ],
+ )
self._test_getblockchaininfo()
self._test_getchaintxstats()
diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py
index 56f596d419..343cb73989 100755
--- a/test/functional/rpc_decodescript.py
+++ b/test/functional/rpc_decodescript.py
@@ -52,7 +52,7 @@ class DecodeScriptTest(BitcoinTestFramework):
rpc_result = self.nodes[0].decodescript('5100')
assert_equal('1 0', rpc_result['asm'])
- # null data scriptSig - no such thing because null data scripts can not be spent.
+ # null data scriptSig - no such thing because null data scripts cannot be spent.
# thus, no test case for that standard transaction type is here.
def decodescript_script_pub_key(self):
diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py
index ccb380e25b..3b6413d4a6 100755
--- a/test/functional/rpc_help.py
+++ b/test/functional/rpc_help.py
@@ -100,7 +100,7 @@ class HelpRpcTest(BitcoinTestFramework):
# command titles
titles = [line[3:-3] for line in node.help().splitlines() if line.startswith('==')]
- components = ['Blockchain', 'Control', 'Generating', 'Mining', 'Network', 'Rawtransactions', 'Util']
+ components = ['Blockchain', 'Control', 'Mining', 'Network', 'Rawtransactions', 'Util']
if self.is_wallet_compiled():
components.append('Wallet')
diff --git a/test/functional/rpc_uptime.py b/test/functional/rpc_uptime.py
index 1a82d1fa41..024e8aec1a 100755
--- a/test/functional/rpc_uptime.py
+++ b/test/functional/rpc_uptime.py
@@ -23,7 +23,7 @@ class UptimeTest(BitcoinTestFramework):
self._test_uptime()
def _test_negative_time(self):
- assert_raises_rpc_error(-8, "Mocktime can not be negative: -1.", self.nodes[0].setmocktime, -1)
+ assert_raises_rpc_error(-8, "Mocktime cannot be negative: -1.", self.nodes[0].setmocktime, -1)
def _test_uptime(self):
wait_time = 10
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 8f75255caf..ecdc3bf424 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -447,11 +447,15 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def get_bin_from_version(version, bin_name, bin_default):
if not version:
return bin_default
+ if version > 219999:
+ # Starting at client version 220000 the first two digits represent
+ # the major version, e.g. v22.0 instead of v0.22.0.
+ version *= 100
return os.path.join(
self.options.previous_releases_path,
re.sub(
- r'\.0$',
- '', # remove trailing .0 for point releases
+ r'\.0$' if version <= 219999 else r'(\.0){1,2}$',
+ '', # Remove trailing dot for point releases, after 22.0 also remove double trailing dot.
'v{}.{}.{}.{}'.format(
(version % 100000000) // 1000000,
(version % 1000000) // 10000,
@@ -473,7 +477,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
versions = [None] * num_nodes
if self.is_syscall_sandbox_compiled() and not self.disable_syscall_sandbox:
for i in range(len(extra_args)):
- if versions[i] is None or versions[i] >= 219900:
+ # The -sandbox argument is not present in the v22.0 release.
+ if versions[i] is None or versions[i] >= 229900:
extra_args[i] = extra_args[i] + ["-sandbox=log-and-abort"]
if binary is None:
binary = [get_bin_from_version(v, 'bitcoind', self.options.bitcoind) for v in versions]
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 289e83579b..e56d4aa492 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -743,6 +743,9 @@ class RPCOverloadWrapper():
def __getattr__(self, name):
return getattr(self.rpc, name)
+ def createwallet_passthrough(self, *args, **kwargs):
+ return self.__getattr__("createwallet")(*args, **kwargs)
+
def createwallet(self, wallet_name, disable_private_keys=None, blank=None, passphrase='', avoid_reuse=None, descriptors=None, load_on_startup=None, external_signer=None):
if descriptors is None:
descriptors = self.descriptors
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 516e8be638..d15edcedd2 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -281,6 +281,7 @@ BASE_SCRIPTS = [
'wallet_send.py --descriptors',
'wallet_create_tx.py --descriptors',
'wallet_taproot.py',
+ 'wallet_inactive_hdchains.py',
'p2p_fingerprint.py',
'feature_uacomment.py',
'feature_init.py',
diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py
index 0d702e44f6..0c9106f800 100755
--- a/test/functional/wallet_encryption.py
+++ b/test/functional/wallet_encryption.py
@@ -35,14 +35,14 @@ class WalletEncryptionTest(BitcoinTestFramework):
assert_raises_rpc_error(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.", self.nodes[0].walletpassphrasechange, 'ff', 'ff')
# Encrypt the wallet
- assert_raises_rpc_error(-8, "passphrase can not be empty", self.nodes[0].encryptwallet, '')
+ assert_raises_rpc_error(-8, "passphrase cannot be empty", self.nodes[0].encryptwallet, '')
self.nodes[0].encryptwallet(passphrase)
# Test that the wallet is encrypted
assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].signmessage, address, msg)
assert_raises_rpc_error(-15, "Error: running with an encrypted wallet, but encryptwallet was called.", self.nodes[0].encryptwallet, 'ff')
- assert_raises_rpc_error(-8, "passphrase can not be empty", self.nodes[0].walletpassphrase, '', 1)
- assert_raises_rpc_error(-8, "passphrase can not be empty", self.nodes[0].walletpassphrasechange, '', 'ff')
+ assert_raises_rpc_error(-8, "passphrase cannot be empty", self.nodes[0].walletpassphrase, '', 1)
+ assert_raises_rpc_error(-8, "passphrase cannot be empty", self.nodes[0].walletpassphrasechange, '', 'ff')
# Check that walletpassphrase works
self.nodes[0].walletpassphrase(passphrase, 2)
diff --git a/test/functional/wallet_inactive_hdchains.py b/test/functional/wallet_inactive_hdchains.py
new file mode 100755
index 0000000000..e1dad00876
--- /dev/null
+++ b/test/functional/wallet_inactive_hdchains.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""
+Test Inactive HD Chains.
+"""
+import os
+import shutil
+import time
+
+from test_framework.authproxy import JSONRPCException
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.wallet_util import (
+ get_generate_key,
+)
+
+
+class InactiveHDChainsTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 2
+ self.extra_args = [["-keypool=10"], ["-nowallet", "-keypool=10"]]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+ self.skip_if_no_bdb()
+ self.skip_if_no_previous_releases()
+
+ def setup_nodes(self):
+ self.add_nodes(self.num_nodes, extra_args=self.extra_args, versions=[
+ None,
+ 170200, # 0.17.2 Does not have the key metadata upgrade
+ ])
+
+ self.start_nodes()
+ self.init_wallet(node=0)
+
+ def prepare_wallets(self, wallet_basename, encrypt=False):
+ self.nodes[0].createwallet(wallet_name=f"{wallet_basename}_base", descriptors=False, blank=True)
+ self.nodes[0].createwallet(wallet_name=f"{wallet_basename}_test", descriptors=False, blank=True)
+ base_wallet = self.nodes[0].get_wallet_rpc(f"{wallet_basename}_base")
+ test_wallet = self.nodes[0].get_wallet_rpc(f"{wallet_basename}_test")
+
+ # Setup both wallets with the same HD seed
+ seed = get_generate_key()
+ base_wallet.sethdseed(True, seed.privkey)
+ test_wallet.sethdseed(True, seed.privkey)
+
+ if encrypt:
+ # Encrypting will generate a new HD seed and flush the keypool
+ test_wallet.encryptwallet("pass")
+ else:
+ # Generate a new HD seed on the test wallet
+ test_wallet.sethdseed()
+
+ return base_wallet, test_wallet
+
+ def do_inactive_test(self, base_wallet, test_wallet, encrypt=False):
+ default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+
+ # The first address should be known by both wallets.
+ addr1 = base_wallet.getnewaddress()
+ assert test_wallet.getaddressinfo(addr1)["ismine"]
+ # The address at index 9 is the first address that the test wallet will not know initially
+ for _ in range(0, 9):
+ base_wallet.getnewaddress()
+ addr2 = base_wallet.getnewaddress()
+ assert not test_wallet.getaddressinfo(addr2)["ismine"]
+
+ # Send to first address on the old seed
+ txid = default.sendtoaddress(addr1, 10)
+ self.generate(self.nodes[0], 1)
+
+ # Wait for the test wallet to see the transaction
+ while True:
+ try:
+ test_wallet.gettransaction(txid)
+ break
+ except JSONRPCException:
+ time.sleep(0.1)
+
+ if encrypt:
+ # The test wallet will not be able to generate the topped up keypool
+ # until it is unlocked. So it still should not know about the second address
+ assert not test_wallet.getaddressinfo(addr2)["ismine"]
+ test_wallet.walletpassphrase("pass", 1)
+
+ # The test wallet should now know about the second address as it
+ # should have generated it in the inactive chain's keypool
+ assert test_wallet.getaddressinfo(addr2)["ismine"]
+
+ # Send to second address on the old seed
+ txid = default.sendtoaddress(addr2, 10)
+ self.generate(self.nodes[0], 1)
+ test_wallet.gettransaction(txid)
+
+ def test_basic(self):
+ self.log.info("Test basic case for inactive HD chains")
+ self.do_inactive_test(*self.prepare_wallets("basic"))
+
+ def test_encrypted_wallet(self):
+ self.log.info("Test inactive HD chains when wallet is encrypted")
+ self.do_inactive_test(*self.prepare_wallets("enc", encrypt=True), encrypt=True)
+
+ def test_without_upgraded_keymeta(self):
+ # Test that it is possible to top up inactive hd chains even if there is no key origin
+ # in CKeyMetadata. This tests for the segfault reported in
+ # https://github.com/bitcoin/bitcoin/issues/21605
+ self.log.info("Test that topping up inactive HD chains does not need upgraded key origin")
+
+ self.nodes[0].createwallet(wallet_name="keymeta_base", descriptors=False, blank=True)
+ # Createwallet is overridden in the test framework so that the descriptor option can be filled
+ # depending on the test's cli args. However we don't want to do that when using old nodes that
+ # do not support descriptors. So we use the createwallet_passthrough function.
+ self.nodes[1].createwallet_passthrough(wallet_name="keymeta_test")
+ base_wallet = self.nodes[0].get_wallet_rpc("keymeta_base")
+ test_wallet = self.nodes[1].get_wallet_rpc("keymeta_test")
+
+ # Setup both wallets with the same HD seed
+ seed = get_generate_key()
+ base_wallet.sethdseed(True, seed.privkey)
+ test_wallet.sethdseed(True, seed.privkey)
+
+ # Encrypting will generate a new HD seed and flush the keypool
+ test_wallet.encryptwallet("pass")
+
+ # Copy test wallet to node 0
+ test_wallet.unloadwallet()
+ test_wallet_dir = os.path.join(self.nodes[1].datadir, "regtest/wallets/keymeta_test")
+ new_test_wallet_dir = os.path.join(self.nodes[0].datadir, "regtest/wallets/keymeta_test")
+ shutil.copytree(test_wallet_dir, new_test_wallet_dir)
+ self.nodes[0].loadwallet("keymeta_test")
+ test_wallet = self.nodes[0].get_wallet_rpc("keymeta_test")
+
+ self.do_inactive_test(base_wallet, test_wallet, encrypt=True)
+
+ def run_test(self):
+ self.generate(self.nodes[0], 101)
+
+ self.test_basic()
+ self.test_encrypted_wallet()
+ self.test_without_upgraded_keymeta()
+
+
+if __name__ == '__main__':
+ InactiveHDChainsTest().main()
diff --git a/test/functional/wallet_timelock.py b/test/functional/wallet_timelock.py
index cf233a00ef..a71cec6607 100755
--- a/test/functional/wallet_timelock.py
+++ b/test/functional/wallet_timelock.py
@@ -30,7 +30,7 @@ class WalletLocktimeTest(BitcoinTestFramework):
)
self.generate(node, 1)
- self.log.info("Check that clock can not change finality of confirmed txs")
+ self.log.info("Check that clock cannot change finality of confirmed txs")
amount_before_ad = node.getreceivedbyaddress(address)
amount_before_lb = node.getreceivedbylabel(label)
list_before_ad = node.listreceivedbyaddress(address_filter=address)
diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py
index 36e72f2dd9..c452e1eafd 100755
--- a/test/functional/wallet_upgradewallet.py
+++ b/test/functional/wallet_upgradewallet.py
@@ -345,5 +345,16 @@ class UpgradeWalletTest(BitcoinTestFramework):
desc_wallet = self.nodes[0].get_wallet_rpc("desc_upgrade")
self.test_upgradewallet(desc_wallet, previous_version=169900, expected_version=169900)
+ self.log.info("Checking that descriptor wallets without privkeys do nothing, successfully")
+ self.nodes[0].createwallet(wallet_name="desc_upgrade_nopriv", descriptors=True, disable_private_keys=True)
+ desc_wallet = self.nodes[0].get_wallet_rpc("desc_upgrade_nopriv")
+ self.test_upgradewallet(desc_wallet, previous_version=169900, expected_version=169900)
+
+ if self.is_bdb_compiled():
+ self.log.info("Upgrading a wallet with private keys disabled")
+ self.nodes[0].createwallet(wallet_name="privkeys_disabled_upgrade", disable_private_keys=True, descriptors=False)
+ disabled_wallet = self.nodes[0].get_wallet_rpc("privkeys_disabled_upgrade")
+ self.test_upgradewallet(disabled_wallet, previous_version=169900, expected_version=169900)
+
if __name__ == '__main__':
UpgradeWalletTest().main()