URI: 
       tmove xpubkey logic to keystore and fix it - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit bfd7709ccd023fb18d60346f09cd3240e51dc732
   DIR parent f6e393d7b602029aad82fc138abd5e5f32390d91
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Wed, 17 Aug 2016 14:28:37 +0200
       
       move xpubkey logic to keystore and fix it
       
       Diffstat:
         M gui/qt/main_window.py               |       4 ++--
         M gui/qt/request_list.py              |       2 +-
         M lib/keystore.py                     |      52 +++++++++++++++++++++++++++++--
         M lib/transaction.py                  |      37 +++----------------------------
         M plugins/cosigner_pool/qt.py         |       7 +++----
         M plugins/trezor/plugin.py            |      20 +++++++++-----------
       
       6 files changed, 67 insertions(+), 55 deletions(-)
       ---
   DIR diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
       t@@ -777,7 +777,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                    self.saved = True
        
            def new_payment_request(self):
       -        addr = self.wallet.get_unused_address(None)
       +        addr = self.wallet.get_unused_address()
                if addr is None:
                    from electrum.wallet import Imported_Wallet
                    if isinstance(self.wallet, Imported_Wallet):
       t@@ -785,7 +785,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                        return
                    if not self.question(_("Warning: The next address will not be recovered automatically if you restore your wallet from seed; you may need to add it manually.\n\nThis occurs because you have too many unused addresses in your wallet. To avoid this situation, use the existing addresses first.\n\nCreate anyway?")):
                        return
       -            addr = self.wallet.create_new_address(None, False)
       +            addr = self.wallet.create_new_address(False)
                self.set_receive_address(addr)
                self.expires_label.hide()
                self.expires_combo.show()
   DIR diff --git a/gui/qt/request_list.py b/gui/qt/request_list.py
       t@@ -107,7 +107,7 @@ class RequestList(MyTreeWidget):
                item = self.itemAt(position)
                if not item:
                    return
       -        addr = str(item.text(2))
       +        addr = str(item.text(1))
                req = self.wallet.receive_requests[addr]
                column = self.currentColumn()
                column_title = self.headerItem().text(column)
   DIR diff --git a/lib/keystore.py b/lib/keystore.py
       t@@ -216,6 +216,22 @@ class Xpub:
                s = ''.join(map(lambda x: bitcoin.int_to_hex(x,2), (c, i)))
                return 'ff' + bitcoin.DecodeBase58Check(self.xpub).encode('hex') + s
        
       +    @classmethod
       +    def parse_xpubkey(self, pubkey):
       +        assert pubkey[0:2] == 'ff'
       +        pk = pubkey.decode('hex')
       +        pk = pk[1:]
       +        xkey = bitcoin.EncodeBase58Check(pk[0:78])
       +        dd = pk[78:]
       +        s = []
       +        while dd:
       +            n = int(bitcoin.rev_hex(dd[0:2].encode('hex')), 16)
       +            dd = dd[2:]
       +            s.append(n)
       +        assert len(s) == 2
       +        return xkey, s
       +
       +
        
        class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
        
       t@@ -429,15 +445,15 @@ class Old_KeyStore(Deterministic_KeyStore):
            def get_master_public_key(self):
                return self.mpk.encode('hex')
        
       -    def get_xpubkeys(self, for_change, n):
       +    def get_xpubkey(self, for_change, n):
                s = ''.join(map(lambda x: bitcoin.int_to_hex(x,2), (for_change, n)))
                mpk = self.mpk.encode('hex')
                x_pubkey = 'fe' + mpk + s
       -        return [ x_pubkey ]
       +        return x_pubkey
        
            @classmethod
            def parse_xpubkey(self, x_pubkey):
       -        assert is_extended_pubkey(x_pubkey)
       +        assert x_pubkey[0:2] == 'fe'
                pk = x_pubkey[2:]
                mpk = pk[0:128]
                dd = pk[128:]
       t@@ -526,6 +542,36 @@ def bip39_to_seed(mnemonic, passphrase):
        
        
        
       +# extended pubkeys
       +
       +def is_xpubkey(x_pubkey):
       +    return x_pubkey[0:2] == 'ff'
       +
       +def parse_xpubkey(x_pubkey):
       +    assert x_pubkey[0:2] == 'ff'
       +    return BIP32_KeyStore.parse_xpubkey(x_pubkey)
       +
       +def xpubkey_to_address(x_pubkey):
       +    if x_pubkey[0:2] in ['02','03','04']:
       +        pubkey = x_pubkey
       +    elif x_pubkey[0:2] == 'ff':
       +        xpub, s = BIP32_KeyStore.parse_xpubkey(x_pubkey)
       +        pubkey = BIP32_KeyStore.derive_pubkey_from_xpub(xpub, s[0], s[1])
       +    elif x_pubkey[0:2] == 'fe':
       +        mpk, s = Old_KeyStore.parse_xpubkey(x_pubkey)
       +        pubkey = Old_KeyStore.get_pubkey_from_mpk(mpk.decode('hex'), s[0], s[1])
       +    elif x_pubkey[0:2] == 'fd':
       +        addrtype = ord(x_pubkey[2:4].decode('hex'))
       +        hash160 = x_pubkey[4:].decode('hex')
       +        pubkey = None
       +        address = hash_160_to_bc_address(hash160, addrtype)
       +    else:
       +        raise BaseException("Cannnot parse pubkey")
       +    if pubkey:
       +        address = public_key_to_bc_address(pubkey.decode('hex'))
       +    return pubkey, address
       +
       +
        keystores = []
        
        def load_keystore(storage, name):
   DIR diff --git a/lib/transaction.py b/lib/transaction.py
       t@@ -41,6 +41,7 @@ import struct
        import struct
        import StringIO
        import random
       +from keystore import xpubkey_to_address
        
        NO_SIGNATURE = 'ff'
        
       t@@ -291,38 +292,6 @@ def parse_sig(x_sig):
                    s.append(None)
            return s
        
       -def is_extended_pubkey(x_pubkey):
       -    return x_pubkey[0:2] in ['fe', 'ff']
       -
       -def x_to_xpub(x_pubkey):
       -    if x_pubkey[0:2] == 'ff':
       -        from account import BIP32_Account
       -        xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       -        return xpub
       -
       -
       -
       -def parse_xpub(x_pubkey):
       -    if x_pubkey[0:2] in ['02','03','04']:
       -        pubkey = x_pubkey
       -    elif x_pubkey[0:2] == 'ff':
       -        from account import BIP32_Account
       -        xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       -        pubkey = BIP32_Account.derive_pubkey_from_xpub(xpub, s[0], s[1])
       -    elif x_pubkey[0:2] == 'fe':
       -        from account import OldAccount
       -        mpk, s = OldAccount.parse_xpubkey(x_pubkey)
       -        pubkey = OldAccount.get_pubkey_from_mpk(mpk.decode('hex'), s[0], s[1])
       -    elif x_pubkey[0:2] == 'fd':
       -        addrtype = ord(x_pubkey[2:4].decode('hex'))
       -        hash160 = x_pubkey[4:].decode('hex')
       -        pubkey = None
       -        address = hash_160_to_bc_address(hash160, addrtype)
       -    else:
       -        raise BaseException("Cannnot parse pubkey")
       -    if pubkey:
       -        address = public_key_to_bc_address(pubkey.decode('hex'))
       -    return pubkey, address
        
        
        def parse_scriptSig(d, bytes):
       t@@ -353,7 +322,7 @@ def parse_scriptSig(d, bytes):
                x_pubkey = decoded[1][1].encode('hex')
                try:
                    signatures = parse_sig([sig])
       -            pubkey, address = parse_xpub(x_pubkey)
       +            pubkey, address = xpubkey_to_address(x_pubkey)
                except:
                    import traceback
                    traceback.print_exc(file=sys.stdout)
       t@@ -382,7 +351,7 @@ def parse_scriptSig(d, bytes):
                print_error("cannot find address in input script", bytes.encode('hex'))
                return
            x_pubkeys = map(lambda x: x[1].encode('hex'), dec2[1:-2])
       -    pubkeys = [parse_xpub(x)[0] for x in x_pubkeys]     # xpub, addr = parse_xpub()
       +    pubkeys = [xpubkey_to_address(x)[0] for x in x_pubkeys]
            redeemScript = Transaction.multisig_script(pubkeys, m)
            # write result in d
            d['num_sig'] = m
   DIR diff --git a/plugins/cosigner_pool/qt.py b/plugins/cosigner_pool/qt.py
       t@@ -157,14 +157,13 @@ class Plugin(BasePlugin):
                    d.cosigner_send_button.hide()
        
            def cosigner_can_sign(self, tx, cosigner_xpub):
       -        from electrum.transaction import x_to_xpub
       +        from electrum.keystore import is_xpubkey, parse_xpubkey
                xpub_set = set([])
                for txin in tx.inputs():
                    for x_pubkey in txin['x_pubkeys']:
       -                xpub = x_to_xpub(x_pubkey)
       -                if xpub:
       +                if is_xpubkey(x_pubkey):
       +                    xpub, s = parse_xpubkey(x_pubkey)
                            xpub_set.add(xpub)
       -
                return cosigner_xpub in xpub_set
        
            def do_send(self, tx):
   DIR diff --git a/plugins/trezor/plugin.py b/plugins/trezor/plugin.py
       t@@ -5,15 +5,13 @@ import threading
        from binascii import hexlify, unhexlify
        from functools import partial
        
       -from electrum.account import BIP32_Account
        from electrum.bitcoin import (bc_address_to_hash_160, xpub_from_pubkey,
                                      public_key_to_bc_address, EncodeBase58Check,
                                      TYPE_ADDRESS, TYPE_SCRIPT)
        from electrum.i18n import _
        from electrum.plugins import BasePlugin, hook
       -from electrum.transaction import (deserialize, is_extended_pubkey,
       -                                  Transaction, x_to_xpub)
       -from electrum.keystore import Hardware_KeyStore
       +from electrum.transaction import deserialize, Transaction
       +from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
        
        from ..hw_wallet import HW_PluginBase
        
       t@@ -66,9 +64,9 @@ class TrezorCompatibleKeyStore(Hardware_KeyStore):
                    tx_hash = txin['prevout_hash']
                    prev_tx[tx_hash] = txin['prev_tx'] 
                    for x_pubkey in txin['x_pubkeys']:
       -                if not is_extended_pubkey(x_pubkey):
       +                if not is_xpubkey(x_pubkey):
                            continue
       -                xpub = x_to_xpub(x_pubkey)
       +                xpub, s = parse_xpubkey(x_pubkey)
                        if xpub == self.get_master_public_key():
                            xpub_path[xpub] = self.get_derivation()
        
       t@@ -254,13 +252,13 @@ class TrezorCompatiblePlugin(HW_PluginBase):
                            x_pubkeys = txin['x_pubkeys']
                            if len(x_pubkeys) == 1:
                                x_pubkey = x_pubkeys[0]
       -                        xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       +                        xpub, s = parse_xpubkey(x_pubkey)
                                xpub_n = self.client_class.expand_path(self.xpub_path[xpub])
                                txinputtype.address_n.extend(xpub_n + s)
                            else:
                                def f(x_pubkey):
       -                            if is_extended_pubkey(x_pubkey):
       -                                xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       +                            if is_xpubkey(x_pubkey):
       +                                xpub, s = parse_xpubkey(x_pubkey)
                                    else:
                                        xpub = xpub_from_pubkey(x_pubkey.decode('hex'))
                                        s = []
       t@@ -278,8 +276,8 @@ class TrezorCompatiblePlugin(HW_PluginBase):
                                )
                                # find which key is mine
                                for x_pubkey in x_pubkeys:
       -                            if is_extended_pubkey(x_pubkey):
       -                                xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       +                            if is_xpubkey(x_pubkey):
       +                                xpub, s = parse_xpubkey(x_pubkey)
                                        if xpub in self.xpub_path:
                                            xpub_n = self.client_class.expand_path(self.xpub_path[xpub])
                                            txinputtype.address_n.extend(xpub_n + s)