Skip to content

Commit

Permalink
Add getdescriptors command
Browse files Browse the repository at this point in the history
  • Loading branch information
Sjors committed May 1, 2019
1 parent 0617dcf commit 841f703
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 6 deletions.
9 changes: 8 additions & 1 deletion hwilib/cli.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#! /usr/bin/env python3

from .commands import backup_device, displayaddress, enumerate, find_device, \
get_client, getmasterxpub, getxpub, getkeypool, prompt_pin, restore_device, send_pin, setup_device, \
get_client, getmasterxpub, getxpub, getkeypool, getdescriptors, prompt_pin, restore_device, send_pin, setup_device, \
signmessage, signtx, wipe_device
from .errors import (
HWWError,
Expand Down Expand Up @@ -38,6 +38,9 @@ def getxpub_handler(args, client):
def getkeypool_handler(args, client):
return getkeypool(client, path=args.path, start=args.start, end=args.end, internal=args.internal, keypool=args.keypool, account=args.account, sh_wpkh=args.sh_wpkh, wpkh=args.wpkh)

def getdescriptors_handler(args, client):
return getdescriptors(client, account=args.account)

def restore_device_handler(args, client):
if args.interactive:
return restore_device(client, label=args.label)
Expand Down Expand Up @@ -110,6 +113,10 @@ def process_commands(cli_args):
getkeypool_parser.add_argument('end', type=int, help='The index to end at.')
getkeypool_parser.set_defaults(func=getkeypool_handler)

getdescriptors_parser = subparsers.add_parser('getdescriptors', help='Return receive and change descriptors for each supported address type, for import into a wallet.')
getdescriptors_parser.add_argument('--account', help='BIP43 account (default: 0)', type=int, default=0)
getdescriptors_parser.set_defaults(func=getdescriptors_handler)

displayaddr_parser = subparsers.add_parser('displayaddress', help='Display an address')
group = displayaddr_parser.add_mutually_exclusive_group(required=True)
group.add_argument('--desc', help='Output Descriptor. E.g. wpkh([00000000/84h/0h/0h]xpub.../0/0), where 00000000 must match --fingerprint and xpub can be obtained with getxpub. See doc/descriptors.md in Bitcoin Core')
Expand Down
20 changes: 20 additions & 0 deletions hwilib/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,26 @@ def getdescriptor(client, master_xpub, testnet=False, path=None, internal=False,

return Descriptor(master_fpr, path_base.replace('m', ''), base_key, path_suffix, client.is_testnet, sh_wpkh, wpkh)

def getdescriptors(client, account=0):
try:
master_xpub = client.get_pubkey_at_path('m/0h')['xpub']
except NotImplementedError as e:
return {'error': str(e), 'code': NOT_IMPLEMENTED}

result = {}

for internal in [False, True]:
descriptors = []
descriptors.append(getdescriptor(client, master_xpub=master_xpub, testnet=client.is_testnet, internal=internal, sh_wpkh=False, wpkh=False, account=account).serialize())
descriptors.append(getdescriptor(client, master_xpub=master_xpub, testnet=client.is_testnet, internal=internal, sh_wpkh=True, wpkh=False, account=account).serialize())
descriptors.append(getdescriptor(client, master_xpub=master_xpub, testnet=client.is_testnet, internal=internal, sh_wpkh=False, wpkh=True, account=account).serialize())
if internal:
result["internal"] = descriptors
else:
result["receive"] = descriptors

return result

def displayaddress(client, path=None, desc=None, sh_wpkh=False, wpkh=False):
if path is not None:
if sh_wpkh == True and wpkh == True:
Expand Down
3 changes: 2 additions & 1 deletion test/test_coldcard.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from hwilib.cli import process_commands
from hwilib.devices.ckcc.protocol import CCProtocolPacker
from hwilib.devices.ckcc.client import ColdcardDevice
from test_device import DeviceTestCase, start_bitcoind, TestDeviceConnect, TestDisplayAddress, TestGetKeypool, TestSignMessage, TestSignTx
from test_device import DeviceTestCase, start_bitcoind, TestDeviceConnect, TestDisplayAddress, TestGetKeypool, TestGetDescriptors, TestSignMessage, TestSignTx

def coldcard_test_suite(simulator, rpc, userpass, interface):
# Start the Coldcard simulator
Expand Down Expand Up @@ -73,6 +73,7 @@ def test_pin(self):
suite.addTest(DeviceTestCase.parameterize(TestColdcardManCommands, rpc, userpass, 'coldcard', '/tmp/ckcc-simulator.sock', '0f056943', '', interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestDeviceConnect, rpc, userpass, 'coldcard', '/tmp/ckcc-simulator.sock', '0f056943', 'tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd', interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestGetKeypool, rpc, userpass, 'coldcard', '/tmp/ckcc-simulator.sock', '0f056943', 'tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd', interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestGetDescriptors, rpc, userpass, 'coldcard', '/tmp/ckcc-simulator.sock', '0f056943', 'tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd', interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestDisplayAddress, rpc, userpass, 'coldcard', '/tmp/ckcc-simulator.sock', '0f056943', 'tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd', interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestSignMessage, rpc, userpass, 'coldcard', '/tmp/ckcc-simulator.sock', '0f056943', 'tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd', interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestSignTx, rpc, userpass, 'coldcard', '/tmp/ckcc-simulator.sock', '0f056943', 'tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd', interface=interface))
Expand Down
28 changes: 28 additions & 0 deletions test/test_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,34 @@ def test_getkeypool(self):
self.assertEqual(keypool_desc['error'], 'Path must end with /*')
self.assertEqual(keypool_desc['code'], -7)

class TestGetDescriptors(DeviceTestCase):
def setUp(self):
self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(self.rpc_userpass))
if '--testnet' not in self.dev_args:
self.dev_args.append('--testnet')
self.emulator.start()

def tearDown(self):
self.emulator.stop()

def test_getdescriptors(self):
descriptors = self.do_command(self.dev_args + ['getdescriptors'])

self.assertIn('receive', descriptors)
self.assertIn('internal', descriptors)
self.assertEqual(len(descriptors['receive']), 3)
self.assertEqual(len(descriptors['internal']), 3)

for descriptor in descriptors['receive']:
info_result = self.rpc.getdescriptorinfo(descriptor)
self.assertTrue(info_result['isrange'])
self.assertTrue(info_result['issolvable'])

for descriptor in descriptors['internal']:
info_result = self.rpc.getdescriptorinfo(descriptor)
self.assertTrue(info_result['isrange'])
self.assertTrue(info_result['issolvable'])

class TestSignTx(DeviceTestCase):
def setUp(self):
self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(self.rpc_userpass))
Expand Down
3 changes: 2 additions & 1 deletion test/test_digitalbitbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import time
import unittest

