electrum

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

commit bfd7709ccd023fb18d60346f09cd3240e51dc732
parent f6e393d7b602029aad82fc138abd5e5f32390d91
Author: ThomasV <thomasv@electrum.org>
Date:   Wed, 17 Aug 2016 14:28:37 +0200

move xpubkey logic to keystore and fix it

Diffstat:
Mgui/qt/main_window.py | 4++--
Mgui/qt/request_list.py | 2+-
Mlib/keystore.py | 52+++++++++++++++++++++++++++++++++++++++++++++++++---
Mlib/transaction.py | 37+++----------------------------------
Mplugins/cosigner_pool/qt.py | 7+++----
Mplugins/trezor/plugin.py | 20+++++++++-----------
6 files changed, 67 insertions(+), 55 deletions(-)

diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py @@ -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): @@ -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() diff --git a/gui/qt/request_list.py b/gui/qt/request_list.py @@ -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) diff --git a/lib/keystore.py b/lib/keystore.py @@ -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): @@ -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:] @@ -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): diff --git a/lib/transaction.py b/lib/transaction.py @@ -41,6 +41,7 @@ import struct import struct import StringIO import random +from keystore import xpubkey_to_address NO_SIGNATURE = 'ff' @@ -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): @@ -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) @@ -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 diff --git a/plugins/cosigner_pool/qt.py b/plugins/cosigner_pool/qt.py @@ -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): diff --git a/plugins/trezor/plugin.py b/plugins/trezor/plugin.py @@ -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 @@ -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() @@ -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 = [] @@ -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)