Skip to content

Commit 1346e14

Browse files
committed
Functional tests for descriptor wallets
1 parent f193ea8 commit 1346e14

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
'p2p_addr_relay.py',
148148
'rpc_net.py',
149149
'wallet_keypool.py',
150+
'wallet_descriptor.py',
150151
'p2p_mempool.py',
151152
'p2p_filter.py',
152153
'rpc_setban.py',

test/functional/wallet_descriptor.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2019 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Test descriptor wallet function."""
6+
7+
from test_framework.test_framework import BitcoinTestFramework
8+
from test_framework.util import (
9+
assert_equal,
10+
assert_raises_rpc_error
11+
)
12+
13+
14+
class WalletDescriptorTest(BitcoinTestFramework):
15+
def set_test_params(self):
16+
self.setup_clean_chain = True
17+
self.num_nodes = 1
18+
self.extra_args = [['-keypool=100']]
19+
20+
def skip_test_if_missing_module(self):
21+
self.skip_if_no_wallet()
22+
23+
def run_test(self):
24+
# Make a descriptor wallet
25+
self.log.info("Making a descriptor wallet")
26+
self.nodes[0].createwallet(wallet_name="desc1", descriptors=True)
27+
self.nodes[0].unloadwallet("")
28+
29+
# A descriptor wallet should have 100 addresses * 3 types = 300 keys
30+
self.log.info("Checking wallet info")
31+
wallet_info = self.nodes[0].getwalletinfo()
32+
assert_equal(wallet_info['keypoolsize'], 300)
33+
assert_equal(wallet_info['keypoolsize_hd_internal'], 300)
34+
assert 'keypoololdest' not in wallet_info
35+
36+
# Check that getnewaddress works
37+
self.log.info("Test that getnewaddress and getrawchangeaddress work")
38+
addr = self.nodes[0].getnewaddress("", "legacy")
39+
addr_info = self.nodes[0].getaddressinfo(addr)
40+
assert addr_info['desc'].startswith('pkh(')
41+
assert_equal(addr_info['hdkeypath'], 'm/44\'/1\'/0\'/0/0')
42+
43+
addr = self.nodes[0].getnewaddress("", "p2sh-segwit")
44+
addr_info = self.nodes[0].getaddressinfo(addr)
45+
assert addr_info['desc'].startswith('sh(wpkh(')
46+
assert_equal(addr_info['hdkeypath'], 'm/49\'/1\'/0\'/0/0')
47+
48+
addr = self.nodes[0].getnewaddress("", "bech32")
49+
addr_info = self.nodes[0].getaddressinfo(addr)
50+
assert addr_info['desc'].startswith('wpkh(')
51+
assert_equal(addr_info['hdkeypath'], 'm/84\'/1\'/0\'/0/0')
52+
53+
# Check that getrawchangeaddress works
54+
addr = self.nodes[0].getrawchangeaddress("legacy")
55+
addr_info = self.nodes[0].getaddressinfo(addr)
56+
assert addr_info['desc'].startswith('pkh(')
57+
assert_equal(addr_info['hdkeypath'], 'm/44\'/1\'/0\'/1/0')
58+
59+
addr = self.nodes[0].getrawchangeaddress("p2sh-segwit")
60+
addr_info = self.nodes[0].getaddressinfo(addr)
61+
assert addr_info['desc'].startswith('sh(wpkh(')
62+
assert_equal(addr_info['hdkeypath'], 'm/49\'/1\'/0\'/1/0')
63+
64+
addr = self.nodes[0].getrawchangeaddress("bech32")
65+
addr_info = self.nodes[0].getaddressinfo(addr)
66+
assert addr_info['desc'].startswith('wpkh(')
67+
assert_equal(addr_info['hdkeypath'], 'm/84\'/1\'/0\'/1/0')
68+
69+
# Make a wallet to receive coins at
70+
self.nodes[0].createwallet(wallet_name="desc2", descriptors=True)
71+
recv_wrpc = self.nodes[0].get_wallet_rpc("desc2")
72+
send_wrpc = self.nodes[0].get_wallet_rpc("desc1")
73+
74+
# Generate some coins
75+
send_wrpc.generatetoaddress(101, send_wrpc.getnewaddress())
76+
77+
# Make transactions
78+
self.log.info("Test sending and receiving")
79+
addr = recv_wrpc.getnewaddress()
80+
send_wrpc.sendtoaddress(addr, 10)
81+
82+
# Make sure things are disabled
83+
self.log.info("Test disabled RPCs")
84+
assert_raises_rpc_error(-4, "This type of wallet does not support this command", recv_wrpc.importprivkey, "cVpF924EspNh8KjYsfhgY96mmxvT6DgdWiTYMtMjuM74hJaU5psW")
85+
assert_raises_rpc_error(-4, "This type of wallet does not support this command", recv_wrpc.importpubkey, send_wrpc.getaddressinfo(send_wrpc.getnewaddress()))
86+
assert_raises_rpc_error(-4, "This type of wallet does not support this command", recv_wrpc.importaddress, recv_wrpc.getnewaddress())
87+
assert_raises_rpc_error(-4, "This type of wallet does not support this command", recv_wrpc.importmulti, [])
88+
assert_raises_rpc_error(-4, "This type of wallet does not support this command", recv_wrpc.addmultisigaddress, 1, [recv_wrpc.getnewaddress()])
89+
assert_raises_rpc_error(-4, "This type of wallet does not support this command", recv_wrpc.dumpprivkey, recv_wrpc.getnewaddress())
90+
assert_raises_rpc_error(-4, "This type of wallet does not support this command", recv_wrpc.dumpwallet, 'wallet.dump')
91+
assert_raises_rpc_error(-4, "This type of wallet does not support this command", recv_wrpc.importwallet, 'wallet.dump')
92+
assert_raises_rpc_error(-4, "This type of wallet does not support this command", recv_wrpc.sethdseed)
93+
94+
self.log.info("Test encryption")
95+
# Get the master fingerprint before encrypt
96+
info1 = send_wrpc.getaddressinfo(send_wrpc.getnewaddress())
97+
98+
# Encrypt wallet 0
99+
send_wrpc.encryptwallet('pass')
100+
send_wrpc.walletpassphrase('pass', 10)
101+
addr = send_wrpc.getnewaddress()
102+
info2 = send_wrpc.getaddressinfo(addr)
103+
assert info1['hdmasterfingerprint'] != info2['hdmasterfingerprint']
104+
send_wrpc.walletlock()
105+
assert 'hdmasterfingerprint' in send_wrpc.getaddressinfo(send_wrpc.getnewaddress())
106+
info3 = send_wrpc.getaddressinfo(addr)
107+
assert_equal(info2['desc'], info3['desc'])
108+
109+
self.log.info("Test that getnewaddress still works after keypool is exhausted in an encrypted wallet")
110+
for i in range(0, 500):
111+
send_wrpc.getnewaddress()
112+
113+
self.log.info("Test that unlock is needed when deriving only hardened keys in an encrypted wallet")
114+
send_wrpc.walletpassphrase('pass', 10)
115+
send_wrpc.importdescriptors([{
116+
"desc": "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/*h)#y4dfsj7n",
117+
"timestamp": "now",
118+
"range": [0,10],
119+
"active": True
120+
}])
121+
send_wrpc.walletlock()
122+
# Exhaust keypool of 100
123+
for i in range(0, 100):
124+
send_wrpc.getnewaddress(address_type='bech32')
125+
# This should now error
126+
assert_raises_rpc_error(-12, "Keypool ran out, please call keypoolrefill first", send_wrpc.getnewaddress, '', 'bech32')
127+
128+
self.log.info("Test born encrypted wallets")
129+
self.nodes[0].createwallet('desc_enc', False, False, 'pass', False, True)
130+
enc_rpc = self.nodes[0].get_wallet_rpc('desc_enc')
131+
enc_rpc.getnewaddress() # Makes sure that we can get a new address from a born encrypted wallet
132+
133+
self.log.info("Test blank descriptor wallets")
134+
self.nodes[0].createwallet(wallet_name='desc_blank', blank=True, descriptors=True)
135+
blank_rpc = self.nodes[0].get_wallet_rpc('desc_blank')
136+
assert_raises_rpc_error(-4, 'This wallet has no available keys', blank_rpc.getnewaddress)
137+
138+
self.log.info("Test descriptor wallet with disabled private keys")
139+
self.nodes[0].createwallet(wallet_name='desc_no_priv', disable_private_keys=True, descriptors=True)
140+
nopriv_rpc = self.nodes[0].get_wallet_rpc('desc_no_priv')
141+
assert_raises_rpc_error(-4, 'This wallet has no available keys', nopriv_rpc.getnewaddress)
142+
143+
if __name__ == '__main__':
144+
WalletDescriptorTest().main ()

0 commit comments

Comments
 (0)