tfix pubkey indexing in imported wallets - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit f0611c456938eb485da765895dc482456fa292d1 DIR parent f4d5efbf3b09d9798fbdd05a6d57ec8b8a1ab076 HTML 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