99except ImportError :
1010 pass
1111
12+ import re
13+
1214from test_framework .blocktools import COINBASE_MATURITY
1315from test_framework .test_framework import BitcoinTestFramework
1416from test_framework .util import (
@@ -24,65 +26,115 @@ def set_test_params(self):
2426 self .setup_clean_chain = True
2527 self .num_nodes = 1
2628 self .extra_args = [['-keypool=100' ]]
27- self .wallet_names = []
2829
2930 def skip_test_if_missing_module (self ):
3031 self .skip_if_no_wallet ()
3132 self .skip_if_no_py_sqlite3 ()
3233
34+ def test_parent_descriptors (self ):
35+ self .log .info ("Check that parent_descs is the same for all RPCs and is normalized" )
36+ self .nodes [0 ].createwallet (wallet_name = "parent_descs" )
37+ wallet = self .nodes [0 ].get_wallet_rpc ("parent_descs" )
38+ default_wallet = self .nodes [0 ].get_wallet_rpc (self .default_wallet_name )
39+
40+ addr = wallet .getnewaddress ()
41+ parent_desc = wallet .getaddressinfo (addr )["parent_desc" ]
42+
43+ # Verify that the parent descriptor is normalized
44+ # First remove the checksum
45+ desc_verify = parent_desc .split ("#" )[0 ]
46+ # Next extract the xpub
47+ desc_verify = re .sub (r"tpub\w+?(?=/)" , "" , desc_verify )
48+ # Extract origin info
49+ origin_match = re .search (r'\[([\da-fh/]+)\]' , desc_verify )
50+ origin_part = origin_match .group (1 ) if origin_match else ""
51+ # Split on "]" for everything after the origin info
52+ after_origin = desc_verify .split ("]" , maxsplit = 1 )[- 1 ]
53+ # Look for the hardened markers “h” inside each piece
54+ # We don't need to check for aspostrophe as normalization will not output aspostrophe
55+ found_hardened_in_origin = "h" in origin_part
56+ found_hardened_after_origin = "h" in after_origin
57+ assert_equal (found_hardened_in_origin , True )
58+ assert_equal (found_hardened_after_origin , False )
59+
60+ # Send some coins so we can check listunspent, listtransactions, listunspent, and gettransaction
61+ since_block = self .nodes [0 ].getbestblockhash ()
62+ txid = default_wallet .sendtoaddress (addr , 1 )
63+ self .generate (self .nodes [0 ], 1 )
64+
65+ unspent = wallet .listunspent ()
66+ assert_equal (len (unspent ), 1 )
67+ assert_equal (unspent [0 ]["parent_descs" ], [parent_desc ])
68+
69+ txs = wallet .listtransactions ()
70+ assert_equal (len (txs ), 1 )
71+ assert_equal (txs [0 ]["parent_descs" ], [parent_desc ])
72+
73+ txs = wallet .listsinceblock (since_block )["transactions" ]
74+ assert_equal (len (txs ), 1 )
75+ assert_equal (txs [0 ]["parent_descs" ], [parent_desc ])
76+
77+ tx = wallet .gettransaction (txid = txid , verbose = True )
78+ assert_equal (tx ["details" ][0 ]["parent_descs" ], [parent_desc ])
79+
80+ wallet .unloadwallet ()
81+
3382 def run_test (self ):
83+ self .generate (self .nodes [0 ], COINBASE_MATURITY + 1 )
84+
3485 # Make a descriptor wallet
3586 self .log .info ("Making a descriptor wallet" )
3687 self .nodes [0 ].createwallet (wallet_name = "desc1" )
88+ wallet = self .nodes [0 ].get_wallet_rpc ("desc1" )
3789
3890 # A descriptor wallet should have 100 addresses * 4 types = 400 keys
3991 self .log .info ("Checking wallet info" )
40- wallet_info = self . nodes [ 0 ] .getwalletinfo ()
92+ wallet_info = wallet .getwalletinfo ()
4193 assert_equal (wallet_info ['format' ], 'sqlite' )
4294 assert_equal (wallet_info ['keypoolsize' ], 400 )
4395 assert_equal (wallet_info ['keypoolsize_hd_internal' ], 400 )
4496 assert 'keypoololdest' not in wallet_info
4597
4698 # Check that getnewaddress works
4799 self .log .info ("Test that getnewaddress and getrawchangeaddress work" )
48- addr = self . nodes [ 0 ] .getnewaddress ("" , "legacy" )
49- addr_info = self . nodes [ 0 ] .getaddressinfo (addr )
100+ addr = wallet .getnewaddress ("" , "legacy" )
101+ addr_info = wallet .getaddressinfo (addr )
50102 assert addr_info ['desc' ].startswith ('pkh(' )
51103 assert_equal (addr_info ['hdkeypath' ], 'm/44h/1h/0h/0/0' )
52104
53- addr = self . nodes [ 0 ] .getnewaddress ("" , "p2sh-segwit" )
54- addr_info = self . nodes [ 0 ] .getaddressinfo (addr )
105+ addr = wallet .getnewaddress ("" , "p2sh-segwit" )
106+ addr_info = wallet .getaddressinfo (addr )
55107 assert addr_info ['desc' ].startswith ('sh(wpkh(' )
56108 assert_equal (addr_info ['hdkeypath' ], 'm/49h/1h/0h/0/0' )
57109
58- addr = self . nodes [ 0 ] .getnewaddress ("" , "bech32" )
59- addr_info = self . nodes [ 0 ] .getaddressinfo (addr )
110+ addr = wallet .getnewaddress ("" , "bech32" )
111+ addr_info = wallet .getaddressinfo (addr )
60112 assert addr_info ['desc' ].startswith ('wpkh(' )
61113 assert_equal (addr_info ['hdkeypath' ], 'm/84h/1h/0h/0/0' )
62114
63- addr = self . nodes [ 0 ] .getnewaddress ("" , "bech32m" )
64- addr_info = self . nodes [ 0 ] .getaddressinfo (addr )
115+ addr = wallet .getnewaddress ("" , "bech32m" )
116+ addr_info = wallet .getaddressinfo (addr )
65117 assert addr_info ['desc' ].startswith ('tr(' )
66118 assert_equal (addr_info ['hdkeypath' ], 'm/86h/1h/0h/0/0' )
67119
68120 # Check that getrawchangeaddress works
69- addr = self . nodes [ 0 ] .getrawchangeaddress ("legacy" )
70- addr_info = self . nodes [ 0 ] .getaddressinfo (addr )
121+ addr = wallet .getrawchangeaddress ("legacy" )
122+ addr_info = wallet .getaddressinfo (addr )
71123 assert addr_info ['desc' ].startswith ('pkh(' )
72124 assert_equal (addr_info ['hdkeypath' ], 'm/44h/1h/0h/1/0' )
73125
74- addr = self . nodes [ 0 ] .getrawchangeaddress ("p2sh-segwit" )
75- addr_info = self . nodes [ 0 ] .getaddressinfo (addr )
126+ addr = wallet .getrawchangeaddress ("p2sh-segwit" )
127+ addr_info = wallet .getaddressinfo (addr )
76128 assert addr_info ['desc' ].startswith ('sh(wpkh(' )
77129 assert_equal (addr_info ['hdkeypath' ], 'm/49h/1h/0h/1/0' )
78130
79- addr = self . nodes [ 0 ] .getrawchangeaddress ("bech32" )
80- addr_info = self . nodes [ 0 ] .getaddressinfo (addr )
131+ addr = wallet .getrawchangeaddress ("bech32" )
132+ addr_info = wallet .getaddressinfo (addr )
81133 assert addr_info ['desc' ].startswith ('wpkh(' )
82134 assert_equal (addr_info ['hdkeypath' ], 'm/84h/1h/0h/1/0' )
83135
84- addr = self . nodes [ 0 ] .getrawchangeaddress ("bech32m" )
85- addr_info = self . nodes [ 0 ] .getaddressinfo (addr )
136+ addr = wallet .getrawchangeaddress ("bech32m" )
137+ addr_info = wallet .getaddressinfo (addr )
86138 assert addr_info ['desc' ].startswith ('tr(' )
87139 assert_equal (addr_info ['hdkeypath' ], 'm/86h/1h/0h/1/0' )
88140
@@ -216,6 +268,7 @@ def run_test(self):
216268 conn .close ()
217269 assert_raises_rpc_error (- 4 , "Unexpected legacy entry in descriptor wallet found." , self .nodes [0 ].loadwallet , "crashme" )
218270
271+ self .test_parent_descriptors ()
219272
220273if __name__ == '__main__' :
221274 WalletDescriptorTest (__file__ ).main ()
0 commit comments