from test_device import DeviceTestCase, start_bitcoind, TestDeviceConnect, TestGetKeypool, TestSignTx, TestSignMessage
from test_device import DeviceTestCase, start_bitcoind, TestDeviceConnect, TestGetKeypool, TestGetDescriptors, TestSignTx, TestSignMessage

from hwilib.cli import process_commands
from hwilib.devices.digitalbitbox import BitboxSimulator, send_plain, send_encrypt
Expand Down Expand Up @@ -129,6 +129,7 @@ def test_backup(self):
suite.addTest(DeviceTestCase.parameterize(TestDBBManCommands, rpc, userpass, type, path, fingerprint, master_xpub, '0000', interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestDeviceConnect, rpc, userpass, type, path, fingerprint, master_xpub, '0000', interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestGetKeypool, rpc, userpass, type, path, fingerprint, master_xpub, '0000', interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestGetDescriptors, rpc, userpass, type, path, fingerprint, master_xpub, '0000', interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestSignTx, rpc, userpass, type, path, fingerprint, master_xpub, '0000', interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestSignMessage, rpc, userpass, type, path, fingerprint, master_xpub, '0000', interface=interface))
return suite
Expand Down
3 changes: 2 additions & 1 deletion test/test_keepkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from hwilib.devices.trezorlib.transport.udp import UdpTransport
from hwilib.devices.trezorlib.debuglink import TrezorClientDebugLink, load_device_by_mnemonic, load_device_by_xprv
from hwilib.devices.trezorlib import device, messages
from test_device import DeviceEmulator, DeviceTestCase, start_bitcoind, TestDeviceConnect, TestDisplayAddress, TestGetKeypool, TestSignMessage, TestSignTx
from test_device import DeviceEmulator, DeviceTestCase, start_bitcoind, TestDeviceConnect, TestDisplayAddress, TestGetKeypool, TestGetDescriptors, TestSignMessage, TestSignTx

