Skip to content

Commit 17f01b0

Browse files
committed
test: Test migration of taproot output scripts
1 parent 1eb9a2a commit 17f01b0

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

test/functional/wallet_migration.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from test_framework.util import (
2626
assert_equal,
2727
assert_raises_rpc_error,
28+
find_vout_for_address,
2829
sha256sum_file,
2930
)
3031
from test_framework.wallet_util import (
@@ -1255,6 +1256,64 @@ def test_miniscript(self):
12551256
assert_equal(watchonly.getaddressinfo(some_keys_addr)["ismine"], True)
12561257
assert_equal(watchonly.getaddressinfo(all_keys_addr)["ismine"], False)
12571258

1259+
def test_taproot(self):
1260+
# It turns out that due to how signing logic works, legacy wallets that have the private key for a Taproot
1261+
# output key will be able to sign and spend those scripts, even though they would not be detected as ISMINE_SPENDABLE.
1262+
self.log.info("Test migration of Taproot scripts")
1263+
def_wallet = self.master_node.get_wallet_rpc(self.default_wallet_name)
1264+
wallet = self.create_legacy_wallet("taproot")
1265+
1266+
privkey, _ = generate_keypair(compressed=True, wif=True)
1267+
1268+
rawtr_desc = descsum_create(f"rawtr({privkey})")
1269+
rawtr_addr = self.master_node.deriveaddresses(rawtr_desc)[0]
1270+
rawtr_spk = self.master_node.validateaddress(rawtr_addr)["scriptPubKey"]
1271+
tr_desc = descsum_create(f"tr({privkey})")
1272+
tr_addr = self.master_node.deriveaddresses(tr_desc)[0]
1273+
tr_spk = self.master_node.validateaddress(tr_addr)["scriptPubKey"]
1274+
tr_script_desc = descsum_create(f"tr(9ffbe722b147f3035c87cb1c60b9a5947dd49c774cc31e94773478711a929ac0,pk({privkey}))")
1275+
tr_script_addr = self.master_node.deriveaddresses(tr_script_desc)[0]
1276+
tr_script_spk = self.master_node.validateaddress(tr_script_addr)["scriptPubKey"]
1277+
1278+
wallet.importaddress(rawtr_spk)
1279+
wallet.importaddress(tr_spk)
1280+
wallet.importaddress(tr_script_spk)
1281+
wallet.importprivkey(privkey)
1282+
1283+
txid = def_wallet.send([{rawtr_addr: 1},{tr_addr: 2}, {tr_script_addr: 3}])["txid"]
1284+
rawtr_vout = find_vout_for_address(self.master_node, txid, rawtr_addr)
1285+
tr_vout = find_vout_for_address(self.master_node, txid, tr_addr)
1286+
tr_script_vout = find_vout_for_address(self.master_node, txid, tr_script_addr)
1287+
self.generate(self.master_node, 6)
1288+
assert_equal(wallet.getbalances()["watchonly"]["trusted"], 6)
1289+
1290+
# Check that the rawtr can be spent by the legacy wallet
1291+
send_res = wallet.send(outputs=[{rawtr_addr: 0.5}], include_watching=True, change_address=def_wallet.getnewaddress(), inputs=[{"txid": txid, "vout": rawtr_vout}])
1292+
assert_equal(send_res["complete"], True)
1293+
self.generate(self.old_node, 6)
1294+
assert_equal(wallet.getbalances()["watchonly"]["trusted"], 5.5)
1295+
assert_equal(wallet.getbalances()["mine"]["trusted"], 0)
1296+
1297+
# Check that the tr() cannot be spent by the legacy wallet
1298+
send_res = wallet.send(outputs=[{def_wallet.getnewaddress(): 4}], include_watching=True, inputs=[{"txid": txid, "vout": tr_vout}, {"txid": txid, "vout": tr_script_vout}])
1299+
assert_equal(send_res["complete"], False)
1300+
1301+
res, wallet = self.migrate_and_get_rpc("taproot")
1302+
1303+
# The rawtr should be migrated
1304+
assert_equal(wallet.getbalances()["mine"], {"trusted": 0.5, "untrusted_pending": 0, "immature": 0})
1305+
assert_equal(wallet.getaddressinfo(rawtr_addr)["ismine"], True)
1306+
assert_equal(wallet.getaddressinfo(tr_addr)["ismine"], False)
1307+
assert_equal(wallet.getaddressinfo(tr_script_addr)["ismine"], False)
1308+
1309+
# The tr() with some keys should be in the watchonly wallet
1310+
assert "taproot_watchonly" in self.master_node.listwallets()
1311+
watchonly = self.master_node.get_wallet_rpc("taproot_watchonly")
1312+
assert_equal(watchonly.getbalances()["mine"], {"trusted": 5, "untrusted_pending": 0, "immature": 0})
1313+
assert_equal(watchonly.getaddressinfo(rawtr_addr)["ismine"], False)
1314+
assert_equal(watchonly.getaddressinfo(tr_addr)["ismine"], True)
1315+
assert_equal(watchonly.getaddressinfo(tr_script_addr)["ismine"], True)
1316+
12581317
def run_test(self):
12591318
self.master_node = self.nodes[0]
12601319
self.old_node = self.nodes[1]
@@ -1285,6 +1344,7 @@ def run_test(self):
12851344
self.test_p2wsh()
12861345
self.test_disallowed_p2wsh()
12871346
self.test_miniscript()
1347+
self.test_taproot()
12881348

12891349
if __name__ == '__main__':
12901350
WalletMigrationTest(__file__).main()

0 commit comments

Comments
 (0)