electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 9c7fd44b58b4eb18711e9206654f92c8b21d0aae
parent eb60e0d2e092e2bddce2734a0bb2efdb6fd5437e
Author: ThomasV <thomasv@electrum.org>
Date:   Sun, 21 Aug 2016 22:44:42 +0200

update ledger plugin

Diffstat:
Mplugins/ledger/__init__.py | 2+-
Mplugins/ledger/ledger.py | 110++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mplugins/ledger/qt.py | 21+++++++++++++++------
3 files changed, 69 insertions(+), 64 deletions(-)

diff --git a/plugins/ledger/__init__.py b/plugins/ledger/__init__.py @@ -3,5 +3,5 @@ from electrum.i18n import _ fullname = 'Ledger Wallet' description = 'Provides support for Ledger hardware wallet' requires = [('btchip', 'github.com/ledgerhq/btchip-python')] -registers_keystore = ('hardware', 'btchip', _("Ledger wallet")) +registers_keystore = ('hardware', 'ledger', _("Ledger wallet")) available_for = ['qt', 'cmdline'] diff --git a/plugins/ledger/ledger.py b/plugins/ledger/ledger.py @@ -27,26 +27,19 @@ except ImportError: class Ledger_KeyStore(Hardware_KeyStore): - wallet_type = 'btchip' device = 'Ledger' - def __init__(self): - Hardware_KeyStore.__init__(self) + def __init__(self, d): + Hardware_KeyStore.__init__(self, d) # Errors and other user interaction is done through the wallet's # handler. The handler is per-window and preserved across # device reconnects - self.handler = None self.force_watching_only = False self.device_checked = False self.signing = False - self.client = None - def get_derivation(self): - return "m/44'/0'/%d'"%self.account_id - - def load(self, storage, name): - self.xpub = storage.get('master_public_keys', {}).get(name) - self.account_id = int(storage.get('account_id')) + def get_client(self): + return self.plugin.get_client() def init_xpub(self): client = self.get_client() @@ -67,42 +60,6 @@ class Ledger_KeyStore(Hardware_KeyStore): # Strip the leading "m/" return BIP32_HW_Wallet.address_id(self, address)[2:] - def get_public_key(self, bip32_path): - # bip32_path is of the form 44'/0'/1' - # S-L-O-W - we don't handle the fingerprint directly, so compute - # it manually from the previous node - # This only happens once so it's bearable - self.get_client() # prompt for the PIN before displaying the dialog if necessary - self.handler.show_message("Computing master public key") - try: - splitPath = bip32_path.split('/') - if splitPath[0] == 'm': - splitPath = splitPath[1:] - bip32_path = bip32_path[2:] - fingerprint = 0 - if len(splitPath) > 1: - prevPath = "/".join(splitPath[0:len(splitPath) - 1]) - nodeData = self.get_client().getWalletPublicKey(prevPath) - publicKey = compress_public_key(nodeData['publicKey']) - h = hashlib.new('ripemd160') - h.update(hashlib.sha256(publicKey).digest()) - fingerprint = unpack(">I", h.digest()[0:4])[0] - nodeData = self.get_client().getWalletPublicKey(bip32_path) - publicKey = compress_public_key(nodeData['publicKey']) - depth = len(splitPath) - lastChild = splitPath[len(splitPath) - 1].split('\'') - if len(lastChild) == 1: - childnum = int(lastChild[0]) - else: - childnum = 0x80000000 | int(lastChild[0]) - xpub = "0488B21E".decode('hex') + chr(depth) + self.i4b(fingerprint) + self.i4b(childnum) + str(nodeData['chainCode']) + str(publicKey) - except Exception, e: - self.give_error(e, True) - finally: - self.handler.clear_dialog() - - return EncodeBase58Check(xpub) - def decrypt_message(self, pubkey, message, password): self.give_error("Not supported") @@ -318,6 +275,21 @@ class Ledger_KeyStore(Hardware_KeyStore): return False, None, None return True, response, response + +class LedgerPlugin(HW_PluginBase): + libraries_available = BTCHIP + keystore_class = Ledger_KeyStore + hw_type='ledger' + client = None + + def btchip_is_connected(self, keystore): + try: + self.get_client().getFirmwareVersion() + except Exception as e: + self.print_error("get_client", str(e)) + return False + return True + def get_client(self, force_pair=True, noPin=False): aborted = False client = self.client @@ -389,15 +361,39 @@ class Ledger_KeyStore(Hardware_KeyStore): return self.client + def get_public_key(self, bip32_path): + # bip32_path is of the form 44'/0'/1' + # S-L-O-W - we don't handle the fingerprint directly, so compute + # it manually from the previous node + # This only happens once so it's bearable + self.get_client() # prompt for the PIN before displaying the dialog if necessary + self.handler.show_message("Computing master public key") + try: + splitPath = bip32_path.split('/') + if splitPath[0] == 'm': + splitPath = splitPath[1:] + bip32_path = bip32_path[2:] + fingerprint = 0 + if len(splitPath) > 1: + prevPath = "/".join(splitPath[0:len(splitPath) - 1]) + nodeData = self.get_client().getWalletPublicKey(prevPath) + publicKey = compress_public_key(nodeData['publicKey']) + h = hashlib.new('ripemd160') + h.update(hashlib.sha256(publicKey).digest()) + fingerprint = unpack(">I", h.digest()[0:4])[0] + nodeData = self.get_client().getWalletPublicKey(bip32_path) + publicKey = compress_public_key(nodeData['publicKey']) + depth = len(splitPath) + lastChild = splitPath[len(splitPath) - 1].split('\'') + if len(lastChild) == 1: + childnum = int(lastChild[0]) + else: + childnum = 0x80000000 | int(lastChild[0]) + xpub = "0488B21E".decode('hex') + chr(depth) + self.i4b(fingerprint) + self.i4b(childnum) + str(nodeData['chainCode']) + str(publicKey) + except Exception, e: + self.give_error(e, True) + finally: + self.handler.clear_dialog() -class LedgerPlugin(HW_PluginBase): - libraries_available = BTCHIP - keystore_class = Ledger_KeyStore + return EncodeBase58Check(xpub) - def btchip_is_connected(self, keystore): - try: - keystore.get_client().getFirmwareVersion() - except Exception as e: - self.print_error("get_client", str(e)) - return False - return True diff --git a/plugins/ledger/qt.py b/plugins/ledger/qt.py @@ -25,12 +25,21 @@ class Plugin(LedgerPlugin): window.show_error(_("Ledger device not detected.\nContinuing in watching-only mode.")) wallet.force_watching_only = True - def on_create_wallet(self, keystore, wizard): - assert type(keystore) == self.keystore_class - keystore.handler = BTChipQTHandler(wizard) - keystore.init_xpub() - print keystore.xpub - wizard.create_wallet(keystore, None) + def create_keystore(self, hw_type, derivation, wizard): + from electrum.keystore import hardware_keystore + # create keystore + handler = BTChipQTHandler(wizard) + client = self.get_client() + xpub = self.get_public_key(derivation) + d = { + 'xpub': self.xpub, + 'type': 'hardware', + 'hw_type': hw_type, + 'derivation': derivation + } + k = hardware_keystore(hw_type, d) + return k + class BTChipQTHandler(QtHandlerBase):