diff --git a/jmbitcoin/jmbitcoin/__init__.py b/jmbitcoin/jmbitcoin/__init__.py index e4fed6e..60cdca6 100644 --- a/jmbitcoin/jmbitcoin/__init__.py +++ b/jmbitcoin/jmbitcoin/__init__.py @@ -22,6 +22,7 @@ from jmbitcoin.snicker import * from jmbitcoin.amount import * from jmbitcoin.bip21 import * from jmbitcoin.output_descriptors import (get_address_descriptor, + get_address_from_descriptor, get_xpub_descriptor) from bitcointx import select_chain_params from bitcointx.core import (x, b2x, b2lx, lx, COutPoint, CTxOut, CTxIn, diff --git a/jmbitcoin/jmbitcoin/output_descriptors.py b/jmbitcoin/jmbitcoin/output_descriptors.py index d590234..000414e 100644 --- a/jmbitcoin/jmbitcoin/output_descriptors.py +++ b/jmbitcoin/jmbitcoin/output_descriptors.py @@ -77,9 +77,22 @@ def get_xpub_descriptor(xpub_key: str, address_type: str) -> str: elif address_type == "p2sh-p2wpkh" or address_type == "p2wpkh": function = "wpkh" else: - raise Exception("Unsupported address type {}".format(address_type)) + raise NotImplementedError( + "Unsupported address type {}".format(address_type)) descriptor = "{}({}/*)".format(function, xpub_key) if address_type == "p2sh-p2wpkh": descriptor = "sh({})".format(descriptor) return add_checksum(descriptor) + +def is_address_descriptor(desc: str) -> bool: + return desc.startswith("addr(") + + +def get_address_from_descriptor(desc: str) -> str: + #example + #'desc': 'addr(2MvAfRVvRAeBS18NT7mKVc1gFim169GkFC5)#h5yn9eq4', + if not is_address_descriptor(desc): + raise ValueError("Not an address descriptor {}".format(desc)) + return desc[5:desc.find(")")] + diff --git a/jmbitcoin/test/test_output_descriptors.py b/jmbitcoin/test/test_output_descriptors.py index a35deba..e7dcfde 100644 --- a/jmbitcoin/test/test_output_descriptors.py +++ b/jmbitcoin/test/test_output_descriptors.py @@ -1,13 +1,27 @@ import jmbitcoin as btc +import pytest def test_address_descriptors(): assert(btc.get_address_descriptor("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i") == "addr(1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i)#ns3f5w84") + assert(btc.get_address_from_descriptor("addr(1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i)#ns3f5w84") == + "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i") assert(btc.get_address_descriptor("3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou") == "addr(3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou)#swk5gt6w") + assert(btc.get_address_from_descriptor("addr(3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou)#swk5gt6w") == + "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou") assert(btc.get_address_descriptor("bc1qt493axn3wl4gzjxvfg03vkacre0m6f2gzfhv5t") == "addr(bc1qt493axn3wl4gzjxvfg03vkacre0m6f2gzfhv5t)#q8mdrmlw") + assert(btc.get_address_from_descriptor("addr(bc1qt493axn3wl4gzjxvfg03vkacre0m6f2gzfhv5t)#q8mdrmlw") == + "bc1qt493axn3wl4gzjxvfg03vkacre0m6f2gzfhv5t") + assert(btc.get_address_descriptor("2MvAfRVvRAeBS18NT7mKVc1gFim169GkFC5") == + "addr(2MvAfRVvRAeBS18NT7mKVc1gFim169GkFC5)#h5yn9eq4") + assert(btc.get_address_from_descriptor("addr(2MvAfRVvRAeBS18NT7mKVc1gFim169GkFC5)#h5yn9eq4") == + "2MvAfRVvRAeBS18NT7mKVc1gFim169GkFC5") + with pytest.raises(ValueError): + btc.get_address_from_descriptor("") + btc.get_address_from_descriptor("pkh(xpub6CMAJ67vZWVXuzjzYXUoJgWrmuvFRiqiUG4dwoXNFmJtpTH3WgviANNxGyZYo27zxbMuqhDDym6fnBxmGaYoxr6LHgNDo1eEghkXHTX4Jnx/*)#flej8438") def test_xpub_descriptors(): diff --git a/jmclient/jmclient/blockchaininterface.py b/jmclient/jmclient/blockchaininterface.py index 3efd79a..48e3035 100644 --- a/jmclient/jmclient/blockchaininterface.py +++ b/jmclient/jmclient/blockchaininterface.py @@ -666,16 +666,10 @@ class BitcoinCoreNoHistoryInterface(BitcoinCoreInterface, RegtestBitcoinCoreMixi assert False return False - def _get_addr_from_desc(self, desc_str): - #example - #'desc': 'addr(2MvAfRVvRAeBS18NT7mKVc1gFim169GkFC5)#h5yn9eq4', - assert desc_str.startswith("addr(") - return desc_str[5:desc_str.find(")")] - def _yield_transactions(self): for u in self.scan_result["unspents"]: tx = {"category": "receive", "address": - self._get_addr_from_desc(u["desc"])} + btc.get_address_from_descriptor(u["desc"])} yield tx def list_transactions(self, num): @@ -686,7 +680,7 @@ class BitcoinCoreNoHistoryInterface(BitcoinCoreInterface, RegtestBitcoinCoreMixi def listunspent(self): return [{ - "address": self._get_addr_from_desc(u["desc"]), + "address": btc.get_address_from_descriptor(u["desc"]), "label": self.wallet_name, "height": u["height"], "txid": u["txid"],