@@ -1201,6 +1201,60 @@ def test_disallowed_p2wsh(self):
1201
1201
1202
1202
wallet .unloadwallet ()
1203
1203
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
+
1204
1258
def run_test (self ):
1205
1259
self .master_node = self .nodes [0 ]
1206
1260
self .old_node = self .nodes [1 ]
@@ -1230,6 +1284,7 @@ def run_test(self):
1230
1284
self .test_manual_keys_import ()
1231
1285
self .test_p2wsh ()
1232
1286
self .test_disallowed_p2wsh ()
1287
+ self .test_miniscript ()
1233
1288
1234
1289
if __name__ == '__main__' :
1235
1290
WalletMigrationTest (__file__ ).main ()
0 commit comments