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:
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)