Skip to content

Commit f895f97

Browse files
committed
test: Scripts with hybrid pubkeys are migrated to watchonly
Descriptors disallows hybrid pubkeys. Anything with hybrid pubkeys should becomes a raw() descriptor that shows up in the watchonly wallet.
1 parent 37b9b73 commit f895f97

File tree

1 file changed

+59
-1
lines changed

1 file changed

+59
-1
lines changed

test/functional/wallet_migration.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@
66

77
import random
88
import shutil
9-
from test_framework.address import script_to_p2sh
9+
from test_framework.address import (
10+
script_to_p2sh,
11+
key_to_p2pkh,
12+
key_to_p2wpkh,
13+
)
1014
from test_framework.descriptors import descsum_create
15+
from test_framework.key import ECPubKey
1116
from test_framework.test_framework import BitcoinTestFramework
1217
from test_framework.messages import COIN, CTransaction, CTxOut
1318
from test_framework.script_util import key_to_p2pkh_script, script_to_p2sh_script, script_to_p2wsh_script
@@ -770,6 +775,58 @@ def test_conflict_txs(self):
770775

771776
wallet.unloadwallet()
772777

778+
def test_hybrid_pubkey(self):
779+
self.log.info("Test migration when wallet contains a hybrid pubkey")
780+
781+
wallet = self.create_legacy_wallet("hybrid_keys")
782+
783+
# Get the hybrid pubkey for one of the keys in the wallet
784+
normal_pubkey = wallet.getaddressinfo(wallet.getnewaddress())["pubkey"]
785+
first_byte = bytes.fromhex(normal_pubkey)[0] + 4 # Get the hybrid pubkey first byte
786+
parsed_pubkey = ECPubKey()
787+
parsed_pubkey.set(bytes.fromhex(normal_pubkey))
788+
parsed_pubkey.compressed = False
789+
hybrid_pubkey_bytes = bytearray(parsed_pubkey.get_bytes())
790+
hybrid_pubkey_bytes[0] = first_byte # Make it hybrid
791+
hybrid_pubkey = hybrid_pubkey_bytes.hex()
792+
793+
# Import the hybrid pubkey
794+
wallet.importpubkey(hybrid_pubkey)
795+
p2pkh_addr = key_to_p2pkh(hybrid_pubkey)
796+
p2pkh_addr_info = wallet.getaddressinfo(p2pkh_addr)
797+
assert_equal(p2pkh_addr_info["iswatchonly"], True)
798+
assert_equal(p2pkh_addr_info["ismine"], False) # Things involving hybrid pubkeys are not spendable
799+
800+
# Also import the p2wpkh for the pubkey to make sure we don't migrate it
801+
p2wpkh_addr = key_to_p2wpkh(hybrid_pubkey)
802+
wallet.importaddress(p2wpkh_addr)
803+
804+
migrate_info = wallet.migratewallet()
805+
806+
# Both addresses should only appear in the watchonly wallet
807+
p2pkh_addr_info = wallet.getaddressinfo(p2pkh_addr)
808+
assert_equal(p2pkh_addr_info["iswatchonly"], False)
809+
assert_equal(p2pkh_addr_info["ismine"], False)
810+
p2wpkh_addr_info = wallet.getaddressinfo(p2wpkh_addr)
811+
assert_equal(p2wpkh_addr_info["iswatchonly"], False)
812+
assert_equal(p2wpkh_addr_info["ismine"], False)
813+
814+
watchonly_wallet = self.nodes[0].get_wallet_rpc(migrate_info["watchonly_name"])
815+
watchonly_p2pkh_addr_info = watchonly_wallet.getaddressinfo(p2pkh_addr)
816+
assert_equal(watchonly_p2pkh_addr_info["iswatchonly"], False)
817+
assert_equal(watchonly_p2pkh_addr_info["ismine"], True)
818+
watchonly_p2wpkh_addr_info = watchonly_wallet.getaddressinfo(p2wpkh_addr)
819+
assert_equal(watchonly_p2wpkh_addr_info["iswatchonly"], False)
820+
assert_equal(watchonly_p2wpkh_addr_info["ismine"], True)
821+
822+
# There should only be raw or addr descriptors
823+
for desc in watchonly_wallet.listdescriptors()["descriptors"]:
824+
if desc["desc"].startswith("raw(") or desc["desc"].startswith("addr("):
825+
continue
826+
assert False, "Hybrid pubkey watchonly wallet has more than just raw() and addr()"
827+
828+
wallet.unloadwallet()
829+
773830
def run_test(self):
774831
self.generate(self.nodes[0], 101)
775832

@@ -787,6 +844,7 @@ def run_test(self):
787844
self.test_addressbook()
788845
self.test_migrate_raw_p2sh()
789846
self.test_conflict_txs()
847+
self.test_hybrid_pubkey()
790848

791849
if __name__ == '__main__':
792850
WalletMigrationTest().main()

0 commit comments

Comments
 (0)