aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional')
-rwxr-xr-xtest/functional/feature_backwards_compatibility.py134
-rwxr-xr-xtest/functional/feature_filelock.py22
-rwxr-xr-xtest/functional/feature_notifications.py34
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py2
-rwxr-xr-xtest/functional/interface_zmq.py2
-rwxr-xr-xtest/functional/rpc_net.py7
-rwxr-xr-xtest/functional/test_framework/test_framework.py32
-rwxr-xr-xtest/functional/test_runner.py71
-rwxr-xr-xtest/functional/tool_wallet.py3
-rwxr-xr-xtest/functional/wallet_descriptor.py13
-rwxr-xr-xtest/functional/wallet_send.py101
-rwxr-xr-xtest/functional/wallet_upgradewallet.py1
12 files changed, 270 insertions, 152 deletions
diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/feature_backwards_compatibility.py
index b161c71a85..e6a53b52db 100755
--- a/test/functional/feature_backwards_compatibility.py
+++ b/test/functional/feature_backwards_compatibility.py
@@ -354,73 +354,75 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
hdkeypath = v17_info["hdkeypath"]
pubkey = v17_info["pubkey"]
- # Copy the 0.16 wallet to the last Bitcoin Core version and open it:
- shutil.copyfile(
- os.path.join(node_v16_wallets_dir, "wallets/u1_v16"),
- os.path.join(node_master_wallets_dir, "u1_v16")
- )
- load_res = node_master.loadwallet("u1_v16")
- # Make sure this wallet opens without warnings. See https://github.com/bitcoin/bitcoin/pull/19054
- assert_equal(load_res['warning'], '')
- wallet = node_master.get_wallet_rpc("u1_v16")
- info = wallet.getaddressinfo(v16_addr)
- descriptor = "wpkh([" + info["hdmasterfingerprint"] + hdkeypath[1:] + "]" + v16_pubkey + ")"
- assert_equal(info["desc"], descsum_create(descriptor))
-
- # Now copy that same wallet back to 0.16 to make sure no automatic upgrade breaks it
- os.remove(os.path.join(node_v16_wallets_dir, "wallets/u1_v16"))
- shutil.copyfile(
- 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"])
- wallet = node_v16.get_wallet_rpc("u1_v16")
- info = wallet.validateaddress(v16_addr)
- assert_equal(info, v16_info)
-
- # Copy the 0.17 wallet to the last Bitcoin Core version and open it:
- node_v17.unloadwallet("u1_v17")
- shutil.copytree(
- os.path.join(node_v17_wallets_dir, "u1_v17"),
- os.path.join(node_master_wallets_dir, "u1_v17")
- )
- node_master.loadwallet("u1_v17")
- wallet = node_master.get_wallet_rpc("u1_v17")
- info = wallet.getaddressinfo(address)
- 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"),
- os.path.join(node_master_wallets_dir, "w1_v19")
- )
- node_master.loadwallet("w1_v19")
- wallet = node_master.get_wallet_rpc("w1_v19")
- assert wallet.getaddressinfo(address_18075)["solvable"]
+ if self.is_bdb_compiled():
+ # Old wallets are BDB and will only work if BDB is compiled
+ # Copy the 0.16 wallet to the last Bitcoin Core version and open it:
+ shutil.copyfile(
+ os.path.join(node_v16_wallets_dir, "wallets/u1_v16"),
+ os.path.join(node_master_wallets_dir, "u1_v16")
+ )
+ load_res = node_master.loadwallet("u1_v16")
+ # Make sure this wallet opens without warnings. See https://github.com/bitcoin/bitcoin/pull/19054
+ assert_equal(load_res['warning'], '')
+ wallet = node_master.get_wallet_rpc("u1_v16")
+ info = wallet.getaddressinfo(v16_addr)
+ descriptor = "wpkh([" + info["hdmasterfingerprint"] + hdkeypath[1:] + "]" + v16_pubkey + ")"
+ assert_equal(info["desc"], descsum_create(descriptor))
+
+ # Now copy that same wallet back to 0.16 to make sure no automatic upgrade breaks it
+ os.remove(os.path.join(node_v16_wallets_dir, "wallets/u1_v16"))
+ shutil.copyfile(
+ 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"])
+ wallet = node_v16.get_wallet_rpc("u1_v16")
+ info = wallet.validateaddress(v16_addr)
+ assert_equal(info, v16_info)
- # 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"]
+ # Copy the 0.17 wallet to the last Bitcoin Core version and open it:
+ node_v17.unloadwallet("u1_v17")
+ shutil.copytree(
+ os.path.join(node_v17_wallets_dir, "u1_v17"),
+ os.path.join(node_master_wallets_dir, "u1_v17")
+ )
+ node_master.loadwallet("u1_v17")
+ wallet = node_master.get_wallet_rpc("u1_v17")
+ info = wallet.getaddressinfo(address)
+ 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"),
+ os.path.join(node_master_wallets_dir, "w1_v19")
+ )
+ node_master.loadwallet("w1_v19")
+ 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/feature_filelock.py b/test/functional/feature_filelock.py
index 7de9a589be..2798d11b0a 100755
--- a/test/functional/feature_filelock.py
+++ b/test/functional/feature_filelock.py
@@ -4,6 +4,8 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Check that it's not possible to start a second bitcoind instance using the same datadir or wallet."""
import os
+import random
+import string
from test_framework.test_framework import BitcoinTestFramework
from test_framework.test_node import ErrorMatch
@@ -27,11 +29,21 @@ class FilelockTest(BitcoinTestFramework):
self.nodes[1].assert_start_raises_init_error(extra_args=['-datadir={}'.format(self.nodes[0].datadir), '-noserver'], expected_msg=expected_msg)
if self.is_wallet_compiled():
- self.nodes[0].createwallet(self.default_wallet_name)
- wallet_dir = os.path.join(datadir, 'wallets')
- self.log.info("Check that we can't start a second bitcoind instance using the same wallet")
- expected_msg = "Error: Error initializing wallet database environment"
- self.nodes[1].assert_start_raises_init_error(extra_args=['-walletdir={}'.format(wallet_dir), '-wallet=' + self.default_wallet_name, '-noserver'], expected_msg=expected_msg, match=ErrorMatch.PARTIAL_REGEX)
+ def check_wallet_filelock(descriptors):
+ wallet_name = ''.join([random.choice(string.ascii_lowercase) for _ in range(6)])
+ self.nodes[0].createwallet(wallet_name=wallet_name, descriptors=descriptors)
+ wallet_dir = os.path.join(datadir, 'wallets')
+ self.log.info("Check that we can't start a second bitcoind instance using the same wallet")
+ if descriptors:
+ expected_msg = "Error: SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another bitcoind?"
+ else:
+ expected_msg = "Error: Error initializing wallet database environment"
+ self.nodes[1].assert_start_raises_init_error(extra_args=['-walletdir={}'.format(wallet_dir), '-wallet=' + wallet_name, '-noserver'], expected_msg=expected_msg, match=ErrorMatch.PARTIAL_REGEX)
+
+ if self.is_bdb_compiled():
+ check_wallet_filelock(False)
+ if self.is_sqlite_compiled():
+ check_wallet_filelock(True)
if __name__ == '__main__':
FilelockTest().main()
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index f2313bac13..b068ce612c 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -5,11 +5,11 @@
"""Test the -alertnotify, -blocknotify and -walletnotify options."""
import os
-from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE, keyhash_to_p2pkh
+from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
+from test_framework.descriptors import descsum_create
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
- hex_str_to_bytes,
)
# Linux allow all characters other than \x00
@@ -49,6 +49,31 @@ class NotificationsTest(BitcoinTestFramework):
super().setup_network()
def run_test(self):
+ if self.is_wallet_compiled():
+ # Setup the descriptors to be imported to the wallet
+ seed = "cTdGmKFWpbvpKQ7ejrdzqYT2hhjyb3GPHnLAK7wdi5Em67YLwSm9"
+ xpriv = "tprv8ZgxMBicQKsPfHCsTwkiM1KT56RXbGGTqvc2hgqzycpwbHqqpcajQeMRZoBD35kW4RtyCemu6j34Ku5DEspmgjKdt2qe4SvRch5Kk8B8A2v"
+ desc_imports = [{
+ "desc": descsum_create("wpkh(" + xpriv + "/0/*)"),
+ "timestamp": 0,
+ "active": True,
+ "keypool": True,
+ },{
+ "desc": descsum_create("wpkh(" + xpriv + "/1/*)"),
+ "timestamp": 0,
+ "active": True,
+ "keypool": True,
+ "internal": True,
+ }]
+ # Make the wallets and import the descriptors
+ # Ensures that node 0 and node 1 share the same wallet for the conflicting transaction tests below.
+ for i, name in enumerate(self.wallet_names):
+ self.nodes[i].createwallet(wallet_name=name, descriptors=self.options.descriptors, blank=True, load_on_startup=True)
+ if self.options.descriptors:
+ self.nodes[i].importdescriptors(desc_imports)
+ else:
+ self.nodes[i].sethdseed(True, seed)
+
self.log.info("test -blocknotify")
block_count = 10
blocks = self.nodes[1].generatetoaddress(block_count, self.nodes[1].getnewaddress() if self.is_wallet_compiled() else ADDRESS_BCRT1_UNSPENDABLE)
@@ -84,11 +109,10 @@ class NotificationsTest(BitcoinTestFramework):
for tx_file in os.listdir(self.walletnotify_dir):
os.remove(os.path.join(self.walletnotify_dir, tx_file))
- # Conflicting transactions tests. Give node 0 same wallet seed as
- # node 1, generate spends from node 0, and check notifications
+ # Conflicting transactions tests.
+ # Generate spends from node 0, and check notifications
# triggered by node 1
self.log.info("test -walletnotify with conflicting transactions")
- self.nodes[0].sethdseed(seed=self.nodes[1].dumpprivkey(keyhash_to_p2pkh(hex_str_to_bytes(self.nodes[1].getwalletinfo()['hdseedid'])[::-1])))
self.nodes[0].rescanblockchain()
self.nodes[0].generatetoaddress(100, ADDRESS_BCRT1_UNSPENDABLE)
self.sync_blocks()
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index 1257dff1ae..2cf0ef2251 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -29,6 +29,8 @@ class TestBitcoinCli(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
+ if self.is_wallet_compiled():
+ self.requires_wallet = True
def skip_test_if_missing_module(self):
self.skip_if_no_cli()
diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py
index 946bfa51d4..e9f61be4d4 100755
--- a/test/functional/interface_zmq.py
+++ b/test/functional/interface_zmq.py
@@ -62,6 +62,8 @@ class ZMQSubscriber:
class ZMQTest (BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
+ if self.is_wallet_compiled():
+ self.requires_wallet = True
def skip_test_if_missing_module(self):
self.skip_if_no_py3_zmq()
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index de0b7f303f..cf46616681 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -25,6 +25,7 @@ from test_framework.util import (
assert_raises_rpc_error,
p2p_port,
)
+from test_framework.wallet import MiniWallet
def assert_net_servicesnames(servicesflag, servicenames):
@@ -48,6 +49,9 @@ class NetTest(BitcoinTestFramework):
self.supports_cli = False
def run_test(self):
+ # We need miniwallet to make a transaction
+ self.wallet = MiniWallet(self.nodes[0])
+ self.wallet.generate(1)
# Get out of IBD for the minfeefilter and getpeerinfo tests.
self.nodes[0].generate(101)
@@ -74,8 +78,7 @@ class NetTest(BitcoinTestFramework):
def test_getpeerinfo(self):
self.log.info("Test getpeerinfo")
# Create a few getpeerinfo last_block/last_transaction values.
- if self.is_wallet_compiled():
- self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
+ self.wallet.send_self_transfer(from_node=self.nodes[0]) # Make a transaction so we can see it in the getpeerinfo results
self.nodes[1].generate(1)
self.sync_all()
time_now = int(time.time())
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 4bda73599d..70a9798449 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -108,6 +108,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# skipped. If list is truncated, wallet creation is skipped and keys
# are not imported.
self.wallet_names = None
+ # 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
self.set_test_params()
assert self.wallet_names is None or len(self.wallet_names) <= self.num_nodes
if self.options.timeout_factor == 0 :
@@ -184,15 +187,30 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
parser.add_argument('--timeout-factor', dest="timeout_factor", type=float, default=1.0, help='adjust test timeouts by a factor. Setting it to 0 disables all timeouts')
group = parser.add_mutually_exclusive_group()
- group.add_argument("--descriptors", default=False, action="store_true",
+ group.add_argument("--descriptors", action='store_const', const=True,
help="Run test using a descriptor wallet", dest='descriptors')
- group.add_argument("--legacy-wallet", default=False, action="store_false",
+ group.add_argument("--legacy-wallet", action='store_const', const=False,
help="Run test using legacy wallets", dest='descriptors')
self.add_options(parser)
self.options = parser.parse_args()
self.options.previous_releases_path = previous_releases_path
+ config = configparser.ConfigParser()
+ config.read_file(open(self.options.configfile))
+ self.config = config
+
+ if self.options.descriptors is None:
+ # Prefer BDB unless it isn't available
+ if self.is_bdb_compiled():
+ self.options.descriptors = False
+ elif self.is_sqlite_compiled():
+ self.options.descriptors = True
+ else:
+ # If neither are compiled, tests requiring a wallet will be skipped and the value of self.options.descriptors won't matter
+ # It still needs to exist and be None in order for tests to work however.
+ self.options.descriptors = None
+
def setup(self):
"""Call this method to start up the test framework object with options set."""
@@ -202,9 +220,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.options.cachedir = os.path.abspath(self.options.cachedir)
- config = configparser.ConfigParser()
- config.read_file(open(self.options.configfile))
- self.config = config
+ config = self.config
+
fname_bitcoind = os.path.join(
config["environment"]["BUILDDIR"],
"src",
@@ -377,7 +394,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
extra_args = self.extra_args
self.add_nodes(self.num_nodes, extra_args)
self.start_nodes()
- if self.is_wallet_compiled():
+ if self.requires_wallet:
self.import_deterministic_coinbase_privkeys()
if not self.setup_clean_chain:
for n in self.nodes:
@@ -769,10 +786,13 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def skip_if_no_wallet(self):
"""Skip the running test if wallet has not been compiled."""
+ self.requires_wallet = True
if not self.is_wallet_compiled():
raise SkipTest("wallet has not been compiled.")
if self.options.descriptors:
self.skip_if_no_sqlite()
+ else:
+ self.skip_if_no_bdb()
def skip_if_no_sqlite(self):
"""Skip the running test if sqlite has not been compiled."""
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 0e6340b69d..1e7d9e4b0d 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -86,29 +86,29 @@ EXTENDED_SCRIPTS = [
BASE_SCRIPTS = [
# Scripts that are run by default.
# Longest test should go first, to favor running tests in parallel
- 'wallet_hd.py',
+ 'wallet_hd.py --legacy-wallet',
'wallet_hd.py --descriptors',
- 'wallet_backup.py',
+ 'wallet_backup.py --legacy-wallet',
'wallet_backup.py --descriptors',
# vv Tests less than 5m vv
'mining_getblocktemplate_longpoll.py',
'feature_maxuploadtarget.py',
'feature_block.py',
- 'rpc_fundrawtransaction.py',
+ 'rpc_fundrawtransaction.py --legacy-wallet',
'rpc_fundrawtransaction.py --descriptors',
'p2p_compactblocks.py',
'feature_segwit.py --legacy-wallet',
# vv Tests less than 2m vv
- 'wallet_basic.py',
+ 'wallet_basic.py --legacy-wallet',
'wallet_basic.py --descriptors',
- 'wallet_labels.py',
+ 'wallet_labels.py --legacy-wallet',
'wallet_labels.py --descriptors',
'p2p_segwit.py',
'p2p_timeouts.py',
'p2p_tx_download.py',
'mempool_updatefromblock.py',
'wallet_dump.py --legacy-wallet',
- 'wallet_listtransactions.py',
+ 'wallet_listtransactions.py --legacy-wallet',
'wallet_listtransactions.py --descriptors',
'feature_taproot.py',
# vv Tests less than 60s vv
@@ -116,21 +116,21 @@ BASE_SCRIPTS = [
'wallet_importmulti.py --legacy-wallet',
'mempool_limit.py',
'rpc_txoutproof.py',
- 'wallet_listreceivedby.py',
+ 'wallet_listreceivedby.py --legacy-wallet',
'wallet_listreceivedby.py --descriptors',
- 'wallet_abandonconflict.py',
+ 'wallet_abandonconflict.py --legacy-wallet',
'wallet_abandonconflict.py --descriptors',
'feature_csv_activation.py',
- 'rpc_rawtransaction.py',
+ 'rpc_rawtransaction.py --legacy-wallet',
'rpc_rawtransaction.py --descriptors',
- 'wallet_address_types.py',
+ 'wallet_address_types.py --legacy-wallet',
'wallet_address_types.py --descriptors',
'feature_bip68_sequence.py',
'p2p_feefilter.py',
'feature_reindex.py',
'feature_abortnode.py',
# vv Tests less than 30s vv
- 'wallet_keypool_topup.py',
+ 'wallet_keypool_topup.py --legacy-wallet',
'wallet_keypool_topup.py --descriptors',
'feature_fee_estimation.py',
'interface_zmq.py',
@@ -138,7 +138,7 @@ BASE_SCRIPTS = [
'interface_bitcoin_cli.py',
'mempool_resurrect.py',
'wallet_txn_doublespend.py --mineblock',
- 'tool_wallet.py',
+ 'tool_wallet.py --legacy-wallet',
'tool_wallet.py --descriptors',
'wallet_txn_clone.py',
'wallet_txn_clone.py --segwit',
@@ -146,14 +146,14 @@ BASE_SCRIPTS = [
'rpc_misc.py',
'interface_rest.py',
'mempool_spend_coinbase.py',
- 'wallet_avoidreuse.py',
+ 'wallet_avoidreuse.py --legacy-wallet',
'wallet_avoidreuse.py --descriptors',
'mempool_reorg.py',
'mempool_persist.py',
- 'wallet_multiwallet.py',
+ 'wallet_multiwallet.py --legacy-wallet',
'wallet_multiwallet.py --descriptors',
'wallet_multiwallet.py --usecli',
- 'wallet_createwallet.py',
+ 'wallet_createwallet.py --legacy-wallet',
'wallet_createwallet.py --usecli',
'wallet_createwallet.py --descriptors',
'wallet_watchonly.py --legacy-wallet',
@@ -161,27 +161,27 @@ BASE_SCRIPTS = [
'wallet_reorgsrestore.py',
'interface_http.py',
'interface_rpc.py',
- 'rpc_psbt.py',
+ 'rpc_psbt.py --legacy-wallet',
'rpc_psbt.py --descriptors',
'rpc_users.py',
'rpc_whitelist.py',
'feature_proxy.py',
- 'rpc_signrawtransaction.py',
+ 'rpc_signrawtransaction.py --legacy-wallet',
'rpc_signrawtransaction.py --descriptors',
- 'wallet_groups.py',
+ 'wallet_groups.py --legacy-wallet',
'p2p_addrv2_relay.py',
'wallet_groups.py --descriptors',
'p2p_disconnect_ban.py',
'rpc_decodescript.py',
'rpc_blockchain.py',
'rpc_deprecated.py',
- 'wallet_disable.py',
+ 'wallet_disable.py --legacy-wallet',
'wallet_disable.py --descriptors',
'p2p_addr_relay.py',
'p2p_getaddr_caching.py',
'p2p_getdata.py',
'rpc_net.py',
- 'wallet_keypool.py',
+ 'wallet_keypool.py --legacy-wallet',
'wallet_keypool.py --descriptors',
'wallet_descriptor.py --descriptors',
'p2p_nobloomfilter_messages.py',
@@ -195,9 +195,9 @@ BASE_SCRIPTS = [
'p2p_invalid_tx.py',
'feature_assumevalid.py',
'example_test.py',
- 'wallet_txn_doublespend.py',
+ 'wallet_txn_doublespend.py --legacy-wallet',
'wallet_txn_doublespend.py --descriptors',
- 'feature_backwards_compatibility.py',
+ 'feature_backwards_compatibility.py --legacy-wallet',
'feature_backwards_compatibility.py --descriptors',
'wallet_txn_clone.py --mineblock',
'feature_notifications.py',
@@ -206,59 +206,60 @@ BASE_SCRIPTS = [
'feature_rbf.py',
'mempool_packages.py',
'mempool_package_onemore.py',
- 'rpc_createmultisig.py',
+ 'rpc_createmultisig.py --legacy-wallet',
'rpc_createmultisig.py --descriptors',
'feature_versionbits_warning.py',
'rpc_preciousblock.py',
- 'wallet_importprunedfunds.py',
+ 'wallet_importprunedfunds.py --legacy-wallet',
'wallet_importprunedfunds.py --descriptors',
'p2p_leak_tx.py',
'p2p_eviction.py',
'rpc_signmessage.py',
'rpc_generateblock.py',
'rpc_generate.py',
- 'wallet_balance.py',
+ 'wallet_balance.py --legacy-wallet',
'wallet_balance.py --descriptors',
- 'feature_nulldummy.py',
+ 'feature_nulldummy.py --legacy-wallet',
'feature_nulldummy.py --descriptors',
'mempool_accept.py',
'mempool_expiry.py',
'wallet_import_rescan.py --legacy-wallet',
'wallet_import_with_label.py --legacy-wallet',
'wallet_importdescriptors.py --descriptors',
- 'wallet_upgradewallet.py',
+ 'wallet_upgradewallet.py --legacy-wallet',
'rpc_bind.py --ipv4',
'rpc_bind.py --ipv6',
'rpc_bind.py --nonloopback',
'mining_basic.py',
'feature_signet.py',
- 'wallet_bumpfee.py',
+ 'wallet_bumpfee.py --legacy-wallet',
'wallet_bumpfee.py --descriptors',
'wallet_implicitsegwit.py --legacy-wallet',
'rpc_named_arguments.py',
- 'wallet_listsinceblock.py',
+ 'wallet_listsinceblock.py --legacy-wallet',
'wallet_listsinceblock.py --descriptors',
'wallet_listdescriptors.py --descriptors',
'p2p_leak.py',
- 'wallet_encryption.py',
+ 'wallet_encryption.py --legacy-wallet',
'wallet_encryption.py --descriptors',
'feature_dersig.py',
'feature_cltv.py',
'rpc_uptime.py',
- 'wallet_resendwallettransactions.py',
+ 'wallet_resendwallettransactions.py --legacy-wallet',
'wallet_resendwallettransactions.py --descriptors',
- 'wallet_fallbackfee.py',
+ 'wallet_fallbackfee.py --legacy-wallet',
'wallet_fallbackfee.py --descriptors',
'rpc_dumptxoutset.py',
'feature_minchainwork.py',
'rpc_estimatefee.py',
'rpc_getblockstats.py',
- 'wallet_create_tx.py',
- 'wallet_send.py',
+ 'wallet_create_tx.py --legacy-wallet',
+ 'wallet_send.py --legacy-wallet',
+ 'wallet_send.py --descriptors',
'wallet_create_tx.py --descriptors',
'p2p_fingerprint.py',
'feature_uacomment.py',
- 'wallet_coinbase_category.py',
+ 'wallet_coinbase_category.py --legacy-wallet',
'wallet_coinbase_category.py --descriptors',
'feature_filelock.py',
'feature_loadblock.py',
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index cca984b292..28103793df 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -350,7 +350,8 @@ class ToolWalletTest(BitcoinTestFramework):
self.log.info('Checking createfromdump')
self.do_tool_createfromdump("load", "wallet.dump")
- self.do_tool_createfromdump("load-bdb", "wallet.dump", "bdb")
+ if self.is_bdb_compiled():
+ self.do_tool_createfromdump("load-bdb", "wallet.dump", "bdb")
if self.is_sqlite_compiled():
self.do_tool_createfromdump("load-sqlite", "wallet.dump", "sqlite")
diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py
index 1de41a5f96..c04a15a67c 100755
--- a/test/functional/wallet_descriptor.py
+++ b/test/functional/wallet_descriptor.py
@@ -23,11 +23,14 @@ class WalletDescriptorTest(BitcoinTestFramework):
self.skip_if_no_sqlite()
def run_test(self):
- # Make a legacy wallet and check it is BDB
- self.nodes[0].createwallet(wallet_name="legacy1", descriptors=False)
- wallet_info = self.nodes[0].getwalletinfo()
- assert_equal(wallet_info['format'], 'bdb')
- self.nodes[0].unloadwallet("legacy1")
+ if self.is_bdb_compiled():
+ # Make a legacy wallet and check it is BDB
+ self.nodes[0].createwallet(wallet_name="legacy1", descriptors=False)
+ wallet_info = self.nodes[0].getwalletinfo()
+ assert_equal(wallet_info['format'], 'bdb')
+ self.nodes[0].unloadwallet("legacy1")
+ else:
+ self.log.warning("Skipping BDB test")
# Make a descriptor wallet
self.log.info("Making a descriptor wallet")
diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py
index 9835c5a2af..880341fdd9 100755
--- a/test/functional/wallet_send.py
+++ b/test/functional/wallet_send.py
@@ -8,6 +8,7 @@ from decimal import Decimal, getcontext
from itertools import product
from test_framework.authproxy import JSONRPCException
+from test_framework.descriptors import descsum_create
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -168,49 +169,91 @@ class WalletSendTest(BitcoinTestFramework):
self.nodes[1].createwallet(wallet_name="w1")
w1 = self.nodes[1].get_wallet_rpc("w1")
# w2 contains the private keys for w3
- self.nodes[1].createwallet(wallet_name="w2")
+ self.nodes[1].createwallet(wallet_name="w2", blank=True)
w2 = self.nodes[1].get_wallet_rpc("w2")
+ xpriv = "tprv8ZgxMBicQKsPfHCsTwkiM1KT56RXbGGTqvc2hgqzycpwbHqqpcajQeMRZoBD35kW4RtyCemu6j34Ku5DEspmgjKdt2qe4SvRch5Kk8B8A2v"
+ xpub = "tpubD6NzVbkrYhZ4YkEfMbRJkQyZe7wTkbTNRECozCtJPtdLRn6cT1QKb8yHjwAPcAr26eHBFYs5iLiFFnCbwPRsncCKUKCfubHDMGKzMVcN1Jg"
+ if self.options.descriptors:
+ w2.importdescriptors([{
+ "desc": descsum_create("wpkh(" + xpriv + "/0/0/*)"),
+ "timestamp": "now",
+ "range": [0, 100],
+ "active": True
+ },{
+ "desc": descsum_create("wpkh(" + xpriv + "/0/1/*)"),
+ "timestamp": "now",
+ "range": [0, 100],
+ "active": True,
+ "internal": True
+ }])
+ else:
+ w2.sethdseed(True)
+
# w3 is a watch-only wallet, based on w2
self.nodes[1].createwallet(wallet_name="w3", disable_private_keys=True)
w3 = self.nodes[1].get_wallet_rpc("w3")
- for _ in range(3):
- a2_receive = w2.getnewaddress()
- a2_change = w2.getrawchangeaddress() # doesn't actually use change derivation
- res = w3.importmulti([{
- "desc": w2.getaddressinfo(a2_receive)["desc"],
+ if self.options.descriptors:
+ # Match the privkeys in w2 for descriptors
+ res = w3.importdescriptors([{
+ "desc": descsum_create("wpkh(" + xpub + "/0/0/*)"),
"timestamp": "now",
+ "range": [0, 100],
"keypool": True,
+ "active": True,
"watchonly": True
},{
- "desc": w2.getaddressinfo(a2_change)["desc"],
+ "desc": descsum_create("wpkh(" + xpub + "/0/1/*)"),
"timestamp": "now",
+ "range": [0, 100],
"keypool": True,
+ "active": True,
"internal": True,
"watchonly": True
}])
assert_equal(res, [{"success": True}, {"success": True}])
- w0.sendtoaddress(a2_receive, 10) # fund w3
- self.nodes[0].generate(1)
- self.sync_blocks()
-
- # w4 has private keys enabled, but only contains watch-only keys (from w2)
- self.nodes[1].createwallet(wallet_name="w4", disable_private_keys=False)
- w4 = self.nodes[1].get_wallet_rpc("w4")
for _ in range(3):
a2_receive = w2.getnewaddress()
- res = w4.importmulti([{
- "desc": w2.getaddressinfo(a2_receive)["desc"],
- "timestamp": "now",
- "keypool": False,
- "watchonly": True
- }])
- assert_equal(res, [{"success": True}])
+ if not self.options.descriptors:
+ # Because legacy wallets use exclusively hardened derivation, we can't do a ranged import like we do for descriptors
+ a2_change = w2.getrawchangeaddress() # doesn't actually use change derivation
+ res = w3.importmulti([{
+ "desc": w2.getaddressinfo(a2_receive)["desc"],
+ "timestamp": "now",
+ "keypool": True,
+ "watchonly": True
+ },{
+ "desc": w2.getaddressinfo(a2_change)["desc"],
+ "timestamp": "now",
+ "keypool": True,
+ "internal": True,
+ "watchonly": True
+ }])
+ assert_equal(res, [{"success": True}, {"success": True}])
- w0.sendtoaddress(a2_receive, 10) # fund w4
+ w0.sendtoaddress(a2_receive, 10) # fund w3
self.nodes[0].generate(1)
self.sync_blocks()
+ if not self.options.descriptors:
+ # w4 has private keys enabled, but only contains watch-only keys (from w2)
+ # This is legacy wallet behavior only as descriptor wallets don't allow watchonly and non-watchonly things in the same wallet.
+ self.nodes[1].createwallet(wallet_name="w4", disable_private_keys=False)
+ w4 = self.nodes[1].get_wallet_rpc("w4")
+ for _ in range(3):
+ a2_receive = w2.getnewaddress()
+ res = w4.importmulti([{
+ "desc": w2.getaddressinfo(a2_receive)["desc"],
+ "timestamp": "now",
+ "keypool": False,
+ "watchonly": True
+ }])
+ assert_equal(res, [{"success": True}])
+
+ w0.sendtoaddress(a2_receive, 10) # fund w4
+ self.nodes[0].generate(1)
+ self.sync_blocks()
+
self.log.info("Send to address...")
self.test_send(from_wallet=w0, to_wallet=w1, amount=1)
self.test_send(from_wallet=w0, to_wallet=w1, amount=1, add_to_wallet=True)
@@ -241,11 +284,15 @@ class WalletSendTest(BitcoinTestFramework):
res = w2.walletprocesspsbt(res["psbt"])
assert res["complete"]
- self.log.info("Create PSBT from wallet w4 with watch-only keys, sign with w2...")
- self.test_send(from_wallet=w4, to_wallet=w1, amount=1, expect_error=(-4, "Insufficient funds"))
- res = self.test_send(from_wallet=w4, to_wallet=w1, amount=1, include_watching=True, add_to_wallet=False)
- res = w2.walletprocesspsbt(res["psbt"])
- assert res["complete"]
+ if not self.options.descriptors:
+ # Descriptor wallets do not allow mixed watch-only and non-watch-only things in the same wallet.
+ # This is specifically testing that w4 ignores its own private keys and creates a psbt with send
+ # which is not something that needs to be tested in descriptor wallets.
+ self.log.info("Create PSBT from wallet w4 with watch-only keys, sign with w2...")
+ self.test_send(from_wallet=w4, to_wallet=w1, amount=1, expect_error=(-4, "Insufficient funds"))
+ res = self.test_send(from_wallet=w4, to_wallet=w1, amount=1, include_watching=True, add_to_wallet=False)
+ res = w2.walletprocesspsbt(res["psbt"])
+ assert res["complete"]
self.log.info("Create OP_RETURN...")
self.test_send(from_wallet=w0, to_wallet=w1, amount=1)
diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py
index d0bb6135a8..fbc0f995d2 100755
--- a/test/functional/wallet_upgradewallet.py
+++ b/test/functional/wallet_upgradewallet.py
@@ -57,6 +57,7 @@ class UpgradeWalletTest(BitcoinTestFramework):
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_network(self):