tfix pubkey indexing in imported wallets - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit f0611c456938eb485da765895dc482456fa292d1
 (DIR) parent f4d5efbf3b09d9798fbdd05a6d57ec8b8a1ab076
 (HTM) Author: ThomasV <thomasv@electrum.org>
       Date:   Wed, 12 Oct 2016 12:03:56 +0200
       
       fix pubkey indexing in imported wallets
       
       Diffstat:
         M gui/qt/address_list.py              |       6 +++---
         M lib/keystore.py                     |      28 +++++++---------------------
         M lib/wallet.py                       |      53 ++++++++++++++++++++++++++-----
       
       3 files changed, 55 insertions(+), 32 deletions(-)
       ---
 (DIR) diff --git a/gui/qt/address_list.py b/gui/qt/address_list.py
       t@@ -95,9 +95,9 @@ class AddressList(MyTreeWidget):
                                address_item.addChild(utxo_item)
        
            def create_menu(self, position):
       -        from electrum.wallet import Multisig_Wallet, Imported_Wallet
       +        from electrum.wallet import Multisig_Wallet
                is_multisig = isinstance(self.wallet, Multisig_Wallet)
       -        is_imported = isinstance(self.wallet, Imported_Wallet)
       +        can_delete = self.wallet.can_delete_address()
                selected = self.selectedItems()
                multi_select = len(selected) > 1
                addrs = [unicode(item.text(0)) for item in selected]
       t@@ -131,7 +131,7 @@ class AddressList(MyTreeWidget):
                    if not is_multisig and not self.wallet.is_watching_only():
                        menu.addAction(_("Sign/verify message"), lambda: self.parent.sign_verify_message(addr))
                        menu.addAction(_("Encrypt/decrypt message"), lambda: self.parent.encrypt_message(addr))
       -            if is_imported:
       +            if can_delete:
                        menu.addAction(_("Remove from wallet"), lambda: self.parent.remove_address(addr))
                    addr_URL = block_explorer_URL(self.config, 'addr', addr)
                    if addr_URL:
 (DIR) diff --git a/lib/keystore.py b/lib/keystore.py
       t@@ -116,8 +116,6 @@ class Imported_KeyStore(Software_KeyStore):
            def __init__(self, d):
                Software_KeyStore.__init__(self)
                self.keypairs = d.get('keypairs', {})
       -        self.receiving_pubkeys = self.keypairs.keys()
       -        self.change_pubkeys = []
        
            def is_deterministic(self):
                return False
       t@@ -138,7 +136,8 @@ class Imported_KeyStore(Software_KeyStore):
                return True
        
            def check_password(self, password):
       -        self.get_private_key((0,0), password)
       +        pubkey = self.keypairs.keys()[0]
       +        self.get_private_key(pubkey, password)
        
            def import_key(self, sec, password):
                try:
       t@@ -147,24 +146,12 @@ class Imported_KeyStore(Software_KeyStore):
                    raise BaseException('Invalid private key')
                # allow overwrite
                self.keypairs[pubkey] = pw_encode(sec, password)
       -        self.receiving_pubkeys = self.keypairs.keys()
                return pubkey
        
            def delete_imported_key(self, key):
                self.keypairs.pop(key)
        
       -    def get_public_key(self, sequence):
       -        for_change, i = sequence
       -        pubkey = (self.change_pubkeys if for_change else self.receiving_pubkeys)[i]
       -        return pubkey
       -
       -    def get_xpubkey(self, c, i):
       -        return self.get_public_key((c,i))
       -
       -    def get_private_key(self, sequence, password):
       -        for_change, i = sequence
       -        assert for_change == 0
       -        pubkey = self.receiving_pubkeys[i]
       +    def get_private_key(self, pubkey, password):
                pk = pw_decode(self.keypairs[pubkey], password)
                # this checks the password
                if pubkey != public_key_from_private_key(pk):
       t@@ -173,15 +160,14 @@ class Imported_KeyStore(Software_KeyStore):
        
            def get_pubkey_derivation(self, x_pubkey):
                if x_pubkey[0:2] in ['02', '03', '04']:
       -            if x_pubkey in self.receiving_pubkeys:
       -                i = self.receiving_pubkeys.index(x_pubkey)
       -                return (False, i)
       +            if x_pubkey in self.keypairs.keys():
       +                return x_pubkey
                elif x_pubkey[0:2] == 'fd':
                    # fixme: this assumes p2pkh
                    _, addr = xpubkey_to_address(x_pubkey)
       -            for i, pubkey in enumerate(self.receiving_pubkeys):
       +            for pubkey in self.keypairs.keys():
                        if public_key_to_bc_address(pubkey.decode('hex')) == addr:
       -                    return (False, i)
       +                    return pubkey
        
            def update_password(self, old_password, new_password):
                self.check_password(old_password)
 (DIR) diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -269,8 +269,23 @@ class Abstract_Wallet(PrintError):
            def get_private_key(self, address, password):
                if self.is_watching_only():
                    return []
       -        sequence = self.get_address_index(address)
       -        return [ self.keystore.get_private_key(sequence, password) ]
       +        if self.keystore.can_import():
       +            i = self.receiving_addresses.index(address)
       +            pubkey = self.receiving_pubkeys[i]
       +            pk = self.keystore.get_private_key(pubkey, password)
       +        else:
       +            sequence = self.get_address_index(address)
       +            pk = self.keystore.get_private_key(sequence, password)
       +        return [pk]
       +
       +    def get_public_key(self, address):
       +        if self.keystore.can_import():
       +            i = self.receiving_addresses.index(address)
       +            pubkey = self.receiving_pubkeys[i]
       +        else:
       +            sequence = self.get_address_index(address)
       +            pubkey = self.get_pubkey(*sequence)
       +        return pubkey
        
            def get_public_keys(self, address):
                sequence = self.get_address_index(address)
       t@@ -1170,7 +1185,6 @@ class Abstract_Wallet(PrintError):
                self.receive_requests[key] = req
                self.storage.put('payment_requests', self.receive_requests)
        
       -
            def add_payment_request(self, req, config):
                import os
                addr = req['address']
       t@@ -1231,6 +1245,9 @@ class Abstract_Wallet(PrintError):
            def can_import_address(self):
                return False
        
       +    def can_delete_address(self):
       +        return False
       +
            def add_address(self, address):
                if address not in self.history:
                    self.history[address] = []
       t@@ -1302,6 +1319,9 @@ class Imported_Wallet(Abstract_Wallet):
                self.add_address(address)
                return address
        
       +    def can_delete_address(self):
       +        return True
       +
            def delete_address(self, address):
                if address not in self.addresses:
                    return
       t@@ -1336,8 +1356,7 @@ class P2PK_Wallet(Abstract_Wallet):
                return pubkey_list[i]
        
            def get_public_keys(self, address):
       -        sequence = self.get_address_index(address)
       -        return [self.get_pubkey(*sequence)]
       +        return [self.get_public_key(address)]
        
            def get_pubkey_index(self, pubkey):
                if pubkey in self.receiving_pubkeys:
       t@@ -1347,9 +1366,15 @@ class P2PK_Wallet(Abstract_Wallet):
                raise BaseExeption('pubkey not found')
        
            def add_input_sig_info(self, txin, address):
       -        txin['derivation'] = derivation = self.get_address_index(address)
       -        x_pubkey = self.keystore.get_xpubkey(*derivation)
       -        pubkey = self.get_pubkey(*derivation)
       +        if not self.keystore.can_import():
       +            txin['derivation'] = derivation = self.get_address_index(address)
       +            x_pubkey = self.keystore.get_xpubkey(*derivation)
       +            pubkey = self.get_pubkey(*derivation)
       +        else:
       +            pubkey = self.get_public_key(address)
       +            assert pubkey is not None
       +            x_pubkey = pubkey
       +
                txin['x_pubkeys'] = [x_pubkey]
                txin['pubkeys'] = [pubkey]
                txin['signatures'] = [None]
       t@@ -1527,6 +1552,17 @@ class Standard_Wallet(Deterministic_Wallet, P2PK_Wallet):
            def save_keystore(self):
                self.storage.put('keystore', self.keystore.dump())
        
       +    def can_delete_address(self):
       +        return self.keystore.can_import()
       +
       +    def delete_address(self, address):
       +        pubkey = self.get_public_key(address)
       +        self.keystore.delete_imported_key(pubkey)
       +        self.save_keystore()
       +        self.receiving_pubkeys.remove(pubkey)
       +        self.receiving_addresses.remove(addr)
       +        self.storage.write()
       +
            def can_import_privkey(self):
                return self.keystore.can_import()
        
       t@@ -1537,6 +1573,7 @@ class Standard_Wallet(Deterministic_Wallet, P2PK_Wallet):
                self.save_pubkeys()
                addr = self.pubkeys_to_address(pubkey)
                self.receiving_addresses.append(addr)
       +        self.storage.write()
                self.add_address(addr)
                return addr