aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtest/functional/rpc_createmultisig.py41
-rwxr-xr-xtest/functional/rpc_psbt.py42
-rw-r--r--test/functional/test_framework/key.py13
-rwxr-xr-xtest/functional/test_framework/test_framework.py18
-rwxr-xr-xtest/functional/test_framework/test_node.py28
-rwxr-xr-xtest/functional/test_runner.py9
-rwxr-xr-xtest/functional/wallet_avoidreuse.py77
-rwxr-xr-xtest/functional/wallet_basic.py84
-rwxr-xr-xtest/functional/wallet_hd.py113
-rwxr-xr-xtest/functional/wallet_keypool.py78
-rwxr-xr-xtest/functional/wallet_keypool_topup.py10
-rwxr-xr-xtest/functional/wallet_labels.py19
12 files changed, 358 insertions, 174 deletions
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index a983716177..56e9ecfcc2 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -4,13 +4,14 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test multisig RPCs"""
+from test_framework.authproxy import JSONRPCException
from test_framework.descriptors import descsum_create, drop_origins
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_raises_rpc_error,
assert_equal,
)
-from test_framework.key import ECPubKey
+from test_framework.key import ECPubKey, ECKey, bytes_to_wif
import binascii
import decimal
@@ -28,10 +29,14 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
self.skip_if_no_wallet()
def get_keys(self):
+ self.pub = []
+ self.priv = []
node0, node1, node2 = self.nodes
- add = [node1.getnewaddress() for _ in range(self.nkeys)]
- self.pub = [node1.getaddressinfo(a)["pubkey"] for a in add]
- self.priv = [node1.dumpprivkey(a) for a in add]
+ for _ in range(self.nkeys):
+ k = ECKey()
+ k.generate()
+ self.pub.append(k.get_pubkey().get_bytes().hex())
+ self.priv.append(bytes_to_wif(k.get_bytes(), k.is_compressed))
self.final = node2.getnewaddress()
def run_test(self):
@@ -64,17 +69,20 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
pk_obj.compressed = False
pk2 = binascii.hexlify(pk_obj.get_bytes()).decode()
+ node0.createwallet(wallet_name='wmulti0', disable_private_keys=True)
+ wmulti0 = node0.get_wallet_rpc('wmulti0')
+
# Check all permutations of keys because order matters apparently
for keys in itertools.permutations([pk0, pk1, pk2]):
# Results should be the same as this legacy one
legacy_addr = node0.createmultisig(2, keys, 'legacy')['address']
- assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'legacy')['address'])
+ assert_equal(legacy_addr, wmulti0.addmultisigaddress(2, keys, '', 'legacy')['address'])
# Generate addresses with the segwit types. These should all make legacy addresses
- assert_equal(legacy_addr, node0.createmultisig(2, keys, 'bech32')['address'])
- assert_equal(legacy_addr, node0.createmultisig(2, keys, 'p2sh-segwit')['address'])
- assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'bech32')['address'])
- assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'p2sh-segwit')['address'])
+ assert_equal(legacy_addr, wmulti0.createmultisig(2, keys, 'bech32')['address'])
+ assert_equal(legacy_addr, wmulti0.createmultisig(2, keys, 'p2sh-segwit')['address'])
+ assert_equal(legacy_addr, wmulti0.addmultisigaddress(2, keys, '', 'bech32')['address'])
+ assert_equal(legacy_addr, wmulti0.addmultisigaddress(2, keys, '', 'p2sh-segwit')['address'])
self.log.info('Testing sortedmulti descriptors with BIP 67 test vectors')
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/rpc_bip67.json'), encoding='utf-8') as f:
@@ -89,6 +97,8 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
assert_equal(self.nodes[0].deriveaddresses(sorted_key_desc)[0], t['address'])
def check_addmultisigaddress_errors(self):
+ if self.options.descriptors:
+ return
self.log.info('Check that addmultisigaddress fails when the private keys are missing')
addresses = [self.nodes[1].getnewaddress(address_type='legacy') for _ in range(2)]
assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses))
@@ -115,6 +125,15 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
def do_multisig(self):
node0, node1, node2 = self.nodes
+ if 'wmulti' not in node1.listwallets():
+ try:
+ node1.loadwallet('wmulti')
+ except JSONRPCException as e:
+ if e.error['code'] == -18 and 'Wallet wmulti not found' in e.error['message']:
+ node1.createwallet(wallet_name='wmulti', disable_private_keys=True)
+ else:
+ raise
+ wmulti = node1.get_wallet_rpc('wmulti')
# Construct the expected descriptor
desc = 'multi({},{})'.format(self.nsigs, ','.join(self.pub))
@@ -134,7 +153,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
assert madd[0:4] == "bcrt" # actually a bech32 address
# compare against addmultisigaddress
- msigw = node1.addmultisigaddress(self.nsigs, self.pub, None, self.output_type)
+ msigw = wmulti.addmultisigaddress(self.nsigs, self.pub, None, self.output_type)
maddw = msigw["address"]
mredeemw = msigw["redeemScript"]
assert_equal(desc, drop_origins(msigw['descriptor']))
@@ -194,6 +213,8 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
txinfo = node0.getrawtransaction(tx, True, blk)
self.log.info("n/m=%d/%d %s size=%d vsize=%d weight=%d" % (self.nsigs, self.nkeys, self.output_type, txinfo["size"], txinfo["vsize"], txinfo["weight"]))
+ wmulti.unloadwallet()
+
if __name__ == '__main__':
RpcCreateMultiSigTest().main()
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index ea8510f92b..51d136d26a 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -48,18 +48,23 @@ class PSBTTest(BitcoinTestFramework):
disconnect_nodes(offline_node, 2)
disconnect_nodes(mining_node, 0)
+ # Create watchonly on online_node
+ online_node.createwallet(wallet_name='wonline', disable_private_keys=True)
+ wonline = online_node.get_wallet_rpc('wonline')
+ w2 = online_node.get_wallet_rpc('')
+
# Mine a transaction that credits the offline address
offline_addr = offline_node.getnewaddress(address_type="p2sh-segwit")
- online_addr = online_node.getnewaddress(address_type="p2sh-segwit")
- online_node.importaddress(offline_addr, "", False)
+ online_addr = w2.getnewaddress(address_type="p2sh-segwit")
+ wonline.importaddress(offline_addr, "", False)
mining_node.sendtoaddress(address=offline_addr, amount=1.0)
mining_node.generate(nblocks=1)
self.sync_blocks([mining_node, online_node])
# Construct an unsigned PSBT on the online node (who doesn't know the output is Segwit, so will include a non-witness UTXO)
- utxos = online_node.listunspent(addresses=[offline_addr])
- raw = online_node.createrawtransaction([{"txid":utxos[0]["txid"], "vout":utxos[0]["vout"]}],[{online_addr:0.9999}])
- psbt = online_node.walletprocesspsbt(online_node.converttopsbt(raw))["psbt"]
+ utxos = wonline.listunspent(addresses=[offline_addr])
+ raw = wonline.createrawtransaction([{"txid":utxos[0]["txid"], "vout":utxos[0]["vout"]}],[{online_addr:0.9999}])
+ psbt = wonline.walletprocesspsbt(online_node.converttopsbt(raw))["psbt"]
assert "non_witness_utxo" in mining_node.decodepsbt(psbt)["inputs"][0]
# Have the offline node sign the PSBT (which will update the UTXO to segwit)
@@ -72,6 +77,8 @@ class PSBTTest(BitcoinTestFramework):
self.sync_blocks([mining_node, online_node])
assert_equal(online_node.gettxout(txid,0)["confirmations"], 1)
+ wonline.unloadwallet()
+
# Reconnect
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[0], 2)
@@ -89,13 +96,23 @@ class PSBTTest(BitcoinTestFramework):
final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex']
self.nodes[0].sendrawtransaction(final_tx)
- # Create p2sh, p2wpkh, and p2wsh addresses
+ # Get pubkeys
pubkey0 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())['pubkey']
pubkey1 = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['pubkey']
pubkey2 = self.nodes[2].getaddressinfo(self.nodes[2].getnewaddress())['pubkey']
- p2sh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "legacy")['address']
- p2wsh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "bech32")['address']
- p2sh_p2wsh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "p2sh-segwit")['address']
+
+ # Setup watchonly wallets
+ self.nodes[2].createwallet(wallet_name='wmulti', disable_private_keys=True)
+ wmulti = self.nodes[2].get_wallet_rpc('wmulti')
+
+ # Create all the addresses
+ p2sh = wmulti.addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "legacy")['address']
+ p2wsh = wmulti.addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "bech32")['address']
+ p2sh_p2wsh = wmulti.addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "p2sh-segwit")['address']
+ if not self.options.descriptors:
+ wmulti.importaddress(p2sh)
+ wmulti.importaddress(p2wsh)
+ wmulti.importaddress(p2sh_p2wsh)
p2wpkh = self.nodes[1].getnewaddress("", "bech32")
p2pkh = self.nodes[1].getnewaddress("", "legacy")
p2sh_p2wpkh = self.nodes[1].getnewaddress("", "p2sh-segwit")
@@ -146,11 +163,14 @@ class PSBTTest(BitcoinTestFramework):
assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[1].walletcreatefundedpsbt, [{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99}, 0, {"feeRate": 10})
# partially sign multisig things with node 1
- psbtx = self.nodes[1].walletcreatefundedpsbt([{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], {self.nodes[1].getnewaddress():29.99})['psbt']
+ psbtx = wmulti.walletcreatefundedpsbt(inputs=[{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], outputs={self.nodes[1].getnewaddress():29.99}, options={'changeAddress': self.nodes[1].getrawchangeaddress()})['psbt']
walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)
psbtx = walletprocesspsbt_out['psbt']
assert_equal(walletprocesspsbt_out['complete'], False)
+ # Unload wmulti, we don't need it anymore
+ wmulti.unloadwallet()
+
# partially sign with node 2. This should be complete and sendable
walletprocesspsbt_out = self.nodes[2].walletprocesspsbt(psbtx)
assert_equal(walletprocesspsbt_out['complete'], True)
@@ -297,7 +317,7 @@ class PSBTTest(BitcoinTestFramework):
# Signer tests
for i, signer in enumerate(signers):
- self.nodes[2].createwallet("wallet{}".format(i))
+ self.nodes[2].createwallet(wallet_name="wallet{}".format(i))
wrpc = self.nodes[2].get_wallet_rpc("wallet{}".format(i))
for key in signer['privkeys']:
wrpc.importprivkey(key)
diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py
index 912c0ca978..f2d6fba4a6 100644
--- a/test/functional/test_framework/key.py
+++ b/test/functional/test_framework/key.py
@@ -8,6 +8,8 @@ keys, and is trivially vulnerable to side channel attacks. Do not use for
anything but tests."""
import random
+from .address import byte_to_base58
+
def modinv(a, n):
"""Compute the modular inverse of a modulo n
@@ -384,3 +386,14 @@ class ECKey():
rb = r.to_bytes((r.bit_length() + 8) // 8, 'big')
sb = s.to_bytes((s.bit_length() + 8) // 8, 'big')
return b'\x30' + bytes([4 + len(rb) + len(sb), 2, len(rb)]) + rb + bytes([2, len(sb)]) + sb
+
+def bytes_to_wif(b, compressed=True):
+ if compressed:
+ b += b'\x01'
+ return byte_to_base58(b, 239)
+
+def generate_wif_key():
+ # Makes a WIF privkey for imports
+ k = ECKey()
+ k.generate()
+ return bytes_to_wif(k.get_bytes(), k.is_compressed)
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index d4cf5f8896..8719bd0d39 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -165,6 +165,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
help="run nodes under the valgrind memory error detector: expect at least a ~10x slowdown, valgrind 3.14 or later required")
parser.add_argument("--randomseed", type=int,
help="set a random seed for deterministically reproducing a previous test run")
+ parser.add_argument("--descriptors", default=False, action="store_true",
+ help="Run test using a descriptor wallet")
self.add_options(parser)
self.options = parser.parse_args()
@@ -333,11 +335,23 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def setup_nodes(self):
"""Override this method to customize test node setup"""
- extra_args = None
+ extra_args = [[]] * self.num_nodes
+ wallets = [[]] * self.num_nodes
if hasattr(self, "extra_args"):
extra_args = self.extra_args
+ wallets = [[x for x in eargs if x.startswith('-wallet=')] for eargs in extra_args]
+ extra_args = [x + ['-nowallet'] for x in extra_args]
self.add_nodes(self.num_nodes, extra_args)
self.start_nodes()
+ for i, n in enumerate(self.nodes):
+ n.extra_args.pop()
+ if '-wallet=0' in n.extra_args or '-nowallet' in n.extra_args or '-disablewallet' in n.extra_args or not self.is_wallet_compiled():
+ continue
+ if '-wallet=' not in wallets[i] and not any([x.startswith('-wallet=') for x in wallets[i]]):
+ wallets[i].append('-wallet=')
+ for w in wallets[i]:
+ wallet_name = w.split('=', 1)[1]
+ n.createwallet(wallet_name=wallet_name, descriptors=self.options.descriptors)
self.import_deterministic_coinbase_privkeys()
if not self.setup_clean_chain:
for n in self.nodes:
@@ -408,6 +422,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
use_cli=self.options.usecli,
start_perf=self.options.perf,
use_valgrind=self.options.valgrind,
+ descriptors=self.options.descriptors,
))
def start_node(self, i, *args, **kwargs):
@@ -547,6 +562,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
bitcoin_cli=self.options.bitcoincli,
coverage_dir=None,
cwd=self.options.tmpdir,
+ descriptors=self.options.descriptors,
))
self.start_node(CACHE_NODE_ID)
cache_node = self.nodes[CACHE_NODE_ID]
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 61214e5553..de724407a0 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -62,7 +62,7 @@ class TestNode():
To make things easier for the test writer, any unrecognised messages will
be dispatched to the RPC connection."""
- def __init__(self, i, datadir, *, chain, rpchost, timewait, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None):
+ def __init__(self, i, datadir, *, chain, rpchost, timewait, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False):
"""
Kwargs:
start_perf (bool): If True, begin profiling the node with `perf` as soon as
@@ -80,6 +80,7 @@ class TestNode():
self.binary = bitcoind
self.coverage_dir = coverage_dir
self.cwd = cwd
+ self.descriptors = descriptors
if extra_conf is not None:
append_config(datadir, extra_conf)
# Most callers will just need to add extra args to the standard list below.
@@ -171,10 +172,10 @@ class TestNode():
def __getattr__(self, name):
"""Dispatches any unrecognised messages to the RPC connection or a CLI instance."""
if self.use_cli:
- return getattr(RPCOverloadWrapper(self.cli, True), name)
+ return getattr(RPCOverloadWrapper(self.cli, True, self.descriptors), name)
else:
assert self.rpc_connected and self.rpc is not None, self._node_msg("Error: no RPC connection")
- return getattr(RPCOverloadWrapper(self.rpc), name)
+ return getattr(RPCOverloadWrapper(self.rpc, descriptors=self.descriptors), name)
def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, **kwargs):
"""Start the node."""
@@ -266,11 +267,11 @@ class TestNode():
def get_wallet_rpc(self, wallet_name):
if self.use_cli:
- return RPCOverloadWrapper(self.cli("-rpcwallet={}".format(wallet_name)), True)
+ return RPCOverloadWrapper(self.cli("-rpcwallet={}".format(wallet_name)), True, self.descriptors)
else:
assert self.rpc_connected and self.rpc, self._node_msg("RPC not connected")
wallet_path = "wallet/{}".format(urllib.parse.quote(wallet_name))
- return RPCOverloadWrapper(self.rpc / wallet_path)
+ return RPCOverloadWrapper(self.rpc / wallet_path, descriptors=self.descriptors)
def stop_node(self, expected_stderr='', wait=0):
"""Stop the node."""
@@ -598,13 +599,28 @@ class TestNodeCLI():
return cli_stdout.rstrip("\n")
class RPCOverloadWrapper():
- def __init__(self, rpc, cli=False):
+ def __init__(self, rpc, cli=False, descriptors=False):
self.rpc = rpc
self.is_cli = cli
+ self.descriptors = descriptors
def __getattr__(self, name):
return getattr(self.rpc, name)
+ def createwallet(self, wallet_name, disable_private_keys=None, blank=None, passphrase=None, avoid_reuse=None, descriptors=None):
+ if self.is_cli:
+ if disable_private_keys is None:
+ disable_private_keys = 'null'
+ if blank is None:
+ blank = 'null'
+ if passphrase is None:
+ passphrase = ''
+ if avoid_reuse is None:
+ avoid_reuse = 'null'
+ if descriptors is None:
+ descriptors = self.descriptors
+ return self.__getattr__('createwallet')(wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors)
+
def importprivkey(self, privkey, label=None, rescan=None):
wallet_info = self.getwalletinfo()
if self.is_cli:
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 1c5afef3a8..b8523e16b7 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -76,6 +76,7 @@ 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 --descriptors',
'wallet_backup.py',
# vv Tests less than 5m vv
'mining_getblocktemplate_longpoll.py',
@@ -86,7 +87,9 @@ BASE_SCRIPTS = [
'feature_segwit.py',
# vv Tests less than 2m vv
'wallet_basic.py',
+ 'wallet_basic.py --descriptors',
'wallet_labels.py',
+ 'wallet_labels.py --descriptors',
'p2p_segwit.py',
'p2p_timeouts.py',
'p2p_tx_download.py',
@@ -109,6 +112,7 @@ BASE_SCRIPTS = [
'feature_abortnode.py',
# vv Tests less than 30s vv
'wallet_keypool_topup.py',
+ 'wallet_keypool_topup.py --descriptors',
'feature_fee_estimation.py',
'interface_zmq.py',
'interface_bitcoin_cli.py',
@@ -122,6 +126,7 @@ BASE_SCRIPTS = [
'interface_rest.py',
'mempool_spend_coinbase.py',
'wallet_avoidreuse.py',
+ 'wallet_avoidreuse.py --descriptors',
'mempool_reorg.py',
'mempool_persist.py',
'wallet_multiwallet.py',
@@ -134,6 +139,7 @@ BASE_SCRIPTS = [
'interface_http.py',
'interface_rpc.py',
'rpc_psbt.py',
+ 'rpc_psbt.py --descriptors',
'rpc_users.py',
'rpc_whitelist.py',
'feature_proxy.py',
@@ -147,6 +153,7 @@ BASE_SCRIPTS = [
'p2p_addr_relay.py',
'rpc_net.py',
'wallet_keypool.py',
+ 'wallet_keypool.py --descriptors',
'wallet_descriptor.py',
'p2p_mempool.py',
'p2p_filter.py',
@@ -169,6 +176,7 @@ BASE_SCRIPTS = [
'mempool_packages.py',
'mempool_package_onemore.py',
'rpc_createmultisig.py',
+ 'rpc_createmultisig.py --descriptors',
'feature_versionbits_warning.py',
'rpc_preciousblock.py',
'wallet_importprunedfunds.py',
@@ -192,6 +200,7 @@ BASE_SCRIPTS = [
'wallet_listsinceblock.py',
'p2p_leak.py',
'wallet_encryption.py',
+ 'wallet_encryption.py --descriptors',
'feature_dersig.py',
'feature_cltv.py',
'rpc_uptime.py',
diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py
index 78a51a1d5f..780cce9d02 100755
--- a/test/functional/wallet_avoidreuse.py
+++ b/test/functional/wallet_avoidreuse.py
@@ -133,7 +133,7 @@ class AvoidReuseTest(BitcoinTestFramework):
tempwallet = ".wallet_avoidreuse.py_test_immutable_wallet.dat"
# Create a wallet with disable_private_keys set; this should work
- self.nodes[1].createwallet(tempwallet, True)
+ self.nodes[1].createwallet(wallet_name=tempwallet, disable_private_keys=True)
w = self.nodes[1].get_wallet_rpc(tempwallet)
# Attempt to unset the disable_private_keys flag; this should not work
@@ -249,43 +249,44 @@ class AvoidReuseTest(BitcoinTestFramework):
# getbalances should show no used, 5 btc trusted
assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})
- # For the second send, we transmute it to a related single-key address
- # to make sure it's also detected as re-use
- fund_spk = self.nodes[0].getaddressinfo(fundaddr)["scriptPubKey"]
- fund_decoded = self.nodes[0].decodescript(fund_spk)
- if second_addr_type == "p2sh-segwit":
- new_fundaddr = fund_decoded["segwit"]["p2sh-segwit"]
- elif second_addr_type == "bech32":
- new_fundaddr = fund_decoded["segwit"]["addresses"][0]
- else:
- new_fundaddr = fundaddr
- assert_equal(second_addr_type, "legacy")
-
- self.nodes[0].sendtoaddress(new_fundaddr, 10)
- self.nodes[0].generate(1)
- self.sync_all()
-
- # listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10)
- assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
- # getbalances should show 10 used, 5 btc trusted
- assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})
-
- # node 1 should now have a balance of 5 (no dirty) or 15 (including dirty)
- assert_approx(self.nodes[1].getbalance(), 5, 0.001)
- assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 15, 0.001)
-
- assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[1].sendtoaddress, retaddr, 10)
-
- self.nodes[1].sendtoaddress(retaddr, 4)
-
- # listunspent should show 2 total outputs (1, 10 btc), one unused (1), one reused (10)
- assert_unspent(self.nodes[1], total_count=2, total_sum=11, reused_count=1, reused_sum=10)
- # getbalances should show 10 used, 1 btc trusted
- assert_balances(self.nodes[1], mine={"used": 10, "trusted": 1})
-
- # node 1 should now have about 1 btc left (no dirty) and 11 (including dirty)
- assert_approx(self.nodes[1].getbalance(), 1, 0.001)
- assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 11, 0.001)
+ if not self.options.descriptors:
+ # For the second send, we transmute it to a related single-key address
+ # to make sure it's also detected as re-use
+ fund_spk = self.nodes[0].getaddressinfo(fundaddr)["scriptPubKey"]
+ fund_decoded = self.nodes[0].decodescript(fund_spk)
+ if second_addr_type == "p2sh-segwit":
+ new_fundaddr = fund_decoded["segwit"]["p2sh-segwit"]
+ elif second_addr_type == "bech32":
+ new_fundaddr = fund_decoded["segwit"]["addresses"][0]
+ else:
+ new_fundaddr = fundaddr
+ assert_equal(second_addr_type, "legacy")
+
+ self.nodes[0].sendtoaddress(new_fundaddr, 10)
+ self.nodes[0].generate(1)
+ self.sync_all()
+
+ # listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10)
+ assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
+ # getbalances should show 10 used, 5 btc trusted
+ assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})
+
+ # node 1 should now have a balance of 5 (no dirty) or 15 (including dirty)
+ assert_approx(self.nodes[1].getbalance(), 5, 0.001)
+ assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 15, 0.001)
+
+ assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[1].sendtoaddress, retaddr, 10)
+
+ self.nodes[1].sendtoaddress(retaddr, 4)
+
+ # listunspent should show 2 total outputs (1, 10 btc), one unused (1), one reused (10)
+ assert_unspent(self.nodes[1], total_count=2, total_sum=11, reused_count=1, reused_sum=10)
+ # getbalances should show 10 used, 1 btc trusted
+ assert_balances(self.nodes[1], mine={"used": 10, "trusted": 1})
+
+ # node 1 should now have about 1 btc left (no dirty) and 11 (including dirty)
+ assert_approx(self.nodes[1].getbalance(), 1, 0.001)
+ assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 11, 0.001)
def test_getbalances_used(self):
'''
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 15746d312c..2dddbf2cf3 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -49,6 +49,7 @@ class WalletTest(BitcoinTestFramework):
return self.nodes[0].decoderawtransaction(txn)['vsize']
def run_test(self):
+
# Check that there's no UTXO on none of the nodes
assert_equal(len(self.nodes[0].listunspent()), 0)
assert_equal(len(self.nodes[1].listunspent()), 0)
@@ -219,7 +220,7 @@ class WalletTest(BitcoinTestFramework):
assert_equal(self.nodes[2].getbalance(), node_2_bal)
node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
- self.start_node(3)
+ self.start_node(3, self.nodes[3].extra_args)
connect_nodes(self.nodes[0], 3)
self.sync_all()
@@ -315,57 +316,59 @@ class WalletTest(BitcoinTestFramework):
# This will raise an exception since generate does not accept a string
assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2")
- # This will raise an exception for the invalid private key format
- assert_raises_rpc_error(-5, "Invalid private key encoding", self.nodes[0].importprivkey, "invalid")
+ if not self.options.descriptors:
- # This will raise an exception for importing an address with the PS2H flag
- temp_address = self.nodes[1].getnewaddress("", "p2sh-segwit")
- assert_raises_rpc_error(-5, "Cannot use the p2sh flag with an address - use a script instead", self.nodes[0].importaddress, temp_address, "label", False, True)
+ # This will raise an exception for the invalid private key format
+ assert_raises_rpc_error(-5, "Invalid private key encoding", self.nodes[0].importprivkey, "invalid")
- # This will raise an exception for attempting to dump the private key of an address you do not own
- assert_raises_rpc_error(-3, "Address does not refer to a key", self.nodes[0].dumpprivkey, temp_address)
+ # This will raise an exception for importing an address with the PS2H flag
+ temp_address = self.nodes[1].getnewaddress("", "p2sh-segwit")
+ assert_raises_rpc_error(-5, "Cannot use the p2sh flag with an address - use a script instead", self.nodes[0].importaddress, temp_address, "label", False, True)
- # This will raise an exception for attempting to get the private key of an invalid Bitcoin address
- assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].dumpprivkey, "invalid")
+ # This will raise an exception for attempting to dump the private key of an address you do not own
+ assert_raises_rpc_error(-3, "Address does not refer to a key", self.nodes[0].dumpprivkey, temp_address)
- # This will raise an exception for attempting to set a label for an invalid Bitcoin address
- assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].setlabel, "invalid address", "label")
+ # This will raise an exception for attempting to get the private key of an invalid Bitcoin address
+ assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].dumpprivkey, "invalid")
- # This will raise an exception for importing an invalid address
- assert_raises_rpc_error(-5, "Invalid Bitcoin address or script", self.nodes[0].importaddress, "invalid")
+ # This will raise an exception for attempting to set a label for an invalid Bitcoin address
+ assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].setlabel, "invalid address", "label")
- # This will raise an exception for attempting to import a pubkey that isn't in hex
- assert_raises_rpc_error(-5, "Pubkey must be a hex string", self.nodes[0].importpubkey, "not hex")
+ # This will raise an exception for importing an invalid address
+ assert_raises_rpc_error(-5, "Invalid Bitcoin address or script", self.nodes[0].importaddress, "invalid")
- # This will raise an exception for importing an invalid pubkey
- assert_raises_rpc_error(-5, "Pubkey is not a valid public key", self.nodes[0].importpubkey, "5361746f736869204e616b616d6f746f")
+ # This will raise an exception for attempting to import a pubkey that isn't in hex
+ assert_raises_rpc_error(-5, "Pubkey must be a hex string", self.nodes[0].importpubkey, "not hex")
- # Import address and private key to check correct behavior of spendable unspents
- # 1. Send some coins to generate new UTXO
- address_to_import = self.nodes[2].getnewaddress()
- txid = self.nodes[0].sendtoaddress(address_to_import, 1)
- self.nodes[0].generate(1)
- self.sync_all(self.nodes[0:3])
+ # This will raise an exception for importing an invalid pubkey
+ assert_raises_rpc_error(-5, "Pubkey is not a valid public key", self.nodes[0].importpubkey, "5361746f736869204e616b616d6f746f")
+
+ # Import address and private key to check correct behavior of spendable unspents
+ # 1. Send some coins to generate new UTXO
+ address_to_import = self.nodes[2].getnewaddress()
+ txid = self.nodes[0].sendtoaddress(address_to_import, 1)
+ self.nodes[0].generate(1)
+ self.sync_all(self.nodes[0:3])
- # 2. Import address from node2 to node1
- self.nodes[1].importaddress(address_to_import)
+ # 2. Import address from node2 to node1
+ self.nodes[1].importaddress(address_to_import)
- # 3. Validate that the imported address is watch-only on node1
- assert self.nodes[1].getaddressinfo(address_to_import)["iswatchonly"]
+ # 3. Validate that the imported address is watch-only on node1
+ assert self.nodes[1].getaddressinfo(address_to_import)["iswatchonly"]
- # 4. Check that the unspents after import are not spendable
- assert_array_result(self.nodes[1].listunspent(),
- {"address": address_to_import},
- {"spendable": False})
+ # 4. Check that the unspents after import are not spendable
+ assert_array_result(self.nodes[1].listunspent(),
+ {"address": address_to_import},
+ {"spendable": False})
- # 5. Import private key of the previously imported address on node1
- priv_key = self.nodes[2].dumpprivkey(address_to_import)
- self.nodes[1].importprivkey(priv_key)
+ # 5. Import private key of the previously imported address on node1
+ priv_key = self.nodes[2].dumpprivkey(address_to_import)
+ self.nodes[1].importprivkey(priv_key)
- # 6. Check that the unspents are now spendable on node1
- assert_array_result(self.nodes[1].listunspent(),
- {"address": address_to_import},
- {"spendable": True})
+ # 6. Check that the unspents are now spendable on node1
+ assert_array_result(self.nodes[1].listunspent(),
+ {"address": address_to_import},
+ {"spendable": True})
# Mine a block from node0 to an address from node1
coinbase_addr = self.nodes[1].getnewaddress()
@@ -460,7 +463,8 @@ class WalletTest(BitcoinTestFramework):
# Try with walletrejectlongchains
# Double chain limit but require combining inputs, so we pass SelectCoinsMinConf
self.stop_node(0)
- self.start_node(0, extra_args=["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)])
+ extra_args = ["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)]
+ self.start_node(0, extra_args=extra_args)
# wait for loadmempool
timeout = 10
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index e4328f2b0e..09f89eb59d 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -27,17 +27,21 @@ class WalletHDTest(BitcoinTestFramework):
def run_test(self):
# Make sure we use hd, keep masterkeyid
- masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']
- assert_equal(len(masterkeyid), 40)
+ hd_fingerprint = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['hdmasterfingerprint']
+ assert_equal(len(hd_fingerprint), 8)
# create an internal key
change_addr = self.nodes[1].getrawchangeaddress()
change_addrV= self.nodes[1].getaddressinfo(change_addr)
- assert_equal(change_addrV["hdkeypath"], "m/0'/1'/0'") #first internal child key
+ if self.options.descriptors:
+ assert_equal(change_addrV["hdkeypath"], "m/84'/1'/0'/1/0")
+ else:
+ assert_equal(change_addrV["hdkeypath"], "m/0'/1'/0'") #first internal child key
# Import a non-HD private key in the HD wallet
- non_hd_add = self.nodes[0].getnewaddress()
- self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))
+ non_hd_add = 'bcrt1qmevj8zfx0wdvp05cqwkmr6mxkfx60yezwjksmt'
+ non_hd_key = 'cS9umN9w6cDMuRVYdbkfE4c7YUFLJRoXMfhQ569uY4odiQbVN8Rt'
+ self.nodes[1].importprivkey(non_hd_key)
# This should be enough to keep the master key and the non-HD key
self.nodes[1].backupwallet(os.path.join(self.nodes[1].datadir, "hd.bak"))
@@ -48,11 +52,14 @@ class WalletHDTest(BitcoinTestFramework):
self.nodes[0].generate(101)
hd_add = None
NUM_HD_ADDS = 10
- for i in range(NUM_HD_ADDS):
+ for i in range(1, NUM_HD_ADDS + 1):
hd_add = self.nodes[1].getnewaddress()
hd_info = self.nodes[1].getaddressinfo(hd_add)
- assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i)+"'")
- assert_equal(hd_info["hdseedid"], masterkeyid)
+ if self.options.descriptors:
+ assert_equal(hd_info["hdkeypath"], "m/84'/1'/0'/0/" + str(i))
+ else:
+ assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i)+"'")
+ assert_equal(hd_info["hdmasterfingerprint"], hd_fingerprint)
self.nodes[0].sendtoaddress(hd_add, 1)
self.nodes[0].generate(1)
self.nodes[0].sendtoaddress(non_hd_add, 1)
@@ -61,7 +68,10 @@ class WalletHDTest(BitcoinTestFramework):
# create an internal key (again)
change_addr = self.nodes[1].getrawchangeaddress()
change_addrV= self.nodes[1].getaddressinfo(change_addr)
- assert_equal(change_addrV["hdkeypath"], "m/0'/1'/1'") #second internal child key
+ if self.options.descriptors:
+ assert_equal(change_addrV["hdkeypath"], "m/84'/1'/0'/1/1")
+ else:
+ assert_equal(change_addrV["hdkeypath"], "m/0'/1'/1'") #second internal child key
self.sync_all()
assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1)
@@ -72,16 +82,19 @@ class WalletHDTest(BitcoinTestFramework):
# otherwise node1 would auto-recover all funds in flag the keypool keys as used
shutil.rmtree(os.path.join(self.nodes[1].datadir, self.chain, "blocks"))
shutil.rmtree(os.path.join(self.nodes[1].datadir, self.chain, "chainstate"))
- shutil.copyfile(os.path.join(self.nodes[1].datadir, "hd.bak"), os.path.join(self.nodes[1].datadir, self.chain, "wallets", "wallet.dat"))
+ shutil.copyfile(os.path.join(self.nodes[1].datadir, "hd.bak"), os.path.join(self.nodes[1].datadir, self.chain, 'wallets', "wallet.dat"))
self.start_node(1)
# Assert that derivation is deterministic
hd_add_2 = None
- for i in range(NUM_HD_ADDS):
+ for i in range(1, NUM_HD_ADDS + 1):
hd_add_2 = self.nodes[1].getnewaddress()
hd_info_2 = self.nodes[1].getaddressinfo(hd_add_2)
- assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(i)+"'")
- assert_equal(hd_info_2["hdseedid"], masterkeyid)
+ if self.options.descriptors:
+ assert_equal(hd_info_2["hdkeypath"], "m/84'/1'/0'/0/" + str(i))
+ else:
+ assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(i)+"'")
+ assert_equal(hd_info_2["hdmasterfingerprint"], hd_fingerprint)
assert_equal(hd_add, hd_add_2)
connect_nodes(self.nodes[0], 1)
self.sync_all()
@@ -117,41 +130,45 @@ class WalletHDTest(BitcoinTestFramework):
if out['value'] != 1:
keypath = self.nodes[1].getaddressinfo(out['scriptPubKey']['addresses'][0])['hdkeypath']
- assert_equal(keypath[0:7], "m/0'/1'")
-
- # Generate a new HD seed on node 1 and make sure it is set
- orig_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']
- self.nodes[1].sethdseed()
- new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']
- assert orig_masterkeyid != new_masterkeyid
- addr = self.nodes[1].getnewaddress()
- assert_equal(self.nodes[1].getaddressinfo(addr)['hdkeypath'], 'm/0\'/0\'/0\'') # Make sure the new address is the first from the keypool
- self.nodes[1].keypoolrefill(1) # Fill keypool with 1 key
-
- # Set a new HD seed on node 1 without flushing the keypool
- new_seed = self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress())
- orig_masterkeyid = new_masterkeyid
- self.nodes[1].sethdseed(False, new_seed)
- new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']
- assert orig_masterkeyid != new_masterkeyid
- addr = self.nodes[1].getnewaddress()
- assert_equal(orig_masterkeyid, self.nodes[1].getaddressinfo(addr)['hdseedid'])
- assert_equal(self.nodes[1].getaddressinfo(addr)['hdkeypath'], 'm/0\'/0\'/1\'') # Make sure the new address continues previous keypool
-
- # Check that the next address is from the new seed
- self.nodes[1].keypoolrefill(1)
- next_addr = self.nodes[1].getnewaddress()
- assert_equal(new_masterkeyid, self.nodes[1].getaddressinfo(next_addr)['hdseedid'])
- assert_equal(self.nodes[1].getaddressinfo(next_addr)['hdkeypath'], 'm/0\'/0\'/0\'') # Make sure the new address is not from previous keypool
- assert next_addr != addr
-
- # Sethdseed parameter validity
- assert_raises_rpc_error(-1, 'sethdseed', self.nodes[0].sethdseed, False, new_seed, 0)
- assert_raises_rpc_error(-5, "Invalid private key", self.nodes[1].sethdseed, False, "not_wif")
- assert_raises_rpc_error(-1, "JSON value is not a boolean as expected", self.nodes[1].sethdseed, "Not_bool")
- assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[1].sethdseed, False, True)
- assert_raises_rpc_error(-5, "Already have this key", self.nodes[1].sethdseed, False, new_seed)
- assert_raises_rpc_error(-5, "Already have this key", self.nodes[1].sethdseed, False, self.nodes[1].dumpprivkey(self.nodes[1].getnewaddress()))
+ if self.options.descriptors:
+ assert_equal(keypath[0:14], "m/84'/1'/0'/1/")
+ else:
+ assert_equal(keypath[0:7], "m/0'/1'")
+
+ if not self.options.descriptors:
+ # Generate a new HD seed on node 1 and make sure it is set
+ orig_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']
+ self.nodes[1].sethdseed()
+ new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']
+ assert orig_masterkeyid != new_masterkeyid
+ addr = self.nodes[1].getnewaddress()
+ assert_equal(self.nodes[1].getaddressinfo(addr)['hdkeypath'], 'm/0\'/0\'/0\'') # Make sure the new address is the first from the keypool
+ self.nodes[1].keypoolrefill(1) # Fill keypool with 1 key
+
+ # Set a new HD seed on node 1 without flushing the keypool
+ new_seed = self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress())
+ orig_masterkeyid = new_masterkeyid
+ self.nodes[1].sethdseed(False, new_seed)
+ new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']
+ assert orig_masterkeyid != new_masterkeyid
+ addr = self.nodes[1].getnewaddress()
+ assert_equal(orig_masterkeyid, self.nodes[1].getaddressinfo(addr)['hdseedid'])
+ assert_equal(self.nodes[1].getaddressinfo(addr)['hdkeypath'], 'm/0\'/0\'/1\'') # Make sure the new address continues previous keypool
+
+ # Check that the next address is from the new seed
+ self.nodes[1].keypoolrefill(1)
+ next_addr = self.nodes[1].getnewaddress()
+ assert_equal(new_masterkeyid, self.nodes[1].getaddressinfo(next_addr)['hdseedid'])
+ assert_equal(self.nodes[1].getaddressinfo(next_addr)['hdkeypath'], 'm/0\'/0\'/0\'') # Make sure the new address is not from previous keypool
+ assert next_addr != addr
+
+ # Sethdseed parameter validity
+ assert_raises_rpc_error(-1, 'sethdseed', self.nodes[0].sethdseed, False, new_seed, 0)
+ assert_raises_rpc_error(-5, "Invalid private key", self.nodes[1].sethdseed, False, "not_wif")
+ assert_raises_rpc_error(-1, "JSON value is not a boolean as expected", self.nodes[1].sethdseed, "Not_bool")
+ assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[1].sethdseed, False, True)
+ assert_raises_rpc_error(-5, "Already have this key", self.nodes[1].sethdseed, False, new_seed)
+ assert_raises_rpc_error(-5, "Already have this key", self.nodes[1].sethdseed, False, self.nodes[1].dumpprivkey(self.nodes[1].getnewaddress()))
if __name__ == '__main__':
WalletHDTest().main ()
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index 9e2f00e62f..40a2b3ab6a 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -22,16 +22,63 @@ class KeyPoolTest(BitcoinTestFramework):
addr_before_encrypting = nodes[0].getnewaddress()
addr_before_encrypting_data = nodes[0].getaddressinfo(addr_before_encrypting)
wallet_info_old = nodes[0].getwalletinfo()
- assert addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid']
+ if not self.options.descriptors:
+ assert addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid']
# Encrypt wallet and wait to terminate
nodes[0].encryptwallet('test')
+ if self.options.descriptors:
+ # Import hardened derivation only descriptors
+ nodes[0].walletpassphrase('test', 10)
+ nodes[0].importdescriptors([
+ {
+ "desc": "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/*h)#y4dfsj7n",
+ "timestamp": "now",
+ "range": [0,0],
+ "active": True
+ },
+ {
+ "desc": "pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1h/*h)#a0nyvl0k",
+ "timestamp": "now",
+ "range": [0,0],
+ "active": True
+ },
+ {
+ "desc": "sh(wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/2h/*h))#lmeu2axg",
+ "timestamp": "now",
+ "range": [0,0],
+ "active": True
+ },
+ {
+ "desc": "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/3h/*h)#jkl636gm",
+ "timestamp": "now",
+ "range": [0,0],
+ "active": True,
+ "internal": True
+ },
+ {
+ "desc": "pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/4h/*h)#l3crwaus",
+ "timestamp": "now",
+ "range": [0,0],
+ "active": True,
+ "internal": True
+ },
+ {
+ "desc": "sh(wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/5h/*h))#qg8wa75f",
+ "timestamp": "now",
+ "range": [0,0],
+ "active": True,
+ "internal": True
+ }
+ ])
+ nodes[0].walletlock()
# Keep creating keys
addr = nodes[0].getnewaddress()
addr_data = nodes[0].getaddressinfo(addr)
wallet_info = nodes[0].getwalletinfo()
- assert addr_before_encrypting_data['hdseedid'] != wallet_info['hdseedid']
- assert addr_data['hdseedid'] == wallet_info['hdseedid']
+ assert addr_before_encrypting_data['hdmasterfingerprint'] != addr_data['hdmasterfingerprint']
+ if not self.options.descriptors:
+ assert addr_data['hdseedid'] == wallet_info['hdseedid']
assert_raises_rpc_error(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)
# put six (plus 2) new keys in the keypool (100% external-, +100% internal-keys, 1 in min)
@@ -39,8 +86,12 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].keypoolrefill(6)
nodes[0].walletlock()
wi = nodes[0].getwalletinfo()
- assert_equal(wi['keypoolsize_hd_internal'], 6)
- assert_equal(wi['keypoolsize'], 6)
+ if self.options.descriptors:
+ assert_equal(wi['keypoolsize_hd_internal'], 18)
+ assert_equal(wi['keypoolsize'], 18)
+ else:
+ assert_equal(wi['keypoolsize_hd_internal'], 6)
+ assert_equal(wi['keypoolsize'], 6)
# drain the internal keys
nodes[0].getrawchangeaddress()
@@ -80,11 +131,15 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].walletpassphrase('test', 100)
nodes[0].keypoolrefill(100)
wi = nodes[0].getwalletinfo()
- assert_equal(wi['keypoolsize_hd_internal'], 100)
- assert_equal(wi['keypoolsize'], 100)
+ if self.options.descriptors:
+ assert_equal(wi['keypoolsize_hd_internal'], 300)
+ assert_equal(wi['keypoolsize'], 300)
+ else:
+ assert_equal(wi['keypoolsize_hd_internal'], 100)
+ assert_equal(wi['keypoolsize'], 100)
# create a blank wallet
- nodes[0].createwallet(wallet_name='w2', blank=True)
+ nodes[0].createwallet(wallet_name='w2', blank=True, disable_private_keys=True)
w2 = nodes[0].get_wallet_rpc('w2')
# refer to initial wallet as w1
@@ -92,8 +147,11 @@ class KeyPoolTest(BitcoinTestFramework):
# import private key and fund it
address = addr.pop()
- privkey = w1.dumpprivkey(address)
- res = w2.importmulti([{'scriptPubKey': {'address': address}, 'keys': [privkey], 'timestamp': 'now'}])
+ desc = w1.getaddressinfo(address)['desc']
+ if self.options.descriptors:
+ res = w2.importdescriptors([{'desc': desc, 'timestamp': 'now'}])
+ else:
+ res = w2.importmulti([{'desc': desc, 'timestamp': 'now'}])
assert_equal(res[0]['success'], True)
w1.walletpassphrase('test', 100)
diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py
index 829633a050..102ed23fba 100755
--- a/test/functional/wallet_keypool_topup.py
+++ b/test/functional/wallet_keypool_topup.py
@@ -79,7 +79,15 @@ class KeypoolRestoreTest(BitcoinTestFramework):
assert_equal(self.nodes[idx].getbalance(), 15)
assert_equal(self.nodes[idx].listtransactions()[0]['category'], "receive")
# Check that we have marked all keys up to the used keypool key as used
- assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress())['hdkeypath'], "m/0'/0'/110'")
+ if self.options.descriptors:
+ if output_type == 'legacy':
+ assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/44'/1'/0'/0/110")
+ elif output_type == 'p2sh-segwit':
+ assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/49'/1'/0'/0/110")
+ elif output_type == 'bech32':
+ assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/84'/1'/0'/0/110")
+ else:
+ assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/0'/0'/110'")
if __name__ == '__main__':
diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py
index 337d2e55d9..f8d1720469 100755
--- a/test/functional/wallet_labels.py
+++ b/test/functional/wallet_labels.py
@@ -115,15 +115,16 @@ class WalletLabelsTest(BitcoinTestFramework):
assert_raises_rpc_error(-11, "No addresses with label", node.getaddressesbylabel, "")
# Check that addmultisigaddress can assign labels.
- for label in labels:
- addresses = []
- for x in range(10):
- addresses.append(node.getnewaddress())
- multisig_address = node.addmultisigaddress(5, addresses, label.name)['address']
- label.add_address(multisig_address)
- label.purpose[multisig_address] = "send"
- label.verify(node)
- node.generate(101)
+ if not self.options.descriptors:
+ for label in labels:
+ addresses = []
+ for x in range(10):
+ addresses.append(node.getnewaddress())
+ multisig_address = node.addmultisigaddress(5, addresses, label.name)['address']
+ label.add_address(multisig_address)
+ label.purpose[multisig_address] = "send"
+ label.verify(node)
+ node.generate(101)
# Check that setlabel can change the label of an address from a
# different label.