Skip to content

Commit

Permalink
test: Scripts with hybrid pubkeys are migrated to watchonly
Browse files Browse the repository at this point in the history
Descriptors disallows hybrid pubkeys. Anything with hybrid pubkeys
should becomes a raw() descriptor that shows up in the watchonly wallet.
  • Loading branch information
achow101 committed Oct 8, 2023
1 parent 62ca75b commit f0c34fd
Showing 1 changed file with 59 additions and 1 deletion.
60 changes: 59 additions & 1 deletion test/functional/wallet_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@

import random
import shutil
from test_framework.address import script_to_p2sh
from test_framework.address import (
script_to_p2sh,
key_to_p2pkh,
key_to_p2wpkh,
)
from test_framework.descriptors import descsum_create
from test_framework.key import ECPubKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import COIN, CTransaction, CTxOut
from test_framework.script_util import key_to_p2pkh_script, script_to_p2sh_script, script_to_p2wsh_script
Expand Down Expand Up @@ -770,6 +775,58 @@ def test_conflict_txs(self):

wallet.unloadwallet()

def test_hybrid_pubkey(self):
self.log.info("Test migration when wallet contains a hybrid pubkey")

wallet = self.create_legacy_wallet("hybrid_keys")

# Get the hybrid pubkey for one of the keys in the wallet
normal_pubkey = wallet.getaddressinfo(wallet.getnewaddress())["pubkey"]
first_byte = bytes.fromhex(normal_pubkey)[0] + 4 # Get the hybrid pubkey first byte
parsed_pubkey = ECPubKey()
parsed_pubkey.set(bytes.fromhex(normal_pubkey))
parsed_pubkey.compressed = False
hybrid_pubkey_bytes = bytearray(parsed_pubkey.get_bytes())
hybrid_pubkey_bytes[0] = first_byte # Make it hybrid
hybrid_pubkey = hybrid_pubkey_bytes.hex()

# Import the hybrid pubkey
wallet.importpubkey(hybrid_pubkey)
p2pkh_addr = key_to_p2pkh(hybrid_pubkey)
p2pkh_addr_info = wallet.getaddressinfo(p2pkh_addr)
assert_equal(p2pkh_addr_info["iswatchonly"], True)
assert_equal(p2pkh_addr_info["ismine"], False) # Things involving hybrid pubkeys are not spendable

# Also import the p2wpkh for the pubkey to make sure we don't migrate it
p2wpkh_addr = key_to_p2wpkh(hybrid_pubkey)
wallet.importaddress(p2wpkh_addr)

migrate_info = wallet.migratewallet()

# Both addresses should only appear in the watchonly wallet
p2pkh_addr_info = wallet.getaddressinfo(p2pkh_addr)
assert_equal(p2pkh_addr_info["iswatchonly"], False)
assert_equal(p2pkh_addr_info["ismine"], False)
p2wpkh_addr_info = wallet.getaddressinfo(p2wpkh_addr)
assert_equal(p2wpkh_addr_info["iswatchonly"], False)
assert_equal(p2wpkh_addr_info["ismine"], False)

watchonly_wallet = self.nodes[0].get_wallet_rpc(migrate_info["watchonly_name"])
watchonly_p2pkh_addr_info = watchonly_wallet.getaddressinfo(p2pkh_addr)
assert_equal(watchonly_p2pkh_addr_info["iswatchonly"], False)
assert_equal(watchonly_p2pkh_addr_info["ismine"], True)
watchonly_p2wpkh_addr_info = watchonly_wallet.getaddressinfo(p2wpkh_addr)
assert_equal(watchonly_p2wpkh_addr_info["iswatchonly"], False)
assert_equal(watchonly_p2wpkh_addr_info["ismine"], True)

# There should only be raw or addr descriptors
for desc in watchonly_wallet.listdescriptors()["descriptors"]:
if desc["desc"].startswith("raw(") or desc["desc"].startswith("addr("):
continue
assert False, "Hybrid pubkey watchonly wallet has more than just raw() and addr()"

wallet.unloadwallet()

def run_test(self):
self.generate(self.nodes[0], 101)

Expand All @@ -787,6 +844,7 @@ def run_test(self):
self.test_addressbook()
self.test_migrate_raw_p2sh()
self.test_conflict_txs()
self.test_hybrid_pubkey()

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

0 comments on commit f0c34fd

Please sign in to comment.