9
9
except ImportError :
10
10
pass
11
11
12
+ import re
13
+
12
14
from test_framework .blocktools import COINBASE_MATURITY
13
15
from test_framework .test_framework import BitcoinTestFramework
14
16
from test_framework .util import (
@@ -29,6 +31,62 @@ def skip_test_if_missing_module(self):
29
31
self .skip_if_no_wallet ()
30
32
self .skip_if_no_py_sqlite3 ()
31
33
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
+
49
+ # Walk the remaining descriptor backwards looking for the hardened indicator.
50
+ # It should not be found until after a ']' is found, and before a '['
51
+ # The hardened indicator 'h' should not be found until after a ']' is found
52
+ found_origin_end = False
53
+ found_hardened_in_origin = False
54
+ found_hardened_after_origin = False
55
+ for c in desc_verify [::- 1 ]:
56
+ if c == "]" :
57
+ found_origin_end = True
58
+ elif c == "[" :
59
+ break
60
+ elif c == "h" or c == "'" :
61
+ if found_origin_end :
62
+ found_hardened_in_origin = True
63
+ else :
64
+ found_hardened_after_origin = True
65
+ assert_equal (found_hardened_in_origin , True )
66
+ assert_equal (found_hardened_after_origin , False )
67
+
68
+ # Send some coins so we can check listunspent, listtransactions, listunspent, and gettransaction
69
+ since_block = self .nodes [0 ].getbestblockhash ()
70
+ txid = default_wallet .sendtoaddress (addr , 1 )
71
+ self .generate (self .nodes [0 ], 1 )
72
+
73
+ unspent = wallet .listunspent ()
74
+ assert_equal (len (unspent ), 1 )
75
+ assert_equal (unspent [0 ]["parent_descs" ], [parent_desc ])
76
+
77
+ txs = wallet .listtransactions ()
78
+ assert_equal (len (txs ), 1 )
79
+ assert_equal (txs [0 ]["parent_descs" ], [parent_desc ])
80
+
81
+ txs = wallet .listsinceblock (since_block )["transactions" ]
82
+ assert_equal (len (txs ), 1 )
83
+ assert_equal (txs [0 ]["parent_descs" ], [parent_desc ])
84
+
85
+ tx = wallet .gettransaction (txid = txid , verbose = True )
86
+ assert_equal (tx ["details" ][0 ]["parent_descs" ], [parent_desc ])
87
+
88
+ wallet .unloadwallet ()
89
+
32
90
def run_test (self ):
33
91
self .generate (self .nodes [0 ], COINBASE_MATURITY + 1 )
34
92
@@ -218,6 +276,7 @@ def run_test(self):
218
276
conn .close ()
219
277
assert_raises_rpc_error (- 4 , "Unexpected legacy entry in descriptor wallet found." , self .nodes [0 ].loadwallet , "crashme" )
220
278
279
+ self .test_parent_descriptors ()
221
280
222
281
if __name__ == '__main__' :
223
282
WalletDescriptorTest (__file__ ).main ()
0 commit comments