@@ -1201,6 +1201,60 @@ def test_disallowed_p2wsh(self):
12011201
12021202 wallet .unloadwallet ()
12031203
1204+ def test_miniscript (self ):
1205+ # It turns out that due to how signing logic works, legacy wallets that have valid miniscript witnessScripts
1206+ # and the private keys for them can still sign and spend them, even though output scripts involving them
1207+ # as a witnessScript would not be detected as ISMINE_SPENDABLE.
1208+ self .log .info ("Test migration of a legacy wallet containing miniscript" )
1209+ def_wallet = self .master_node .get_wallet_rpc (self .default_wallet_name )
1210+ wallet = self .create_legacy_wallet ("miniscript" )
1211+
1212+ privkey , _ = generate_keypair (compressed = True , wif = True )
1213+
1214+ # Make a descriptor where we only have some of the keys. This will be migrated to the watchonly wallet.
1215+ some_keys_priv_desc = descsum_create (f"wsh(or_b(pk({ privkey } ),s:pk(029ffbe722b147f3035c87cb1c60b9a5947dd49c774cc31e94773478711a929ac0)))" )
1216+ some_keys_addr = self .master_node .deriveaddresses (some_keys_priv_desc )[0 ]
1217+
1218+ # Make a descriptor where we have all of the keys. This will stay in the migrated wallet
1219+ all_keys_priv_desc = descsum_create (f"wsh(and_v(v:pk({ privkey } ),1))" )
1220+ all_keys_addr = self .master_node .deriveaddresses (all_keys_priv_desc )[0 ]
1221+
1222+ imp = wallet .importmulti ([
1223+ {
1224+ "desc" : some_keys_priv_desc ,
1225+ "timestamp" : "now" ,
1226+ },
1227+ {
1228+ "desc" : all_keys_priv_desc ,
1229+ "timestamp" : "now" ,
1230+ }
1231+ ])
1232+ assert_equal (imp [0 ]["success" ], True )
1233+ assert_equal (imp [1 ]["success" ], True )
1234+
1235+ def_wallet .sendtoaddress (some_keys_addr , 1 )
1236+ def_wallet .sendtoaddress (all_keys_addr , 1 )
1237+ self .generate (self .master_node , 6 )
1238+ # Check that the miniscript can be spent by the legacy wallet
1239+ send_res = wallet .send (outputs = [{some_keys_addr : 1 },{all_keys_addr : 0.75 }], include_watching = True , change_address = def_wallet .getnewaddress ())
1240+ assert_equal (send_res ["complete" ], True )
1241+ self .generate (self .old_node , 6 )
1242+ assert_equal (wallet .getbalances ()["watchonly" ]["trusted" ], 1.75 )
1243+
1244+ _ , wallet = self .migrate_and_get_rpc ("miniscript" )
1245+
1246+ # The miniscript with all keys should be in the migrated wallet
1247+ assert_equal (wallet .getbalances ()["mine" ], {"trusted" : 0.75 , "untrusted_pending" : 0 , "immature" : 0 })
1248+ assert_equal (wallet .getaddressinfo (all_keys_addr )["ismine" ], True )
1249+ assert_equal (wallet .getaddressinfo (some_keys_addr )["ismine" ], False )
1250+
1251+ # The miniscript with some keys should be in the watchonly wallet
1252+ assert "miniscript_watchonly" in self .master_node .listwallets ()
1253+ watchonly = self .master_node .get_wallet_rpc ("miniscript_watchonly" )
1254+ assert_equal (watchonly .getbalances ()["mine" ], {"trusted" : 1 , "untrusted_pending" : 0 , "immature" : 0 })
1255+ assert_equal (watchonly .getaddressinfo (some_keys_addr )["ismine" ], True )
1256+ assert_equal (watchonly .getaddressinfo (all_keys_addr )["ismine" ], False )
1257+
12041258 def run_test (self ):
12051259 self .master_node = self .nodes [0 ]
12061260 self .old_node = self .nodes [1 ]
@@ -1230,6 +1284,7 @@ def run_test(self):
12301284 self .test_manual_keys_import ()
12311285 self .test_p2wsh ()
12321286 self .test_disallowed_p2wsh ()
1287+ self .test_miniscript ()
12331288
12341289if __name__ == '__main__' :
12351290 WalletMigrationTest (__file__ ).main ()
0 commit comments