aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/feature_bind_port_discover.py78
-rwxr-xr-xtest/functional/feature_bind_port_externalip.py75
-rwxr-xr-xtest/functional/feature_proxy.py2
-rwxr-xr-xtest/functional/p2p_message_capture.py2
-rwxr-xr-xtest/functional/rpc_blockchain.py9
-rw-r--r--test/functional/test_framework/script.py1
-rwxr-xr-xtest/functional/test_framework/test_node.py3
-rwxr-xr-xtest/functional/test_runner.py3
-rwxr-xr-xtest/functional/wallet_inactive_hdchains.py147
-rwxr-xr-xtest/functional/wallet_taproot.py108
-rwxr-xr-xtest/functional/wallet_upgradewallet.py11
11 files changed, 401 insertions, 38 deletions
diff --git a/test/functional/feature_bind_port_discover.py b/test/functional/feature_bind_port_discover.py
new file mode 100755
index 0000000000..6e07f2f16c
--- /dev/null
+++ b/test/functional/feature_bind_port_discover.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020-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 that -discover does not add all interfaces' addresses if we listen on only some of them
+"""
+
+from test_framework.test_framework import BitcoinTestFramework, SkipTest
+from test_framework.util import assert_equal
+
+# We need to bind to a routable address for this test to exercise the relevant code
+# and also must have another routable address on another interface which must not
+# be named "lo" or "lo0".
+# To set these routable addresses on the machine, use:
+# Linux:
+# ifconfig lo:0 1.1.1.1/32 up && ifconfig lo:1 2.2.2.2/32 up # to set up
+# ifconfig lo:0 down && ifconfig lo:1 down # to remove it, after the test
+# FreeBSD:
+# ifconfig em0 1.1.1.1/32 alias && ifconfig wlan0 2.2.2.2/32 alias # to set up
+# ifconfig em0 1.1.1.1 -alias && ifconfig wlan0 2.2.2.2 -alias # to remove it, after the test
+ADDR1 = '1.1.1.1'
+ADDR2 = '2.2.2.2'
+
+BIND_PORT = 31001
+
+class BindPortDiscoverTest(BitcoinTestFramework):
+ def set_test_params(self):
+ # Avoid any -bind= on the command line. Force the framework to avoid adding -bind=127.0.0.1.
+ self.setup_clean_chain = True
+ self.bind_to_localhost_only = False
+ self.extra_args = [
+ ['-discover', f'-port={BIND_PORT}'], # bind on any
+ ['-discover', f'-bind={ADDR1}:{BIND_PORT}'],
+ ]
+ self.num_nodes = len(self.extra_args)
+
+ def add_options(self, parser):
+ parser.add_argument(
+ "--ihave1111and2222", action='store_true', dest="ihave1111and2222",
+ help=f"Run the test, assuming {ADDR1} and {ADDR2} are configured on the machine",
+ default=False)
+
+ def skip_test_if_missing_module(self):
+ if not self.options.ihave1111and2222:
+ raise SkipTest(
+ f"To run this test make sure that {ADDR1} and {ADDR2} (routable addresses) are "
+ "assigned to the interfaces on this machine and rerun with --ihave1111and2222")
+
+ def run_test(self):
+ self.log.info(
+ "Test that if -bind= is not passed then all addresses are "
+ "added to localaddresses")
+ found_addr1 = False
+ found_addr2 = False
+ for local in self.nodes[0].getnetworkinfo()['localaddresses']:
+ if local['address'] == ADDR1:
+ found_addr1 = True
+ assert_equal(local['port'], BIND_PORT)
+ if local['address'] == ADDR2:
+ found_addr2 = True
+ assert_equal(local['port'], BIND_PORT)
+ assert found_addr1
+ assert found_addr2
+
+ self.log.info(
+ "Test that if -bind= is passed then only that address is "
+ "added to localaddresses")
+ found_addr1 = False
+ for local in self.nodes[1].getnetworkinfo()['localaddresses']:
+ if local['address'] == ADDR1:
+ found_addr1 = True
+ assert_equal(local['port'], BIND_PORT)
+ assert local['address'] != ADDR2
+ assert found_addr1
+
+if __name__ == '__main__':
+ BindPortDiscoverTest().main()
diff --git a/test/functional/feature_bind_port_externalip.py b/test/functional/feature_bind_port_externalip.py
new file mode 100755
index 0000000000..6a74ce5738
--- /dev/null
+++ b/test/functional/feature_bind_port_externalip.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020-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 that the proper port is used for -externalip=
+"""
+
+from test_framework.test_framework import BitcoinTestFramework, SkipTest
+from test_framework.util import assert_equal, p2p_port
+
+# We need to bind to a routable address for this test to exercise the relevant code.
+# To set a routable address on the machine use:
+# Linux:
+# ifconfig lo:0 1.1.1.1/32 up # to set up
+# ifconfig lo:0 down # to remove it, after the test
+# FreeBSD:
+# ifconfig lo0 1.1.1.1/32 alias # to set up
+# ifconfig lo0 1.1.1.1 -alias # to remove it, after the test
+ADDR = '1.1.1.1'
+
+# array of tuples [arguments, expected port in localaddresses]
+EXPECTED = [
+ [['-externalip=2.2.2.2', '-port=30001'], 30001],
+ [['-externalip=2.2.2.2', '-port=30002', f'-bind={ADDR}'], 30002],
+ [['-externalip=2.2.2.2', f'-bind={ADDR}'], 'default_p2p_port'],
+ [['-externalip=2.2.2.2', '-port=30003', f'-bind={ADDR}:30004'], 30004],
+ [['-externalip=2.2.2.2', f'-bind={ADDR}:30005'], 30005],
+ [['-externalip=2.2.2.2:30006', '-port=30007'], 30006],
+ [['-externalip=2.2.2.2:30008', '-port=30009', f'-bind={ADDR}'], 30008],
+ [['-externalip=2.2.2.2:30010', f'-bind={ADDR}'], 30010],
+ [['-externalip=2.2.2.2:30011', '-port=30012', f'-bind={ADDR}:30013'], 30011],
+ [['-externalip=2.2.2.2:30014', f'-bind={ADDR}:30015'], 30014],
+ [['-externalip=2.2.2.2', '-port=30016', f'-bind={ADDR}:30017',
+ f'-whitebind={ADDR}:30018'], 30017],
+ [['-externalip=2.2.2.2', '-port=30019',
+ f'-whitebind={ADDR}:30020'], 30020],
+]
+
+class BindPortExternalIPTest(BitcoinTestFramework):
+ def set_test_params(self):
+ # Avoid any -bind= on the command line. Force the framework to avoid adding -bind=127.0.0.1.
+ self.setup_clean_chain = True
+ self.bind_to_localhost_only = False
+ self.num_nodes = len(EXPECTED)
+ self.extra_args = list(map(lambda e: e[0], EXPECTED))
+
+ def add_options(self, parser):
+ parser.add_argument(
+ "--ihave1111", action='store_true', dest="ihave1111",
+ help=f"Run the test, assuming {ADDR} is configured on the machine",
+ default=False)
+
+ def skip_test_if_missing_module(self):
+ if not self.options.ihave1111:
+ raise SkipTest(
+ f"To run this test make sure that {ADDR} (a routable address) is assigned "
+ "to one of the interfaces on this machine and rerun with --ihave1111")
+
+ def run_test(self):
+ self.log.info("Test the proper port is used for -externalip=")
+ for i in range(len(EXPECTED)):
+ expected_port = EXPECTED[i][1]
+ if expected_port == 'default_p2p_port':
+ expected_port = p2p_port(i)
+ found = False
+ for local in self.nodes[i].getnetworkinfo()['localaddresses']:
+ if local['address'] == '2.2.2.2':
+ assert_equal(local['port'], expected_port)
+ found = True
+ break
+ assert found
+
+if __name__ == '__main__':
+ BindPortExternalIPTest().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/p2p_message_capture.py b/test/functional/p2p_message_capture.py
index edde9a6ecf..0a7ae44de4 100755
--- a/test/functional/p2p_message_capture.py
+++ b/test/functional/p2p_message_capture.py
@@ -20,7 +20,7 @@ LENGTH_SIZE = 4
MSGTYPE_SIZE = 12
def mini_parser(dat_file):
- """Parse a data file created by CaptureMessage.
+ """Parse a data file created by CaptureMessageToFile.
From the data file we'll only check the structure.
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/test_framework/script.py b/test/functional/test_framework/script.py
index 7791ae5392..2b70eab4e4 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -27,6 +27,7 @@ from .messages import (
from .ripemd160 import ripemd160
MAX_SCRIPT_ELEMENT_SIZE = 520
+MAX_PUBKEYS_PER_MULTI_A = 999
LOCKTIME_THRESHOLD = 500000000
ANNEX_TAG = 0x50
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..b0f24e3b97 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -276,11 +276,13 @@ BASE_SCRIPTS = [
'feature_minchainwork.py',
'rpc_estimatefee.py',
'rpc_getblockstats.py',
+ 'feature_bind_port_externalip.py',
'wallet_create_tx.py --legacy-wallet',
'wallet_send.py --legacy-wallet',
'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',
@@ -290,6 +292,7 @@ BASE_SCRIPTS = [
'feature_loadblock.py',
'p2p_dos_header_tree.py',
'p2p_add_connections.py',
+ 'feature_bind_port_discover.py',
'p2p_unrequested_blocks.py',
'p2p_blockfilters.py',
'p2p_message_capture.py',
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_taproot.py b/test/functional/wallet_taproot.py
index 17eab25457..24758830a3 100755
--- a/test/functional/wallet_taproot.py
+++ b/test/functional/wallet_taproot.py
@@ -12,8 +12,11 @@ from test_framework.util import assert_equal
from test_framework.descriptors import descsum_create
from test_framework.script import (
CScript,
+ MAX_PUBKEYS_PER_MULTI_A,
OP_1,
OP_CHECKSIG,
+ OP_CHECKSIGADD,
+ OP_NUMEQUAL,
taproot_construct,
)
from test_framework.segwit_addr import encode_segwit_address
@@ -167,6 +170,17 @@ def pk(hex_key):
"""Construct a script expression for taproot_construct for pk(hex_key)."""
return (None, CScript([bytes.fromhex(hex_key), OP_CHECKSIG]))
+def multi_a(k, hex_keys, sort=False):
+ """Construct a script expression for taproot_construct for a multi_a script."""
+ xkeys = [bytes.fromhex(hex_key) for hex_key in hex_keys]
+ if sort:
+ xkeys.sort()
+ ops = [xkeys[0], OP_CHECKSIG]
+ for i in range(1, len(hex_keys)):
+ ops += [xkeys[i], OP_CHECKSIGADD]
+ ops += [k, OP_NUMEQUAL]
+ return (None, CScript(ops))
+
def compute_taproot_address(pubkey, scripts):
"""Compute the address for a taproot output with given inner key and scripts."""
tap = taproot_construct(pubkey, scripts)
@@ -194,19 +208,6 @@ class WalletTaprootTest(BitcoinTestFramework):
pass
@staticmethod
- def rand_keys(n):
- ret = []
- idxes = set()
- for _ in range(n):
- while True:
- i = random.randrange(len(KEYS))
- if not i in idxes:
- break
- idxes.add(i)
- ret.append(KEYS[i])
- return ret
-
- @staticmethod
def make_desc(pattern, privmap, keys, pub_only = False):
pat = pattern.replace("$H", H_POINT)
for i in range(len(privmap)):
@@ -275,7 +276,8 @@ class WalletTaprootTest(BitcoinTestFramework):
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
test_balance = int(self.rpc_online.getbalance() * 100000000)
ret_amnt = random.randrange(100000, test_balance)
- res = self.rpc_online.sendtoaddress(address=self.boring.getnewaddress(), amount=Decimal(ret_amnt) / 100000000, subtractfeefromamount=True)
+ # Increase fee_rate to compensate for the wallet's inability to estimate fees for script path spends.
+ res = self.rpc_online.sendtoaddress(address=self.boring.getnewaddress(), amount=Decimal(ret_amnt) / 100000000, subtractfeefromamount=True, fee_rate=200)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
assert(self.rpc_online.gettransaction(res)["confirmations"] > 0)
@@ -306,7 +308,8 @@ class WalletTaprootTest(BitcoinTestFramework):
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
test_balance = int(self.psbt_online.getbalance() * 100000000)
ret_amnt = random.randrange(100000, test_balance)
- psbt = self.psbt_online.walletcreatefundedpsbt([], [{self.boring.getnewaddress(): Decimal(ret_amnt) / 100000000}], None, {"subtractFeeFromOutputs":[0]})['psbt']
+ # Increase fee_rate to compensate for the wallet's inability to estimate fees for script path spends.
+ psbt = self.psbt_online.walletcreatefundedpsbt([], [{self.boring.getnewaddress(): Decimal(ret_amnt) / 100000000}], None, {"subtractFeeFromOutputs":[0], "fee_rate": 200})['psbt']
res = self.psbt_offline.walletprocesspsbt(psbt)
assert(res['complete'])
rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
@@ -314,8 +317,9 @@ class WalletTaprootTest(BitcoinTestFramework):
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
assert(self.psbt_online.gettransaction(txid)['confirmations'] > 0)
- def do_test(self, comment, pattern, privmap, treefn, nkeys):
- keys = self.rand_keys(nkeys * 4)
+ def do_test(self, comment, pattern, privmap, treefn):
+ nkeys = len(privmap)
+ keys = random.sample(KEYS, nkeys * 4)
self.do_test_addr(comment, pattern, privmap, treefn, keys[0:nkeys])
self.do_test_sendtoaddress(comment, pattern, privmap, treefn, keys[0:nkeys], keys[nkeys:2*nkeys])
self.do_test_psbt(comment, pattern, privmap, treefn, keys[2*nkeys:3*nkeys], keys[3*nkeys:4*nkeys])
@@ -349,64 +353,98 @@ class WalletTaprootTest(BitcoinTestFramework):
"tr(XPRV)",
"tr($1/*)",
[True],
- lambda k1: (key(k1), []),
- 1
+ lambda k1: (key(k1), [])
)
self.do_test(
"tr(H,XPRV)",
"tr($H,pk($1/*))",
[True],
- lambda k1: (key(H_POINT), [pk(k1)]),
- 1
+ lambda k1: (key(H_POINT), [pk(k1)])
)
self.do_test(
"wpkh(XPRV)",
"wpkh($1/*)",
[True],
- None,
- 1
+ None
)
self.do_test(
"tr(XPRV,{H,{H,XPUB}})",
"tr($1/*,{pk($H),{pk($H),pk($2/*)}})",
[True, False],
- lambda k1, k2: (key(k1), [pk(H_POINT), [pk(H_POINT), pk(k2)]]),
- 2
+ lambda k1, k2: (key(k1), [pk(H_POINT), [pk(H_POINT), pk(k2)]])
)
self.do_test(
"wsh(multi(1,XPRV,XPUB))",
"wsh(multi(1,$1/*,$2/*))",
[True, False],
- None,
- 2
+ None
)
self.do_test(
"tr(XPRV,{XPUB,XPUB})",
"tr($1/*,{pk($2/*),pk($2/*)})",
[True, False],
- lambda k1, k2: (key(k1), [pk(k2), pk(k2)]),
- 2
+ lambda k1, k2: (key(k1), [pk(k2), pk(k2)])
)
self.do_test(
"tr(XPRV,{{XPUB,H},{H,XPUB}})",
"tr($1/*,{{pk($2/*),pk($H)},{pk($H),pk($2/*)}})",
[True, False],
- lambda k1, k2: (key(k1), [[pk(k2), pk(H_POINT)], [pk(H_POINT), pk(k2)]]),
- 2
+ lambda k1, k2: (key(k1), [[pk(k2), pk(H_POINT)], [pk(H_POINT), pk(k2)]])
)
self.do_test(
"tr(XPUB,{{H,{H,XPUB}},{H,{H,{H,XPRV}}}})",
"tr($1/*,{{pk($H),{pk($H),pk($2/*)}},{pk($H),{pk($H),{pk($H),pk($3/*)}}}})",
[False, False, True],
- lambda k1, k2, k3: (key(k1), [[pk(H_POINT), [pk(H_POINT), pk(k2)]], [pk(H_POINT), [pk(H_POINT), [pk(H_POINT), pk(k3)]]]]),
- 3
+ lambda k1, k2, k3: (key(k1), [[pk(H_POINT), [pk(H_POINT), pk(k2)]], [pk(H_POINT), [pk(H_POINT), [pk(H_POINT), pk(k3)]]]])
)
self.do_test(
"tr(XPRV,{XPUB,{{XPUB,{H,H}},{{H,H},XPUB}}})",
"tr($1/*,{pk($2/*),{{pk($2/*),{pk($H),pk($H)}},{{pk($H),pk($H)},pk($2/*)}}})",
[True, False],
- lambda k1, k2: (key(k1), [pk(k2), [[pk(k2), [pk(H_POINT), pk(H_POINT)]], [[pk(H_POINT), pk(H_POINT)], pk(k2)]]]),
- 2
+ lambda k1, k2: (key(k1), [pk(k2), [[pk(k2), [pk(H_POINT), pk(H_POINT)]], [[pk(H_POINT), pk(H_POINT)], pk(k2)]]])
+ )
+ self.do_test(
+ "tr(H,multi_a(1,XPRV))",
+ "tr($H,multi_a(1,$1/*))",
+ [True],
+ lambda k1: (key(H_POINT), [multi_a(1, [k1])])
+ )
+ self.do_test(
+ "tr(H,sortedmulti_a(1,XPRV,XPUB))",
+ "tr($H,sortedmulti_a(1,$1/*,$2/*))",
+ [True, False],
+ lambda k1, k2: (key(H_POINT), [multi_a(1, [k1, k2], True)])
+ )
+ self.do_test(
+ "tr(H,multi_a(1,XPUB,XPRV))",
+ "tr($H,multi_a(1,$1/*,$2/*))",
+ [False, True],
+ lambda k1, k2: (key(H_POINT), [multi_a(1, [k1, k2])])
+ )
+ self.do_test(
+ "tr(H,sortedmulti_a(1,XPUB,XPRV,XPRV))",
+ "tr($H,sortedmulti_a(1,$1/*,$2/*,$3/*))",
+ [False, True, True],
+ lambda k1, k2, k3: (key(H_POINT), [multi_a(1, [k1, k2, k3], True)])
+ )
+ self.do_test(
+ "tr(H,multi_a(2,XPRV,XPUB,XPRV))",
+ "tr($H,multi_a(2,$1/*,$2/*,$3/*))",
+ [True, False, True],
+ lambda k1, k2, k3: (key(H_POINT), [multi_a(2, [k1, k2, k3])])
+ )
+ self.do_test(
+ "tr(XPUB,{{XPUB,{XPUB,sortedmulti_a(2,XPRV,XPUB,XPRV)}})",
+ "tr($2/*,{pk($2/*),{pk($2/*),sortedmulti_a(2,$1/*,$2/*,$3/*)}})",
+ [True, False, True],
+ lambda k1, k2, k3: (key(k2), [pk(k2), [pk(k2), multi_a(2, [k1, k2, k3], True)]])
+ )
+ rnd_pos = random.randrange(MAX_PUBKEYS_PER_MULTI_A)
+ self.do_test(
+ "tr(XPUB,multi_a(1,H...,XPRV,H...))",
+ "tr($2/*,multi_a(1" + (",$H" * rnd_pos) + ",$1/*" + (",$H" * (MAX_PUBKEYS_PER_MULTI_A - 1 - rnd_pos)) + "))",
+ [True, False],
+ lambda k1, k2: (key(k2), [multi_a(1, ([H_POINT] * rnd_pos) + [k1] + ([H_POINT] * (MAX_PUBKEYS_PER_MULTI_A - 1 - rnd_pos)))])
)
self.log.info("Sending everything back...")
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()