tCreate hw_wallet directory for common code - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit e461c1c818e5ffff7a510d372661a0e7eb3482c3 DIR parent 6b68968d045abe4a1e2c1ee9fa27e8e040e15114 HTML Author: Neil Booth <kyuupichan@gmail.com> Date: Sat, 30 Jan 2016 12:20:05 +0900 Create hw_wallet directory for common code Quite a lot of code under trezor/ can be shared with the Ledger code. This is the first step for wallets. Diffstat: A plugins/hw_wallet/__init__.py | 1 + A plugins/hw_wallet/hw_wallet.py | 107 +++++++++++++++++++++++++++++++ M plugins/trezor/plugin.py | 88 +------------------------------ 3 files changed, 110 insertions(+), 86 deletions(-) --- DIR diff --git a/plugins/hw_wallet/__init__.py b/plugins/hw_wallet/__init__.py t@@ -0,0 +1 @@ +from hw_wallet import BIP44_HW_Wallet DIR diff --git a/plugins/hw_wallet/hw_wallet.py b/plugins/hw_wallet/hw_wallet.py t@@ -0,0 +1,107 @@ +#!/usr/bin/env python2 +# -*- mode: python -*- +# +# Electrum - lightweight Bitcoin client +# Copyright (C) 2016 The Electrum developers +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from struct import pack + +from electrum.wallet import BIP44_Wallet + +class BIP44_HW_Wallet(BIP44_Wallet): + '''A BIP44 hardware wallet base class.''' + # Derived classes must set: + # - device + # - DEVICE_IDS + # - wallet_type + + restore_wallet_class = BIP44_Wallet + max_change_outputs = 1 + + def __init__(self, storage): + BIP44_Wallet.__init__(self, storage) + # After timeout seconds we clear the device session + self.session_timeout = storage.get('session_timeout', 180) + # 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 = True + + def set_session_timeout(self, seconds): + self.print_error("setting session timeout to %d seconds" % seconds) + self.session_timeout = seconds + self.storage.put('session_timeout', seconds) + + def unpaired(self): + '''A device paired with the wallet was diconnected. This can be + called in any thread context.''' + self.print_error("unpaired") + self.force_watching_only = True + self.handler.watching_only_changed() + + def paired(self): + '''A device paired with the wallet was (re-)connected. This can be + called in any thread context.''' + self.print_error("paired") + self.force_watching_only = False + self.handler.watching_only_changed() + + def timeout(self): + '''Called when the wallet session times out. Note this is called from + the Plugins thread.''' + client = self.get_client(force_pair=False) + if client: + client.clear_session() + self.print_error("timed out") + + def get_action(self): + pass + + def can_create_accounts(self): + return True + + def can_export(self): + return False + + def is_watching_only(self): + '''The wallet is watching-only if its trezor device is unpaired.''' + assert not self.has_seed() + return self.force_watching_only + + def can_change_password(self): + return False + + def get_client(self, force_pair=True): + return self.plugin.get_client(self, force_pair) + + def first_address(self): + '''Used to check a hardware wallet matches a software wallet''' + account = self.accounts.get('0') + derivation = self.address_derivation('0', 0, 0) + return (account.first_address()[0] if account else None, derivation) + + def derive_xkeys(self, root, derivation, password): + if self.master_public_keys.get(self.root_name): + return BIP44_wallet.derive_xkeys(self, root, derivation, password) + + # When creating a wallet we need to ask the device for the + # master public key + xpub = self.get_public_key(derivation) + return xpub, None + + def i4b(self, x): + return pack('>I', x) DIR diff --git a/plugins/trezor/plugin.py b/plugins/trezor/plugin.py t@@ -5,7 +5,6 @@ import time from binascii import unhexlify from functools import partial -from struct import pack from electrum.account import BIP32_Account from electrum.bitcoin import (bc_address_to_hash_160, xpub_from_pubkey, t@@ -15,7 +14,7 @@ from electrum.i18n import _ from electrum.plugins import BasePlugin, hook from electrum.transaction import (deserialize, is_extended_pubkey, Transaction, x_to_xpub) -from electrum.wallet import BIP44_Wallet +from ..hw_wallet import BIP44_HW_Wallet from electrum.util import ThreadJob t@@ -25,87 +24,7 @@ TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4) class DeviceDisconnectedError(Exception): pass -class TrezorCompatibleWallet(BIP44_Wallet): - # Extend BIP44 Wallet as required by hardware implementation. - # Derived classes must set: - # - device - # - DEVICE_IDS - # - wallet_type - - restore_wallet_class = BIP44_Wallet - max_change_outputs = 1 - - def __init__(self, storage): - BIP44_Wallet.__init__(self, storage) - # After timeout seconds we clear the device session - self.session_timeout = storage.get('session_timeout', 180) - # 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 = True - - def set_session_timeout(self, seconds): - self.print_error("setting session timeout to %d seconds" % seconds) - self.session_timeout = seconds - self.storage.put('session_timeout', seconds) - - def unpaired(self): - '''A device paired with the wallet was diconnected. This can be - called in any thread context.''' - self.print_error("unpaired") - self.force_watching_only = True - self.handler.watching_only_changed() - - def paired(self): - '''A device paired with the wallet was (re-)connected. This can be - called in any thread context.''' - self.print_error("paired") - self.force_watching_only = False - self.handler.watching_only_changed() - - def timeout(self): - '''Called when the wallet session times out. Note this is called from - the Plugins thread.''' - client = self.get_client(force_pair=False) - if client: - client.clear_session() - self.print_error("timed out") - - def get_action(self): - pass - - def can_create_accounts(self): - return True - - def can_export(self): - return False - - def is_watching_only(self): - '''The wallet is watching-only if its trezor device is unpaired.''' - assert not self.has_seed() - return self.force_watching_only - - def can_change_password(self): - return False - - def get_client(self, force_pair=True): - return self.plugin.get_client(self, force_pair) - - def first_address(self): - '''Used to check a hardware wallet matches a software wallet''' - account = self.accounts.get('0') - derivation = self.address_derivation('0', 0, 0) - return (account.first_address()[0] if account else None, derivation) - - def derive_xkeys(self, root, derivation, password): - if self.master_public_keys.get(self.root_name): - return BIP44_wallet.derive_xkeys(self, root, derivation, password) - - # When creating a wallet we need to ask the device for the - # master public key - xpub = self.get_public_key(derivation) - return xpub, None +class TrezorCompatibleWallet(BIP44_HW_Wallet): def get_public_key(self, bip32_path): client = self.get_client() t@@ -116,9 +35,6 @@ class TrezorCompatibleWallet(BIP44_Wallet): + node.chain_code + node.public_key) return EncodeBase58Check(xpub) - def i4b(self, x): - return pack('>I', x) - def decrypt_message(self, pubkey, message, password): address = public_key_to_bc_address(pubkey.decode('hex')) client = self.get_client()