Skip to content

Commit 1eb9a2a

Browse files
committed
test: Test migration of miniscript in legacy wallets
1 parent e8c3efc commit 1eb9a2a

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

test/functional/wallet_migration.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

12341289
if __name__ == '__main__':
12351290
WalletMigrationTest(__file__).main()

0 commit comments

Comments
 (0)