from hwilib.cli import process_commands
from hwilib.devices.keepkey import KeepkeyClient
Expand Down Expand Up @@ -231,6 +231,7 @@ def keepkey_test_suite(emulator, rpc, userpass, interface):
suite = unittest.TestSuite()
suite.addTest(DeviceTestCase.parameterize(TestDeviceConnect, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestGetKeypool, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestGetDescriptors, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestSignTx, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestDisplayAddress, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestSignMessage, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
Expand Down
3 changes: 2 additions & 1 deletion test/test_ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import unittest

from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
from test_device import DeviceTestCase, start_bitcoind, TestDeviceConnect, TestDisplayAddress, TestGetKeypool, TestSignMessage, TestSignTx
from test_device import DeviceTestCase, start_bitcoind, TestDeviceConnect, TestDisplayAddress, TestGetKeypool, TestGetDescriptors, TestSignMessage, TestSignTx

from hwilib.cli import process_commands

Expand Down Expand Up @@ -76,6 +76,7 @@ def test_backup(self):
suite.addTest(DeviceTestCase.parameterize(TestLedgerDisabledCommands, rpc, userpass, 'ledger', path, fingerprint, master_xpub, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestDeviceConnect, rpc, userpass, 'ledger', path, fingerprint, master_xpub, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestGetKeypool, rpc, userpass, 'ledger', path, fingerprint, master_xpub, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestGetDescriptors, rpc, userpass, 'ledger', path, fingerprint, master_xpub, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestSignTx, rpc, userpass, 'ledger', path, fingerprint, master_xpub, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestDisplayAddress, rpc, userpass, 'ledger', path, fingerprint, master_xpub, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestSignMessage, rpc, userpass, 'ledger', path, fingerprint, master_xpub, interface=interface))
Expand Down
3 changes: 2 additions & 1 deletion test/test_trezor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from hwilib.devices.trezorlib.transport.udp import UdpTransport
from hwilib.devices.trezorlib.debuglink import TrezorClientDebugLink, load_device_by_mnemonic, load_device_by_xprv
from hwilib.devices.trezorlib import device, messages
from test_device import DeviceEmulator, DeviceTestCase, start_bitcoind, TestDeviceConnect, TestDisplayAddress, TestGetKeypool, TestSignMessage, TestSignTx
from test_device import DeviceEmulator, DeviceTestCase, start_bitcoind, TestDeviceConnect, TestDisplayAddress, TestGetKeypool, TestGetDescriptors, TestSignMessage, TestSignTx

from hwilib.cli import process_commands
from hwilib.devices.trezor import TrezorClient
Expand Down Expand Up @@ -231,6 +231,7 @@ def trezor_test_suite(emulator, rpc, userpass, interface):
suite = unittest.TestSuite()
suite.addTest(DeviceTestCase.parameterize(TestDeviceConnect, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestGetKeypool, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestGetDescriptors, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestSignTx, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestDisplayAddress, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
suite.addTest(DeviceTestCase.parameterize(TestSignMessage, rpc, userpass, type, path, fingerprint, master_xpub, emulator=dev_emulator, interface=interface))
Expand Down

0 comments on commit 841f703

Please sign in to comment.