integrate electrum-3.0.6 changes
This commit is contained in:
parent
a3aa9f4015
commit
184a9d68d8
|
@ -1,3 +1,7 @@
|
||||||
|
# Release 3.0.6 :
|
||||||
|
|
||||||
|
* Integrate changes from Electrum-3.0.6
|
||||||
|
|
||||||
# Release 3.0.5 : (Security update)
|
# Release 3.0.5 : (Security update)
|
||||||
|
|
||||||
This is a follow-up to the 3.0.4 release, which did not completely fix
|
This is a follow-up to the 3.0.4 release, which did not completely fix
|
||||||
|
|
|
@ -278,6 +278,7 @@ def run_offline_command(config, config_options):
|
||||||
# arguments passed to function
|
# arguments passed to function
|
||||||
args = [config.get(x) for x in cmd.params]
|
args = [config.get(x) for x in cmd.params]
|
||||||
# decode json arguments
|
# decode json arguments
|
||||||
|
if cmdname not in ('setconfig',):
|
||||||
args = list(map(json_decode, args))
|
args = list(map(json_decode, args))
|
||||||
# options
|
# options
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
|
|
@ -923,6 +923,10 @@ class ElectrumWindow(App):
|
||||||
return
|
return
|
||||||
if not self.wallet.can_export():
|
if not self.wallet.can_export():
|
||||||
return
|
return
|
||||||
|
try:
|
||||||
key = str(self.wallet.export_private_key(addr, password)[0])
|
key = str(self.wallet.export_private_key(addr, password)[0])
|
||||||
pk_label.data = key
|
pk_label.data = key
|
||||||
|
except InvalidPassword:
|
||||||
|
self.show_error("Invalid PIN")
|
||||||
|
return
|
||||||
self.protected(_("Enter your PIN code in order to decrypt your private key"), show_private_key, (addr, pk_label))
|
self.protected(_("Enter your PIN code in order to decrypt your private key"), show_private_key, (addr, pk_label))
|
||||||
|
|
|
@ -93,6 +93,6 @@ class AddressDialog(WindowModalDialog):
|
||||||
def show_qr(self):
|
def show_qr(self):
|
||||||
text = self.address
|
text = self.address
|
||||||
try:
|
try:
|
||||||
self.parent.show_qrcode(text, 'Address')
|
self.parent.show_qrcode(text, 'Address', parent=self)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.show_message(str(e))
|
self.show_message(str(e))
|
||||||
|
|
|
@ -2135,6 +2135,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
self.show_message(_("This is a watching-only wallet"))
|
self.show_message(_("This is a watching-only wallet"))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if isinstance(self.wallet, Multisig_Wallet):
|
||||||
|
self.show_message(_('WARNING: This is a multi-signature wallet.') + '\n' +
|
||||||
|
_('It can not be "backed up" by simply exporting these private keys.'))
|
||||||
|
|
||||||
d = WindowModalDialog(self, _('Private keys'))
|
d = WindowModalDialog(self, _('Private keys'))
|
||||||
d.setMinimumSize(850, 300)
|
d.setMinimumSize(850, 300)
|
||||||
vbox = QVBoxLayout(d)
|
vbox = QVBoxLayout(d)
|
||||||
|
@ -2160,14 +2164,16 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
private_keys = {}
|
private_keys = {}
|
||||||
addresses = self.wallet.get_addresses()
|
addresses = self.wallet.get_addresses()
|
||||||
done = False
|
done = False
|
||||||
|
cancelled = False
|
||||||
def privkeys_thread():
|
def privkeys_thread():
|
||||||
for addr in addresses:
|
for addr in addresses:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
if done:
|
if done or cancelled:
|
||||||
break
|
break
|
||||||
privkey = self.wallet.export_private_key(addr, password)[0]
|
privkey = self.wallet.export_private_key(addr, password)[0]
|
||||||
private_keys[addr] = privkey
|
private_keys[addr] = privkey
|
||||||
self.computing_privkeys_signal.emit()
|
self.computing_privkeys_signal.emit()
|
||||||
|
if not cancelled:
|
||||||
self.computing_privkeys_signal.disconnect()
|
self.computing_privkeys_signal.disconnect()
|
||||||
self.show_privkeys_signal.emit()
|
self.show_privkeys_signal.emit()
|
||||||
|
|
||||||
|
@ -2176,9 +2182,20 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
e.setText(s)
|
e.setText(s)
|
||||||
b.setEnabled(True)
|
b.setEnabled(True)
|
||||||
self.show_privkeys_signal.disconnect()
|
self.show_privkeys_signal.disconnect()
|
||||||
|
nonlocal done
|
||||||
|
done = True
|
||||||
|
|
||||||
|
def on_dialog_closed(*args):
|
||||||
|
nonlocal done
|
||||||
|
nonlocal cancelled
|
||||||
|
if not done:
|
||||||
|
cancelled = True
|
||||||
|
self.computing_privkeys_signal.disconnect()
|
||||||
|
self.show_privkeys_signal.disconnect()
|
||||||
|
|
||||||
self.computing_privkeys_signal.connect(lambda: e.setText("Please wait... %d/%d"%(len(private_keys),len(addresses))))
|
self.computing_privkeys_signal.connect(lambda: e.setText("Please wait... %d/%d"%(len(private_keys),len(addresses))))
|
||||||
self.show_privkeys_signal.connect(show_privkeys)
|
self.show_privkeys_signal.connect(show_privkeys)
|
||||||
|
d.finished.connect(on_dialog_closed)
|
||||||
threading.Thread(target=privkeys_thread).start()
|
threading.Thread(target=privkeys_thread).start()
|
||||||
|
|
||||||
if not d.exec_():
|
if not d.exec_():
|
||||||
|
@ -2549,7 +2566,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
unit_combo = QComboBox()
|
unit_combo = QComboBox()
|
||||||
unit_combo.addItems(units)
|
unit_combo.addItems(units)
|
||||||
unit_combo.setCurrentIndex(units.index(self.base_unit()))
|
unit_combo.setCurrentIndex(units.index(self.base_unit()))
|
||||||
def on_unit(x):
|
def on_unit(x, nz):
|
||||||
unit_result = units[unit_combo.currentIndex()]
|
unit_result = units[unit_combo.currentIndex()]
|
||||||
if self.base_unit() == unit_result:
|
if self.base_unit() == unit_result:
|
||||||
return
|
return
|
||||||
|
@ -2564,13 +2581,14 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
else:
|
else:
|
||||||
raise Exception('Unknown base unit')
|
raise Exception('Unknown base unit')
|
||||||
self.config.set_key('decimal_point', self.decimal_point, True)
|
self.config.set_key('decimal_point', self.decimal_point, True)
|
||||||
|
nz.setMaximum(self.decimal_point)
|
||||||
self.history_list.update()
|
self.history_list.update()
|
||||||
self.request_list.update()
|
self.request_list.update()
|
||||||
self.address_list.update()
|
self.address_list.update()
|
||||||
for edit, amount in zip(edits, amounts):
|
for edit, amount in zip(edits, amounts):
|
||||||
edit.setAmount(amount)
|
edit.setAmount(amount)
|
||||||
self.update_status()
|
self.update_status()
|
||||||
unit_combo.currentIndexChanged.connect(on_unit)
|
unit_combo.currentIndexChanged.connect(lambda x: on_unit(x, nz))
|
||||||
gui_widgets.append((unit_label, unit_combo))
|
gui_widgets.append((unit_label, unit_combo))
|
||||||
|
|
||||||
block_explorers = sorted(util.block_explorer_info().keys())
|
block_explorers = sorted(util.block_explorer_info().keys())
|
||||||
|
|
|
@ -113,8 +113,7 @@ class QRDialog(WindowModalDialog):
|
||||||
|
|
||||||
def copy_to_clipboard():
|
def copy_to_clipboard():
|
||||||
p = qscreen.grabWindow(qrw.winId())
|
p = qscreen.grabWindow(qrw.winId())
|
||||||
p.save(filename, 'png')
|
QApplication.clipboard().setPixmap(p)
|
||||||
QApplication.clipboard().setImage(QImage(filename))
|
|
||||||
self.show_message(_("QR code copied to clipboard"))
|
self.show_message(_("QR code copied to clipboard"))
|
||||||
|
|
||||||
b = QPushButton(_("Copy"))
|
b = QPushButton(_("Copy"))
|
||||||
|
|
16
gui/stdio.py
16
gui/stdio.py
|
@ -85,12 +85,11 @@ class ElectrumGui:
|
||||||
delta = (80 - sum(width) - 4)/3
|
delta = (80 - sum(width) - 4)/3
|
||||||
format_str = "%"+"%d"%width[0]+"s"+"%"+"%d"%(width[1]+delta)+"s"+"%" \
|
format_str = "%"+"%d"%width[0]+"s"+"%"+"%d"%(width[1]+delta)+"s"+"%" \
|
||||||
+ "%d"%(width[2]+delta)+"s"+"%"+"%d"%(width[3]+delta)+"s"
|
+ "%d"%(width[2]+delta)+"s"+"%"+"%d"%(width[3]+delta)+"s"
|
||||||
b = 0
|
|
||||||
messages = []
|
messages = []
|
||||||
|
|
||||||
for item in self.wallet.get_history():
|
for item in self.wallet.get_history():
|
||||||
tx_hash, confirmations, value, timestamp, balance = item
|
tx_hash, height, conf, timestamp, delta, balance = item
|
||||||
if confirmations:
|
if conf:
|
||||||
try:
|
try:
|
||||||
time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
|
time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -99,7 +98,7 @@ class ElectrumGui:
|
||||||
time_str = 'unconfirmed'
|
time_str = 'unconfirmed'
|
||||||
|
|
||||||
label = self.wallet.get_label(tx_hash)
|
label = self.wallet.get_label(tx_hash)
|
||||||
messages.append( format_str%( time_str, label, format_satoshis(value, whitespaces=True), format_satoshis(balance, whitespaces=True) ) )
|
messages.append( format_str%( time_str, label, format_satoshis(delta, whitespaces=True), format_satoshis(balance, whitespaces=True) ) )
|
||||||
|
|
||||||
self.print_list(messages[::-1], format_str%( _("Date"), _("Description"), _("Amount"), _("Balance")))
|
self.print_list(messages[::-1], format_str%( _("Date"), _("Description"), _("Amount"), _("Balance")))
|
||||||
|
|
||||||
|
@ -149,12 +148,13 @@ class ElectrumGui:
|
||||||
for i, x in enumerate( self.wallet.network.banner.split('\n') ):
|
for i, x in enumerate( self.wallet.network.banner.split('\n') ):
|
||||||
print( x )
|
print( x )
|
||||||
|
|
||||||
def print_list(self, list, firstline):
|
def print_list(self, lst, firstline):
|
||||||
self.maxpos = len(list)
|
lst = list(lst)
|
||||||
|
self.maxpos = len(lst)
|
||||||
if not self.maxpos: return
|
if not self.maxpos: return
|
||||||
print(firstline)
|
print(firstline)
|
||||||
for i in range(self.maxpos):
|
for i in range(self.maxpos):
|
||||||
msg = list[i] if i < len(list) else ""
|
msg = lst[i] if i < len(lst) else ""
|
||||||
print(msg)
|
print(msg)
|
||||||
|
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ class ElectrumGui:
|
||||||
print(_('Invalid Fee'))
|
print(_('Invalid Fee'))
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.wallet.use_encryption:
|
if self.wallet.has_password():
|
||||||
password = self.password_dialog()
|
password = self.password_dialog()
|
||||||
if not password:
|
if not password:
|
||||||
return
|
return
|
||||||
|
|
BIN
icons/unpaid.png
BIN
icons/unpaid.png
Binary file not shown.
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 23 KiB |
|
@ -34,7 +34,7 @@ from functools import wraps
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from .import util
|
from .import util
|
||||||
from .util import bfh, bh2u, format_satoshis
|
from .util import bfh, bh2u, format_satoshis, json_decode
|
||||||
from .import bitcoin
|
from .import bitcoin
|
||||||
from .bitcoin import is_address, hash_160, COIN, TYPE_ADDRESS
|
from .bitcoin import is_address, hash_160, COIN, TYPE_ADDRESS
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
|
@ -151,10 +151,8 @@ class Commands:
|
||||||
@command('')
|
@command('')
|
||||||
def setconfig(self, key, value):
|
def setconfig(self, key, value):
|
||||||
"""Set a configuration variable. 'value' may be a string or a Python expression."""
|
"""Set a configuration variable. 'value' may be a string or a Python expression."""
|
||||||
try:
|
if key not in ('rpcuser', 'rpcpassword'):
|
||||||
value = ast.literal_eval(value)
|
value = json_decode(value)
|
||||||
except:
|
|
||||||
pass
|
|
||||||
self.config.set_key(key, value)
|
self.config.set_key(key, value)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import sys
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import time
|
import time
|
||||||
import csv
|
import csv
|
||||||
|
import decimal
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from .bitcoin import COIN
|
from .bitcoin import COIN
|
||||||
|
@ -197,7 +198,11 @@ class FxThread(ThreadJob):
|
||||||
def ccy_amount_str(self, amount, commas):
|
def ccy_amount_str(self, amount, commas):
|
||||||
prec = CCY_PRECISIONS.get(self.ccy, 2)
|
prec = CCY_PRECISIONS.get(self.ccy, 2)
|
||||||
fmt_str = "{:%s.%df}" % ("," if commas else "", max(0, prec))
|
fmt_str = "{:%s.%df}" % ("," if commas else "", max(0, prec))
|
||||||
return fmt_str.format(round(amount, prec))
|
try:
|
||||||
|
rounded_amount = round(amount, prec)
|
||||||
|
except decimal.InvalidOperation:
|
||||||
|
rounded_amount = amount
|
||||||
|
return fmt_str.format(rounded_amount)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# This runs from the plugins thread which catches exceptions
|
# This runs from the plugins thread which catches exceptions
|
||||||
|
|
|
@ -171,6 +171,9 @@ class Mnemonic(object):
|
||||||
n_custom = int(math.ceil(math.log(custom_entropy, 2)))
|
n_custom = int(math.ceil(math.log(custom_entropy, 2)))
|
||||||
n = max(16, num_bits - n_custom)
|
n = max(16, num_bits - n_custom)
|
||||||
print_error("make_seed", prefix, "adding %d bits"%n)
|
print_error("make_seed", prefix, "adding %d bits"%n)
|
||||||
|
my_entropy = 1
|
||||||
|
while my_entropy < pow(2, n - bpw):
|
||||||
|
# try again if seed would not contain enough words
|
||||||
my_entropy = ecdsa.util.randrange(pow(2, n))
|
my_entropy = ecdsa.util.randrange(pow(2, n))
|
||||||
nonce = 0
|
nonce = 0
|
||||||
while True:
|
while True:
|
||||||
|
|
|
@ -45,6 +45,14 @@ class SerializationError(Exception):
|
||||||
""" Thrown when there's a problem deserializing or serializing """
|
""" Thrown when there's a problem deserializing or serializing """
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownTxinType(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NotRecognizedRedeemScript(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BCDataStream(object):
|
class BCDataStream(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.input = None
|
self.input = None
|
||||||
|
@ -302,7 +310,8 @@ def parse_scriptSig(d, _bytes):
|
||||||
if match_decoded(decoded, match):
|
if match_decoded(decoded, match):
|
||||||
item = decoded[0][1]
|
item = decoded[0][1]
|
||||||
if item[0] != 0:
|
if item[0] != 0:
|
||||||
# payto_pubkey
|
# assert item[0] == 0x30
|
||||||
|
# pay-to-pubkey
|
||||||
d['type'] = 'p2pk'
|
d['type'] = 'p2pk'
|
||||||
d['address'] = "(pubkey)"
|
d['address'] = "(pubkey)"
|
||||||
d['signatures'] = [bh2u(item)]
|
d['signatures'] = [bh2u(item)]
|
||||||
|
@ -358,7 +367,7 @@ def parse_redeemScript(s):
|
||||||
match_multisig = [ op_m ] + [opcodes.OP_PUSHDATA4]*n + [ op_n, opcodes.OP_CHECKMULTISIG ]
|
match_multisig = [ op_m ] + [opcodes.OP_PUSHDATA4]*n + [ op_n, opcodes.OP_CHECKMULTISIG ]
|
||||||
if not match_decoded(dec2, match_multisig):
|
if not match_decoded(dec2, match_multisig):
|
||||||
print_error("cannot find address in input script", bh2u(s))
|
print_error("cannot find address in input script", bh2u(s))
|
||||||
return
|
raise NotRecognizedRedeemScript()
|
||||||
x_pubkeys = [bh2u(x[1]) for x in dec2[1:-2]]
|
x_pubkeys = [bh2u(x[1]) for x in dec2[1:-2]]
|
||||||
pubkeys = [safe_parse_pubkey(x) for x in x_pubkeys]
|
pubkeys = [safe_parse_pubkey(x) for x in x_pubkeys]
|
||||||
redeemScript = multisig_script(pubkeys, m)
|
redeemScript = multisig_script(pubkeys, m)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
ELECTRUM_VERSION = '3.0.5' # version of the client package
|
ELECTRUM_VERSION = '3.0.6' # version of the client package
|
||||||
PROTOCOL_VERSION = '1.2' # protocol version requested
|
PROTOCOL_VERSION = '1.2' # protocol version requested
|
||||||
|
|
||||||
# The hash of the mnemonic seed must begin with this
|
# The hash of the mnemonic seed must begin with this
|
||||||
|
|
|
@ -360,6 +360,7 @@ class Abstract_Wallet(PrintError):
|
||||||
def add_unverified_tx(self, tx_hash, tx_height):
|
def add_unverified_tx(self, tx_hash, tx_height):
|
||||||
if tx_height == 0 and tx_hash in self.verified_tx:
|
if tx_height == 0 and tx_hash in self.verified_tx:
|
||||||
self.verified_tx.pop(tx_hash)
|
self.verified_tx.pop(tx_hash)
|
||||||
|
if self.verifier:
|
||||||
self.verifier.merkle_roots.pop(tx_hash, None)
|
self.verifier.merkle_roots.pop(tx_hash, None)
|
||||||
|
|
||||||
# tx will be verified only if height > 0
|
# tx will be verified only if height > 0
|
||||||
|
|
|
@ -84,7 +84,8 @@ class WsClientThread(util.DaemonThread):
|
||||||
l = self.subscriptions.get(addr, [])
|
l = self.subscriptions.get(addr, [])
|
||||||
l.append((ws, amount))
|
l.append((ws, amount))
|
||||||
self.subscriptions[addr] = l
|
self.subscriptions[addr] = l
|
||||||
self.network.send([('blockchain.address.subscribe', [addr])], self.response_queue.put)
|
h = self.network.addr_to_scripthash(addr)
|
||||||
|
self.network.send([('blockchain.scripthash.subscribe', [h])], self.response_queue.put)
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -100,10 +101,13 @@ class WsClientThread(util.DaemonThread):
|
||||||
result = r.get('result')
|
result = r.get('result')
|
||||||
if result is None:
|
if result is None:
|
||||||
continue
|
continue
|
||||||
if method == 'blockchain.address.subscribe':
|
if method == 'blockchain.scripthash.subscribe':
|
||||||
self.network.send([('blockchain.address.get_balance', params)], self.response_queue.put)
|
self.network.send([('blockchain.scripthash.get_balance', params)], self.response_queue.put)
|
||||||
elif method == 'blockchain.address.get_balance':
|
elif method == 'blockchain.scripthash.get_balance':
|
||||||
addr = params[0]
|
h = params[0]
|
||||||
|
addr = self.network.h2addr.get(h, None)
|
||||||
|
if addr is None:
|
||||||
|
util.print_error("can't find address for scripthash: %s" % h)
|
||||||
l = self.subscriptions.get(addr, [])
|
l = self.subscriptions.get(addr, [])
|
||||||
for ws, amount in l:
|
for ws, amount in l:
|
||||||
if not ws.closed:
|
if not ws.closed:
|
||||||
|
|
|
@ -33,6 +33,10 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
BTCHIP = False
|
BTCHIP = False
|
||||||
|
|
||||||
|
MSG_NEEDS_FW_UPDATE_GENERIC = _('Firmware version too old. Please update at') + \
|
||||||
|
' https://www.ledgerwallet.com'
|
||||||
|
|
||||||
|
|
||||||
class Ledger_Client():
|
class Ledger_Client():
|
||||||
def __init__(self, hidDevice):
|
def __init__(self, hidDevice):
|
||||||
self.dongleObject = btchip(hidDevice)
|
self.dongleObject = btchip(hidDevice)
|
||||||
|
@ -56,6 +60,21 @@ class Ledger_Client():
|
||||||
def i4b(self, x):
|
def i4b(self, x):
|
||||||
return pack('>I', x)
|
return pack('>I', x)
|
||||||
|
|
||||||
|
def test_pin_unlocked(func):
|
||||||
|
"""Function decorator to test the Ledger for being unlocked, and if not,
|
||||||
|
raise a human-readable exception.
|
||||||
|
"""
|
||||||
|
def catch_exception(self, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
return func(self, *args, **kwargs)
|
||||||
|
except BTChipException as e:
|
||||||
|
if e.sw == 0x6982:
|
||||||
|
raise Exception(_('Your Ledger is locked. Please unlock it.'))
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
return catch_exception
|
||||||
|
|
||||||
|
@test_pin_unlocked
|
||||||
def get_xpub(self, bip32_path, xtype):
|
def get_xpub(self, bip32_path, xtype):
|
||||||
self.checkDevice()
|
self.checkDevice()
|
||||||
# bip32_path is of the form 44'/133'/1'
|
# bip32_path is of the form 44'/133'/1'
|
||||||
|
@ -72,7 +91,7 @@ class Ledger_Client():
|
||||||
if len(splitPath) > 1:
|
if len(splitPath) > 1:
|
||||||
prevPath = "/".join(splitPath[0:len(splitPath) - 1])
|
prevPath = "/".join(splitPath[0:len(splitPath) - 1])
|
||||||
nodeData = self.dongleObject.getWalletPublicKey(prevPath)
|
nodeData = self.dongleObject.getWalletPublicKey(prevPath)
|
||||||
publicKey = compress_public_key(nodeData['publicKey'])#
|
publicKey = compress_public_key(nodeData['publicKey'])
|
||||||
h = hashlib.new('ripemd160')
|
h = hashlib.new('ripemd160')
|
||||||
h.update(hashlib.sha256(publicKey).digest())
|
h.update(hashlib.sha256(publicKey).digest())
|
||||||
fingerprint = unpack(">I", h.digest()[0:4])[0]
|
fingerprint = unpack(">I", h.digest()[0:4])[0]
|
||||||
|
@ -117,7 +136,7 @@ class Ledger_Client():
|
||||||
|
|
||||||
if not checkFirmware(firmware):
|
if not checkFirmware(firmware):
|
||||||
self.dongleObject.dongle.close()
|
self.dongleObject.dongle.close()
|
||||||
raise Exception("HW1 firmware version too old. Please update at https://www.ledgerwallet.com")
|
raise Exception(MSG_NEEDS_FW_UPDATE_GENERIC)
|
||||||
try:
|
try:
|
||||||
self.dongleObject.getOperationMode()
|
self.dongleObject.getOperationMode()
|
||||||
except BTChipException as e:
|
except BTChipException as e:
|
||||||
|
|
Loading…
Reference in New Issue