Merge remote-tracking branch 'upstream/master' into upstreamMerge
@ -1,3 +1,11 @@
|
|||||||
|
# Release 3.3.2 - (December 21, 2018)
|
||||||
|
|
||||||
|
* Fix Qt history export bug
|
||||||
|
* Improve network timeouts
|
||||||
|
* Prepend server transaction_broadcast error messages with
|
||||||
|
explanatory message. Render error messages as plain text.
|
||||||
|
|
||||||
|
|
||||||
# Release 3.3.1 - (December 20, 2018)
|
# Release 3.3.1 - (December 20, 2018)
|
||||||
|
|
||||||
* Qt: Fix invoices tab crash (#4941)
|
* Qt: Fix invoices tab crash (#4941)
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit bce0d7a427ecf2106bf4d1ec56feb4067a50b234
|
Subproject commit d586021ba0d4820d6587cff000756b3d035d4f08
|
||||||
@ -109,6 +109,13 @@ class ElectrumWindow(App):
|
|||||||
def toggle_oneserver(self, x):
|
def toggle_oneserver(self, x):
|
||||||
self.oneserver = not self.oneserver
|
self.oneserver = not self.oneserver
|
||||||
|
|
||||||
|
proxy_str = StringProperty('')
|
||||||
|
def update_proxy_str(self, proxy: dict):
|
||||||
|
mode = proxy.get('mode')
|
||||||
|
host = proxy.get('host')
|
||||||
|
port = proxy.get('port')
|
||||||
|
self.proxy_str = (host + ':' + port) if mode else _('None')
|
||||||
|
|
||||||
def choose_server_dialog(self, popup):
|
def choose_server_dialog(self, popup):
|
||||||
from .uix.dialogs.choice_dialog import ChoiceDialog
|
from .uix.dialogs.choice_dialog import ChoiceDialog
|
||||||
protocol = 's'
|
protocol = 's'
|
||||||
@ -288,6 +295,7 @@ class ElectrumWindow(App):
|
|||||||
self.auto_connect = net_params.auto_connect
|
self.auto_connect = net_params.auto_connect
|
||||||
self.oneserver = net_params.oneserver
|
self.oneserver = net_params.oneserver
|
||||||
self.proxy_config = net_params.proxy if net_params.proxy else {}
|
self.proxy_config = net_params.proxy if net_params.proxy else {}
|
||||||
|
self.update_proxy_str(self.proxy_config)
|
||||||
|
|
||||||
self.plugins = kwargs.get('plugins', [])
|
self.plugins = kwargs.get('plugins', [])
|
||||||
self.gui_object = kwargs.get('gui_object', None)
|
self.gui_object = kwargs.get('gui_object', None)
|
||||||
@ -667,6 +675,7 @@ class ElectrumWindow(App):
|
|||||||
self.tabs = self.root.ids['tabs']
|
self.tabs = self.root.ids['tabs']
|
||||||
|
|
||||||
def update_interfaces(self, dt):
|
def update_interfaces(self, dt):
|
||||||
|
net_params = self.network.get_parameters()
|
||||||
self.num_nodes = len(self.network.get_interfaces())
|
self.num_nodes = len(self.network.get_interfaces())
|
||||||
self.num_chains = len(self.network.get_blockchains())
|
self.num_chains = len(self.network.get_blockchains())
|
||||||
chain = self.network.blockchain()
|
chain = self.network.blockchain()
|
||||||
@ -675,6 +684,10 @@ class ElectrumWindow(App):
|
|||||||
interface = self.network.interface
|
interface = self.network.interface
|
||||||
if interface:
|
if interface:
|
||||||
self.server_host = interface.host
|
self.server_host = interface.host
|
||||||
|
else:
|
||||||
|
self.server_host = str(net_params.host) + ' (connecting...)'
|
||||||
|
self.proxy_config = net_params.proxy or {}
|
||||||
|
self.update_proxy_str(self.proxy_config)
|
||||||
|
|
||||||
def on_network_event(self, event, *args):
|
def on_network_event(self, event, *args):
|
||||||
Logger.info('network event: '+ event)
|
Logger.info('network event: '+ event)
|
||||||
@ -924,8 +937,11 @@ class ElectrumWindow(App):
|
|||||||
self.wallet.invoices.save()
|
self.wallet.invoices.save()
|
||||||
self.update_tab('invoices')
|
self.update_tab('invoices')
|
||||||
else:
|
else:
|
||||||
msg = msg[:500] if msg else _('There was an error broadcasting the transaction.')
|
display_msg = _('The server returned an error when broadcasting the transaction.')
|
||||||
self.show_error(msg)
|
if msg:
|
||||||
|
display_msg += '\n' + msg
|
||||||
|
display_msg = display_msg[:500]
|
||||||
|
self.show_error(display_msg)
|
||||||
|
|
||||||
if self.network and self.network.is_connected():
|
if self.network and self.network.is_connected():
|
||||||
self.show_info(_('Sending'))
|
self.show_info(_('Sending'))
|
||||||
|
|||||||
@ -24,10 +24,7 @@ Popup:
|
|||||||
|
|
||||||
CardSeparator
|
CardSeparator
|
||||||
SettingsItem:
|
SettingsItem:
|
||||||
proxy: app.proxy_config.get('mode')
|
title: _("Proxy") + ': ' + app.proxy_str
|
||||||
host: app.proxy_config.get('host')
|
|
||||||
port: app.proxy_config.get('port')
|
|
||||||
title: _("Proxy") + ': ' + ((self.host +':' + self.port) if self.proxy else _('None'))
|
|
||||||
description: _('Proxy configuration')
|
description: _('Proxy configuration')
|
||||||
action: lambda x: app.popup_dialog('proxy')
|
action: lambda x: app.popup_dialog('proxy')
|
||||||
|
|
||||||
|
|||||||
@ -73,5 +73,4 @@ Popup:
|
|||||||
if proxy['mode']=='none': proxy = None
|
if proxy['mode']=='none': proxy = None
|
||||||
net_params = net_params._replace(proxy=proxy)
|
net_params = net_params._replace(proxy=proxy)
|
||||||
app.network.run_from_another_thread(app.network.set_parameters(net_params))
|
app.network.run_from_another_thread(app.network.set_parameters(net_params))
|
||||||
app.proxy_config = proxy if proxy else {}
|
|
||||||
nd.dismiss()
|
nd.dismiss()
|
||||||
|
|||||||
@ -23,7 +23,7 @@ Popup:
|
|||||||
height: '36dp'
|
height: '36dp'
|
||||||
size_hint_x: 3
|
size_hint_x: 3
|
||||||
size_hint_y: None
|
size_hint_y: None
|
||||||
text: app.server_host
|
text: app.network.get_parameters().host
|
||||||
Label:
|
Label:
|
||||||
height: '36dp'
|
height: '36dp'
|
||||||
size_hint_x: 1
|
size_hint_x: 1
|
||||||
@ -36,7 +36,7 @@ Popup:
|
|||||||
height: '36dp'
|
height: '36dp'
|
||||||
size_hint_x: 3
|
size_hint_x: 3
|
||||||
size_hint_y: None
|
size_hint_y: None
|
||||||
text: app.server_port
|
text: app.network.get_parameters().port
|
||||||
Widget
|
Widget
|
||||||
Button:
|
Button:
|
||||||
id: chooser
|
id: chooser
|
||||||
|
|||||||
@ -152,8 +152,11 @@ class AddressList(MyTreeView):
|
|||||||
is_multisig = isinstance(self.wallet, Multisig_Wallet)
|
is_multisig = isinstance(self.wallet, Multisig_Wallet)
|
||||||
can_delete = self.wallet.can_delete_address()
|
can_delete = self.wallet.can_delete_address()
|
||||||
selected = self.selected_in_column(1)
|
selected = self.selected_in_column(1)
|
||||||
|
if not selected:
|
||||||
|
return
|
||||||
multi_select = len(selected) > 1
|
multi_select = len(selected) > 1
|
||||||
addrs = [self.model().itemFromIndex(item).text() for item in selected]
|
addrs = [self.model().itemFromIndex(item).text() for item in selected]
|
||||||
|
menu = QMenu()
|
||||||
if not multi_select:
|
if not multi_select:
|
||||||
idx = self.indexAt(position)
|
idx = self.indexAt(position)
|
||||||
col = idx.column()
|
col = idx.column()
|
||||||
@ -162,8 +165,6 @@ class AddressList(MyTreeView):
|
|||||||
return
|
return
|
||||||
addr = addrs[0]
|
addr = addrs[0]
|
||||||
|
|
||||||
menu = QMenu()
|
|
||||||
if not multi_select:
|
|
||||||
addr_column_title = self.model().horizontalHeaderItem(2).text()
|
addr_column_title = self.model().horizontalHeaderItem(2).text()
|
||||||
addr_idx = idx.sibling(idx.row(), 2)
|
addr_idx = idx.sibling(idx.row(), 2)
|
||||||
|
|
||||||
|
|||||||
@ -57,7 +57,8 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin):
|
|||||||
collapse_info = QPushButton(_("Show report contents"))
|
collapse_info = QPushButton(_("Show report contents"))
|
||||||
collapse_info.clicked.connect(
|
collapse_info.clicked.connect(
|
||||||
lambda: self.msg_box(QMessageBox.NoIcon,
|
lambda: self.msg_box(QMessageBox.NoIcon,
|
||||||
self, _("Report contents"), self.get_report_string()))
|
self, _("Report contents"), self.get_report_string(),
|
||||||
|
rich_text=True))
|
||||||
|
|
||||||
main_box.addWidget(collapse_info)
|
main_box.addWidget(collapse_info)
|
||||||
|
|
||||||
|
|||||||
@ -89,6 +89,7 @@ class HistoryModel(QAbstractItemModel, PrintError):
|
|||||||
self.view = None # type: HistoryList
|
self.view = None # type: HistoryList
|
||||||
self.transactions = OrderedDictWithIndex()
|
self.transactions = OrderedDictWithIndex()
|
||||||
self.tx_status_cache = {} # type: Dict[str, Tuple[int, str]]
|
self.tx_status_cache = {} # type: Dict[str, Tuple[int, str]]
|
||||||
|
self.summary = None
|
||||||
|
|
||||||
def set_view(self, history_list: 'HistoryList'):
|
def set_view(self, history_list: 'HistoryList'):
|
||||||
# FIXME HistoryModel and HistoryList mutually depend on each other.
|
# FIXME HistoryModel and HistoryList mutually depend on each other.
|
||||||
|
|||||||
@ -86,6 +86,7 @@ class StatusBarButton(QPushButton):
|
|||||||
self.clicked.connect(self.onPress)
|
self.clicked.connect(self.onPress)
|
||||||
self.func = func
|
self.func = func
|
||||||
self.setIconSize(QSize(25,25))
|
self.setIconSize(QSize(25,25))
|
||||||
|
self.setCursor(QCursor(Qt.PointingHandCursor))
|
||||||
|
|
||||||
def onPress(self, checked=False):
|
def onPress(self, checked=False):
|
||||||
'''Drops the unwanted PyQt5 "checked" argument'''
|
'''Drops the unwanted PyQt5 "checked" argument'''
|
||||||
@ -610,7 +611,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
|||||||
_("Before reporting a bug, upgrade to the most recent version of Electrum (latest release or git HEAD), and include the version number in your report."),
|
_("Before reporting a bug, upgrade to the most recent version of Electrum (latest release or git HEAD), and include the version number in your report."),
|
||||||
_("Try to explain not only what the bug is, but how it occurs.")
|
_("Try to explain not only what the bug is, but how it occurs.")
|
||||||
])
|
])
|
||||||
self.show_message(msg, title="Electrum - " + _("Reporting Bugs"))
|
self.show_message(msg, title="Electrum - " + _("Reporting Bugs"), rich_text=True)
|
||||||
|
|
||||||
def notify_transactions(self):
|
def notify_transactions(self):
|
||||||
if self.tx_notification_queue.qsize() == 0:
|
if self.tx_notification_queue.qsize() == 0:
|
||||||
@ -1697,7 +1698,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
|||||||
self.invoice_list.update()
|
self.invoice_list.update()
|
||||||
self.do_clear()
|
self.do_clear()
|
||||||
else:
|
else:
|
||||||
parent.show_error(msg)
|
display_msg = _('The server returned an error when broadcasting the transaction.')
|
||||||
|
if msg:
|
||||||
|
display_msg += '\n' + msg
|
||||||
|
parent.show_error(display_msg)
|
||||||
|
|
||||||
WaitingDialog(self, _('Broadcasting transaction...'),
|
WaitingDialog(self, _('Broadcasting transaction...'),
|
||||||
broadcast_thread, broadcast_done, self.on_error)
|
broadcast_thread, broadcast_done, self.on_error)
|
||||||
|
|||||||
@ -190,24 +190,24 @@ class MessageBoxMixin(object):
|
|||||||
parent, title or '',
|
parent, title or '',
|
||||||
msg, buttons=Yes|No, defaultButton=No) == Yes
|
msg, buttons=Yes|No, defaultButton=No) == Yes
|
||||||
|
|
||||||
def show_warning(self, msg, parent=None, title=None):
|
def show_warning(self, msg, parent=None, title=None, **kwargs):
|
||||||
return self.msg_box(QMessageBox.Warning, parent,
|
return self.msg_box(QMessageBox.Warning, parent,
|
||||||
title or _('Warning'), msg)
|
title or _('Warning'), msg, **kwargs)
|
||||||
|
|
||||||
def show_error(self, msg, parent=None):
|
def show_error(self, msg, parent=None, **kwargs):
|
||||||
return self.msg_box(QMessageBox.Warning, parent,
|
return self.msg_box(QMessageBox.Warning, parent,
|
||||||
_('Error'), msg)
|
_('Error'), msg, **kwargs)
|
||||||
|
|
||||||
def show_critical(self, msg, parent=None, title=None):
|
def show_critical(self, msg, parent=None, title=None, **kwargs):
|
||||||
return self.msg_box(QMessageBox.Critical, parent,
|
return self.msg_box(QMessageBox.Critical, parent,
|
||||||
title or _('Critical Error'), msg)
|
title or _('Critical Error'), msg, **kwargs)
|
||||||
|
|
||||||
def show_message(self, msg, parent=None, title=None):
|
def show_message(self, msg, parent=None, title=None, **kwargs):
|
||||||
return self.msg_box(QMessageBox.Information, parent,
|
return self.msg_box(QMessageBox.Information, parent,
|
||||||
title or _('Information'), msg)
|
title or _('Information'), msg, **kwargs)
|
||||||
|
|
||||||
def msg_box(self, icon, parent, title, text, buttons=QMessageBox.Ok,
|
def msg_box(self, icon, parent, title, text, buttons=QMessageBox.Ok,
|
||||||
defaultButton=QMessageBox.NoButton):
|
defaultButton=QMessageBox.NoButton, rich_text=False):
|
||||||
parent = parent or self.top_level_window()
|
parent = parent or self.top_level_window()
|
||||||
if type(icon) is QPixmap:
|
if type(icon) is QPixmap:
|
||||||
d = QMessageBox(QMessageBox.Information, title, str(text), buttons, parent)
|
d = QMessageBox(QMessageBox.Information, title, str(text), buttons, parent)
|
||||||
@ -216,7 +216,12 @@ class MessageBoxMixin(object):
|
|||||||
d = QMessageBox(icon, title, str(text), buttons, parent)
|
d = QMessageBox(icon, title, str(text), buttons, parent)
|
||||||
d.setWindowModality(Qt.WindowModal)
|
d.setWindowModality(Qt.WindowModal)
|
||||||
d.setDefaultButton(defaultButton)
|
d.setDefaultButton(defaultButton)
|
||||||
d.setTextInteractionFlags(Qt.TextSelectableByMouse | Qt.LinksAccessibleByMouse)
|
if rich_text:
|
||||||
|
d.setTextInteractionFlags(Qt.TextSelectableByMouse| Qt.LinksAccessibleByMouse)
|
||||||
|
d.setTextFormat(Qt.RichText)
|
||||||
|
else:
|
||||||
|
d.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||||
|
d.setTextFormat(Qt.PlainText)
|
||||||
return d.exec_()
|
return d.exec_()
|
||||||
|
|
||||||
class WindowModalDialog(QDialog, MessageBoxMixin):
|
class WindowModalDialog(QDialog, MessageBoxMixin):
|
||||||
|
|||||||
@ -206,7 +206,9 @@ class ElectrumGui:
|
|||||||
try:
|
try:
|
||||||
self.network.run_from_another_thread(self.network.broadcast_transaction(tx))
|
self.network.run_from_another_thread(self.network.broadcast_transaction(tx))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(repr(e))
|
display_msg = _('The server returned an error when broadcasting the transaction.')
|
||||||
|
display_msg += '\n' + repr(e)
|
||||||
|
print(display_msg)
|
||||||
else:
|
else:
|
||||||
print(_('Payment sent.'))
|
print(_('Payment sent.'))
|
||||||
#self.do_clear()
|
#self.do_clear()
|
||||||
|
|||||||
@ -15,7 +15,7 @@ from electrum.storage import WalletStorage
|
|||||||
from electrum.network import NetworkParameters
|
from electrum.network import NetworkParameters
|
||||||
from electrum.interface import deserialize_server
|
from electrum.interface import deserialize_server
|
||||||
|
|
||||||
_ = lambda x:x
|
_ = lambda x:x # i18n
|
||||||
|
|
||||||
|
|
||||||
class ElectrumGui:
|
class ElectrumGui:
|
||||||
@ -370,7 +370,9 @@ class ElectrumGui:
|
|||||||
try:
|
try:
|
||||||
self.network.run_from_another_thread(self.network.broadcast_transaction(tx))
|
self.network.run_from_another_thread(self.network.broadcast_transaction(tx))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.show_message(repr(e))
|
display_msg = _('The server returned an error when broadcasting the transaction.')
|
||||||
|
display_msg += '\n' + repr(e)
|
||||||
|
self.show_message(display_msg)
|
||||||
else:
|
else:
|
||||||
self.show_message(_('Payment sent.'))
|
self.show_message(_('Payment sent.'))
|
||||||
self.do_clear()
|
self.do_clear()
|
||||||
|
|||||||
@ -737,6 +737,7 @@ class Network(PrintError):
|
|||||||
timeout = self.get_network_timeout_seconds(NetworkTimeout.Urgent)
|
timeout = self.get_network_timeout_seconds(NetworkTimeout.Urgent)
|
||||||
out = await self.interface.session.send_request('blockchain.transaction.broadcast', [str(tx)], timeout=timeout)
|
out = await self.interface.session.send_request('blockchain.transaction.broadcast', [str(tx)], timeout=timeout)
|
||||||
if out != tx.txid():
|
if out != tx.txid():
|
||||||
|
# note: this is untrusted input from the server
|
||||||
raise Exception(out)
|
raise Exception(out)
|
||||||
return out # txid
|
return out # txid
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from PyQt5.Qt import QVBoxLayout, QLabel
|
from PyQt5.QtWidgets import QVBoxLayout, QLabel
|
||||||
|
|
||||||
from electrum.gui.qt.password_dialog import PasswordLayout, PW_PASSPHRASE
|
from electrum.gui.qt.password_dialog import PasswordLayout, PW_PASSPHRASE
|
||||||
from electrum.gui.qt.util import *
|
from electrum.gui.qt.util import *
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from PyQt5.Qt import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.Qt import QGridLayout, QInputDialog, QPushButton
|
from PyQt5.QtWidgets import QGridLayout, QInputDialog, QPushButton
|
||||||
from PyQt5.Qt import QVBoxLayout, QLabel
|
from PyQt5.QtWidgets import QVBoxLayout, QLabel
|
||||||
|
|
||||||
from electrum.gui.qt.util import *
|
from electrum.gui.qt.util import *
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
|
|||||||
@ -7,7 +7,7 @@ from binascii import hexlify, unhexlify
|
|||||||
|
|
||||||
import websocket
|
import websocket
|
||||||
|
|
||||||
from PyQt5.Qt import QDialog, QLineEdit, QTextEdit, QVBoxLayout, QLabel
|
from PyQt5.QtWidgets import QDialog, QLineEdit, QTextEdit, QVBoxLayout, QLabel
|
||||||
import PyQt5.QtCore as QtCore
|
import PyQt5.QtCore as QtCore
|
||||||
from PyQt5.QtWidgets import *
|
from PyQt5.QtWidgets import *
|
||||||
|
|
||||||
|
|||||||
@ -170,19 +170,22 @@ class Plugin(RevealerPlugin):
|
|||||||
code_id = self.versioned_seed.checksum
|
code_id = self.versioned_seed.checksum
|
||||||
dialog.show_message(''.join([_("{} encrypted for Revealer {}_{} saved as PNG and PDF at: ").format(self.was, version, code_id),
|
dialog.show_message(''.join([_("{} encrypted for Revealer {}_{} saved as PNG and PDF at: ").format(self.was, version, code_id),
|
||||||
"<b>", self.get_path_to_revealer_file(), "</b>", "<br/>",
|
"<b>", self.get_path_to_revealer_file(), "</b>", "<br/>",
|
||||||
"<br/>", "<b>", _("Always check you backups.")]))
|
"<br/>", "<b>", _("Always check you backups.")]),
|
||||||
|
rich_text=True)
|
||||||
dialog.close()
|
dialog.close()
|
||||||
|
|
||||||
def ext_warning(self, dialog):
|
def ext_warning(self, dialog):
|
||||||
dialog.show_message(''.join(["<b>",_("Warning"), ": </b>",
|
dialog.show_message(''.join(["<b>",_("Warning"), ": </b>",
|
||||||
_("your seed extension will <b>not</b> be included in the encrypted backup.")]))
|
_("your seed extension will <b>not</b> be included in the encrypted backup.")]),
|
||||||
|
rich_text=True)
|
||||||
dialog.close()
|
dialog.close()
|
||||||
|
|
||||||
def bdone(self, dialog):
|
def bdone(self, dialog):
|
||||||
version = self.versioned_seed.version
|
version = self.versioned_seed.version
|
||||||
code_id = self.versioned_seed.checksum
|
code_id = self.versioned_seed.checksum
|
||||||
dialog.show_message(''.join([_("Digital Revealer ({}_{}) saved as PNG and PDF at:").format(version, code_id),
|
dialog.show_message(''.join([_("Digital Revealer ({}_{}) saved as PNG and PDF at:").format(version, code_id),
|
||||||
"<br/>","<b>", self.get_path_to_revealer_file(), '</b>']))
|
"<br/>","<b>", self.get_path_to_revealer_file(), '</b>']),
|
||||||
|
rich_text=True)
|
||||||
|
|
||||||
|
|
||||||
def customtxt_limits(self):
|
def customtxt_limits(self):
|
||||||
@ -208,7 +211,8 @@ class Plugin(RevealerPlugin):
|
|||||||
.format(warning=_("Warning"),
|
.format(warning=_("Warning"),
|
||||||
ver0=_("Revealers starting with 0 are not secure due to a vulnerability."),
|
ver0=_("Revealers starting with 0 are not secure due to a vulnerability."),
|
||||||
url=_("More info at: {}").format(f'<a href="{link}">{link}</a>'),
|
url=_("More info at: {}").format(f'<a href="{link}">{link}</a>'),
|
||||||
risk=_("Proceed at your own risk.")))
|
risk=_("Proceed at your own risk.")),
|
||||||
|
rich_text=True)
|
||||||
|
|
||||||
def cypherseed_dialog(self, window):
|
def cypherseed_dialog(self, window):
|
||||||
self.warn_old_revealer()
|
self.warn_old_revealer()
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from PyQt5.Qt import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.Qt import QGridLayout, QInputDialog, QPushButton
|
from PyQt5.QtWidgets import QGridLayout, QInputDialog, QPushButton
|
||||||
from PyQt5.Qt import QVBoxLayout, QLabel
|
from PyQt5.QtWidgets import QVBoxLayout, QLabel
|
||||||
|
|
||||||
from electrum.gui.qt.util import *
|
from electrum.gui.qt.util import *
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from PyQt5.Qt import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.Qt import QGridLayout, QInputDialog, QPushButton
|
from PyQt5.QtWidgets import QGridLayout, QInputDialog, QPushButton
|
||||||
from PyQt5.Qt import QVBoxLayout, QLabel
|
from PyQt5.QtWidgets import QVBoxLayout, QLabel
|
||||||
|
|
||||||
from electrum.gui.qt.util import *
|
from electrum.gui.qt.util import *
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
|
|||||||
@ -45,7 +45,7 @@ from electrum.mnemonic import Mnemonic
|
|||||||
from electrum.wallet import Multisig_Wallet, Deterministic_Wallet
|
from electrum.wallet import Multisig_Wallet, Deterministic_Wallet
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.plugin import BasePlugin, hook
|
from electrum.plugin import BasePlugin, hook
|
||||||
from electrum.util import NotEnoughFunds
|
from electrum.util import NotEnoughFunds, UserFacingException
|
||||||
from electrum.storage import STO_EV_USER_PW
|
from electrum.storage import STO_EV_USER_PW
|
||||||
from electrum.network import Network
|
from electrum.network import Network
|
||||||
|
|
||||||
@ -319,7 +319,13 @@ class Wallet_2fa(Multisig_Wallet):
|
|||||||
otp = int(otp)
|
otp = int(otp)
|
||||||
long_user_id, short_id = self.get_user_id()
|
long_user_id, short_id = self.get_user_id()
|
||||||
raw_tx = tx.serialize()
|
raw_tx = tx.serialize()
|
||||||
r = server.sign(short_id, raw_tx, otp)
|
try:
|
||||||
|
r = server.sign(short_id, raw_tx, otp)
|
||||||
|
except TrustedCoinException as e:
|
||||||
|
if e.status_code == 400: # invalid OTP
|
||||||
|
raise UserFacingException(_('Invalid one-time password.')) from e
|
||||||
|
else:
|
||||||
|
raise
|
||||||
if r:
|
if r:
|
||||||
raw_tx = r.get('transaction')
|
raw_tx = r.get('transaction')
|
||||||
tx.update(raw_tx)
|
tx.update(raw_tx)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
ELECTRUM_VERSION = '3.3.1' # version of the client package
|
ELECTRUM_VERSION = '3.3.2' # version of the client package
|
||||||
APK_VERSION = '3.3.1.0' # read by buildozer.spec
|
APK_VERSION = '3.3.2.0' # read by buildozer.spec
|
||||||
|
|
||||||
PROTOCOL_VERSION = '1.4' # protocol version requested
|
PROTOCOL_VERSION = '1.4' # protocol version requested
|
||||||
|
|
||||||
|
|||||||
BIN
icons/clock1.png
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 7.4 KiB |
BIN
icons/clock2.png
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 8.3 KiB |
BIN
icons/clock3.png
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 7.1 KiB |
BIN
icons/clock4.png
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 7.3 KiB |
BIN
icons/clock5.pdn
Normal file
BIN
icons/clock5.png
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 9.8 KiB |